Skip to content

Commit

Permalink
fix(js): do not depend on nx for typescript utils (#16642)
Browse files Browse the repository at this point in the history
  • Loading branch information
FrozenPandaz authored Apr 28, 2023
1 parent 6e745f8 commit feef647
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 22 deletions.
4 changes: 1 addition & 3 deletions packages/devkit/src/utils/module-federation/share.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@ import type {
import { AdditionalSharedConfig, SharedFunction } from './models';
import { dirname, join, normalize } from 'path';
import { readRootPackageJson } from './package-json';
import { readTsPathMappings } from './typescript';
import { readTsPathMappings, getRootTsConfigPath } from './typescript';
import {
collectPackageSecondaryEntryPoints,
collectWorkspaceLibrarySecondaryEntryPoints,
} from './secondary-entry-points';
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
import { getRootTsConfigPath } from 'nx/src/plugins/js/utils/typescript';
import type { ProjectGraph } from 'nx/src/config/project-graph';
import { requireNx } from '../../../nx';

Expand Down
24 changes: 21 additions & 3 deletions packages/devkit/src/utils/module-federation/typescript.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { existsSync } from 'fs';
import { ParsedCommandLine } from 'typescript';
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
import { getRootTsConfigPath } from 'nx/src/plugins/js/utils/typescript';
import { dirname } from 'path';
import { dirname, join } from 'path';
import { requireNx } from '../../../nx';

const { workspaceRoot } = requireNx();

let tsConfig: ParsedCommandLine;
let tsPathMappings: ParsedCommandLine['options']['paths'];
Expand Down Expand Up @@ -48,3 +49,20 @@ export function readTsConfig(tsConfigPath: string): ParsedCommandLine {
dirname(tsConfigPath)
);
}

export function getRootTsConfigPath(): string | null {
const tsConfigFileName = getRootTsConfigFileName();

return tsConfigFileName ? join(workspaceRoot, tsConfigFileName) : null;
}

function getRootTsConfigFileName(): string | null {
for (const tsConfigName of ['tsconfig.base.json', 'tsconfig.json']) {
const tsConfigPath = join(workspaceRoot, tsConfigName);
if (existsSync(tsConfigPath)) {
return tsConfigName;
}
}

return null;
}
5 changes: 0 additions & 5 deletions packages/js/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,3 @@ export {
} from 'nx/src/plugins/js/lock-file/lock-file';
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
export { createPackageJson } from 'nx/src/plugins/js/package-json/create-package-json';
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
export {
findNodes,
getRootTsConfigPath,
} from 'nx/src/plugins/js/utils/typescript';
3 changes: 1 addition & 2 deletions packages/js/src/internal.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
export { resolveModuleByImport } from 'nx/src/plugins/js/utils/typescript';
export { resolveModuleByImport } from './utils/typescript/ast-utils';
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
export {
registerTsProject,
Expand Down
112 changes: 110 additions & 2 deletions packages/js/src/utils/typescript/ast-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,85 @@ import type { Tree } from '@nx/devkit';
import type * as ts from 'typescript';
// TODO(colum): replace when https:/nrwl/nx/pull/15497 is merged
import { getSourceNodes } from '@nx/workspace/src/utilities/typescript';
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
import { findNodes } from 'nx/src/plugins/js/utils/typescript';
import { ensureTypescript } from './ensure-typescript';
import { Node, SyntaxKind } from 'typescript';
import { workspaceRoot } from '@nx/devkit';
import { dirname } from 'path';

const normalizedAppRoot = workspaceRoot.replace(/\\/g, '/');

let tsModule: typeof import('typescript');

let compilerHost: {
host: ts.CompilerHost;
options: ts.CompilerOptions;
moduleResolutionCache: ts.ModuleResolutionCache;
};

/**
* Find a module based on its import
*
* @param importExpr Import used to resolve to a module
* @param filePath
* @param tsConfigPath
*/
export function resolveModuleByImport(
importExpr: string,
filePath: string,
tsConfigPath: string
) {
compilerHost = compilerHost || getCompilerHost(tsConfigPath);
const { options, host, moduleResolutionCache } = compilerHost;

const { resolvedModule } = tsModule.resolveModuleName(
importExpr,
filePath,
options,
host,
moduleResolutionCache
);

if (!resolvedModule) {
return;
} else {
return resolvedModule.resolvedFileName.replace(`${normalizedAppRoot}/`, '');
}
}

function getCompilerHost(tsConfigPath: string) {
const options = readTsConfigOptions(tsConfigPath);
const host = tsModule.createCompilerHost(options, true);
const moduleResolutionCache = tsModule.createModuleResolutionCache(
workspaceRoot,
host.getCanonicalFileName
);
return { options, host, moduleResolutionCache };
}

function readTsConfigOptions(tsConfigPath: string) {
if (!tsModule) {
tsModule = require('typescript');
}

const readResult = tsModule.readConfigFile(
tsConfigPath,
tsModule.sys.readFile
);

// we don't need to scan the files, we only care about options
const host: Partial<ts.ParseConfigHost> = {
readDirectory: () => [],
readFile: () => '',
fileExists: tsModule.sys.fileExists,
};

return tsModule.parseJsonConfigFileContent(
readResult.config,
host as ts.ParseConfigHost,
dirname(tsConfigPath)
).options;
}

function nodesByPosition(first: ts.Node, second: ts.Node): number {
return first.getStart() - second.getStart();
}
Expand Down Expand Up @@ -345,3 +418,38 @@ export function findClass(

return clazz;
}

export function findNodes(
node: Node,
kind: SyntaxKind | SyntaxKind[],
max = Infinity
): Node[] {
if (!node || max == 0) {
return [];
}

const arr: Node[] = [];
const hasMatch = Array.isArray(kind)
? kind.includes(node.kind)
: node.kind === kind;
if (hasMatch) {
arr.push(node);
max--;
}
if (max > 0) {
for (const child of node.getChildren()) {
findNodes(child, kind, max).forEach((node) => {
if (max > 0) {
arr.push(node);
}
max--;
});

if (max <= 0) {
break;
}
}
}

return arr;
}
14 changes: 7 additions & 7 deletions packages/js/src/utils/typescript/ts-config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
import {
joinPathFragments,
offsetFromRoot,
Tree,
updateJson,
workspaceRoot,
} from '@nx/devkit';
import { offsetFromRoot, Tree, updateJson, workspaceRoot } from '@nx/devkit';
import { existsSync } from 'fs';
import { dirname, join } from 'path';

Expand Down Expand Up @@ -42,6 +36,12 @@ export function getRelativePathToRootTsConfig(
return offsetFromRoot(targetPath) + getRootTsConfigPathInTree(tree);
}

export function getRootTsConfigPath(): string | null {
const tsConfigFileName = getRootTsConfigFileName();

return tsConfigFileName ? join(workspaceRoot, tsConfigFileName) : null;
}

export function getRootTsConfigFileName(tree?: Tree): string | null {
for (const tsConfigName of ['tsconfig.base.json', 'tsconfig.json']) {
const pathExists = tree
Expand Down

1 comment on commit feef647

@vercel
Copy link

@vercel vercel bot commented on feef647 Apr 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nx-dev – ./

nx-five.vercel.app
nx.dev
nx-dev-nrwl.vercel.app
nx-dev-git-master-nrwl.vercel.app

Please sign in to comment.