chore(core): refactor explicit-project-dependencies unit tests (#10317)
This commit is contained in:
parent
f25e94a5dc
commit
a89c360f46
@ -1,223 +1,656 @@
|
||||
import { vol } from 'memfs';
|
||||
import type { Workspace } from '../../config/workspace-json-project-json';
|
||||
import { defaultFileHasher } from '../../hasher/file-hasher';
|
||||
import { createProjectFileMap } from '../file-map-utils';
|
||||
import { ProjectGraphBuilder } from '../project-graph-builder';
|
||||
import { buildExplicitTypeScriptDependencies } from './explicit-project-dependencies';
|
||||
|
||||
jest.mock('fs', () => require('memfs').fs);
|
||||
jest.mock('nx/src/utils/app-root', () => ({
|
||||
workspaceRoot: '/root',
|
||||
}));
|
||||
|
||||
import { vol } from 'memfs';
|
||||
import { buildExplicitTypeScriptDependencies } from './explicit-project-dependencies';
|
||||
import { defaultFileHasher } from '../../hasher/file-hasher';
|
||||
import {
|
||||
ProjectGraphProcessorContext,
|
||||
ProjectGraphProjectNode,
|
||||
} from '../../config/project-graph';
|
||||
import { ProjectGraphBuilder } from '../project-graph-builder';
|
||||
// projectName => tsconfig import path
|
||||
const dependencyProjectNamesToImportPaths = {
|
||||
proj2: '@proj/my-second-proj',
|
||||
proj3a: '@proj/project-3',
|
||||
proj4ab: '@proj/proj4ab',
|
||||
};
|
||||
|
||||
describe('explicit project dependencies', () => {
|
||||
let ctx: ProjectGraphProcessorContext;
|
||||
let projects: Record<string, ProjectGraphProjectNode>;
|
||||
let fsJson;
|
||||
beforeEach(() => {
|
||||
const workspaceJson = {
|
||||
projects: {
|
||||
proj: {
|
||||
root: 'libs/proj',
|
||||
},
|
||||
proj2: {
|
||||
root: 'libs/proj2',
|
||||
},
|
||||
proj3a: {
|
||||
root: 'libs/proj3a',
|
||||
},
|
||||
proj123: {
|
||||
root: 'libs/proj123',
|
||||
},
|
||||
proj1234: {
|
||||
root: 'libs/proj1234',
|
||||
},
|
||||
'proj1234-child': {
|
||||
root: 'libs/proj1234-child',
|
||||
},
|
||||
},
|
||||
};
|
||||
const nxJson = {
|
||||
npmScope: 'proj',
|
||||
};
|
||||
const tsConfig = {
|
||||
compilerOptions: {
|
||||
baseUrl: '.',
|
||||
paths: {
|
||||
'@proj/proj': ['libs/proj/index.ts'],
|
||||
'@proj/my-second-proj': ['libs/proj2/index.ts'],
|
||||
'@proj/project-3': ['libs/proj3a/index.ts'],
|
||||
'@proj/proj123': ['libs/proj123/index.ts'],
|
||||
'@proj/proj1234': ['libs/proj1234/index.ts'],
|
||||
'@proj/proj1234-child': ['libs/proj1234-child/index.ts'],
|
||||
'@proj/proj4ab': ['libs/proj4ab/index.ts'],
|
||||
},
|
||||
},
|
||||
};
|
||||
fsJson = {
|
||||
'./package.json': `{
|
||||
"name": "test",
|
||||
"dependencies": [],
|
||||
"devDependencies": []
|
||||
}`,
|
||||
'./workspace.json': JSON.stringify(workspaceJson),
|
||||
'./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/proj3a/index.ts': `export const a = 3;`,
|
||||
'./libs/proj4ab/index.ts': `export const a = 4;`,
|
||||
'./libs/proj123/index.ts': 'export const a = 5',
|
||||
'./libs/proj1234/index.ts': `export const a = 6
|
||||
import { a } from '@proj/proj1234-child'
|
||||
`,
|
||||
'./libs/proj1234-child/index.ts': 'export const a = 7',
|
||||
'./libs/proj1234/a.b.ts': `// nx-ignore-next-line
|
||||
import('@proj/proj2')
|
||||
/* nx-ignore-next-line */
|
||||
import {a} from '@proj/proj3a
|
||||
`,
|
||||
'./libs/proj1234/b.c.ts': `// nx-ignore-next-line
|
||||
require('@proj/proj4ab#a')
|
||||
// nx-ignore-next-line
|
||||
import('@proj/proj2')
|
||||
/* nx-ignore-next-line */
|
||||
import {a} from '@proj/proj3a
|
||||
const a = {
|
||||
// nx-ignore-next-line
|
||||
loadChildren: '@proj/3a'
|
||||
}
|
||||
const b = {
|
||||
// nx-ignore-next-line
|
||||
loadChildren: '@proj/3a',
|
||||
children: [{
|
||||
// nx-ignore-next-line
|
||||
loadChildren: '@proj/proj2,
|
||||
// nx-ignore-next-line
|
||||
loadChildren: '@proj/proj3a'
|
||||
}]
|
||||
}
|
||||
`,
|
||||
};
|
||||
vol.fromJSON(fsJson, '/root');
|
||||
vol.reset();
|
||||
});
|
||||
|
||||
defaultFileHasher.init();
|
||||
describe('static imports, dynamic imports, and commonjs requires', () => {
|
||||
it('should build explicit dependencies for static imports, and top-level dynamic imports and commonjs requires', () => {
|
||||
const sourceProjectName = 'proj';
|
||||
const { ctx, builder } = createVirtualWorkspace({
|
||||
sourceProjectName,
|
||||
sourceProjectFiles: [
|
||||
{
|
||||
path: 'libs/proj/index.ts',
|
||||
content: `
|
||||
import {a} from '@proj/my-second-proj';
|
||||
await import('@proj/project-3');
|
||||
require('@proj/proj4ab');
|
||||
import * as npmPackage from 'npm-package';
|
||||
`,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
ctx = {
|
||||
const res = buildExplicitTypeScriptDependencies(
|
||||
ctx.workspace,
|
||||
builder.graph,
|
||||
ctx.filesToProcess
|
||||
);
|
||||
|
||||
expect(res).toEqual([
|
||||
{
|
||||
sourceProjectName,
|
||||
sourceProjectFile: 'libs/proj/index.ts',
|
||||
targetProjectName: 'proj2',
|
||||
},
|
||||
{
|
||||
sourceProjectName,
|
||||
sourceProjectFile: 'libs/proj/index.ts',
|
||||
targetProjectName: 'proj3a',
|
||||
},
|
||||
{
|
||||
sourceProjectName,
|
||||
sourceProjectFile: 'libs/proj/index.ts',
|
||||
targetProjectName: 'proj4ab',
|
||||
},
|
||||
{
|
||||
sourceProjectName,
|
||||
sourceProjectFile: 'libs/proj/index.ts',
|
||||
targetProjectName: 'npm:npm-package',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should build explicit dependencies for static exports', () => {
|
||||
const sourceProjectName = 'proj';
|
||||
const { ctx, builder } = createVirtualWorkspace({
|
||||
sourceProjectName,
|
||||
sourceProjectFiles: [
|
||||
{
|
||||
path: 'libs/proj/index.ts',
|
||||
content: `
|
||||
export {a} from '@proj/my-second-proj';
|
||||
export * as project3 from '@proj/project-3';
|
||||
export * from '@proj/proj4ab';
|
||||
`,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const res = buildExplicitTypeScriptDependencies(
|
||||
ctx.workspace,
|
||||
builder.graph,
|
||||
ctx.filesToProcess
|
||||
);
|
||||
|
||||
expect(res).toEqual([
|
||||
{
|
||||
sourceProjectName,
|
||||
sourceProjectFile: 'libs/proj/index.ts',
|
||||
targetProjectName: 'proj2',
|
||||
},
|
||||
{
|
||||
sourceProjectName,
|
||||
sourceProjectFile: 'libs/proj/index.ts',
|
||||
targetProjectName: 'proj3a',
|
||||
},
|
||||
{
|
||||
sourceProjectName,
|
||||
sourceProjectFile: 'libs/proj/index.ts',
|
||||
targetProjectName: 'proj4ab',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it(`should build explicit dependencies for TypeScript's import/export require syntax, and side-effectful import`, () => {
|
||||
const sourceProjectName = 'proj';
|
||||
const { ctx, builder } = createVirtualWorkspace({
|
||||
sourceProjectName,
|
||||
sourceProjectFiles: [
|
||||
{
|
||||
path: 'libs/proj/index.ts',
|
||||
content: `
|
||||
import i = require("@proj/my-second-proj");
|
||||
export import i = require("@proj/project-3");
|
||||
import '@proj/proj4ab';
|
||||
`,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const res = buildExplicitTypeScriptDependencies(
|
||||
ctx.workspace,
|
||||
builder.graph,
|
||||
ctx.filesToProcess
|
||||
);
|
||||
|
||||
expect(res).toEqual([
|
||||
{
|
||||
sourceProjectName,
|
||||
sourceProjectFile: 'libs/proj/index.ts',
|
||||
targetProjectName: 'proj2',
|
||||
},
|
||||
{
|
||||
sourceProjectName,
|
||||
sourceProjectFile: 'libs/proj/index.ts',
|
||||
targetProjectName: 'proj3a',
|
||||
},
|
||||
{
|
||||
sourceProjectName,
|
||||
sourceProjectFile: 'libs/proj/index.ts',
|
||||
targetProjectName: 'proj4ab',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should build explicit dependencies for nested dynamic imports and commonjs requires', () => {
|
||||
const sourceProjectName = 'proj';
|
||||
const { ctx, builder } = createVirtualWorkspace({
|
||||
sourceProjectName,
|
||||
sourceProjectFiles: [
|
||||
{
|
||||
path: 'libs/proj/nested-dynamic-import.ts',
|
||||
content: `
|
||||
async function nestedInAFunction() {
|
||||
await import('@proj/project-3');
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
path: 'libs/proj/nested-require.ts',
|
||||
content: `
|
||||
function nestedInAFunction() {
|
||||
require('@proj/proj4ab');
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
path: 'libs/proj/component.tsx',
|
||||
content: `
|
||||
export function App() {
|
||||
import('@proj/my-second-proj')
|
||||
return (
|
||||
<GlobalStateProvider>
|
||||
<Shell></Shell>
|
||||
</GlobalStateProvider>
|
||||
);
|
||||
}
|
||||
`,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const res = buildExplicitTypeScriptDependencies(
|
||||
ctx.workspace,
|
||||
builder.graph,
|
||||
ctx.filesToProcess
|
||||
);
|
||||
|
||||
expect(res).toEqual([
|
||||
{
|
||||
sourceProjectName,
|
||||
sourceProjectFile: 'libs/proj/component.tsx',
|
||||
targetProjectName: 'proj2',
|
||||
},
|
||||
{
|
||||
sourceProjectName,
|
||||
sourceProjectFile: 'libs/proj/nested-dynamic-import.ts',
|
||||
targetProjectName: 'proj3a',
|
||||
},
|
||||
{
|
||||
sourceProjectName,
|
||||
sourceProjectFile: 'libs/proj/nested-require.ts',
|
||||
targetProjectName: 'proj4ab',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should build explicit dependencies when relative paths are used', () => {
|
||||
const sourceProjectName = 'proj';
|
||||
const { ctx, builder } = createVirtualWorkspace({
|
||||
sourceProjectName,
|
||||
sourceProjectFiles: [
|
||||
{
|
||||
path: 'libs/proj/absolute-path.ts',
|
||||
content: `
|
||||
import('../../libs/proj3a/index.ts');
|
||||
`,
|
||||
},
|
||||
{
|
||||
path: 'libs/proj/relative-path.ts',
|
||||
content: `
|
||||
import('../proj4ab/index.ts');
|
||||
`,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const res = buildExplicitTypeScriptDependencies(
|
||||
ctx.workspace,
|
||||
builder.graph,
|
||||
ctx.filesToProcess
|
||||
);
|
||||
|
||||
expect(res).toEqual([
|
||||
{
|
||||
sourceProjectName,
|
||||
sourceProjectFile: 'libs/proj/absolute-path.ts',
|
||||
targetProjectName: 'proj3a',
|
||||
},
|
||||
{
|
||||
sourceProjectName,
|
||||
sourceProjectFile: 'libs/proj/relative-path.ts',
|
||||
targetProjectName: 'proj4ab',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should not build explicit dependencies when nx-ignore-next-line comments are present', () => {
|
||||
const sourceProjectName = 'proj';
|
||||
const { ctx, builder } = createVirtualWorkspace({
|
||||
sourceProjectName,
|
||||
sourceProjectFiles: [
|
||||
{
|
||||
path: 'libs/proj/static-import-1.ts',
|
||||
content: `
|
||||
// nx-ignore-next-line
|
||||
import {a} from '@proj/my-second-proj';
|
||||
`,
|
||||
},
|
||||
{
|
||||
path: 'libs/proj/static-import-2.ts',
|
||||
content: `
|
||||
/* nx-ignore-next-line */
|
||||
import {a} from '@proj/my-second-proj';
|
||||
`,
|
||||
},
|
||||
{
|
||||
path: 'libs/proj/dynamic-import-1.ts',
|
||||
content: `
|
||||
// nx-ignore-next-line
|
||||
await import('@proj/project-3');
|
||||
`,
|
||||
},
|
||||
{
|
||||
path: 'libs/proj/dynamic-import-2.ts',
|
||||
content: `
|
||||
/* nx-ignore-next-line */
|
||||
await import('@proj/project-3');
|
||||
`,
|
||||
},
|
||||
{
|
||||
path: 'libs/proj/dynamic-import-3.ts',
|
||||
content: `
|
||||
async function nestedInAFunction() {
|
||||
/* nx-ignore-next-line */
|
||||
await import('@proj/project-3');
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
path: 'libs/proj/require-1.ts',
|
||||
content: `
|
||||
// nx-ignore-next-line
|
||||
require('@proj/proj4ab');
|
||||
`,
|
||||
},
|
||||
{
|
||||
path: 'libs/proj/require-2.ts',
|
||||
content: `
|
||||
/* nx-ignore-next-line */
|
||||
require('@proj/proj4ab');
|
||||
`,
|
||||
},
|
||||
{
|
||||
path: 'libs/proj/require-3.ts',
|
||||
content: `
|
||||
function nestedInAFunction() {
|
||||
/* nx-ignore-next-line */
|
||||
require('@proj/proj4ab');
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
path: 'libs/proj/comments-with-excess-whitespace.ts',
|
||||
content: `
|
||||
/*
|
||||
nx-ignore-next-line
|
||||
|
||||
*/
|
||||
require('@proj/proj4ab');
|
||||
// nx-ignore-next-line
|
||||
import('@proj/proj4ab');
|
||||
/*
|
||||
|
||||
nx-ignore-next-line */
|
||||
import { foo } from '@proj/proj4ab';
|
||||
`,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const res = buildExplicitTypeScriptDependencies(
|
||||
ctx.workspace,
|
||||
builder.graph,
|
||||
ctx.filesToProcess
|
||||
);
|
||||
|
||||
expect(res).toEqual([]);
|
||||
});
|
||||
|
||||
it('should not build explicit dependencies for stringified or templatized import/require statements', () => {
|
||||
const sourceProjectName = 'proj';
|
||||
const { ctx, builder } = createVirtualWorkspace({
|
||||
sourceProjectName,
|
||||
sourceProjectFiles: [
|
||||
{
|
||||
path: 'libs/proj/stringified-imports-and-require.ts',
|
||||
content: `
|
||||
"import {a} from '@proj/my-second-proj';";
|
||||
'await import("@proj/my-second-proj");';
|
||||
\`require('@proj/my-second-proj');\`
|
||||
`,
|
||||
},
|
||||
/**
|
||||
* TODO: Refactor usage of Scanner to fix these.
|
||||
*
|
||||
* The use of a template literal before a templatized import/require
|
||||
* currently causes Nx to interpret the import/require as if they were not templatized and were declarared directly
|
||||
* in the source code.
|
||||
*/
|
||||
// Also reported here: https://github.com/nrwl/nx/issues/8938
|
||||
// {
|
||||
// path: 'libs/proj/file-1.ts',
|
||||
// content: `
|
||||
// const npmScope = 'myorg';
|
||||
// console.log(\`@\${npmScope}\`);
|
||||
|
||||
// console.log(\`import {foo} from '@proj/my-second-proj'\`)
|
||||
// `,
|
||||
// },
|
||||
// {
|
||||
// path: 'libs/proj/file-2.ts',
|
||||
// content: `
|
||||
// const v = \`\${val}
|
||||
// \${val}
|
||||
// \${val} \${val}
|
||||
|
||||
// \${val} \${val}
|
||||
|
||||
// \`;
|
||||
// tree.write('/path/to/file.ts', \`import something from "@proj/project-3";\`);
|
||||
// `,
|
||||
// },
|
||||
// {
|
||||
// path: 'libs/proj/file-3.ts',
|
||||
// content: `
|
||||
// \`\${Tree}\`;
|
||||
// \`\`;
|
||||
// \`import { A } from '@proj/my-second-proj'\`;
|
||||
// \`import { B, C, D } from '@proj/project-3'\`;
|
||||
// \`require('@proj/proj4ab')\`;
|
||||
// `,
|
||||
// },
|
||||
// {
|
||||
// path: 'libs/proj/file-4.ts',
|
||||
// // Ensure unterminated template literal does not break project graph creation
|
||||
// content: `
|
||||
// \`\${Tree\`;
|
||||
// \`\`;
|
||||
// \`import { A } from '@proj/my-second-proj'\`;
|
||||
// \`import { B, C, D } from '@proj/project-3'\`;
|
||||
// \`require('@proj/proj4ab')\`;
|
||||
// `,
|
||||
// },
|
||||
],
|
||||
});
|
||||
|
||||
const res = buildExplicitTypeScriptDependencies(
|
||||
ctx.workspace,
|
||||
builder.graph,
|
||||
ctx.filesToProcess
|
||||
);
|
||||
|
||||
expect(res).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* In version 8, Angular deprecated the loadChildren string syntax in favor of using dynamic imports, but it is still
|
||||
* fully supported by the framework:
|
||||
*
|
||||
* https://angular.io/guide/deprecations#loadchildren-string-syntax
|
||||
*/
|
||||
describe('legacy Angular loadChildren string syntax', () => {
|
||||
it('should build explicit dependencies for legacy Angular loadChildren string syntax', () => {
|
||||
const sourceProjectName = 'proj';
|
||||
const { ctx, builder } = createVirtualWorkspace({
|
||||
sourceProjectName,
|
||||
sourceProjectFiles: [
|
||||
{
|
||||
path: 'libs/proj/file-1.ts',
|
||||
content: `
|
||||
const a = { loadChildren: '@proj/proj4ab#a' };
|
||||
`,
|
||||
},
|
||||
{
|
||||
path: 'libs/proj/file-2.ts',
|
||||
content: `
|
||||
const routes: Routes = [{
|
||||
path: 'lazy',
|
||||
loadChildren: '@proj/project-3#LazyModule',
|
||||
}];
|
||||
`,
|
||||
},
|
||||
/**
|
||||
* TODO: This case, where a no subsitution template literal is used, is not working
|
||||
*/
|
||||
// {
|
||||
// path: 'libs/proj/no-substitution-template-literal.ts',
|
||||
// content: `
|
||||
// const a = {
|
||||
// loadChildren: \`@proj/my-second-proj\`
|
||||
// };
|
||||
// `,
|
||||
// },
|
||||
],
|
||||
});
|
||||
|
||||
const res = buildExplicitTypeScriptDependencies(
|
||||
ctx.workspace,
|
||||
builder.graph,
|
||||
ctx.filesToProcess
|
||||
);
|
||||
|
||||
expect(res).toEqual([
|
||||
{
|
||||
sourceProjectName,
|
||||
sourceProjectFile: 'libs/proj/file-1.ts',
|
||||
targetProjectName: 'proj4ab',
|
||||
},
|
||||
{
|
||||
sourceProjectName,
|
||||
sourceProjectFile: 'libs/proj/file-2.ts',
|
||||
targetProjectName: 'proj3a',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should not build explicit dependencies when nx-ignore-next-line comments are present', () => {
|
||||
const sourceProjectName = 'proj';
|
||||
const { ctx, builder } = createVirtualWorkspace({
|
||||
sourceProjectName,
|
||||
sourceProjectFiles: [
|
||||
{
|
||||
path: 'libs/proj/file-1.ts',
|
||||
content: `
|
||||
const a = {
|
||||
// nx-ignore-next-line
|
||||
loadChildren: '@proj/proj4ab#a'
|
||||
};
|
||||
`,
|
||||
},
|
||||
/**
|
||||
* TODO: This case, where a multi-line comment is used, is not working
|
||||
*/
|
||||
// {
|
||||
// path: 'libs/proj/file-2.ts',
|
||||
// content: `
|
||||
// const a = {
|
||||
// /* nx-ignore-next-line */
|
||||
// loadChildren: '@proj/proj4ab#a'
|
||||
// };
|
||||
// `,
|
||||
// },
|
||||
/**
|
||||
* TODO: These cases, where loadChildren is on the same line as the variable declaration, are not working
|
||||
*/
|
||||
// {
|
||||
// path: 'libs/proj/file-3.ts',
|
||||
// content: `
|
||||
// // nx-ignore-next-line
|
||||
// const a = { loadChildren: '@proj/proj4ab#a' };
|
||||
// `,
|
||||
// },
|
||||
// {
|
||||
// path: 'libs/proj/file-4.ts',
|
||||
// content: `
|
||||
// /* nx-ignore-next-line */
|
||||
// const a = { loadChildren: '@proj/proj4ab#a' };
|
||||
// `,
|
||||
// },
|
||||
],
|
||||
});
|
||||
|
||||
const res = buildExplicitTypeScriptDependencies(
|
||||
ctx.workspace,
|
||||
builder.graph,
|
||||
ctx.filesToProcess
|
||||
);
|
||||
|
||||
expect(res).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
interface VirtualWorkspaceConfig {
|
||||
sourceProjectName: string;
|
||||
sourceProjectFiles: {
|
||||
path: string;
|
||||
content: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a minimal workspace and virtual file-system for the given files and dependency
|
||||
* projects in order to be able to execute `buildExplicitTypeScriptDependencies()` in the tests.
|
||||
*/
|
||||
function createVirtualWorkspace(config: VirtualWorkspaceConfig) {
|
||||
const nxJson = {
|
||||
npmScope: 'proj',
|
||||
};
|
||||
const workspaceJson = {
|
||||
projects: {
|
||||
[config.sourceProjectName]: {
|
||||
root: `libs/${config.sourceProjectName}`,
|
||||
},
|
||||
},
|
||||
};
|
||||
const fsJson = {
|
||||
'./package.json': `{
|
||||
"name": "test",
|
||||
"dependencies": {
|
||||
"npm-package": "1.0.0"
|
||||
},
|
||||
"devDependencies": []
|
||||
}`,
|
||||
'./workspace.json': JSON.stringify(workspaceJson),
|
||||
'./nx.json': JSON.stringify(nxJson),
|
||||
...config.sourceProjectFiles.reduce(
|
||||
(acc, file) => ({
|
||||
...acc,
|
||||
[file.path]: file.content,
|
||||
}),
|
||||
{}
|
||||
),
|
||||
};
|
||||
const tsConfig = {
|
||||
compilerOptions: {
|
||||
baseUrl: '.',
|
||||
paths: {
|
||||
[`@proj/${config.sourceProjectName}`]: [
|
||||
`libs/${config.sourceProjectName}/index.ts`,
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const builder = new ProjectGraphBuilder();
|
||||
builder.addNode({
|
||||
name: config.sourceProjectName,
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: `libs/${config.sourceProjectName}`,
|
||||
files: config.sourceProjectFiles.map(({ path }) => ({
|
||||
file: path,
|
||||
})),
|
||||
},
|
||||
});
|
||||
builder.addExternalNode({
|
||||
name: 'npm:npm-package',
|
||||
type: 'npm',
|
||||
data: {
|
||||
version: '1.0.0',
|
||||
packageName: 'npm-package',
|
||||
},
|
||||
});
|
||||
|
||||
for (const [projectName, tsconfigPath] of Object.entries(
|
||||
dependencyProjectNamesToImportPaths
|
||||
)) {
|
||||
fsJson[`libs/${projectName}/index.ts`] = ``;
|
||||
workspaceJson.projects[projectName] = {
|
||||
root: `libs/${projectName}`,
|
||||
};
|
||||
tsConfig.compilerOptions.paths[tsconfigPath] = [
|
||||
`libs/${projectName}/index.ts`,
|
||||
];
|
||||
builder.addNode({
|
||||
name: projectName,
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: `libs/${projectName}`,
|
||||
files: [{ file: `libs/${projectName}/index.ts` }],
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
fsJson['./tsconfig.base.json'] = JSON.stringify(tsConfig);
|
||||
|
||||
vol.fromJSON(fsJson, '/root');
|
||||
|
||||
defaultFileHasher.init();
|
||||
|
||||
return {
|
||||
ctx: {
|
||||
workspace: {
|
||||
...workspaceJson,
|
||||
...nxJson,
|
||||
} as any,
|
||||
} as Workspace,
|
||||
filesToProcess: createProjectFileMap(
|
||||
workspaceJson,
|
||||
defaultFileHasher.allFileData()
|
||||
).projectFileMap,
|
||||
} as any;
|
||||
|
||||
projects = {
|
||||
proj3a: {
|
||||
name: 'proj3a',
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj3a',
|
||||
files: [{ file: 'libs/proj3a/index.ts' }],
|
||||
},
|
||||
},
|
||||
proj2: {
|
||||
name: 'proj2',
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj2',
|
||||
files: [{ file: 'libs/proj2/index.ts' }],
|
||||
},
|
||||
},
|
||||
proj: {
|
||||
name: 'proj',
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj',
|
||||
files: [{ file: 'libs/proj/index.ts' }],
|
||||
},
|
||||
},
|
||||
proj1234: {
|
||||
name: 'proj1234',
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj1234',
|
||||
files: [
|
||||
{ file: 'libs/proj1234/index.ts' },
|
||||
{ file: 'libs/proj1234/a.b.ts' },
|
||||
{ file: 'libs/proj1234/b.c.ts' },
|
||||
],
|
||||
},
|
||||
},
|
||||
proj123: {
|
||||
name: 'proj123',
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj123',
|
||||
files: [{ file: 'libs/proj123/index.ts' }],
|
||||
},
|
||||
},
|
||||
proj4ab: {
|
||||
name: 'proj4ab',
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj4ab',
|
||||
files: [{ file: 'libs/proj4ab/index.ts' }],
|
||||
},
|
||||
},
|
||||
'proj1234-child': {
|
||||
name: 'proj1234-child',
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/proj1234-child',
|
||||
files: [{ file: 'libs/proj1234-child/index.ts' }],
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
it(`should add dependencies for projects based on file imports`, () => {
|
||||
const builder = new ProjectGraphBuilder();
|
||||
Object.values(projects).forEach((p) => {
|
||||
builder.addNode(p);
|
||||
});
|
||||
|
||||
const res = buildExplicitTypeScriptDependencies(
|
||||
ctx.workspace,
|
||||
builder.graph,
|
||||
ctx.filesToProcess
|
||||
);
|
||||
|
||||
expect(res).toEqual([
|
||||
{
|
||||
sourceProjectFile: 'libs/proj/index.ts',
|
||||
sourceProjectName: 'proj',
|
||||
targetProjectName: 'proj2',
|
||||
},
|
||||
{
|
||||
sourceProjectFile: 'libs/proj/index.ts',
|
||||
sourceProjectName: 'proj',
|
||||
targetProjectName: 'proj3a',
|
||||
},
|
||||
{
|
||||
sourceProjectFile: 'libs/proj/index.ts',
|
||||
sourceProjectName: 'proj',
|
||||
targetProjectName: 'proj4ab',
|
||||
},
|
||||
{
|
||||
sourceProjectFile: 'libs/proj1234/index.ts',
|
||||
sourceProjectName: 'proj1234',
|
||||
targetProjectName: 'proj1234-child',
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
},
|
||||
builder,
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user