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';
|
} from '@nrwl/workspace';
|
||||||
import { callRule, createEmptyWorkspace } from '@nrwl/workspace/testing';
|
import { callRule, createEmptyWorkspace } from '@nrwl/workspace/testing';
|
||||||
import { runMigration } from '../../utils/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('add-template-support-and-presets-to-eslint', () => {
|
||||||
describe('tslint-only workspace', () => {
|
describe('tslint-only workspace', () => {
|
||||||
@ -71,6 +81,66 @@ describe('add-template-support-and-presets-to-eslint', () => {
|
|||||||
}),
|
}),
|
||||||
tree
|
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 () => {
|
it('should do nothing', async () => {
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import {
|
|||||||
} from '@nrwl/workspace';
|
} from '@nrwl/workspace';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { offsetFromRoot } from '@nrwl/devkit';
|
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
|
* 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 {
|
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
|
* 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 { TargetProjectLocator } from '@nrwl/workspace/src/core/target-project-locator';
|
||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
jest.mock('fs', () => require('memfs').fs);
|
jest.mock('fs', () => require('memfs').fs);
|
||||||
jest.mock('@nrwl/workspace/src/utils/app-root', () => ({
|
jest.mock('../../../workspace/src/utilities/app-root', () => ({
|
||||||
appRootPath: '/root',
|
appRootPath: '/root',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -1166,8 +1166,7 @@ function runRule(
|
|||||||
(global as any).npmScope = 'mycompany';
|
(global as any).npmScope = 'mycompany';
|
||||||
(global as any).projectGraph = projectGraph;
|
(global as any).projectGraph = projectGraph;
|
||||||
(global as any).targetProjectLocator = new TargetProjectLocator(
|
(global as any).targetProjectLocator = new TargetProjectLocator(
|
||||||
projectGraph.nodes,
|
projectGraph.nodes
|
||||||
(path) => readFileSync(join('/root', path)).toString()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
|
|||||||
@ -3,6 +3,16 @@ import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
import { createEmptyWorkspace } from '@nrwl/workspace/testing';
|
||||||
import { createApp, createLib, createWebApp } from '../utils/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', () => {
|
describe('Migrate babel setup', () => {
|
||||||
let tree: Tree;
|
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 () => {
|
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 () => {
|
it(`should not migrate non-React projects`, async () => {
|
||||||
tree = await createWebApp(tree, 'demo');
|
tree = await createWebApp(tree, 'demo');
|
||||||
|
|
||||||
|
projectGraph.dependencies.demo = [];
|
||||||
|
|
||||||
tree = await schematicRunner
|
tree = await schematicRunner
|
||||||
.runSchematicAsync('babelrc-9.4.0', {}, tree)
|
.runSchematicAsync('babelrc-9.4.0', {}, tree)
|
||||||
.toPromise();
|
.toPromise();
|
||||||
|
|||||||
@ -4,13 +4,13 @@ import {
|
|||||||
SchematicContext,
|
SchematicContext,
|
||||||
Tree,
|
Tree,
|
||||||
} from '@angular-devkit/schematics';
|
} from '@angular-devkit/schematics';
|
||||||
import { getFullProjectGraphFromHost } from '@nrwl/workspace/src/utils/ast-utils';
|
|
||||||
import {
|
import {
|
||||||
stripIndent,
|
stripIndent,
|
||||||
stripIndents,
|
stripIndents,
|
||||||
} from '@angular-devkit/core/src/utils/literals';
|
} from '@angular-devkit/core/src/utils/literals';
|
||||||
import { initRootBabelConfig } from '../utils/rules';
|
import { initRootBabelConfig } from '../utils/rules';
|
||||||
import { addDepsToPackageJson, formatFiles } from '@nrwl/workspace';
|
import { addDepsToPackageJson, formatFiles } from '@nrwl/workspace';
|
||||||
|
import { createProjectGraph } from '@nrwl/workspace/src/core/project-graph';
|
||||||
|
|
||||||
let addedEmotionPreset = false;
|
let addedEmotionPreset = false;
|
||||||
|
|
||||||
@ -25,7 +25,12 @@ export default function update(): Rule {
|
|||||||
return (host: Tree, context: SchematicContext) => {
|
return (host: Tree, context: SchematicContext) => {
|
||||||
const updates = [];
|
const updates = [];
|
||||||
const conflicts: Array<[string, string]> = [];
|
const conflicts: Array<[string, string]> = [];
|
||||||
const projectGraph = getFullProjectGraphFromHost(host);
|
const projectGraph = createProjectGraph(
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
false
|
||||||
|
);
|
||||||
if (host.exists('/babel.config.json')) {
|
if (host.exists('/babel.config.json')) {
|
||||||
context.logger.info(
|
context.logger.info(
|
||||||
`
|
`
|
||||||
|
|||||||
@ -1,6 +1,16 @@
|
|||||||
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||||
import { readJson, Tree } from '@nrwl/devkit';
|
import { readJson, Tree } from '@nrwl/devkit';
|
||||||
import { createBabelrcForWorkspaceLibs } from './create-babelrc-for-workspace-libs';
|
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', () => {
|
describe('Create missing .babelrc files', () => {
|
||||||
let tree: Tree;
|
let tree: Tree;
|
||||||
@ -53,6 +63,52 @@ describe('Create missing .babelrc files', () => {
|
|||||||
);
|
);
|
||||||
tree.write('apps/webapp/index.ts', `import '@proj/weblib';`);
|
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);
|
await createBabelrcForWorkspaceLibs(tree);
|
||||||
|
|
||||||
expect(readJson(tree, 'libs/weblib/.babelrc')).toMatchObject({
|
expect(readJson(tree, 'libs/weblib/.babelrc')).toMatchObject({
|
||||||
|
|||||||
@ -1,11 +1,15 @@
|
|||||||
import { formatFiles, getProjects, Tree } from '@nrwl/devkit';
|
import { formatFiles, getProjects, Tree } from '@nrwl/devkit';
|
||||||
import { reverse } from '@nrwl/workspace/src/core/project-graph';
|
import {
|
||||||
import { createProjectGraphFromTree } from '@nrwl/workspace/src/utilities/create-project-graph-from-tree';
|
createProjectGraph,
|
||||||
import { hasDependentAppUsingWebBuild } from '@nrwl/web/src/migrations/update-11-5-2/utils';
|
reverse,
|
||||||
|
} from '@nrwl/workspace/src/core/project-graph';
|
||||||
|
import { hasDependentAppUsingWebBuild } from './utils';
|
||||||
|
|
||||||
export async function createBabelrcForWorkspaceLibs(host: Tree) {
|
export async function createBabelrcForWorkspaceLibs(host: Tree) {
|
||||||
const projects = getProjects(host);
|
const projects = getProjects(host);
|
||||||
const graph = reverse(createProjectGraphFromTree(host));
|
const graph = reverse(
|
||||||
|
createProjectGraph(undefined, undefined, undefined, false)
|
||||||
|
);
|
||||||
|
|
||||||
for (const [name, p] of projects.entries()) {
|
for (const [name, p] of projects.entries()) {
|
||||||
if (!hasDependentAppUsingWebBuild(name, graph, projects)) {
|
if (!hasDependentAppUsingWebBuild(name, graph, projects)) {
|
||||||
|
|||||||
@ -3,13 +3,11 @@ import {
|
|||||||
ProjectGraphContext,
|
ProjectGraphContext,
|
||||||
ProjectGraphNodeRecords,
|
ProjectGraphNodeRecords,
|
||||||
} from '../project-graph-models';
|
} from '../project-graph-models';
|
||||||
import { FileRead } from '../../file-utils';
|
|
||||||
|
|
||||||
export interface BuildDependencies {
|
export interface BuildDependencies {
|
||||||
(
|
(
|
||||||
ctx: ProjectGraphContext,
|
ctx: ProjectGraphContext,
|
||||||
nodes: ProjectGraphNodeRecords,
|
nodes: ProjectGraphNodeRecords,
|
||||||
addDependency: AddProjectDependency,
|
addDependency: AddProjectDependency
|
||||||
fileRead: FileRead
|
|
||||||
): void;
|
): void;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { buildExplicitPackageJsonDependencies } from '@nrwl/workspace/src/core/project-graph/build-dependencies/explicit-package-json-dependencies';
|
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 {
|
import {
|
||||||
AddProjectDependency,
|
AddProjectDependency,
|
||||||
DependencyType,
|
DependencyType,
|
||||||
@ -8,7 +8,6 @@ import {
|
|||||||
} from '../project-graph-models';
|
} from '../project-graph-models';
|
||||||
import { createProjectFileMap } from '../../file-graph';
|
import { createProjectFileMap } from '../../file-graph';
|
||||||
import { readWorkspaceFiles } from '../../file-utils';
|
import { readWorkspaceFiles } from '../../file-utils';
|
||||||
import { appRootPath } from '../../../utilities/app-root';
|
|
||||||
|
|
||||||
jest.mock('../../../utilities/app-root', () => ({
|
jest.mock('../../../utilities/app-root', () => ({
|
||||||
appRootPath: '/root',
|
appRootPath: '/root',
|
||||||
@ -107,9 +106,7 @@ describe('explicit package json dependencies', () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
buildExplicitPackageJsonDependencies(ctx, projects, addDependency, (s) => {
|
buildExplicitPackageJsonDependencies(ctx, projects, addDependency);
|
||||||
return fs.readFileSync(`${appRootPath}/${s}`).toString();
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(dependencyMap).toEqual({
|
expect(dependencyMap).toEqual({
|
||||||
proj: [
|
proj: [
|
||||||
|
|||||||
@ -4,20 +4,19 @@ import {
|
|||||||
ProjectGraphContext,
|
ProjectGraphContext,
|
||||||
ProjectGraphNodeRecords,
|
ProjectGraphNodeRecords,
|
||||||
} from '../project-graph-models';
|
} from '../project-graph-models';
|
||||||
import { FileRead } from '../../file-utils';
|
import { defaultFileRead } from '../../file-utils';
|
||||||
import { parseJsonWithComments } from '@nrwl/workspace/src/utilities/fileutils';
|
import { parseJsonWithComments } from '@nrwl/workspace/src/utilities/fileutils';
|
||||||
import { joinPathFragments } from '@nrwl/devkit';
|
import { joinPathFragments } from '@nrwl/devkit';
|
||||||
|
|
||||||
export function buildExplicitPackageJsonDependencies(
|
export function buildExplicitPackageJsonDependencies(
|
||||||
ctx: ProjectGraphContext,
|
ctx: ProjectGraphContext,
|
||||||
nodes: ProjectGraphNodeRecords,
|
nodes: ProjectGraphNodeRecords,
|
||||||
addDependency: AddProjectDependency,
|
addDependency: AddProjectDependency
|
||||||
fileRead: FileRead
|
|
||||||
) {
|
) {
|
||||||
Object.keys(ctx.fileMap).forEach((source) => {
|
Object.keys(ctx.fileMap).forEach((source) => {
|
||||||
Object.values(ctx.fileMap[source]).forEach((f) => {
|
Object.values(ctx.fileMap[source]).forEach((f) => {
|
||||||
if (isPackageJsonAtProjectRoot(nodes, f.file)) {
|
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,
|
sourceProject: string,
|
||||||
fileName: string,
|
fileName: string,
|
||||||
nodes: ProjectGraphNodeRecords,
|
nodes: ProjectGraphNodeRecords,
|
||||||
addDependency: AddProjectDependency,
|
addDependency: AddProjectDependency
|
||||||
fileRead: FileRead
|
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const deps = readDeps(parseJsonWithComments(fileRead(fileName)));
|
const deps = readDeps(parseJsonWithComments(defaultFileRead(fileName)));
|
||||||
deps.forEach((d) => {
|
deps.forEach((d) => {
|
||||||
// package.json refers to another project in the monorepo
|
// package.json refers to another project in the monorepo
|
||||||
if (nodes[d]) {
|
if (nodes[d]) {
|
||||||
|
|||||||
@ -196,9 +196,7 @@ describe('explicit project dependencies', () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
buildExplicitTypeScriptDependencies(ctx, projects, addDependency, (s) => {
|
buildExplicitTypeScriptDependencies(ctx, projects, addDependency);
|
||||||
return fs.readFileSync(`${appRootPath}/${s}`).toString();
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(dependencyMap).toEqual({
|
expect(dependencyMap).toEqual({
|
||||||
proj1234: [
|
proj1234: [
|
||||||
|
|||||||
@ -6,16 +6,14 @@ import {
|
|||||||
} from '../project-graph-models';
|
} from '../project-graph-models';
|
||||||
import { TypeScriptImportLocator } from './typescript-import-locator';
|
import { TypeScriptImportLocator } from './typescript-import-locator';
|
||||||
import { TargetProjectLocator } from '../../target-project-locator';
|
import { TargetProjectLocator } from '../../target-project-locator';
|
||||||
import { FileRead } from '../../file-utils';
|
|
||||||
|
|
||||||
export function buildExplicitTypeScriptDependencies(
|
export function buildExplicitTypeScriptDependencies(
|
||||||
ctx: ProjectGraphContext,
|
ctx: ProjectGraphContext,
|
||||||
nodes: ProjectGraphNodeRecords,
|
nodes: ProjectGraphNodeRecords,
|
||||||
addDependency: AddProjectDependency,
|
addDependency: AddProjectDependency
|
||||||
fileRead: FileRead
|
|
||||||
) {
|
) {
|
||||||
const importLocator = new TypeScriptImportLocator(fileRead);
|
const importLocator = new TypeScriptImportLocator();
|
||||||
const targetProjectLocator = new TargetProjectLocator(nodes, fileRead);
|
const targetProjectLocator = new TargetProjectLocator(nodes);
|
||||||
Object.keys(ctx.fileMap).forEach((source) => {
|
Object.keys(ctx.fileMap).forEach((source) => {
|
||||||
Object.values(ctx.fileMap[source]).forEach((f) => {
|
Object.values(ctx.fileMap[source]).forEach((f) => {
|
||||||
importLocator.fromFile(
|
importLocator.fromFile(
|
||||||
|
|||||||
@ -2,14 +2,14 @@ import type * as ts from 'typescript';
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { DependencyType } from '../project-graph-models';
|
import { DependencyType } from '../project-graph-models';
|
||||||
import { stripSourceCode } from '../../../utilities/strip-source-code';
|
import { stripSourceCode } from '../../../utilities/strip-source-code';
|
||||||
import { FileRead } from '../../file-utils';
|
import { defaultFileRead } from '../../file-utils';
|
||||||
|
|
||||||
let tsModule: any;
|
let tsModule: any;
|
||||||
|
|
||||||
export class TypeScriptImportLocator {
|
export class TypeScriptImportLocator {
|
||||||
private readonly scanner: ts.Scanner;
|
private readonly scanner: ts.Scanner;
|
||||||
|
|
||||||
constructor(private readonly fileRead: FileRead) {
|
constructor() {
|
||||||
tsModule = require('typescript');
|
tsModule = require('typescript');
|
||||||
this.scanner = tsModule.createScanner(tsModule.ScriptTarget.Latest, false);
|
this.scanner = tsModule.createScanner(tsModule.ScriptTarget.Latest, false);
|
||||||
}
|
}
|
||||||
@ -31,7 +31,7 @@ export class TypeScriptImportLocator {
|
|||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const content = this.fileRead(filePath);
|
const content = defaultFileRead(filePath);
|
||||||
const strippedContent = stripSourceCode(this.scanner, content);
|
const strippedContent = stripSourceCode(this.scanner, content);
|
||||||
if (strippedContent !== '') {
|
if (strippedContent !== '') {
|
||||||
const tsFile = tsModule.createSourceFile(
|
const tsFile = tsModule.createSourceFile(
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import { AddProjectNode, ProjectGraphContext } from '../project-graph-models';
|
import { AddProjectNode, ProjectGraphContext } from '../project-graph-models';
|
||||||
import { FileRead } from '../../file-utils';
|
|
||||||
|
|
||||||
export interface BuildNodes {
|
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 * as stripJsonComments from 'strip-json-comments';
|
||||||
import { ProjectGraphContext, AddProjectNode } from '../project-graph-models';
|
import { AddProjectNode, ProjectGraphContext } from '../project-graph-models';
|
||||||
import { FileRead } from '../../file-utils';
|
import { defaultFileRead } from '../../file-utils';
|
||||||
|
|
||||||
export function buildNpmPackageNodes(
|
export function buildNpmPackageNodes(
|
||||||
ctx: ProjectGraphContext,
|
ctx: ProjectGraphContext,
|
||||||
addNode: AddProjectNode,
|
addNode: AddProjectNode
|
||||||
fileRead: FileRead
|
|
||||||
) {
|
) {
|
||||||
const packageJson = JSON.parse(stripJsonComments(fileRead('package.json')));
|
const packageJson = JSON.parse(
|
||||||
|
stripJsonComments(defaultFileRead('package.json'))
|
||||||
|
);
|
||||||
const deps = {
|
const deps = {
|
||||||
...packageJson.dependencies,
|
...packageJson.dependencies,
|
||||||
...packageJson.devDependencies,
|
...packageJson.devDependencies,
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
import { AddProjectNode, ProjectGraphContext } from '../project-graph-models';
|
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 {
|
try {
|
||||||
const packageJsonString = fileRead(`${projectRoot}/package.json`);
|
const packageJsonString = defaultFileRead(
|
||||||
|
`${projectRoot}/package.json`
|
||||||
|
).toString();
|
||||||
const parsedPackagedJson = JSON.parse(packageJsonString);
|
const parsedPackagedJson = JSON.parse(packageJsonString);
|
||||||
const res = {};
|
const res = {};
|
||||||
// handle no scripts
|
// handle no scripts
|
||||||
@ -21,52 +23,53 @@ function convertNpmScriptsToTargets(projectRoot: string, fileRead: FileRead) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildWorkspaceProjectNodes(fileRead: FileRead) {
|
export function buildWorkspaceProjectNodes(
|
||||||
return (ctx: ProjectGraphContext, addNode: AddProjectNode) => {
|
ctx: ProjectGraphContext,
|
||||||
const toAdd = [];
|
addNode: AddProjectNode
|
||||||
|
) {
|
||||||
|
const toAdd = [];
|
||||||
|
|
||||||
Object.keys(ctx.fileMap).forEach((key) => {
|
Object.keys(ctx.fileMap).forEach((key) => {
|
||||||
const p = ctx.workspaceJson.projects[key];
|
const p = ctx.workspaceJson.projects[key];
|
||||||
if (!p.targets) {
|
if (!p.targets) {
|
||||||
p.targets = convertNpmScriptsToTargets(p.root, fileRead);
|
p.targets = convertNpmScriptsToTargets(p.root);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO, types and projectType should allign
|
// TODO, types and projectType should allign
|
||||||
const projectType =
|
const projectType =
|
||||||
p.projectType === 'application'
|
p.projectType === 'application'
|
||||||
? key.endsWith('-e2e')
|
? key.endsWith('-e2e')
|
||||||
? 'e2e'
|
? 'e2e'
|
||||||
: 'app'
|
: 'app'
|
||||||
: 'lib';
|
: 'lib';
|
||||||
const tags =
|
const tags =
|
||||||
ctx.nxJson.projects && ctx.nxJson.projects[key]
|
ctx.nxJson.projects && ctx.nxJson.projects[key]
|
||||||
? ctx.nxJson.projects[key].tags || []
|
? ctx.nxJson.projects[key].tags || []
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
toAdd.push({
|
toAdd.push({
|
||||||
name: key,
|
name: key,
|
||||||
type: projectType,
|
type: projectType,
|
||||||
data: {
|
data: {
|
||||||
...p,
|
...p,
|
||||||
tags,
|
tags,
|
||||||
files: ctx.fileMap[key],
|
files: ctx.fileMap[key],
|
||||||
},
|
},
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// Sort by root directory length (do we need this?)
|
// Sort by root directory length (do we need this?)
|
||||||
toAdd.sort((a, b) => {
|
toAdd.sort((a, b) => {
|
||||||
if (!a.data.root) return -1;
|
if (!a.data.root) return -1;
|
||||||
if (!b.data.root) return -1;
|
if (!b.data.root) return -1;
|
||||||
return a.data.root.length > b.data.root.length ? -1 : 1;
|
return a.data.root.length > b.data.root.length ? -1 : 1;
|
||||||
});
|
});
|
||||||
|
|
||||||
toAdd.forEach((n) => {
|
toAdd.forEach((n) => {
|
||||||
addNode({
|
addNode({
|
||||||
name: n.name,
|
name: n.name,
|
||||||
type: n.type,
|
type: n.type,
|
||||||
data: n.data,
|
data: n.data,
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
import { assertWorkspaceValidity } from '../assert-workspace-validity';
|
import { assertWorkspaceValidity } from '../assert-workspace-validity';
|
||||||
import { createProjectFileMap, ProjectFileMap } from '../file-graph';
|
import { createProjectFileMap, ProjectFileMap } from '../file-graph';
|
||||||
import {
|
import {
|
||||||
defaultFileRead,
|
|
||||||
FileData,
|
FileData,
|
||||||
FileRead,
|
|
||||||
filesChanged,
|
filesChanged,
|
||||||
readNxJson,
|
readNxJson,
|
||||||
readWorkspaceFiles,
|
readWorkspaceFiles,
|
||||||
@ -37,7 +35,6 @@ export function createProjectGraph(
|
|||||||
workspaceJson = readWorkspaceJson(),
|
workspaceJson = readWorkspaceJson(),
|
||||||
nxJson = readNxJson(),
|
nxJson = readNxJson(),
|
||||||
workspaceFiles = readWorkspaceFiles(),
|
workspaceFiles = readWorkspaceFiles(),
|
||||||
fileRead: FileRead = defaultFileRead,
|
|
||||||
cache: false | ProjectGraphCache = readCache(),
|
cache: false | ProjectGraphCache = readCache(),
|
||||||
shouldCache: boolean = true
|
shouldCache: boolean = true
|
||||||
): ProjectGraph {
|
): ProjectGraph {
|
||||||
@ -63,7 +60,6 @@ export function createProjectGraph(
|
|||||||
};
|
};
|
||||||
const projectGraph = buildProjectGraph(
|
const projectGraph = buildProjectGraph(
|
||||||
ctx,
|
ctx,
|
||||||
fileRead,
|
|
||||||
diff.partiallyConstructedProjectGraph
|
diff.partiallyConstructedProjectGraph
|
||||||
);
|
);
|
||||||
if (shouldCache) {
|
if (shouldCache) {
|
||||||
@ -76,7 +72,7 @@ export function createProjectGraph(
|
|||||||
nxJson: normalizedNxJson,
|
nxJson: normalizedNxJson,
|
||||||
fileMap: projectFileMap,
|
fileMap: projectFileMap,
|
||||||
};
|
};
|
||||||
const projectGraph = buildProjectGraph(ctx, fileRead, null);
|
const projectGraph = buildProjectGraph(ctx, null);
|
||||||
if (shouldCache) {
|
if (shouldCache) {
|
||||||
writeCache(rootFiles, projectGraph);
|
writeCache(rootFiles, projectGraph);
|
||||||
}
|
}
|
||||||
@ -97,13 +93,12 @@ function buildProjectGraph(
|
|||||||
workspaceJson: any;
|
workspaceJson: any;
|
||||||
fileMap: ProjectFileMap;
|
fileMap: ProjectFileMap;
|
||||||
},
|
},
|
||||||
fileRead: FileRead,
|
|
||||||
projectGraph: ProjectGraph
|
projectGraph: ProjectGraph
|
||||||
) {
|
) {
|
||||||
performance.mark('build project graph:start');
|
performance.mark('build project graph:start');
|
||||||
const builder = new ProjectGraphBuilder(projectGraph);
|
const builder = new ProjectGraphBuilder(projectGraph);
|
||||||
const buildNodesFns: BuildNodes[] = [
|
const buildNodesFns: BuildNodes[] = [
|
||||||
buildWorkspaceProjectNodes(fileRead),
|
buildWorkspaceProjectNodes,
|
||||||
buildNpmPackageNodes,
|
buildNpmPackageNodes,
|
||||||
];
|
];
|
||||||
const buildDependenciesFns: BuildDependencies[] = [
|
const buildDependenciesFns: BuildDependencies[] = [
|
||||||
@ -111,9 +106,9 @@ function buildProjectGraph(
|
|||||||
buildImplicitProjectDependencies,
|
buildImplicitProjectDependencies,
|
||||||
buildExplicitPackageJsonDependencies,
|
buildExplicitPackageJsonDependencies,
|
||||||
];
|
];
|
||||||
buildNodesFns.forEach((f) => f(ctx, builder.addNode.bind(builder), fileRead));
|
buildNodesFns.forEach((f) => f(ctx, builder.addNode.bind(builder)));
|
||||||
buildDependenciesFns.forEach((f) =>
|
buildDependenciesFns.forEach((f) =>
|
||||||
f(ctx, builder.nodes, builder.addDependency.bind(builder), fileRead)
|
f(ctx, builder.nodes, builder.addDependency.bind(builder))
|
||||||
);
|
);
|
||||||
const r = builder.build();
|
const r = builder.build();
|
||||||
performance.mark('build project graph:end');
|
performance.mark('build project graph:end');
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { resolveModuleByImport } from '../utilities/typescript';
|
import { resolveModuleByImport } from '../utilities/typescript';
|
||||||
import { defaultFileRead, FileRead, normalizedProjectRoot } from './file-utils';
|
import { defaultFileRead, normalizedProjectRoot } from './file-utils';
|
||||||
import {
|
import {
|
||||||
ProjectGraphNode,
|
ProjectGraphNode,
|
||||||
ProjectGraphNodeRecords,
|
ProjectGraphNodeRecords,
|
||||||
@ -31,15 +31,12 @@ export class TargetProjectLocator {
|
|||||||
private npmProjects = this.sortedProjects.filter(isNpmProject);
|
private npmProjects = this.sortedProjects.filter(isNpmProject);
|
||||||
private tsConfigPath = this.getRootTsConfigPath();
|
private tsConfigPath = this.getRootTsConfigPath();
|
||||||
private absTsConfigPath = join(appRootPath, this.tsConfigPath);
|
private absTsConfigPath = join(appRootPath, this.tsConfigPath);
|
||||||
private paths = parseJsonWithComments(this.fileRead(this.tsConfigPath))
|
private paths = parseJsonWithComments(defaultFileRead(this.tsConfigPath))
|
||||||
?.compilerOptions?.paths;
|
?.compilerOptions?.paths;
|
||||||
private typescriptResolutionCache = new Map<string, string | null>();
|
private typescriptResolutionCache = new Map<string, string | null>();
|
||||||
private npmResolutionCache = new Map<string, string | null>();
|
private npmResolutionCache = new Map<string, string | null>();
|
||||||
|
|
||||||
constructor(
|
constructor(private nodes: ProjectGraphNodeRecords) {}
|
||||||
private nodes: ProjectGraphNodeRecords,
|
|
||||||
private fileRead: FileRead = defaultFileRead
|
|
||||||
) {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a project based on its import
|
* Find a project based on its import
|
||||||
@ -132,7 +129,7 @@ export class TargetProjectLocator {
|
|||||||
|
|
||||||
private getRootTsConfigPath() {
|
private getRootTsConfigPath() {
|
||||||
try {
|
try {
|
||||||
this.fileRead('tsconfig.base.json');
|
defaultFileRead('tsconfig.base.json');
|
||||||
return 'tsconfig.base.json';
|
return 'tsconfig.base.json';
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return 'tsconfig.json';
|
return 'tsconfig.json';
|
||||||
|
|||||||
@ -7,6 +7,12 @@ import { Schema } from '../schema';
|
|||||||
import { checkDependencies } from './check-dependencies';
|
import { checkDependencies } from './check-dependencies';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||||
import { libraryGenerator } from '../../library/library';
|
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', () => {
|
describe('checkDependencies', () => {
|
||||||
let tree: Tree;
|
let tree: Tree;
|
||||||
@ -27,6 +33,36 @@ describe('checkDependencies', () => {
|
|||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-source',
|
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', () => {
|
describe('static dependencies', () => {
|
||||||
@ -90,6 +126,10 @@ describe('checkDependencies', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should not error if there are no dependents', async () => {
|
it('should not error if there are no dependents', async () => {
|
||||||
|
projectGraph = {
|
||||||
|
nodes: projectGraph.nodes,
|
||||||
|
dependencies: {},
|
||||||
|
};
|
||||||
expect(() => {
|
expect(() => {
|
||||||
checkDependencies(tree, schema);
|
checkDependencies(tree, schema);
|
||||||
}).not.toThrow();
|
}).not.toThrow();
|
||||||
|
|||||||
@ -1,37 +1,39 @@
|
|||||||
import { Tree } from '@nrwl/devkit';
|
|
||||||
import {
|
import {
|
||||||
|
createProjectGraph,
|
||||||
onlyWorkspaceProjects,
|
onlyWorkspaceProjects,
|
||||||
ProjectGraph,
|
ProjectGraph,
|
||||||
reverse,
|
reverse,
|
||||||
} from '../../../core/project-graph';
|
} from '../../../core/project-graph';
|
||||||
import { Schema } from '../schema';
|
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
|
* 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.
|
* 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) {
|
if (schema.forceRemove) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const graph: ProjectGraph = createProjectGraphFromTree(tree);
|
const graph: ProjectGraph = createProjectGraph(
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
const reverseGraph = onlyWorkspaceProjects(reverse(graph));
|
const reverseGraph = onlyWorkspaceProjects(reverse(graph));
|
||||||
|
|
||||||
const deps = reverseGraph.dependencies[schema.projectName] || [];
|
const deps = reverseGraph.dependencies[schema.projectName] || [];
|
||||||
|
|
||||||
if (deps.length === 0) {
|
if (deps.length > 0) {
|
||||||
return;
|
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`,
|
`${process.cwd()}/proj`,
|
||||||
'mycompany',
|
'mycompany',
|
||||||
projectGraph,
|
projectGraph,
|
||||||
new TargetProjectLocator(projectGraph.nodes, (path) =>
|
new TargetProjectLocator(projectGraph.nodes)
|
||||||
readFileSync(join('/root', path)).toString()
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
return rule.apply(sourceFile);
|
return rule.apply(sourceFile);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,37 +1,10 @@
|
|||||||
import {
|
import { Tree } from '@nrwl/devkit';
|
||||||
getWorkspacePath,
|
|
||||||
readJson,
|
|
||||||
Tree,
|
|
||||||
visitNotIgnoredFiles,
|
|
||||||
} from '@nrwl/devkit';
|
|
||||||
import { createProjectGraph } from '../core/project-graph/project-graph';
|
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) {
|
export function createProjectGraphFromTree(tree: Tree) {
|
||||||
const workspaceJson = readJson(tree, getWorkspacePath(tree));
|
return createProjectGraph(undefined, undefined, undefined, false);
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,7 +26,7 @@ import {
|
|||||||
onlyWorkspaceProjects,
|
onlyWorkspaceProjects,
|
||||||
ProjectGraph,
|
ProjectGraph,
|
||||||
} from '../core/project-graph';
|
} 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 { extname, join, normalize, Path } from '@angular-devkit/core';
|
||||||
import { NxJson, NxJsonProjectConfig } from '../core/shared-interfaces';
|
import { NxJson, NxJsonProjectConfig } from '../core/shared-interfaces';
|
||||||
import { addInstallTask } from './rules/add-install-task';
|
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
|
* Method for utilizing the project graph in schematics
|
||||||
*/
|
*/
|
||||||
export function getProjectGraphFromHost(host: Tree): ProjectGraph {
|
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 {
|
export function getFullProjectGraphFromHost(host: Tree): ProjectGraph {
|
||||||
const workspaceJson = readJsonInTree(host, getWorkspacePath(host));
|
return createProjectGraph(undefined, undefined, undefined, false);
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(v13): remove this deprecated method
|
||||||
|
/**
|
||||||
|
* @deprecated This method is deprecated
|
||||||
|
*/
|
||||||
export function getFileDataInHost(host: Tree, path: Path): FileData {
|
export function getFileDataInHost(host: Tree, path: Path): FileData {
|
||||||
return {
|
return {
|
||||||
file: path,
|
file: path,
|
||||||
|
|||||||
@ -1,70 +1,49 @@
|
|||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import { SchematicContext, Tree } from '@angular-devkit/schematics';
|
|
||||||
import { getWorkspace } from '@nrwl/workspace';
|
|
||||||
import {
|
import {
|
||||||
getFullProjectGraphFromHost,
|
chain,
|
||||||
|
SchematicContext,
|
||||||
|
Tree,
|
||||||
|
Rule,
|
||||||
|
} from '@angular-devkit/schematics';
|
||||||
|
import { getWorkspace, visitNotIgnoredFiles } from '@nrwl/workspace';
|
||||||
|
import {
|
||||||
findNodes,
|
findNodes,
|
||||||
insert,
|
insert,
|
||||||
ReplaceChange,
|
ReplaceChange,
|
||||||
} from '@nrwl/workspace/src/utils/ast-utils';
|
} from '@nrwl/workspace/src/utils/ast-utils';
|
||||||
|
import { normalize } from '@angular-devkit/core';
|
||||||
|
|
||||||
export interface PackageNameMapping {
|
export interface PackageNameMapping {
|
||||||
[packageName: string]: string;
|
[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
|
* Updates all the imports found in the workspace
|
||||||
*
|
*
|
||||||
* @param packageNameMapping The packageNameMapping provided to the schematic
|
* @param packageNameMapping The packageNameMapping provided to the schematic
|
||||||
*/
|
*/
|
||||||
export function renamePackageImports(packageNameMapping: PackageNameMapping) {
|
export function renamePackageImports(
|
||||||
return async (tree: Tree, _context: SchematicContext): Promise<void> => {
|
packageNameMapping: PackageNameMapping
|
||||||
|
): Rule {
|
||||||
|
return async (tree: Tree, _context: SchematicContext) => {
|
||||||
const workspace = await getWorkspace(tree);
|
const workspace = await getWorkspace(tree);
|
||||||
|
|
||||||
const projectNamesThatImportAPackageToRename = getProjectNamesWithDepsToRename(
|
const rules = [];
|
||||||
packageNameMapping,
|
workspace.projects.forEach((project) => {
|
||||||
tree
|
rules.push(
|
||||||
);
|
visitNotIgnoredFiles((file) => {
|
||||||
|
|
||||||
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
|
|
||||||
if (!/([jt])sx?$/.test(file)) {
|
if (!/([jt])sx?$/.test(file)) {
|
||||||
return;
|
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');
|
const contents = tree.read(file).toString('utf-8');
|
||||||
if (
|
const fileIncludesPackageToRename = Object.keys(
|
||||||
!Object.keys(packageNameMapping).some((packageName) =>
|
packageNameMapping
|
||||||
contents.includes(packageName)
|
).some((packageName) => {
|
||||||
)
|
return contents.includes(packageName);
|
||||||
) {
|
});
|
||||||
|
|
||||||
|
if (!fileIncludesPackageToRename) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +86,10 @@ export function renamePackageImports(packageNameMapping: PackageNameMapping) {
|
|||||||
// update the file in the tree
|
// update the file in the tree
|
||||||
insert(tree, file, changes);
|
insert(tree, file, changes);
|
||||||
}
|
}
|
||||||
});
|
}, normalize(project.root))
|
||||||
});
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return chain(rules);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user