Skip to content

Commit

Permalink
fix(js): handle nested wildcard imports and paths that start with # (#…
Browse files Browse the repository at this point in the history
…19056)

(cherry picked from commit 4b344ac)
  • Loading branch information
FrozenPandaz committed Sep 7, 2023
1 parent a7bc9d3 commit 2194422
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 136 deletions.
Original file line number Diff line number Diff line change
@@ -1,27 +1,21 @@
import { vol } from 'memfs';
jest.mock('../../../../utils/workspace-root', () => ({
workspaceRoot: '/root',
}));
jest.mock('fs', () => require('memfs').fs);
import { TargetProjectLocator } from './target-project-locator';
import {
ProjectGraphExternalNode,
ProjectGraphProcessorContext,
ProjectGraphProjectNode,
} from '../../../../config/project-graph';

jest.mock('nx/src/utils/workspace-root', () => ({
workspaceRoot: '/root',
}));
jest.mock('fs', () => require('memfs').fs);

describe('findTargetProjectWithImport', () => {
let projects: Record<string, ProjectGraphProjectNode>;
let npmProjects: Record<string, ProjectGraphExternalNode>;
let fsJson;
let targetProjectLocator: TargetProjectLocator;
beforeEach(() => {
const projecstConfigurations = {
projects: {
proj1: {},
},
};
const nxJson = {
npmScope: 'proj',
};
Expand All @@ -44,109 +38,16 @@ describe('findTargetProjectWithImport', () => {
'@proj/proj1234/*': ['libs/proj1234/*'],
'@proj/proj1234-child': ['libs/proj1234-child'],
'@proj/proj1234-child/*': ['libs/proj1234-child/*'],
'#hash-path': ['libs/hash-project/src/index.ts'],
'parent-path/*': ['libs/parent-path/*'],
},
},
};
fsJson = {
'./workspace.json': JSON.stringify(projecstConfigurations),
'./nx.json': JSON.stringify(nxJson),
'./tsconfig.base.json': JSON.stringify(tsConfig),
'./libs/proj/index.ts': `import {a} from '@proj/my-second-proj';
import('@proj/project-3');
const a = { loadChildren: '@proj/proj4ab#a' };
`,
'./libs/proj2/index.ts': `export const a = 2;`,
'./libs/proj2/deep/index.ts': `export const a = 22;`,
'./libs/proj3a/index.ts': `export const a = 3;`,
'./libs/proj4ab/index.ts': `export const a = 4;`,
'./libs/proj5/index.ts': `export const a = 5;`,
'./libs/proj6/index.ts': `export const a = 6;`,
'./libs/proj7/index.ts': `export const a = 7;`,
'./libs/proj123/index.ts': 'export const a = 123',
'./libs/proj1234/index.ts': 'export const a = 1234',
'./libs/proj1234-child/index.ts': 'export const a = 12345',
};
vol.fromJSON(fsJson, '/root');

const ctx = {
workspace: {
...projecstConfigurations,
...nxJson,
} as any,
fileMap: {
rootProj: [
{
file: 'index.ts',
hash: 'some-hash',
},
],
proj: [
{
file: 'libs/proj/index.ts',
hash: 'some-hash',
},
],
proj2: [
{
file: 'libs/proj2/index.ts',
hash: 'some-hash',
},
{
file: 'libs/proj2/deep/index.ts',
hash: 'some-hash',
},
],
proj3a: [
{
file: 'libs/proj3a/index.ts',
hash: 'some-hash',
},
],
proj4ab: [
{
file: 'libs/proj4ab/index.ts',
hash: 'some-hash',
},
],
proj5: [
{
file: 'libs/proj5/index.ts',
hash: 'some-hash',
},
],
proj6: [
{
file: 'libs/proj6/index.ts',
hash: 'some-hash',
},
],
proj7: [
{
file: 'libs/proj7/index.ts',
hash: 'some-hash',
},
],
proj123: [
{
file: 'libs/proj123/index.ts',
hash: 'some-hash',
},
],
proj1234: [
{
file: 'libs/proj1234/index.ts',
hash: 'some-hash',
},
],
'proj1234-child': [
{
file: 'libs/proj1234-child/index.ts',
hash: 'some-hash',
},
],
},
} as any;

projects = {
rootProj: {
name: 'rootProj',
Expand Down Expand Up @@ -225,6 +126,27 @@ describe('findTargetProjectWithImport', () => {
root: 'libs/proj1234-child',
},
},
'hash-project': {
name: 'hash-project',
type: 'lib',
data: {
root: 'libs/hash-project',
},
},
'parent-project': {
name: 'parent-project',
type: 'lib',
data: {
root: 'libs/parent-path',
},
},
'child-project': {
name: 'child-project',
type: 'lib',
data: {
root: 'libs/parent-path/child-path',
},
},
};
npmProjects = {
'npm:@ng/core': {
Expand Down Expand Up @@ -380,7 +302,7 @@ describe('findTargetProjectWithImport', () => {
expect(parentProj).toEqual('proj1234');
});

it('should be able to npm dependencies', () => {
it('should be able to locate npm dependencies', () => {
const result1 = targetProjectLocator.findProjectWithImport(
'@ng/core',
'libs/proj1/index.ts'
Expand All @@ -394,14 +316,31 @@ describe('findTargetProjectWithImport', () => {
expect(result2).toEqual('npm:npm-package');
});

it('should be able to resolve a module using a normalized path', () => {
const proj4ab = targetProjectLocator.findProjectWithImport(
'@proj/proj4ab#a',
it('should be able to resolve wildcard paths', () => {
const parentProject = targetProjectLocator.findProjectWithImport(
'parent-path',
'libs/proj1/index.ts'
);

expect(parentProject).toEqual('parent-project');

const childProject = targetProjectLocator.findProjectWithImport(
'parent-path/child-path',
'libs/proj1/index.ts'
);

expect(childProject).toEqual('child-project');
});

it('should be able to resolve paths that start with a #', () => {
const proj = targetProjectLocator.findProjectWithImport(
'#hash-path',
'libs/proj1/index.ts'
);

expect(proj4ab).toEqual('proj4ab');
expect(proj).toEqual('hash-project');
});

it('should be able to resolve a modules when npm packages exist', () => {
const proj5 = targetProjectLocator.findProjectWithImport(
'@proj/proj5',
Expand Down Expand Up @@ -785,14 +724,6 @@ describe('findTargetProjectWithImport (without tsconfig.json)', () => {
expect(result2).toEqual('npm:npm-package');
});

it('should be able to resolve a module using a normalized path', () => {
const proj4ab = targetProjectLocator.findProjectWithImport(
'@proj/proj4ab#a',
'libs/proj1/index.ts'
);

expect(proj4ab).toEqual('proj4ab');
});
it('should be able to resolve paths that have similar names', () => {
const proj = targetProjectLocator.findProjectWithImport(
'@proj/proj123',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
resolveModuleByImport,
} from '../../utils/typescript';
import { isRelativePath, readJsonFile } from '../../../../utils/fileutils';
import { dirname, join, posix } from 'path';
import { dirname, join, posix, relative, resolve } from 'path';
import { workspaceRoot } from '../../../../utils/workspace-root';
import {
ProjectGraphExternalNode,
Expand Down Expand Up @@ -40,33 +40,33 @@ export class TargetProjectLocator {
* @param filePath
*/
findProjectWithImport(importExpr: string, filePath: string): string {
const normalizedImportExpr = importExpr.split('#')[0];
if (isRelativePath(normalizedImportExpr)) {
const resolvedModule = posix.join(
dirname(filePath),
normalizedImportExpr
);
if (isRelativePath(importExpr)) {
const resolvedModule = posix.join(dirname(filePath), importExpr);
return this.findProjectOfResolvedModule(resolvedModule);
}

// find project using tsconfig paths
const paths = this.findPaths(normalizedImportExpr);
if (paths) {
const results = this.findPaths(importExpr);
if (results) {
const [path, paths] = results;
for (let p of paths) {
const maybeResolvedProject = this.findProjectOfResolvedModule(p);
const r = p.endsWith('/*')
? join(dirname(p), relative(path.replace(/\*$/, ''), importExpr))
: p;
const maybeResolvedProject = this.findProjectOfResolvedModule(r);
if (maybeResolvedProject) {
return maybeResolvedProject;
}
}
}

if (builtInModuleSet.has(normalizedImportExpr)) {
this.npmResolutionCache.set(normalizedImportExpr, null);
if (builtInModuleSet.has(importExpr)) {
this.npmResolutionCache.set(importExpr, null);
return null;
}

// try to find npm package before using expensive typescript resolution
const npmProject = this.findNpmPackage(normalizedImportExpr);
const npmProject = this.findNpmPackage(importExpr);
if (npmProject) {
return npmProject;
}
Expand All @@ -76,7 +76,7 @@ export class TargetProjectLocator {
// and existed only because of the incomplete `paths` matching
// if import cannot be matched using tsconfig `paths` the compilation would fail anyway
const resolvedProject = this.resolveImportWithTypescript(
normalizedImportExpr,
importExpr,
filePath
);
if (resolvedProject) {
Expand All @@ -86,15 +86,15 @@ export class TargetProjectLocator {

try {
const resolvedModule = this.resolveImportWithRequire(
normalizedImportExpr,
importExpr,
filePath
);

return this.findProjectOfResolvedModule(resolvedModule);
} catch {}

// nothing found, cache for later
this.npmResolutionCache.set(normalizedImportExpr, null);
this.npmResolutionCache.set(importExpr, null);
return null;
}

Expand All @@ -108,7 +108,7 @@ export class TargetProjectLocator {
return undefined;
}
if (this.paths[normalizedImportExpr]) {
return this.paths[normalizedImportExpr];
return [normalizedImportExpr, this.paths[normalizedImportExpr]];
}
const wildcardPath = Object.keys(this.paths).find(
(path) =>
Expand All @@ -117,7 +117,7 @@ export class TargetProjectLocator {
normalizedImportExpr === path.replace(/\/\*$/, ''))
);
if (wildcardPath) {
return this.paths[wildcardPath];
return [wildcardPath, this.paths[wildcardPath]];
}
return undefined;
}
Expand Down

0 comments on commit 2194422

Please sign in to comment.