diff --git a/packages/angular/src/migrations/update-10-5-0/add-template-support-and-presets-to-eslint.spec.ts b/packages/angular/src/migrations/update-10-5-0/add-template-support-and-presets-to-eslint.spec.ts index b17f44b49e..30f7cdb5ff 100644 --- a/packages/angular/src/migrations/update-10-5-0/add-template-support-and-presets-to-eslint.spec.ts +++ b/packages/angular/src/migrations/update-10-5-0/add-template-support-and-presets-to-eslint.spec.ts @@ -6,6 +6,16 @@ import { } from '@nrwl/workspace'; import { callRule, createEmptyWorkspace } from '@nrwl/workspace/testing'; import { runMigration } from '../../utils/testing'; +import { + DependencyType, + ProjectGraph, +} from '@nrwl/workspace/src/core/project-graph'; + +let projectGraph: ProjectGraph; +jest.mock('@nrwl/workspace/src/core/project-graph', () => ({ + ...jest.requireActual('@nrwl/workspace/src/core/project-graph'), + createProjectGraph: jest.fn().mockImplementation(() => projectGraph), +})); describe('add-template-support-and-presets-to-eslint', () => { describe('tslint-only workspace', () => { @@ -71,6 +81,66 @@ describe('add-template-support-and-presets-to-eslint', () => { }), tree ); + + projectGraph = { + nodes: { + app1: { + name: 'app1', + type: 'app', + data: { + files: [], + root: 'apps/app1', + }, + }, + app2: { + name: 'app2', + type: 'app', + data: { + files: [], + root: 'apps/app2', + }, + }, + lib1: { + name: 'lib1', + type: 'app', + data: { + files: [], + root: 'apps/lib1', + }, + }, + 'npm:@angular/core': { + name: 'npm:@angular/core', + type: 'npm', + data: { + files: [], + }, + }, + }, + dependencies: { + app1: [ + { + type: DependencyType.static, + source: 'app1', + target: 'npm:@angular/core', + }, + ], + app2: [ + { + type: DependencyType.static, + source: 'app2', + target: 'npm:@angular/core', + }, + ], + lib1: [ + { + type: DependencyType.static, + source: 'lib1', + target: 'npm:@angular/core', + }, + ], + 'npm:@angular/core': [], + }, + }; }); it('should do nothing', async () => { diff --git a/packages/angular/src/migrations/update-10-5-0/add-template-support-and-presets-to-eslint.ts b/packages/angular/src/migrations/update-10-5-0/add-template-support-and-presets-to-eslint.ts index 6b462c364a..2029b64aee 100644 --- a/packages/angular/src/migrations/update-10-5-0/add-template-support-and-presets-to-eslint.ts +++ b/packages/angular/src/migrations/update-10-5-0/add-template-support-and-presets-to-eslint.ts @@ -11,7 +11,7 @@ import { } from '@nrwl/workspace'; import { join } from 'path'; import { offsetFromRoot } from '@nrwl/devkit'; -import { getFullProjectGraphFromHost } from '@nrwl/workspace/src/utils/ast-utils'; +import { createProjectGraph } from '@nrwl/workspace/src/core/project-graph'; /** * It was decided with Jason that we would do a simple replacement in this migration @@ -40,7 +40,7 @@ function addHTMLPatternToBuilderConfig( } function updateProjectESLintConfigsAndBuilders(host: Tree): Rule { - const graph = getFullProjectGraphFromHost(host); + const graph = createProjectGraph(undefined, undefined, undefined, false); /** * Make sure user is already using ESLint and is up to date with diff --git a/packages/eslint-plugin-nx/tests/rules/enforce-module-boundaries.spec.ts b/packages/eslint-plugin-nx/tests/rules/enforce-module-boundaries.spec.ts index afd182e35e..db1436684d 100644 --- a/packages/eslint-plugin-nx/tests/rules/enforce-module-boundaries.spec.ts +++ b/packages/eslint-plugin-nx/tests/rules/enforce-module-boundaries.spec.ts @@ -13,7 +13,7 @@ import enforceModuleBoundaries, { import { TargetProjectLocator } from '@nrwl/workspace/src/core/target-project-locator'; import { readFileSync } from 'fs'; jest.mock('fs', () => require('memfs').fs); -jest.mock('@nrwl/workspace/src/utils/app-root', () => ({ +jest.mock('../../../workspace/src/utilities/app-root', () => ({ appRootPath: '/root', })); @@ -1166,8 +1166,7 @@ function runRule( (global as any).npmScope = 'mycompany'; (global as any).projectGraph = projectGraph; (global as any).targetProjectLocator = new TargetProjectLocator( - projectGraph.nodes, - (path) => readFileSync(join('/root', path)).toString() + projectGraph.nodes ); const config = { diff --git a/packages/react/src/migrations/update-9-4-0/babelrc-9-4-0.spec.ts b/packages/react/src/migrations/update-9-4-0/babelrc-9-4-0.spec.ts index 1e93e25e53..376052a194 100644 --- a/packages/react/src/migrations/update-9-4-0/babelrc-9-4-0.spec.ts +++ b/packages/react/src/migrations/update-9-4-0/babelrc-9-4-0.spec.ts @@ -3,6 +3,16 @@ import { SchematicTestRunner } from '@angular-devkit/schematics/testing'; import * as path from 'path'; import { createEmptyWorkspace } from '@nrwl/workspace/testing'; import { createApp, createLib, createWebApp } from '../utils/testing'; +import { + DependencyType, + ProjectGraph, +} from '@nrwl/workspace/src/core/project-graph'; + +let projectGraph: ProjectGraph; +jest.mock('@nrwl/workspace/src/core/project-graph', () => ({ + ...jest.requireActual('@nrwl/workspace/src/core/project-graph'), + createProjectGraph: jest.fn().mockImplementation(() => projectGraph), +})); describe('Migrate babel setup', () => { let tree: Tree; @@ -24,6 +34,51 @@ describe('Migrate babel setup', () => { }, }) ); + projectGraph = { + nodes: { + demo: { + name: 'demo', + type: 'app', + data: { + root: 'apps/demo', + files: [], + }, + }, + ui: { + name: 'ui', + type: 'lib', + data: { + root: 'libs/ui', + files: [], + }, + }, + 'npm:react': { + name: 'npm:react', + type: 'npm', + data: { + files: [], + packageName: 'react', + }, + }, + }, + dependencies: { + demo: [ + { + type: DependencyType.static, + source: 'demo', + target: 'npm:react', + }, + ], + ui: [ + { + type: DependencyType.static, + source: 'ui', + target: 'npm:react', + }, + ], + 'npm:react': [], + }, + }; }); it(`should create .babelrc for projects without them`, async () => { @@ -54,6 +109,8 @@ describe('Migrate babel setup', () => { it(`should not migrate non-React projects`, async () => { tree = await createWebApp(tree, 'demo'); + projectGraph.dependencies.demo = []; + tree = await schematicRunner .runSchematicAsync('babelrc-9.4.0', {}, tree) .toPromise(); diff --git a/packages/react/src/migrations/update-9-4-0/babelrc-9-4-0.ts b/packages/react/src/migrations/update-9-4-0/babelrc-9-4-0.ts index 1183236485..37ce5df73f 100644 --- a/packages/react/src/migrations/update-9-4-0/babelrc-9-4-0.ts +++ b/packages/react/src/migrations/update-9-4-0/babelrc-9-4-0.ts @@ -4,13 +4,13 @@ import { SchematicContext, Tree, } from '@angular-devkit/schematics'; -import { getFullProjectGraphFromHost } from '@nrwl/workspace/src/utils/ast-utils'; import { stripIndent, stripIndents, } from '@angular-devkit/core/src/utils/literals'; import { initRootBabelConfig } from '../utils/rules'; import { addDepsToPackageJson, formatFiles } from '@nrwl/workspace'; +import { createProjectGraph } from '@nrwl/workspace/src/core/project-graph'; let addedEmotionPreset = false; @@ -25,7 +25,12 @@ export default function update(): Rule { return (host: Tree, context: SchematicContext) => { const updates = []; const conflicts: Array<[string, string]> = []; - const projectGraph = getFullProjectGraphFromHost(host); + const projectGraph = createProjectGraph( + undefined, + undefined, + undefined, + false + ); if (host.exists('/babel.config.json')) { context.logger.info( ` diff --git a/packages/web/src/migrations/update-11-5-2/create-babelrc-for-workspace-libs.spec.ts b/packages/web/src/migrations/update-11-5-2/create-babelrc-for-workspace-libs.spec.ts index 70868dc241..0567c172ec 100644 --- a/packages/web/src/migrations/update-11-5-2/create-babelrc-for-workspace-libs.spec.ts +++ b/packages/web/src/migrations/update-11-5-2/create-babelrc-for-workspace-libs.spec.ts @@ -1,6 +1,16 @@ import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; import { readJson, Tree } from '@nrwl/devkit'; import { createBabelrcForWorkspaceLibs } from './create-babelrc-for-workspace-libs'; +import { + DependencyType, + ProjectGraph, +} from '@nrwl/workspace/src/core/project-graph'; + +let projectGraph: ProjectGraph; +jest.mock('@nrwl/workspace/src/core/project-graph', () => ({ + ...jest.requireActual('@nrwl/workspace/src/core/project-graph'), + createProjectGraph: jest.fn().mockImplementation(() => projectGraph), +})); describe('Create missing .babelrc files', () => { let tree: Tree; @@ -53,6 +63,52 @@ describe('Create missing .babelrc files', () => { ); tree.write('apps/webapp/index.ts', `import '@proj/weblib';`); + projectGraph = { + nodes: { + webapp: { + name: 'webapp', + type: 'app', + data: { + files: [], + root: 'apps/webapp', + }, + }, + nodeapp: { + name: 'nodeapp', + type: 'app', + data: { + files: [], + root: 'apps/nodeapp', + }, + }, + weblib: { + name: 'weblib', + type: 'lib', + data: { + files: [], + root: 'libs/weblib', + }, + }, + nodelib: { + name: 'nodelib', + type: 'lib', + data: { + files: [], + root: 'libs/nodelib', + }, + }, + }, + dependencies: { + webapp: [ + { + type: DependencyType.static, + source: 'webapp', + target: 'weblib', + }, + ], + }, + }; + await createBabelrcForWorkspaceLibs(tree); expect(readJson(tree, 'libs/weblib/.babelrc')).toMatchObject({ diff --git a/packages/web/src/migrations/update-11-5-2/create-babelrc-for-workspace-libs.ts b/packages/web/src/migrations/update-11-5-2/create-babelrc-for-workspace-libs.ts index 6599c68e74..a754aeba00 100644 --- a/packages/web/src/migrations/update-11-5-2/create-babelrc-for-workspace-libs.ts +++ b/packages/web/src/migrations/update-11-5-2/create-babelrc-for-workspace-libs.ts @@ -1,11 +1,15 @@ import { formatFiles, getProjects, Tree } from '@nrwl/devkit'; -import { reverse } from '@nrwl/workspace/src/core/project-graph'; -import { createProjectGraphFromTree } from '@nrwl/workspace/src/utilities/create-project-graph-from-tree'; -import { hasDependentAppUsingWebBuild } from '@nrwl/web/src/migrations/update-11-5-2/utils'; +import { + createProjectGraph, + reverse, +} from '@nrwl/workspace/src/core/project-graph'; +import { hasDependentAppUsingWebBuild } from './utils'; export async function createBabelrcForWorkspaceLibs(host: Tree) { const projects = getProjects(host); - const graph = reverse(createProjectGraphFromTree(host)); + const graph = reverse( + createProjectGraph(undefined, undefined, undefined, false) + ); for (const [name, p] of projects.entries()) { if (!hasDependentAppUsingWebBuild(name, graph, projects)) { diff --git a/packages/workspace/src/core/project-graph/build-dependencies/build-dependencies.ts b/packages/workspace/src/core/project-graph/build-dependencies/build-dependencies.ts index 3a3c7d48f9..62961502d1 100644 --- a/packages/workspace/src/core/project-graph/build-dependencies/build-dependencies.ts +++ b/packages/workspace/src/core/project-graph/build-dependencies/build-dependencies.ts @@ -3,13 +3,11 @@ import { ProjectGraphContext, ProjectGraphNodeRecords, } from '../project-graph-models'; -import { FileRead } from '../../file-utils'; export interface BuildDependencies { ( ctx: ProjectGraphContext, nodes: ProjectGraphNodeRecords, - addDependency: AddProjectDependency, - fileRead: FileRead + addDependency: AddProjectDependency ): void; } diff --git a/packages/workspace/src/core/project-graph/build-dependencies/explicit-package-json-dependencies.spec.ts b/packages/workspace/src/core/project-graph/build-dependencies/explicit-package-json-dependencies.spec.ts index d9013520d4..196309542e 100644 --- a/packages/workspace/src/core/project-graph/build-dependencies/explicit-package-json-dependencies.spec.ts +++ b/packages/workspace/src/core/project-graph/build-dependencies/explicit-package-json-dependencies.spec.ts @@ -1,5 +1,5 @@ import { buildExplicitPackageJsonDependencies } from '@nrwl/workspace/src/core/project-graph/build-dependencies/explicit-package-json-dependencies'; -import { fs, vol } from 'memfs'; +import { vol } from 'memfs'; import { AddProjectDependency, DependencyType, @@ -8,7 +8,6 @@ import { } from '../project-graph-models'; import { createProjectFileMap } from '../../file-graph'; import { readWorkspaceFiles } from '../../file-utils'; -import { appRootPath } from '../../../utilities/app-root'; jest.mock('../../../utilities/app-root', () => ({ appRootPath: '/root', @@ -107,9 +106,7 @@ describe('explicit package json dependencies', () => { } ); - buildExplicitPackageJsonDependencies(ctx, projects, addDependency, (s) => { - return fs.readFileSync(`${appRootPath}/${s}`).toString(); - }); + buildExplicitPackageJsonDependencies(ctx, projects, addDependency); expect(dependencyMap).toEqual({ proj: [ diff --git a/packages/workspace/src/core/project-graph/build-dependencies/explicit-package-json-dependencies.ts b/packages/workspace/src/core/project-graph/build-dependencies/explicit-package-json-dependencies.ts index 58bf0c0cf0..dde9a84452 100644 --- a/packages/workspace/src/core/project-graph/build-dependencies/explicit-package-json-dependencies.ts +++ b/packages/workspace/src/core/project-graph/build-dependencies/explicit-package-json-dependencies.ts @@ -4,20 +4,19 @@ import { ProjectGraphContext, ProjectGraphNodeRecords, } from '../project-graph-models'; -import { FileRead } from '../../file-utils'; +import { defaultFileRead } from '../../file-utils'; import { parseJsonWithComments } from '@nrwl/workspace/src/utilities/fileutils'; import { joinPathFragments } from '@nrwl/devkit'; export function buildExplicitPackageJsonDependencies( ctx: ProjectGraphContext, nodes: ProjectGraphNodeRecords, - addDependency: AddProjectDependency, - fileRead: FileRead + addDependency: AddProjectDependency ) { Object.keys(ctx.fileMap).forEach((source) => { Object.values(ctx.fileMap[source]).forEach((f) => { if (isPackageJsonAtProjectRoot(nodes, f.file)) { - processPackageJson(source, f.file, nodes, addDependency, fileRead); + processPackageJson(source, f.file, nodes, addDependency); } }); }); @@ -38,11 +37,10 @@ function processPackageJson( sourceProject: string, fileName: string, nodes: ProjectGraphNodeRecords, - addDependency: AddProjectDependency, - fileRead: FileRead + addDependency: AddProjectDependency ) { try { - const deps = readDeps(parseJsonWithComments(fileRead(fileName))); + const deps = readDeps(parseJsonWithComments(defaultFileRead(fileName))); deps.forEach((d) => { // package.json refers to another project in the monorepo if (nodes[d]) { diff --git a/packages/workspace/src/core/project-graph/build-dependencies/explicit-project-dependencies.spec.ts b/packages/workspace/src/core/project-graph/build-dependencies/explicit-project-dependencies.spec.ts index 9a885472c8..3ce22df367 100644 --- a/packages/workspace/src/core/project-graph/build-dependencies/explicit-project-dependencies.spec.ts +++ b/packages/workspace/src/core/project-graph/build-dependencies/explicit-project-dependencies.spec.ts @@ -196,9 +196,7 @@ describe('explicit project dependencies', () => { } ); - buildExplicitTypeScriptDependencies(ctx, projects, addDependency, (s) => { - return fs.readFileSync(`${appRootPath}/${s}`).toString(); - }); + buildExplicitTypeScriptDependencies(ctx, projects, addDependency); expect(dependencyMap).toEqual({ proj1234: [ diff --git a/packages/workspace/src/core/project-graph/build-dependencies/explicit-project-dependencies.ts b/packages/workspace/src/core/project-graph/build-dependencies/explicit-project-dependencies.ts index 6d6137d157..f83e080154 100644 --- a/packages/workspace/src/core/project-graph/build-dependencies/explicit-project-dependencies.ts +++ b/packages/workspace/src/core/project-graph/build-dependencies/explicit-project-dependencies.ts @@ -6,16 +6,14 @@ import { } from '../project-graph-models'; import { TypeScriptImportLocator } from './typescript-import-locator'; import { TargetProjectLocator } from '../../target-project-locator'; -import { FileRead } from '../../file-utils'; export function buildExplicitTypeScriptDependencies( ctx: ProjectGraphContext, nodes: ProjectGraphNodeRecords, - addDependency: AddProjectDependency, - fileRead: FileRead + addDependency: AddProjectDependency ) { - const importLocator = new TypeScriptImportLocator(fileRead); - const targetProjectLocator = new TargetProjectLocator(nodes, fileRead); + const importLocator = new TypeScriptImportLocator(); + const targetProjectLocator = new TargetProjectLocator(nodes); Object.keys(ctx.fileMap).forEach((source) => { Object.values(ctx.fileMap[source]).forEach((f) => { importLocator.fromFile( diff --git a/packages/workspace/src/core/project-graph/build-dependencies/typescript-import-locator.ts b/packages/workspace/src/core/project-graph/build-dependencies/typescript-import-locator.ts index e35fc03bdb..441b068b37 100644 --- a/packages/workspace/src/core/project-graph/build-dependencies/typescript-import-locator.ts +++ b/packages/workspace/src/core/project-graph/build-dependencies/typescript-import-locator.ts @@ -2,14 +2,14 @@ import type * as ts from 'typescript'; import * as path from 'path'; import { DependencyType } from '../project-graph-models'; import { stripSourceCode } from '../../../utilities/strip-source-code'; -import { FileRead } from '../../file-utils'; +import { defaultFileRead } from '../../file-utils'; let tsModule: any; export class TypeScriptImportLocator { private readonly scanner: ts.Scanner; - constructor(private readonly fileRead: FileRead) { + constructor() { tsModule = require('typescript'); this.scanner = tsModule.createScanner(tsModule.ScriptTarget.Latest, false); } @@ -31,7 +31,7 @@ export class TypeScriptImportLocator { ) { return; } - const content = this.fileRead(filePath); + const content = defaultFileRead(filePath); const strippedContent = stripSourceCode(this.scanner, content); if (strippedContent !== '') { const tsFile = tsModule.createSourceFile( diff --git a/packages/workspace/src/core/project-graph/build-nodes/build-nodes.ts b/packages/workspace/src/core/project-graph/build-nodes/build-nodes.ts index aa5b205174..2e5cbd2467 100644 --- a/packages/workspace/src/core/project-graph/build-nodes/build-nodes.ts +++ b/packages/workspace/src/core/project-graph/build-nodes/build-nodes.ts @@ -1,6 +1,5 @@ import { AddProjectNode, ProjectGraphContext } from '../project-graph-models'; -import { FileRead } from '../../file-utils'; export interface BuildNodes { - (ctx: ProjectGraphContext, addNode: AddProjectNode, fileRead: FileRead): void; + (ctx: ProjectGraphContext, addNode: AddProjectNode): void; } diff --git a/packages/workspace/src/core/project-graph/build-nodes/npm-packages.ts b/packages/workspace/src/core/project-graph/build-nodes/npm-packages.ts index 827e7be752..a76ee9d179 100644 --- a/packages/workspace/src/core/project-graph/build-nodes/npm-packages.ts +++ b/packages/workspace/src/core/project-graph/build-nodes/npm-packages.ts @@ -1,13 +1,14 @@ import * as stripJsonComments from 'strip-json-comments'; -import { ProjectGraphContext, AddProjectNode } from '../project-graph-models'; -import { FileRead } from '../../file-utils'; +import { AddProjectNode, ProjectGraphContext } from '../project-graph-models'; +import { defaultFileRead } from '../../file-utils'; export function buildNpmPackageNodes( ctx: ProjectGraphContext, - addNode: AddProjectNode, - fileRead: FileRead + addNode: AddProjectNode ) { - const packageJson = JSON.parse(stripJsonComments(fileRead('package.json'))); + const packageJson = JSON.parse( + stripJsonComments(defaultFileRead('package.json')) + ); const deps = { ...packageJson.dependencies, ...packageJson.devDependencies, diff --git a/packages/workspace/src/core/project-graph/build-nodes/workspace-projects.ts b/packages/workspace/src/core/project-graph/build-nodes/workspace-projects.ts index 3f5dc1b6f3..cf38434538 100644 --- a/packages/workspace/src/core/project-graph/build-nodes/workspace-projects.ts +++ b/packages/workspace/src/core/project-graph/build-nodes/workspace-projects.ts @@ -1,9 +1,11 @@ import { AddProjectNode, ProjectGraphContext } from '../project-graph-models'; -import { FileRead } from '../../file-utils'; +import { defaultFileRead } from '../../file-utils'; -function convertNpmScriptsToTargets(projectRoot: string, fileRead: FileRead) { +function convertNpmScriptsToTargets(projectRoot: string) { try { - const packageJsonString = fileRead(`${projectRoot}/package.json`); + const packageJsonString = defaultFileRead( + `${projectRoot}/package.json` + ).toString(); const parsedPackagedJson = JSON.parse(packageJsonString); const res = {}; // handle no scripts @@ -21,52 +23,53 @@ function convertNpmScriptsToTargets(projectRoot: string, fileRead: FileRead) { } } -export function buildWorkspaceProjectNodes(fileRead: FileRead) { - return (ctx: ProjectGraphContext, addNode: AddProjectNode) => { - const toAdd = []; +export function buildWorkspaceProjectNodes( + ctx: ProjectGraphContext, + addNode: AddProjectNode +) { + const toAdd = []; - Object.keys(ctx.fileMap).forEach((key) => { - const p = ctx.workspaceJson.projects[key]; - if (!p.targets) { - p.targets = convertNpmScriptsToTargets(p.root, fileRead); - } + Object.keys(ctx.fileMap).forEach((key) => { + const p = ctx.workspaceJson.projects[key]; + if (!p.targets) { + p.targets = convertNpmScriptsToTargets(p.root); + } - // TODO, types and projectType should allign - const projectType = - p.projectType === 'application' - ? key.endsWith('-e2e') - ? 'e2e' - : 'app' - : 'lib'; - const tags = - ctx.nxJson.projects && ctx.nxJson.projects[key] - ? ctx.nxJson.projects[key].tags || [] - : []; + // TODO, types and projectType should allign + const projectType = + p.projectType === 'application' + ? key.endsWith('-e2e') + ? 'e2e' + : 'app' + : 'lib'; + const tags = + ctx.nxJson.projects && ctx.nxJson.projects[key] + ? ctx.nxJson.projects[key].tags || [] + : []; - toAdd.push({ - name: key, - type: projectType, - data: { - ...p, - tags, - files: ctx.fileMap[key], - }, - }); + toAdd.push({ + name: key, + type: projectType, + data: { + ...p, + tags, + files: ctx.fileMap[key], + }, }); + }); - // Sort by root directory length (do we need this?) - toAdd.sort((a, b) => { - if (!a.data.root) return -1; - if (!b.data.root) return -1; - return a.data.root.length > b.data.root.length ? -1 : 1; - }); + // Sort by root directory length (do we need this?) + toAdd.sort((a, b) => { + if (!a.data.root) return -1; + if (!b.data.root) return -1; + return a.data.root.length > b.data.root.length ? -1 : 1; + }); - toAdd.forEach((n) => { - addNode({ - name: n.name, - type: n.type, - data: n.data, - }); + toAdd.forEach((n) => { + addNode({ + name: n.name, + type: n.type, + data: n.data, }); - }; + }); } diff --git a/packages/workspace/src/core/project-graph/project-graph.ts b/packages/workspace/src/core/project-graph/project-graph.ts index e36062c271..dbc05278a6 100644 --- a/packages/workspace/src/core/project-graph/project-graph.ts +++ b/packages/workspace/src/core/project-graph/project-graph.ts @@ -1,9 +1,7 @@ import { assertWorkspaceValidity } from '../assert-workspace-validity'; import { createProjectFileMap, ProjectFileMap } from '../file-graph'; import { - defaultFileRead, FileData, - FileRead, filesChanged, readNxJson, readWorkspaceFiles, @@ -37,7 +35,6 @@ export function createProjectGraph( workspaceJson = readWorkspaceJson(), nxJson = readNxJson(), workspaceFiles = readWorkspaceFiles(), - fileRead: FileRead = defaultFileRead, cache: false | ProjectGraphCache = readCache(), shouldCache: boolean = true ): ProjectGraph { @@ -63,7 +60,6 @@ export function createProjectGraph( }; const projectGraph = buildProjectGraph( ctx, - fileRead, diff.partiallyConstructedProjectGraph ); if (shouldCache) { @@ -76,7 +72,7 @@ export function createProjectGraph( nxJson: normalizedNxJson, fileMap: projectFileMap, }; - const projectGraph = buildProjectGraph(ctx, fileRead, null); + const projectGraph = buildProjectGraph(ctx, null); if (shouldCache) { writeCache(rootFiles, projectGraph); } @@ -97,13 +93,12 @@ function buildProjectGraph( workspaceJson: any; fileMap: ProjectFileMap; }, - fileRead: FileRead, projectGraph: ProjectGraph ) { performance.mark('build project graph:start'); const builder = new ProjectGraphBuilder(projectGraph); const buildNodesFns: BuildNodes[] = [ - buildWorkspaceProjectNodes(fileRead), + buildWorkspaceProjectNodes, buildNpmPackageNodes, ]; const buildDependenciesFns: BuildDependencies[] = [ @@ -111,9 +106,9 @@ function buildProjectGraph( buildImplicitProjectDependencies, buildExplicitPackageJsonDependencies, ]; - buildNodesFns.forEach((f) => f(ctx, builder.addNode.bind(builder), fileRead)); + buildNodesFns.forEach((f) => f(ctx, builder.addNode.bind(builder))); buildDependenciesFns.forEach((f) => - f(ctx, builder.nodes, builder.addDependency.bind(builder), fileRead) + f(ctx, builder.nodes, builder.addDependency.bind(builder)) ); const r = builder.build(); performance.mark('build project graph:end'); diff --git a/packages/workspace/src/core/target-project-locator.ts b/packages/workspace/src/core/target-project-locator.ts index 36611d784b..a1309c10ae 100644 --- a/packages/workspace/src/core/target-project-locator.ts +++ b/packages/workspace/src/core/target-project-locator.ts @@ -1,5 +1,5 @@ import { resolveModuleByImport } from '../utilities/typescript'; -import { defaultFileRead, FileRead, normalizedProjectRoot } from './file-utils'; +import { defaultFileRead, normalizedProjectRoot } from './file-utils'; import { ProjectGraphNode, ProjectGraphNodeRecords, @@ -31,15 +31,12 @@ export class TargetProjectLocator { private npmProjects = this.sortedProjects.filter(isNpmProject); private tsConfigPath = this.getRootTsConfigPath(); private absTsConfigPath = join(appRootPath, this.tsConfigPath); - private paths = parseJsonWithComments(this.fileRead(this.tsConfigPath)) + private paths = parseJsonWithComments(defaultFileRead(this.tsConfigPath)) ?.compilerOptions?.paths; private typescriptResolutionCache = new Map(); private npmResolutionCache = new Map(); - constructor( - private nodes: ProjectGraphNodeRecords, - private fileRead: FileRead = defaultFileRead - ) {} + constructor(private nodes: ProjectGraphNodeRecords) {} /** * Find a project based on its import @@ -132,7 +129,7 @@ export class TargetProjectLocator { private getRootTsConfigPath() { try { - this.fileRead('tsconfig.base.json'); + defaultFileRead('tsconfig.base.json'); return 'tsconfig.base.json'; } catch (e) { return 'tsconfig.json'; diff --git a/packages/workspace/src/generators/remove/lib/check-dependencies.spec.ts b/packages/workspace/src/generators/remove/lib/check-dependencies.spec.ts index 2926bccc86..ba1b09265b 100644 --- a/packages/workspace/src/generators/remove/lib/check-dependencies.spec.ts +++ b/packages/workspace/src/generators/remove/lib/check-dependencies.spec.ts @@ -7,6 +7,12 @@ import { Schema } from '../schema'; import { checkDependencies } from './check-dependencies'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; import { libraryGenerator } from '../../library/library'; +import { DependencyType, ProjectGraph } from '../../../core/project-graph'; +let projectGraph: ProjectGraph; +jest.mock('../../../core/project-graph', () => ({ + ...jest.requireActual('../../../core/project-graph'), + createProjectGraph: jest.fn().mockImplementation(() => projectGraph), +})); describe('checkDependencies', () => { let tree: Tree; @@ -27,6 +33,36 @@ describe('checkDependencies', () => { await libraryGenerator(tree, { name: 'my-source', }); + + projectGraph = { + nodes: { + 'my-source': { + name: 'my-source', + type: 'lib', + data: { + files: [], + root: 'libs/my-source', + }, + }, + 'my-dependent': { + name: 'my-dependent', + type: 'lib', + data: { + files: [], + root: 'libs/my-dependent', + }, + }, + }, + dependencies: { + 'my-source': [ + { + type: DependencyType.static, + source: 'my-dependent', + target: 'my-source', + }, + ], + }, + }; }); describe('static dependencies', () => { @@ -90,6 +126,10 @@ describe('checkDependencies', () => { }); it('should not error if there are no dependents', async () => { + projectGraph = { + nodes: projectGraph.nodes, + dependencies: {}, + }; expect(() => { checkDependencies(tree, schema); }).not.toThrow(); diff --git a/packages/workspace/src/generators/remove/lib/check-dependencies.ts b/packages/workspace/src/generators/remove/lib/check-dependencies.ts index c144efa96b..84a0fc7da3 100644 --- a/packages/workspace/src/generators/remove/lib/check-dependencies.ts +++ b/packages/workspace/src/generators/remove/lib/check-dependencies.ts @@ -1,37 +1,39 @@ -import { Tree } from '@nrwl/devkit'; import { + createProjectGraph, onlyWorkspaceProjects, ProjectGraph, reverse, } from '../../../core/project-graph'; import { Schema } from '../schema'; -import { createProjectGraphFromTree } from '../../../utilities/create-project-graph-from-tree'; /** * Check whether the project to be removed is depended on by another project * * Throws an error if the project is in use, unless the `--forceRemove` option is used. */ -export function checkDependencies(tree: Tree, schema: Schema) { +export function checkDependencies(_, schema: Schema) { if (schema.forceRemove) { return; } - const graph: ProjectGraph = createProjectGraphFromTree(tree); + const graph: ProjectGraph = createProjectGraph( + undefined, + undefined, + undefined, + false + ); const reverseGraph = onlyWorkspaceProjects(reverse(graph)); const deps = reverseGraph.dependencies[schema.projectName] || []; - if (deps.length === 0) { - return; + if (deps.length > 0) { + throw new Error( + `${ + schema.projectName + } is still depended on by the following projects:\n${deps + .map((x) => x.target) + .join('\n')}` + ); } - - throw new Error( - `${ - schema.projectName - } is still depended on by the following projects:\n${deps - .map((x) => x.target) - .join('\n')}` - ); } diff --git a/packages/workspace/src/tslint/nxEnforceModuleBoundariesRule.spec.ts b/packages/workspace/src/tslint/nxEnforceModuleBoundariesRule.spec.ts index 73da20a3e8..619a6b1677 100644 --- a/packages/workspace/src/tslint/nxEnforceModuleBoundariesRule.spec.ts +++ b/packages/workspace/src/tslint/nxEnforceModuleBoundariesRule.spec.ts @@ -1068,9 +1068,7 @@ function runRule( `${process.cwd()}/proj`, 'mycompany', projectGraph, - new TargetProjectLocator(projectGraph.nodes, (path) => - readFileSync(join('/root', path)).toString() - ) + new TargetProjectLocator(projectGraph.nodes) ); return rule.apply(sourceFile); } diff --git a/packages/workspace/src/utilities/create-project-graph-from-tree.ts b/packages/workspace/src/utilities/create-project-graph-from-tree.ts index ad07f94da2..ff13ab364e 100644 --- a/packages/workspace/src/utilities/create-project-graph-from-tree.ts +++ b/packages/workspace/src/utilities/create-project-graph-from-tree.ts @@ -1,37 +1,10 @@ -import { - getWorkspacePath, - readJson, - Tree, - visitNotIgnoredFiles, -} from '@nrwl/devkit'; +import { Tree } from '@nrwl/devkit'; import { createProjectGraph } from '../core/project-graph/project-graph'; -import { FileData } from '../core/file-utils'; -import { extname } from 'path'; +// TODO(v13): remove this deprecated method +/** + * @deprecated This method is deprecated and is synonymous to {@link createProjectGraph}() + */ export function createProjectGraphFromTree(tree: Tree) { - const workspaceJson = readJson(tree, getWorkspacePath(tree)); - const nxJson = readJson(tree, 'nx.json'); - - const files: FileData[] = []; - - visitNotIgnoredFiles(tree, '', (file) => { - files.push({ - file, - ext: extname(file), - hash: '', - }); - }); - - const readFile = (path) => { - return tree.read(path).toString('utf-8'); - }; - - return createProjectGraph( - workspaceJson, - nxJson, - files, - readFile, - false, - false - ); + return createProjectGraph(undefined, undefined, undefined, false); } diff --git a/packages/workspace/src/utils/ast-utils.ts b/packages/workspace/src/utils/ast-utils.ts index a2156ca5e7..80d0df025b 100644 --- a/packages/workspace/src/utils/ast-utils.ts +++ b/packages/workspace/src/utils/ast-utils.ts @@ -26,7 +26,7 @@ import { onlyWorkspaceProjects, ProjectGraph, } from '../core/project-graph'; -import { FileData, FileRead } from '../core/file-utils'; +import { FileData } from '../core/file-utils'; import { extname, join, normalize, Path } from '@angular-devkit/core'; import { NxJson, NxJsonProjectConfig } from '../core/shared-interfaces'; import { addInstallTask } from './rules/add-install-task'; @@ -357,57 +357,27 @@ export function readJsonInTree(host: Tree, path: string): T { } } +// TODO(v13): remove this deprecated method /** + * @deprecated This method is deprecated and is synonymous to {@link onlyWorkspaceProjects}({@link createProjectGraph}()) * Method for utilizing the project graph in schematics */ export function getProjectGraphFromHost(host: Tree): ProjectGraph { - return onlyWorkspaceProjects(getFullProjectGraphFromHost(host)); + return onlyWorkspaceProjects(createProjectGraph()); } +// TODO(v13): remove this deprecated method +/** + * @deprecated This method is deprecated and is synonymous to {@link createProjectGraph}() + */ export function getFullProjectGraphFromHost(host: Tree): ProjectGraph { - const workspaceJson = readJsonInTree(host, getWorkspacePath(host)); - const nxJson = readJsonInTree(host, '/nx.json'); - - const fileRead: FileRead = (f: string) => { - try { - return host.read(f).toString(); - } catch (e) { - throw new Error(`${f} does not exist`); - } - }; - - const workspaceFiles: FileData[] = []; - - workspaceFiles.push( - ...allFilesInDirInHost(host, normalize(''), { recursive: false }).map((f) => - getFileDataInHost(host, f) - ) - ); - workspaceFiles.push( - ...allFilesInDirInHost(host, normalize('tools')).map((f) => - getFileDataInHost(host, f) - ) - ); - - // Add files for workspace projects - Object.keys(workspaceJson.projects).forEach((projectName) => { - const project = workspaceJson.projects[projectName]; - workspaceFiles.push( - ...allFilesInDirInHost(host, normalize(project.root)).map((f) => - getFileDataInHost(host, f) - ) - ); - }); - - return createProjectGraph( - workspaceJson, - nxJson, - workspaceFiles, - fileRead, - false - ); + return createProjectGraph(undefined, undefined, undefined, false); } +// TODO(v13): remove this deprecated method +/** + * @deprecated This method is deprecated + */ export function getFileDataInHost(host: Tree, path: Path): FileData { return { file: path, diff --git a/packages/workspace/src/utils/rules/rename-package-imports.ts b/packages/workspace/src/utils/rules/rename-package-imports.ts index 1bb8a6ede3..4e41246736 100644 --- a/packages/workspace/src/utils/rules/rename-package-imports.ts +++ b/packages/workspace/src/utils/rules/rename-package-imports.ts @@ -1,70 +1,49 @@ import * as ts from 'typescript'; -import { SchematicContext, Tree } from '@angular-devkit/schematics'; -import { getWorkspace } from '@nrwl/workspace'; import { - getFullProjectGraphFromHost, + chain, + SchematicContext, + Tree, + Rule, +} from '@angular-devkit/schematics'; +import { getWorkspace, visitNotIgnoredFiles } from '@nrwl/workspace'; +import { findNodes, insert, ReplaceChange, } from '@nrwl/workspace/src/utils/ast-utils'; +import { normalize } from '@angular-devkit/core'; export interface PackageNameMapping { [packageName: string]: string; } -const getProjectNamesWithDepsToRename = ( - packageNameMapping: PackageNameMapping, - tree: Tree -) => { - const packagesToRename = Object.entries(packageNameMapping); - const projectGraph = getFullProjectGraphFromHost(tree); - - return Object.entries(projectGraph.dependencies) - .filter(([, deps]) => - deps.some( - (dep) => - dep.type === 'static' && - packagesToRename.some( - ([packageName]) => packageName === dep.target.replace('npm:', '') - ) - ) - ) - .map(([projectName]) => projectName); -}; - /** * Updates all the imports found in the workspace * * @param packageNameMapping The packageNameMapping provided to the schematic */ -export function renamePackageImports(packageNameMapping: PackageNameMapping) { - return async (tree: Tree, _context: SchematicContext): Promise => { +export function renamePackageImports( + packageNameMapping: PackageNameMapping +): Rule { + return async (tree: Tree, _context: SchematicContext) => { const workspace = await getWorkspace(tree); - const projectNamesThatImportAPackageToRename = getProjectNamesWithDepsToRename( - packageNameMapping, - tree - ); - - const projectsThatImportPackage = [...workspace.projects].filter(([name]) => - projectNamesThatImportAPackageToRename.includes(name) - ); - - projectsThatImportPackage - .map(([, definition]) => tree.getDir(definition.root)) - .forEach((projectDir) => { - projectDir.visit((file) => { - // only look at .(j|t)s(x) files + const rules = []; + workspace.projects.forEach((project) => { + rules.push( + visitNotIgnoredFiles((file) => { if (!/([jt])sx?$/.test(file)) { return; } - // if it doesn't contain at least 1 reference to the packages to be renamed bail out + const contents = tree.read(file).toString('utf-8'); - if ( - !Object.keys(packageNameMapping).some((packageName) => - contents.includes(packageName) - ) - ) { + const fileIncludesPackageToRename = Object.keys( + packageNameMapping + ).some((packageName) => { + return contents.includes(packageName); + }); + + if (!fileIncludesPackageToRename) { return; } @@ -107,7 +86,10 @@ export function renamePackageImports(packageNameMapping: PackageNameMapping) { // update the file in the tree insert(tree, file, changes); } - }); - }); + }, normalize(project.root)) + ); + }); + + return chain(rules); }; }