feat(core): remove readFile argument from createProjectGraph (#5206)
* feat(core): deprecate creating a project graph from a host * feat(core): remove readFile argument from createProjectGraph
This commit is contained in:
parent
4dac0a2122
commit
bfb194843f
@ -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 () => {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 = {
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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(
|
||||
`
|
||||
|
||||
@ -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({
|
||||
|
||||
@ -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)) {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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: [
|
||||
|
||||
@ -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]) {
|
||||
|
||||
@ -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: [
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@ -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');
|
||||
|
||||
@ -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<string, string | null>();
|
||||
private npmResolutionCache = new Map<string, string | null>();
|
||||
|
||||
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';
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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')}`
|
||||
);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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<T = any>(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<NxJson>(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,
|
||||
|
||||
@ -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<void> => {
|
||||
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);
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user