cleanup(repo): remove unused ext from file data and fix ext regex matcher (#6550)

This commit is contained in:
Miroslav Jonaš 2021-08-04 15:45:07 +02:00 committed by GitHub
parent 1c19db5ff3
commit 3aca62af68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 429 additions and 162 deletions

View File

@ -81,7 +81,7 @@ function run(
context: BuilderContext context: BuilderContext
): Observable<BuilderOutput> { ): Observable<BuilderOutput> {
const { target, dependencies } = calculateProjectDependencies( const { target, dependencies } = calculateProjectDependencies(
readCachedProjectGraph(), readCachedProjectGraph('4.0'),
context context
); );

View File

@ -17,7 +17,7 @@ export async function* delegateBuildExecutor(
context: ExecutorContext context: ExecutorContext
) { ) {
const { target, dependencies } = calculateProjectDependencies( const { target, dependencies } = calculateProjectDependencies(
readCachedProjectGraph(), readCachedProjectGraph('4.0'),
context.root, context.root,
context.projectName, context.projectName,
context.targetName, context.targetName,

View File

@ -51,7 +51,7 @@ export function createLibraryExecutor(
context: ExecutorContext context: ExecutorContext
) { ) {
const { target, dependencies } = calculateProjectDependencies( const { target, dependencies } = calculateProjectDependencies(
readCachedProjectGraph(), readCachedProjectGraph('4.0'),
context.root, context.root,
context.projectName, context.projectName,
context.targetName, context.targetName,

View File

@ -45,7 +45,7 @@ function addHTMLPatternToBuilderConfig(
async function updateProjectESLintConfigsAndBuilders( async function updateProjectESLintConfigsAndBuilders(
host: Tree host: Tree
): Promise<Rule> { ): Promise<Rule> {
const graph = await createProjectGraphAsync(); const graph = await createProjectGraphAsync('4.0');
/** /**
* 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

View File

@ -9,7 +9,8 @@ import type {
export interface FileData { export interface FileData {
file: string; file: string;
hash: string; hash: string;
ext: string; /** @deprecated this field will be removed in v13. Use {@link path.extname} to parse extension */
ext?: string;
deps?: string[]; deps?: string[];
} }
@ -29,6 +30,7 @@ export interface ProjectGraph<T = any> {
// this is optional otherwise it might break folks who use project graph creation // this is optional otherwise it might break folks who use project graph creation
allWorkspaceFiles?: FileData[]; allWorkspaceFiles?: FileData[];
version?: string;
} }
/** /**

View File

@ -106,6 +106,13 @@ export class ProjectGraphBuilder {
} }
} }
/**
* Set version of the project graph
*/
setVersion(version: string): void {
this.graph.version = version;
}
getUpdatedProjectGraph(): ProjectGraph { getUpdatedProjectGraph(): ProjectGraph {
for (const sourceProject of Object.keys(this.graph.nodes)) { for (const sourceProject of Object.keys(this.graph.nodes)) {
const alreadySetTargetProjects = const alreadySetTargetProjects =

View File

@ -129,7 +129,7 @@ export default createESLintRule<Options, MessageIds>({
*/ */
try { try {
(global as any).projectGraph = mapProjectGraphFiles( (global as any).projectGraph = mapProjectGraphFiles(
readCachedProjectGraph() readCachedProjectGraph('4.0')
); );
} catch {} } catch {}
} }

View File

@ -1526,7 +1526,7 @@ linter.defineParser('@typescript-eslint/parser', parser);
linter.defineRule(enforceModuleBoundariesRuleName, enforceModuleBoundaries); linter.defineRule(enforceModuleBoundariesRuleName, enforceModuleBoundaries);
function createFile(f) { function createFile(f) {
return { file: f, ext: extname(f), hash: '' }; return { file: f, hash: '' };
} }
function runRule( function runRule(

View File

@ -27,7 +27,7 @@ export default async function exportExecutor(
let dependencies: DependentBuildableProjectNode[] = []; let dependencies: DependentBuildableProjectNode[] = [];
if (!options.buildLibsFromSource) { if (!options.buildLibsFromSource) {
const result = calculateProjectDependencies( const result = calculateProjectDependencies(
readCachedProjectGraph(), readCachedProjectGraph('4.0'),
context.root, context.root,
context.projectName, context.projectName,
'build', // this should be generalized 'build', // this should be generalized

View File

@ -54,7 +54,7 @@ export default async function* serveExecutor(
const root = resolve(context.root, buildOptions.root); const root = resolve(context.root, buildOptions.root);
if (!options.buildLibsFromSource) { if (!options.buildLibsFromSource) {
const result = calculateProjectDependencies( const result = calculateProjectDependencies(
readCachedProjectGraph(), readCachedProjectGraph('4.0'),
context.root, context.root,
context.projectName, context.projectName,
'build', // should be generalized 'build', // should be generalized

View File

@ -19,7 +19,7 @@ export async function packageExecutor(
const libRoot = context.workspace.projects[context.projectName].root; const libRoot = context.workspace.projects[context.projectName].root;
const normalizedOptions = normalizeOptions(options, context, libRoot); const normalizedOptions = normalizeOptions(options, context, libRoot);
const { target, dependencies } = calculateProjectDependencies( const { target, dependencies } = calculateProjectDependencies(
readCachedProjectGraph(), readCachedProjectGraph('4.0'),
context.root, context.root,
context.projectName, context.projectName,
context.targetName, context.targetName,

View File

@ -28,7 +28,7 @@ export default function update(): Rule {
return async (host: Tree, context: SchematicContext) => { return async (host: Tree, context: SchematicContext) => {
const updates = []; const updates = [];
const conflicts: Array<[string, string]> = []; const conflicts: Array<[string, string]> = [];
const projectGraph = await createProjectGraphAsync(); const projectGraph = await createProjectGraphAsync('4.0');
if (host.exists('/babel.config.json')) { if (host.exists('/babel.config.json')) {
context.logger.info( context.logger.info(
` `

View File

@ -68,7 +68,7 @@ export default async function* devServerExecutor(
if (!buildOptions.buildLibsFromSource) { if (!buildOptions.buildLibsFromSource) {
const { target, dependencies } = calculateProjectDependencies( const { target, dependencies } = calculateProjectDependencies(
readCachedProjectGraph(), readCachedProjectGraph('4.0'),
context.root, context.root,
context.projectName, context.projectName,
'build', // should be generalized 'build', // should be generalized

View File

@ -56,7 +56,7 @@ export default async function* run(
context: ExecutorContext context: ExecutorContext
) { ) {
const project = context.workspace.projects[context.projectName]; const project = context.workspace.projects[context.projectName];
const projectGraph = readCachedProjectGraph(); const projectGraph = readCachedProjectGraph('4.0');
const sourceRoot = project.sourceRoot; const sourceRoot = project.sourceRoot;
const { target, dependencies } = calculateProjectDependencies( const { target, dependencies } = calculateProjectDependencies(
projectGraph, projectGraph,

View File

@ -7,7 +7,7 @@ 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(await createProjectGraphAsync()); const graph = reverse(await createProjectGraphAsync('4.0'));
for (const [name, p] of projects.entries()) { for (const [name, p] of projects.entries()) {
if (!hasDependentAppUsingWebBuild(name, graph, projects)) { if (!hasDependentAppUsingWebBuild(name, graph, projects)) {

View File

@ -37,7 +37,7 @@ export async function affected(
await connectToNxCloudUsingScan(nxArgs.scan); await connectToNxCloudUsingScan(nxArgs.scan);
const projectGraph = await createProjectGraphAsync(); const projectGraph = await createProjectGraphAsync('4.0');
const projects = projectsToRun(nxArgs, projectGraph); const projects = projectsToRun(nxArgs, projectGraph);
const projectsNotExcluded = applyExclude(projects, nxArgs); const projectsNotExcluded = applyExclude(projects, nxArgs);
const env = readEnvironment(nxArgs.target, projectsNotExcluded); const env = readEnvironment(nxArgs.target, projectsNotExcluded);

View File

@ -204,7 +204,7 @@ export async function generateGraph(
}, },
affectedProjects: string[] affectedProjects: string[]
): Promise<void> { ): Promise<void> {
let graph = onlyWorkspaceProjects(await createProjectGraphAsync()); let graph = onlyWorkspaceProjects(await createProjectGraphAsync('4.0'));
const layout = workspaceLayout(); const layout = workspaceLayout();
const projects = Object.values(graph.nodes) as ProjectGraphNode[]; const projects = Object.values(graph.nodes) as ProjectGraphNode[];

View File

@ -85,7 +85,7 @@ async function getPatternsFromApps(
affectedFiles: string[], affectedFiles: string[],
matchAllPattern: string matchAllPattern: string
): Promise<string[]> { ): Promise<string[]> {
const graph = onlyWorkspaceProjects(await createProjectGraphAsync()); const graph = onlyWorkspaceProjects(await createProjectGraphAsync('4.0'));
const affectedGraph = filterAffected( const affectedGraph = filterAffected(
graph, graph,
calculateFileChanges(affectedFiles) calculateFileChanges(affectedFiles)

View File

@ -8,7 +8,7 @@ import { output } from '../utilities/output';
import * as path from 'path'; import * as path from 'path';
export async function workspaceLint(): Promise<void> { export async function workspaceLint(): Promise<void> {
const graph = onlyWorkspaceProjects(await createProjectGraphAsync()); const graph = onlyWorkspaceProjects(await createProjectGraphAsync('4.0'));
const cliErrorOutputConfigs = new WorkspaceIntegrityChecks( const cliErrorOutputConfigs = new WorkspaceIntegrityChecks(
graph, graph,
@ -25,7 +25,7 @@ export async function workspaceLint(): Promise<void> {
function readAllFilesFromAppsAndLibs() { function readAllFilesFromAppsAndLibs() {
const wl = workspaceLayout(); const wl = workspaceLayout();
return readWorkspaceFiles() return readWorkspaceFiles('4.0')
.map((f) => f.file) .map((f) => f.file)
.filter( .filter(
(f) => f.startsWith(`${wl.appsDir}/`) || f.startsWith(`${wl.libsDir}/`) (f) => f.startsWith(`${wl.appsDir}/`) || f.startsWith(`${wl.libsDir}/`)

View File

@ -26,7 +26,7 @@ export async function runMany(parsedArgs: yargs.Arguments & RawNxArgs) {
await connectToNxCloudUsingScan(nxArgs.scan); await connectToNxCloudUsingScan(nxArgs.scan);
const projectGraph = await createProjectGraphAsync(); const projectGraph = await createProjectGraphAsync('4.0');
const projects = projectsToRun(nxArgs, projectGraph); const projects = projectsToRun(nxArgs, projectGraph);
const projectsNotExcluded = applyExclude(projects, nxArgs); const projectsNotExcluded = applyExclude(projects, nxArgs);
const env = readEnvironment(nxArgs.target, projectsNotExcluded); const env = readEnvironment(nxArgs.target, projectsNotExcluded);

View File

@ -31,7 +31,7 @@ export async function runOne(opts: {
await connectToNxCloudUsingScan(nxArgs.scan); await connectToNxCloudUsingScan(nxArgs.scan);
const projectGraph = await createProjectGraphAsync(); const projectGraph = await createProjectGraphAsync('4.0');
const { projects, projectsMap } = getProjects( const { projects, projectsMap } = getProjects(
projectGraph, projectGraph,
nxArgs.withDeps, nxArgs.withDeps,

View File

@ -1,7 +1,6 @@
import { WorkspaceIntegrityChecks } from './workspace-integrity-checks'; import { WorkspaceIntegrityChecks } from './workspace-integrity-checks';
import * as chalk from 'chalk'; import * as chalk from 'chalk';
import { ProjectType } from '../core/project-graph'; import { ProjectType } from '../core/project-graph';
import { extname } from 'path';
describe('WorkspaceIntegrityChecks', () => { describe('WorkspaceIntegrityChecks', () => {
describe('workspace.json is in sync with the filesystem', () => { describe('workspace.json is in sync with the filesystem', () => {
@ -106,5 +105,5 @@ describe('WorkspaceIntegrityChecks', () => {
}); });
function createFile(f) { function createFile(f) {
return { file: f, ext: extname(f), hash: '' }; return { file: f, hash: '' };
} }

View File

@ -122,13 +122,11 @@ describe('project graph', () => {
const affected = filterAffected(graph, [ const affected = filterAffected(graph, [
{ {
file: 'something-for-api.txt', file: 'something-for-api.txt',
ext: '.txt',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => [new WholeFileChange()], getChanges: () => [new WholeFileChange()],
}, },
{ {
file: 'libs/ui/src/index.ts', file: 'libs/ui/src/index.ts',
ext: '.ts',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => [new WholeFileChange()], getChanges: () => [new WholeFileChange()],
}, },
@ -182,7 +180,6 @@ describe('project graph', () => {
const affected = filterAffected(graph, [ const affected = filterAffected(graph, [
{ {
file: 'package.json', file: 'package.json',
ext: '.json',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => jsonDiff(packageJson, updatedPackageJson), getChanges: () => jsonDiff(packageJson, updatedPackageJson),
}, },
@ -238,7 +235,6 @@ describe('project graph', () => {
const affected = filterAffected(graph, [ const affected = filterAffected(graph, [
{ {
file: 'package.json', file: 'package.json',
ext: '.json',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => jsonDiff(packageJson, updatedPackageJson), getChanges: () => jsonDiff(packageJson, updatedPackageJson),
}, },
@ -259,7 +255,6 @@ describe('project graph', () => {
const affected = filterAffected(graph, [ const affected = filterAffected(graph, [
{ {
file: 'package.json', file: 'package.json',
ext: '.json',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => jsonDiff(packageJson, updatedPackageJson), getChanges: () => jsonDiff(packageJson, updatedPackageJson),
}, },

View File

@ -41,7 +41,6 @@ describe('getImplicitlyTouchedProjectsByJsonChanges', () => {
{ {
file: 'package.json', file: 'package.json',
hash: 'some-hash', hash: 'some-hash',
ext: '.json',
getChanges: () => [getModifiedChange(['some', 'deep-field'])], getChanges: () => [getModifiedChange(['some', 'deep-field'])],
}, },
], ],
@ -57,7 +56,6 @@ describe('getImplicitlyTouchedProjectsByJsonChanges', () => {
{ {
file: 'package.json', file: 'package.json',
hash: 'some-hash', hash: 'some-hash',
ext: '.json',
getChanges: () => [ getChanges: () => [
getModifiedChange(['some', 'deep-glob-anything']), getModifiedChange(['some', 'deep-glob-anything']),
getModifiedChange(['match-anything']), getModifiedChange(['match-anything']),
@ -77,7 +75,6 @@ describe('getImplicitlyTouchedProjectsByJsonChanges', () => {
{ {
file: 'package.json', file: 'package.json',
hash: 'some-hash', hash: 'some-hash',
ext: '.json',
getChanges: () => [new WholeFileChange()], getChanges: () => [new WholeFileChange()],
}, },
], ],

View File

@ -67,7 +67,6 @@ describe('getTouchedNpmPackages', () => {
{ {
file: 'package.json', file: 'package.json',
hash: 'some-hash', hash: 'some-hash',
ext: '.json',
getChanges: () => [ getChanges: () => [
{ {
type: DiffType.Modified, type: DiffType.Modified,
@ -98,7 +97,6 @@ describe('getTouchedNpmPackages', () => {
{ {
file: 'package.json', file: 'package.json',
hash: 'some-hash', hash: 'some-hash',
ext: '.json',
getChanges: () => [ getChanges: () => [
{ {
type: DiffType.Deleted, type: DiffType.Deleted,
@ -137,7 +135,6 @@ describe('getTouchedNpmPackages', () => {
{ {
file: 'package.json', file: 'package.json',
hash: 'some-hash', hash: 'some-hash',
ext: '.json',
getChanges: () => [ getChanges: () => [
{ {
type: DiffType.Added, type: DiffType.Added,
@ -177,7 +174,6 @@ describe('getTouchedNpmPackages', () => {
{ {
file: 'package.json', file: 'package.json',
hash: 'some-hash', hash: 'some-hash',
ext: '.json',
getChanges: () => [new WholeFileChange()], getChanges: () => [new WholeFileChange()],
}, },
], ],

View File

@ -8,7 +8,6 @@ describe('getTouchedProjectsInNxJson', () => {
[ [
{ {
file: 'source.ts', file: 'source.ts',
ext: '.ts',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => [new WholeFileChange()], getChanges: () => [new WholeFileChange()],
}, },
@ -31,7 +30,6 @@ describe('getTouchedProjectsInNxJson', () => {
[ [
{ {
file: 'nx.json', file: 'nx.json',
ext: '.json',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => [new WholeFileChange()], getChanges: () => [new WholeFileChange()],
}, },
@ -57,7 +55,6 @@ describe('getTouchedProjectsInNxJson', () => {
[ [
{ {
file: 'nx.json', file: 'nx.json',
ext: '.json',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => [ getChanges: () => [
{ {
@ -92,7 +89,6 @@ describe('getTouchedProjectsInNxJson', () => {
[ [
{ {
file: 'nx.json', file: 'nx.json',
ext: '.json',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => [ getChanges: () => [
{ {
@ -137,7 +133,6 @@ describe('getTouchedProjectsInNxJson', () => {
[ [
{ {
file: 'nx.json', file: 'nx.json',
ext: '.json',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => [ getChanges: () => [
{ {
@ -174,7 +169,6 @@ describe('getTouchedProjectsInNxJson', () => {
[ [
{ {
file: 'nx.json', file: 'nx.json',
ext: '.json',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => [ getChanges: () => [
{ {

View File

@ -45,7 +45,6 @@ describe('getTouchedProjectsFromTsConfig', () => {
[ [
{ {
file: 'source.ts', file: 'source.ts',
ext: '.ts',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => [new WholeFileChange()], getChanges: () => [new WholeFileChange()],
}, },
@ -69,7 +68,6 @@ describe('getTouchedProjectsFromTsConfig', () => {
[ [
{ {
file: tsConfig, file: tsConfig,
ext: '.json',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => [new WholeFileChange()], getChanges: () => [new WholeFileChange()],
}, },
@ -89,7 +87,6 @@ describe('getTouchedProjectsFromTsConfig', () => {
[ [
{ {
file: tsConfig, file: tsConfig,
ext: '.json',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => getChanges: () =>
jsonDiff( jsonDiff(
@ -121,7 +118,6 @@ describe('getTouchedProjectsFromTsConfig', () => {
[ [
{ {
file: tsConfig, file: tsConfig,
ext: '.json',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => getChanges: () =>
jsonDiff( jsonDiff(
@ -153,7 +149,6 @@ describe('getTouchedProjectsFromTsConfig', () => {
[ [
{ {
file: tsConfig, file: tsConfig,
ext: '.json',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => getChanges: () =>
jsonDiff( jsonDiff(
@ -187,7 +182,6 @@ describe('getTouchedProjectsFromTsConfig', () => {
[ [
{ {
file: tsConfig, file: tsConfig,
ext: '.json',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => getChanges: () =>
jsonDiff( jsonDiff(
@ -219,7 +213,6 @@ describe('getTouchedProjectsFromTsConfig', () => {
[ [
{ {
file: tsConfig, file: tsConfig,
ext: '.json',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => getChanges: () =>
jsonDiff( jsonDiff(
@ -256,7 +249,6 @@ describe('getTouchedProjectsFromTsConfig', () => {
[ [
{ {
file: tsConfig, file: tsConfig,
ext: '.json',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => getChanges: () =>
jsonDiff( jsonDiff(
@ -291,7 +283,6 @@ describe('getTouchedProjectsFromTsConfig', () => {
[ [
{ {
file: tsConfig, file: tsConfig,
ext: '.json',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => getChanges: () =>
jsonDiff( jsonDiff(

View File

@ -8,7 +8,6 @@ describe('getTouchedProjectsInWorkspaceJson', () => {
[ [
{ {
file: 'source.ts', file: 'source.ts',
ext: '.ts',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => [new WholeFileChange()], getChanges: () => [new WholeFileChange()],
}, },
@ -31,7 +30,6 @@ describe('getTouchedProjectsInWorkspaceJson', () => {
[ [
{ {
file: 'workspace.json', file: 'workspace.json',
ext: '.json',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => [new WholeFileChange()], getChanges: () => [new WholeFileChange()],
}, },
@ -56,7 +54,6 @@ describe('getTouchedProjectsInWorkspaceJson', () => {
[ [
{ {
file: 'workspace.json', file: 'workspace.json',
ext: '.json',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => [ getChanges: () => [
{ {
@ -90,7 +87,6 @@ describe('getTouchedProjectsInWorkspaceJson', () => {
[ [
{ {
file: 'workspace.json', file: 'workspace.json',
ext: '.json',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => [ getChanges: () => [
{ {
@ -131,7 +127,6 @@ describe('getTouchedProjectsInWorkspaceJson', () => {
[ [
{ {
file: 'workspace.json', file: 'workspace.json',
ext: '.json',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => [ getChanges: () => [
{ {
@ -166,7 +161,6 @@ describe('getTouchedProjectsInWorkspaceJson', () => {
[ [
{ {
file: 'workspace.json', file: 'workspace.json',
ext: '.json',
hash: 'some-hash', hash: 'some-hash',
getChanges: () => [ getChanges: () => [
{ {

View File

@ -7,7 +7,6 @@ import {
function getFileChanges(files: string[]) { function getFileChanges(files: string[]) {
return files.map((f) => ({ return files.map((f) => ({
file: f, file: f,
ext: `.${f.split('.').pop()}`,
hash: 'some-hash', hash: 'some-hash',
getChanges: () => [new WholeFileChange()], getChanges: () => [new WholeFileChange()],
})); }));

View File

@ -22,19 +22,17 @@ describe('createFileMap', () => {
}, },
}; };
const files = [ const files = [
{ file: 'apps/demo/src/main.ts', hash: 'some-hash', ext: '.ts' }, { file: 'apps/demo/src/main.ts', hash: 'some-hash' },
{ file: 'apps/demo-e2e/src/main.ts', hash: 'some-hash', ext: '.ts' }, { file: 'apps/demo-e2e/src/main.ts', hash: 'some-hash' },
{ file: 'libs/ui/src/index.ts', hash: 'some-hash', ext: '.ts' }, { file: 'libs/ui/src/index.ts', hash: 'some-hash' },
]; ];
const result = createProjectFileMap(workspaceJson, files); const result = createProjectFileMap(workspaceJson, files);
expect(result).toEqual({ expect(result).toEqual({
demo: [{ file: 'apps/demo/src/main.ts', hash: 'some-hash', ext: '.ts' }], demo: [{ file: 'apps/demo/src/main.ts', hash: 'some-hash' }],
'demo-e2e': [ 'demo-e2e': [{ file: 'apps/demo-e2e/src/main.ts', hash: 'some-hash' }],
{ file: 'apps/demo-e2e/src/main.ts', hash: 'some-hash', ext: '.ts' }, ui: [{ file: 'libs/ui/src/index.ts', hash: 'some-hash' }],
],
ui: [{ file: 'libs/ui/src/index.ts', hash: 'some-hash', ext: '.ts' }],
}); });
}); });
}); });

View File

@ -1,4 +1,8 @@
import { toOldFormatOrNull, Workspaces } from '@nrwl/tao/src/shared/workspace'; import {
toOldFormatOrNull,
WorkspaceJsonConfiguration,
Workspaces,
} from '@nrwl/tao/src/shared/workspace';
import type { import type {
FileData, FileData,
NxJsonConfiguration, NxJsonConfiguration,
@ -17,6 +21,7 @@ import { fileExists, readJsonFile } from '../utilities/fileutils';
import { jsonDiff } from '../utilities/json-diff'; import { jsonDiff } from '../utilities/json-diff';
import { defaultFileHasher } from './hasher/file-hasher'; import { defaultFileHasher } from './hasher/file-hasher';
import type { Environment } from './shared-interfaces'; import type { Environment } from './shared-interfaces';
import { projectFileDataCompatAdapter } from './project-graph/project-graph';
const ignore = require('ignore'); const ignore = require('ignore');
@ -114,13 +119,13 @@ function getFileData(filePath: string): FileData {
return { return {
file, file,
hash: defaultFileHasher.hashFile(filePath), hash: defaultFileHasher.hashFile(filePath),
ext: extname(filePath),
}; };
} }
export function allFilesInDir( export function allFilesInDir(
dirName: string, dirName: string,
recurse: boolean = true recurse: boolean = true,
projectGraphVersion = '3.0'
): FileData[] { ): FileData[] {
const ignoredGlobs = getIgnoredGlobs(); const ignoredGlobs = getIgnoredGlobs();
const relDirName = relative(appRootPath, dirName); const relDirName = relative(appRootPath, dirName);
@ -139,9 +144,14 @@ export function allFilesInDir(
const s = statSync(child); const s = statSync(child);
if (!s.isDirectory()) { if (!s.isDirectory()) {
// add starting with "apps/myapp/..." or "libs/mylib/..." // add starting with "apps/myapp/..." or "libs/mylib/..."
res.push(getFileData(child)); res.push(
projectFileDataCompatAdapter(
getFileData(child),
projectGraphVersion
)
);
} else if (s.isDirectory() && recurse) { } else if (s.isDirectory() && recurse) {
res = [...res, ...allFilesInDir(child)]; res = [...res, ...allFilesInDir(child, true, projectGraphVersion)];
} }
} catch (e) {} } catch (e) {}
}); });
@ -160,7 +170,7 @@ export function readFileIfExisting(path: string) {
return existsSync(path) ? readFileSync(path, 'utf-8') : ''; return existsSync(path) ? readFileSync(path, 'utf-8') : '';
} }
export function readWorkspaceJson() { export function readWorkspaceJson(): WorkspaceJsonConfiguration {
return readWorkspaceConfig({ return readWorkspaceConfig({
format: 'nx', format: 'nx',
path: appRootPath, path: appRootPath,
@ -234,20 +244,28 @@ export function rootWorkspaceFileNames(): string[] {
return [`package.json`, workspaceFileName(), `nx.json`, `tsconfig.base.json`]; return [`package.json`, workspaceFileName(), `nx.json`, `tsconfig.base.json`];
} }
export function rootWorkspaceFileData(): FileData[] { export function rootWorkspaceFileData(projectGraphVersion = '3.0'): FileData[] {
return rootWorkspaceFileNames().map((f) => return rootWorkspaceFileNames().map((f) =>
getFileData(`${appRootPath}/${f}`) projectFileDataCompatAdapter(
getFileData(`${appRootPath}/${f}`),
projectGraphVersion
)
); );
} }
export function readWorkspaceFiles(): FileData[] { export function readWorkspaceFiles(projectGraphVersion = '3.0'): FileData[] {
performance.mark('read workspace files:start'); performance.mark('read workspace files:start');
if (defaultFileHasher.usesGitForHashing) { if (defaultFileHasher.usesGitForHashing) {
const ignoredGlobs = getIgnoredGlobs(); const ignoredGlobs = getIgnoredGlobs();
const r = defaultFileHasher.workspaceFiles const r = defaultFileHasher.workspaceFiles
.filter((f) => !ignoredGlobs.ignores(f)) .filter((f) => !ignoredGlobs.ignores(f))
.map((f) => getFileData(`${appRootPath}/${f}`)); .map((f) =>
projectFileDataCompatAdapter(
getFileData(`${appRootPath}/${f}`),
projectGraphVersion
)
);
performance.mark('read workspace files:end'); performance.mark('read workspace files:end');
performance.measure( performance.measure(
'read workspace files', 'read workspace files',
@ -258,15 +276,24 @@ export function readWorkspaceFiles(): FileData[] {
return r; return r;
} else { } else {
const r = []; const r = [];
r.push(...rootWorkspaceFileData()); r.push(...rootWorkspaceFileData(projectGraphVersion));
// Add known workspace files and directories // Add known workspace files and directories
appendArray(r, allFilesInDir(appRootPath, false)); appendArray(r, allFilesInDir(appRootPath, false, projectGraphVersion));
appendArray(r, allFilesInDir(`${appRootPath}/tools`)); appendArray(
r,
allFilesInDir(`${appRootPath}/tools`, true, projectGraphVersion)
);
const wl = workspaceLayout(); const wl = workspaceLayout();
appendArray(r, allFilesInDir(`${appRootPath}/${wl.appsDir}`)); appendArray(
r,
allFilesInDir(`${appRootPath}/${wl.appsDir}`, true, projectGraphVersion)
);
if (wl.appsDir !== wl.libsDir) { if (wl.appsDir !== wl.libsDir) {
appendArray(r, allFilesInDir(`${appRootPath}/${wl.libsDir}`)); appendArray(
r,
allFilesInDir(`${appRootPath}/${wl.libsDir}`, true, projectGraphVersion)
);
} }
performance.mark('read workspace files:end'); performance.mark('read workspace files:end');
performance.measure( performance.measure(

View File

@ -44,7 +44,7 @@ describe('Hasher', () => {
type: 'lib', type: 'lib',
data: { data: {
root: '', root: '',
files: [{ file: '/file', ext: '.ts', hash: 'file.hash' }], files: [{ file: '/file.ts', hash: 'file.hash' }],
}, },
}, },
}, },
@ -75,7 +75,7 @@ describe('Hasher', () => {
expect(hash.details.command).toEqual('proj|build||{"prop":"prop-value"}'); expect(hash.details.command).toEqual('proj|build||{"prop":"prop-value"}');
expect(hash.details.nodes).toEqual({ expect(hash.details.nodes).toEqual({
proj: '/file|file.hash|{"root":"proj-from-workspace.json"}|"proj-from-nx.json"', proj: '/file.ts|file.hash|{"root":"proj-from-workspace.json"}|"proj-from-nx.json"',
}); });
expect(hash.details.implicitDeps).toEqual({ expect(hash.details.implicitDeps).toEqual({
'yarn.lock': 'yarn.lock.hash', 'yarn.lock': 'yarn.lock.hash',
@ -99,7 +99,7 @@ describe('Hasher', () => {
type: 'lib', type: 'lib',
data: { data: {
root: '', root: '',
files: [{ file: '/file', ext: '.ts', hash: 'some-hash' }], files: [{ file: '/file.ts', hash: 'some-hash' }],
}, },
}, },
}, },
@ -143,7 +143,7 @@ describe('Hasher', () => {
type: 'lib', type: 'lib',
data: { data: {
root: '', root: '',
files: [{ file: '/filea', ext: '.ts', hash: 'a.hash' }], files: [{ file: '/filea.ts', hash: 'a.hash' }],
}, },
}, },
child: { child: {
@ -151,7 +151,7 @@ describe('Hasher', () => {
type: 'lib', type: 'lib',
data: { data: {
root: '', root: '',
files: [{ file: '/fileb', ext: '.ts', hash: 'b.hash' }], files: [{ file: '/fileb.ts', hash: 'b.hash' }],
}, },
}, },
}, },
@ -172,8 +172,8 @@ describe('Hasher', () => {
// note that the parent hash is based on parent source files only! // note that the parent hash is based on parent source files only!
expect(hash.details.nodes).toEqual({ expect(hash.details.nodes).toEqual({
parent: '/filea|a.hash|""|""', parent: '/filea.ts|a.hash|""|""',
child: '/fileb|b.hash|""|""', child: '/fileb.ts|b.hash|""|""',
}); });
}); });
@ -188,7 +188,7 @@ describe('Hasher', () => {
type: 'lib', type: 'lib',
data: { data: {
root: '', root: '',
files: [{ file: '/filea', ext: '.ts', hash: 'a.hash' }], files: [{ file: '/filea.ts', hash: 'a.hash' }],
}, },
}, },
projb: { projb: {
@ -196,7 +196,7 @@ describe('Hasher', () => {
type: 'lib', type: 'lib',
data: { data: {
root: '', root: '',
files: [{ file: '/fileb', ext: '.ts', hash: 'b.hash' }], files: [{ file: '/fileb.ts', hash: 'b.hash' }],
}, },
}, },
}, },
@ -223,8 +223,8 @@ describe('Hasher', () => {
expect(tasksHash.value).toContain('proj'); //project expect(tasksHash.value).toContain('proj'); //project
expect(tasksHash.value).toContain('build'); //target expect(tasksHash.value).toContain('build'); //target
expect(tasksHash.details.nodes).toEqual({ expect(tasksHash.details.nodes).toEqual({
proja: '/filea|a.hash|""|""', proja: '/filea.ts|a.hash|""|""',
projb: '/fileb|b.hash|""|""', projb: '/fileb.ts|b.hash|""|""',
}); });
const hashb = await hasher.hashTaskWithDepsAndContext({ const hashb = await hasher.hashTaskWithDepsAndContext({
@ -240,8 +240,8 @@ describe('Hasher', () => {
expect(hashb.value).toContain('proj'); //project expect(hashb.value).toContain('proj'); //project
expect(hashb.value).toContain('build'); //target expect(hashb.value).toContain('build'); //target
expect(hashb.details.nodes).toEqual({ expect(hashb.details.nodes).toEqual({
proja: '/filea|a.hash|""|""', proja: '/filea.ts|a.hash|""|""',
projb: '/fileb|b.hash|""|""', projb: '/fileb.ts|b.hash|""|""',
}); });
}); });
@ -265,12 +265,10 @@ describe('Hasher', () => {
{ {
file: 'global1', file: 'global1',
hash: 'hash1', hash: 'hash1',
ext: '',
}, },
{ {
file: 'global2', file: 'global2',
hash: 'hash2', hash: 'hash2',
ext: '',
}, },
], ],
}, },

View File

@ -102,7 +102,6 @@ describe('nx deps utils', () => {
files: [ files: [
{ {
file: 'index.ts', file: 'index.ts',
ext: 'ts',
hash: 'hash1', hash: 'hash1',
}, },
], ],
@ -116,7 +115,6 @@ describe('nx deps utils', () => {
mylib: [ mylib: [
{ {
file: 'index.ts', file: 'index.ts',
ext: 'ts',
hash: 'hash1', hash: 'hash1',
}, },
], ],
@ -131,7 +129,6 @@ describe('nx deps utils', () => {
mylib: { mylib: {
'index.ts': { 'index.ts': {
file: 'index.ts', file: 'index.ts',
ext: 'ts',
hash: 'hash1', hash: 'hash1',
}, },
}, },
@ -148,7 +145,6 @@ describe('nx deps utils', () => {
files: [ files: [
{ {
file: 'index.ts', file: 'index.ts',
ext: 'ts',
hash: 'hash1', hash: 'hash1',
}, },
], ],
@ -162,14 +158,12 @@ describe('nx deps utils', () => {
mylib: [ mylib: [
{ {
file: 'index.ts', file: 'index.ts',
ext: 'ts',
hash: 'hash1', hash: 'hash1',
}, },
], ],
secondlib: [ secondlib: [
{ {
file: 'index.ts', file: 'index.ts',
ext: 'ts',
hash: 'hash2', hash: 'hash2',
}, },
], ],
@ -183,7 +177,6 @@ describe('nx deps utils', () => {
secondlib: [ secondlib: [
{ {
file: 'index.ts', file: 'index.ts',
ext: 'ts',
hash: 'hash2', hash: 'hash2',
}, },
], ],
@ -192,13 +185,12 @@ describe('nx deps utils', () => {
mylib: { mylib: {
'index.ts': { 'index.ts': {
file: 'index.ts', file: 'index.ts',
ext: 'ts',
hash: 'hash1', hash: 'hash1',
}, },
}, },
}); });
expect(r.filesToProcess).toEqual({ expect(r.filesToProcess).toEqual({
secondlib: [{ ext: 'ts', file: 'index.ts', hash: 'hash2' }], secondlib: [{ file: 'index.ts', hash: 'hash2' }],
}); });
}); });
@ -212,17 +204,14 @@ describe('nx deps utils', () => {
files: [ files: [
{ {
file: 'index1.ts', file: 'index1.ts',
ext: 'ts',
hash: 'hash1', hash: 'hash1',
}, },
{ {
file: 'index2.ts', file: 'index2.ts',
ext: 'ts',
hash: 'hash2', hash: 'hash2',
}, },
{ {
file: 'index3.ts', file: 'index3.ts',
ext: 'ts',
hash: 'hash3', hash: 'hash3',
}, },
], ],
@ -236,17 +225,14 @@ describe('nx deps utils', () => {
mylib: [ mylib: [
{ {
file: 'index1.ts', file: 'index1.ts',
ext: 'ts',
hash: 'hash1', hash: 'hash1',
}, },
{ {
file: 'index2.ts', file: 'index2.ts',
ext: 'ts',
hash: 'hash2b', hash: 'hash2b',
}, },
{ {
file: 'index4.ts', file: 'index4.ts',
ext: 'ts',
hash: 'hash4', hash: 'hash4',
}, },
], ],
@ -260,12 +246,10 @@ describe('nx deps utils', () => {
mylib: [ mylib: [
{ {
file: 'index2.ts', file: 'index2.ts',
ext: 'ts',
hash: 'hash2b', hash: 'hash2b',
}, },
{ {
file: 'index4.ts', file: 'index4.ts',
ext: 'ts',
hash: 'hash4', hash: 'hash4',
}, },
], ],
@ -274,7 +258,6 @@ describe('nx deps utils', () => {
mylib: { mylib: {
'index1.ts': { 'index1.ts': {
file: 'index1.ts', file: 'index1.ts',
ext: 'ts',
hash: 'hash1', hash: 'hash1',
}, },
}, },

View File

@ -92,7 +92,7 @@ export function writeCache(
version: packageJsonDeps[p], version: packageJsonDeps[p],
})); }));
const newValue: ProjectGraphCache = { const newValue: ProjectGraphCache = {
version: '3.0', version: projectGraph.version || '4.0',
deps: packageJsonDeps, deps: packageJsonDeps,
pathMappings: tsConfig.compilerOptions.paths || {}, pathMappings: tsConfig.compilerOptions.paths || {},
nxJsonPlugins, nxJsonPlugins,
@ -119,7 +119,9 @@ export function shouldRecomputeWholeGraph(
if ( if (
Object.keys(cache.nodes).some( Object.keys(cache.nodes).some(
(p) => (p) =>
(cache.nodes[p].type === 'app' || cache.nodes[p].type === 'lib') && (cache.nodes[p].type === 'app' ||
cache.nodes[p].type === 'lib' ||
cache.nodes[p].type === 'e2e') &&
!workspaceJson.projects[p] !workspaceJson.projects[p]
) )
) { ) {

View File

@ -4,7 +4,12 @@ jest.mock('fs', () => require('memfs').fs);
jest.mock('@nrwl/tao/src/utils/app-root', () => ({ jest.mock('@nrwl/tao/src/utils/app-root', () => ({
appRootPath: '/root', appRootPath: '/root',
})); }));
import { createProjectGraphAsync } from './project-graph'; import {
createProjectGraphAsync,
projectFileDataCompatAdapter,
projectGraphMigrate3to4,
projectGraphCompat4to3,
} from './project-graph';
import { import {
NxJsonConfiguration, NxJsonConfiguration,
stripIndents, stripIndents,
@ -239,4 +244,170 @@ describe('project graph', () => {
}, },
]); ]);
}); });
describe('project graph adapters', () => {
it('should map FileData to deprecated graph version', () => {
expect(
projectFileDataCompatAdapter({ file: 'a.ts', hash: 'some hash' }, '3.0')
).toEqual({ file: 'a.ts', hash: 'some hash', ext: '.ts' });
expect(
projectFileDataCompatAdapter(
{
file: 'a.ts',
hash: 'some hash',
deps: [],
},
'3.0'
)
).toEqual({ file: 'a.ts', hash: 'some hash', ext: '.ts', deps: [] });
expect(
projectFileDataCompatAdapter(
{
file: 'a.ts',
hash: 'some hash',
ext: '.keepthis',
},
'3.0'
)
).toEqual({ file: 'a.ts', hash: 'some hash', ext: '.keepthis' });
});
it('should map FileData to latest graph version', () => {
expect(
projectFileDataCompatAdapter(
{ file: 'a.ts', hash: 'some hash', ext: '.ts' },
'4.0'
)
).toEqual({ file: 'a.ts', hash: 'some hash' });
expect(
projectFileDataCompatAdapter(
{ file: 'a.ts', hash: 'some hash', ext: '.ts', deps: [] },
'4.0'
)
).toEqual({ file: 'a.ts', hash: 'some hash', deps: [] });
});
it('should map nodes to deprecated graph version', () => {
const source = {
nodes: {
node1: {
name: 'node1',
type: 'app',
data: {
files: [
{ file: 'index.ts', hash: 'some hash' },
{
file: 'node1.jpeg',
hash: 'some hash',
ext: '.keepextension',
},
],
},
},
node2: {
name: 'node2',
type: 'lib',
data: {
files: [{ file: 'node2.html', hash: 'some hash', deps: [] }],
},
},
},
dependencies: {},
version: '4.0',
};
const result = {
nodes: {
node1: {
name: 'node1',
type: 'app',
data: {
files: [
{ file: 'index.ts', hash: 'some hash', ext: '.ts' },
{
file: 'node1.jpeg',
hash: 'some hash',
ext: '.keepextension',
},
],
},
},
node2: {
name: 'node2',
type: 'lib',
data: {
files: [
{
file: 'node2.html',
hash: 'some hash',
deps: [],
ext: '.html',
},
],
},
},
},
dependencies: {},
version: '3.0',
};
expect(projectGraphCompat4to3(source)).toEqual(result);
});
it('should map nodes to latest graph version', () => {
const source = {
nodes: {
node1: {
name: 'node1',
type: 'app',
data: {
files: [
{ file: 'index.ts', hash: 'some hash', ext: '.ts' },
{
file: 'node1.jpeg',
hash: 'some hash',
ext: '.keepextension',
},
],
},
},
node2: {
name: 'node2',
type: 'lib',
data: {
files: [
{
file: 'node2.html',
hash: 'some hash',
deps: [],
ext: '.html',
},
],
},
},
},
dependencies: {},
version: '3.0',
};
const result = {
nodes: {
node1: {
name: 'node1',
type: 'app',
data: {
files: [
{ file: 'index.ts', hash: 'some hash' },
{ file: 'node1.jpeg', hash: 'some hash' },
],
},
},
node2: {
name: 'node2',
type: 'lib',
data: {
files: [{ file: 'node2.html', hash: 'some hash', deps: [] }],
},
},
},
dependencies: {},
version: '4.0',
};
expect(projectGraphMigrate3to4(source)).toEqual(result);
});
});
}); });

View File

@ -6,12 +6,13 @@ import type {
ProjectConfiguration, ProjectConfiguration,
ProjectFileMap, ProjectFileMap,
ProjectGraph, ProjectGraph,
ProjectGraphNode,
ProjectGraphProcessorContext, ProjectGraphProcessorContext,
WorkspaceJsonConfiguration, WorkspaceJsonConfiguration,
} from '@nrwl/devkit'; } from '@nrwl/devkit';
import { ProjectGraphBuilder, readJsonFile, logger } from '@nrwl/devkit'; import { ProjectGraphBuilder, readJsonFile, logger } from '@nrwl/devkit';
import { appRootPath } from '@nrwl/tao/src/utils/app-root'; import { appRootPath } from '@nrwl/tao/src/utils/app-root';
import { join } from 'path'; import { join, extname } from 'path';
import { performance } from 'perf_hooks'; import { performance } from 'perf_hooks';
import { assertWorkspaceValidity } from '../assert-workspace-validity'; import { assertWorkspaceValidity } from '../assert-workspace-validity';
import { createProjectFileMap } from '../file-graph'; import { createProjectFileMap } from '../file-graph';
@ -41,27 +42,127 @@ import {
/** /**
* Synchronously reads the latest cached copy of the workspace's ProjectGraph. * Synchronously reads the latest cached copy of the workspace's ProjectGraph.
* @throws {Error} if there is no cached ProjectGraph to read from * @throws {Error} if there is no cached ProjectGraph to read from
* @param {string} projectGraphVersion Version to map ProjectGraph to
* @returns {ProjectGraph}
*/ */
export function readCachedProjectGraph(): ProjectGraph { export function readCachedProjectGraph(
projectGraphVersion = '3.0'
): ProjectGraph {
const projectGraphCache: ProjectGraphCache | false = readCache(); const projectGraphCache: ProjectGraphCache | false = readCache();
if (!projectGraphCache) { if (!projectGraphCache) {
throw new Error(` throw new Error(`
[readCachedProjectGraph] ERROR: No cached ProjectGraph is available. [readCachedProjectGraph] ERROR: No cached ProjectGraph is available.
If you are leveraging \`readCachedProjectGraph()\` directly then you will need to refactor your usage to first ensure that If you are leveraging \`readCachedProjectGraph()\` directly then you will need to refactor your usage to first ensure that
the ProjectGraph is created by calling \`await createProjectGraphAsync()\` somewhere before attempting to read the data. the ProjectGraph is created by calling \`await createProjectGraphAsync()\` somewhere before attempting to read the data.
If you encounter this error as part of running standard \`nx\` commands then please open an issue on https://github.com/nrwl/nx If you encounter this error as part of running standard \`nx\` commands then please open an issue on https://github.com/nrwl/nx
`); `);
} }
return { let projectGraph: ProjectGraph = {
version: projectGraphCache.version,
nodes: projectGraphCache.nodes, nodes: projectGraphCache.nodes,
dependencies: projectGraphCache.dependencies, dependencies: projectGraphCache.dependencies,
}; };
if (projectGraphVersion !== projectGraph.version) {
projectGraph =
projectGraphVersion === '3.0'
? projectGraphCompat4to3(projectGraph)
: projectGraphMigrate3to4(projectGraph);
}
return projectGraph;
} }
export async function createProjectGraphAsync(): Promise<ProjectGraph> { /**
return createProjectGraph(); * Migrate project graph from v3 to v4
* @param {ProjectGraph} projectGraph
*/
export function projectGraphMigrate3to4(
projectGraph: ProjectGraph
): ProjectGraph {
const nodes: Record<string, ProjectGraphNode> = {};
Object.entries(projectGraph.nodes).forEach(([name, node]) => {
const files = node.data.files.map(({ file, hash, deps }) => ({
file,
hash,
...(deps && { deps }),
}));
nodes[name] = {
...node,
data: {
...node.data,
files,
},
};
});
return {
...projectGraph,
nodes,
version: '4.0',
};
}
/**
* Backwards compatibility adapter for project Nodes
* @param {ProjectGraph} projectGraph
* @returns {ProjectGraph}
*/
export function projectGraphCompat4to3(
projectGraph: ProjectGraph
): ProjectGraph {
const nodes: Record<string, ProjectGraphNode> = {};
Object.entries(projectGraph.nodes).forEach(([name, node]) => {
const files = node.data.files.map(({ file, hash, ext, deps }) => ({
file,
hash,
ext: ext || extname(file),
...(deps && { deps }),
}));
nodes[name] = {
...node,
data: {
...node.data,
files,
},
};
});
return {
...projectGraph,
nodes,
version: '3.0',
};
}
/**
* Backwards compatibility adapter for FileData
* @param {FileData} fileData
* @param {string?} projectGraphVersion
* @returns
*/
export function projectFileDataCompatAdapter(
fileData: FileData,
projectGraphVersion: string
): FileData {
const { file, hash, ext, deps } = fileData;
if (projectGraphVersion !== '3.0') {
return { file, hash, ...{ deps } };
} else {
return { file, hash, ext: ext || extname(file), ...{ deps } };
}
}
export async function createProjectGraphAsync(
projectGraphVersion = '3.0'
): Promise<ProjectGraph> {
return createProjectGraph(
undefined,
undefined,
undefined,
projectGraphVersion
);
} }
function readCombinedDeps() { function readCombinedDeps() {
@ -74,10 +175,16 @@ function readCombinedDeps() {
* @deprecated This function is deprecated in favor of the new asynchronous version {@link createProjectGraphAsync} * @deprecated This function is deprecated in favor of the new asynchronous version {@link createProjectGraphAsync}
*/ */
export function createProjectGraph( export function createProjectGraph(
workspaceJson = readWorkspaceJson(), workspaceJson?: WorkspaceJsonConfiguration,
nxJson = readNxJson(), nxJson?: NxJsonConfiguration,
workspaceFiles = readWorkspaceFiles() workspaceFiles?: FileData[],
projectGraphVersion?: string
): ProjectGraph { ): ProjectGraph {
projectGraphVersion = projectGraphVersion || '3.0';
workspaceJson = workspaceJson || readWorkspaceJson();
nxJson = nxJson || readNxJson();
workspaceFiles = workspaceFiles || readWorkspaceFiles(projectGraphVersion);
const cacheEnabled = process.env.NX_CACHE_PROJECT_GRAPH !== 'false'; const cacheEnabled = process.env.NX_CACHE_PROJECT_GRAPH !== 'false';
let cache = cacheEnabled ? readCache() : false; let cache = cacheEnabled ? readCache() : false;
assertWorkspaceValidity(workspaceJson, nxJson); assertWorkspaceValidity(workspaceJson, nxJson);
@ -90,15 +197,14 @@ export function createProjectGraph(
let cachedFileData = {}; let cachedFileData = {};
if ( if (
cache && cache &&
cache.version === '3.0' && (cache.version === '3.0' || cache.version === '4.0') &&
!shouldRecomputeWholeGraph( !shouldRecomputeWholeGraph(
cache, cache,
packageJsonDeps, packageJsonDeps,
workspaceJson, workspaceJson,
normalizedNxJson, normalizedNxJson,
rootTsConfig rootTsConfig
) && )
cacheEnabled
) { ) {
const fromCache = extractCachedFileData(projectFileMap, cache); const fromCache = extractCachedFileData(projectFileMap, cache);
filesToProcess = fromCache.filesToProcess; filesToProcess = fromCache.filesToProcess;
@ -110,7 +216,17 @@ export function createProjectGraph(
projectFileMap, projectFileMap,
filesToProcess filesToProcess
); );
const projectGraph = buildProjectGraph(context, cachedFileData); let projectGraph = buildProjectGraph(
context,
cachedFileData,
projectGraphVersion
);
if (cache && cache.version && projectGraphVersion !== cache.version) {
projectGraph =
projectGraphVersion === '3.0'
? projectGraphCompat4to3(projectGraph)
: projectGraphMigrate3to4(projectGraph);
}
if (cacheEnabled) { if (cacheEnabled) {
writeCache(packageJsonDeps, nxJson, rootTsConfig, projectGraph); writeCache(packageJsonDeps, nxJson, rootTsConfig, projectGraph);
} }
@ -135,7 +251,8 @@ function addWorkspaceFiles(
function buildProjectGraph( function buildProjectGraph(
ctx: ProjectGraphProcessorContext, ctx: ProjectGraphProcessorContext,
cachedFileData: { [project: string]: { [file: string]: FileData } } cachedFileData: { [project: string]: { [file: string]: FileData } },
projectGraphVersion: string
) { ) {
performance.mark('build project graph:start'); performance.mark('build project graph:start');
@ -155,6 +272,7 @@ function buildProjectGraph(
buildExplicitTypeScriptDependencies(ctx, builder); buildExplicitTypeScriptDependencies(ctx, builder);
buildExplicitPackageJsonDependencies(ctx, builder); buildExplicitPackageJsonDependencies(ctx, builder);
buildImplicitProjectDependencies(ctx, builder); buildImplicitProjectDependencies(ctx, builder);
builder.setVersion(projectGraphVersion);
const initProjectGraph = builder.getUpdatedProjectGraph(); const initProjectGraph = builder.getUpdatedProjectGraph();
const r = updateProjectGraphWithPlugins(ctx, initProjectGraph); const r = updateProjectGraphWithPlugins(ctx, initProjectGraph);
@ -175,16 +293,16 @@ function createContext(
fileMap: ProjectFileMap, fileMap: ProjectFileMap,
filesToProcess: ProjectFileMap filesToProcess: ProjectFileMap
): ProjectGraphProcessorContext { ): ProjectGraphProcessorContext {
const projects = Object.keys(workspaceJson.projects).reduce( const projects: Record<
(map, projectName) => { string,
map[projectName] = { ProjectConfiguration & NxJsonProjectConfiguration
...workspaceJson.projects[projectName], > = Object.keys(workspaceJson.projects).reduce((map, projectName) => {
...nxJson.projects[projectName], map[projectName] = {
}; ...workspaceJson.projects[projectName],
return map; ...nxJson.projects[projectName],
}, };
{} as Record<string, ProjectConfiguration & NxJsonProjectConfiguration> return map;
); }, {});
return { return {
workspace: { workspace: {
...workspaceJson, ...workspaceJson,

View File

@ -77,14 +77,12 @@ describe('findTargetProjectWithImport', () => {
{ {
file: 'libs/proj/index.ts', file: 'libs/proj/index.ts',
hash: 'some-hash', hash: 'some-hash',
ext: '.ts',
}, },
], ],
proj2: [ proj2: [
{ {
file: 'libs/proj2/index.ts', file: 'libs/proj2/index.ts',
hash: 'some-hash', hash: 'some-hash',
ext: '.ts',
}, },
{ {
file: 'libs/proj2/deep/index.ts', file: 'libs/proj2/deep/index.ts',
@ -96,14 +94,12 @@ describe('findTargetProjectWithImport', () => {
{ {
file: 'libs/proj3a/index.ts', file: 'libs/proj3a/index.ts',
hash: 'some-hash', hash: 'some-hash',
ext: '.ts',
}, },
], ],
proj4ab: [ proj4ab: [
{ {
file: 'libs/proj4ab/index.ts', file: 'libs/proj4ab/index.ts',
hash: 'some-hash', hash: 'some-hash',
ext: '.ts',
}, },
], ],
proj5: [ proj5: [
@ -131,21 +127,18 @@ describe('findTargetProjectWithImport', () => {
{ {
file: 'libs/proj123/index.ts', file: 'libs/proj123/index.ts',
hash: 'some-hash', hash: 'some-hash',
ext: '.ts',
}, },
], ],
proj1234: [ proj1234: [
{ {
file: 'libs/proj1234/index.ts', file: 'libs/proj1234/index.ts',
hash: 'some-hash', hash: 'some-hash',
ext: '.ts',
}, },
], ],
'proj1234-child': [ 'proj1234-child': [
{ {
file: 'libs/proj1234-child/index.ts', file: 'libs/proj1234-child/index.ts',
hash: 'some-hash', hash: 'some-hash',
ext: '.ts',
}, },
], ],
}, },

View File

@ -18,7 +18,7 @@ export async function tscExecutor(
const normalizedOptions = normalizeOptions(options, context); const normalizedOptions = normalizeOptions(options, context);
// const projectRoot = context.workspace.projects[context.projectName].root; // const projectRoot = context.workspace.projects[context.projectName].root;
const projectGraph = readCachedProjectGraph(); const projectGraph = readCachedProjectGraph('4.0');
const { target, dependencies } = calculateProjectDependencies( const { target, dependencies } = calculateProjectDependencies(
projectGraph, projectGraph,
context.root, context.root,

View File

@ -16,7 +16,7 @@ export async function checkDependencies(_, schema: Schema): Promise<void> {
return; return;
} }
const graph: ProjectGraph = await createProjectGraphAsync(); const graph: ProjectGraph = await createProjectGraphAsync('4.0');
const reverseGraph = onlyWorkspaceProjects(reverse(graph)); const reverseGraph = onlyWorkspaceProjects(reverse(graph));

View File

@ -10,6 +10,7 @@ import {
import { Rule } from './nxEnforceModuleBoundariesRule'; import { Rule } from './nxEnforceModuleBoundariesRule';
import { TargetProjectLocator } from '../core/target-project-locator'; import { TargetProjectLocator } from '../core/target-project-locator';
import { mapProjectGraphFiles } from '../utils/runtime-lint-utils'; import { mapProjectGraphFiles } from '../utils/runtime-lint-utils';
import { FileData } from 'packages/devkit/src/project-graph/interfaces';
jest.mock('fs', () => require('memfs').fs); jest.mock('fs', () => require('memfs').fs);
jest.mock('@nrwl/tao/src/utils/app-root', () => ({ appRootPath: '/root' })); jest.mock('@nrwl/tao/src/utils/app-root', () => ({ appRootPath: '/root' }));
@ -1155,8 +1156,8 @@ describe('Enforce Module Boundaries (tslint)', () => {
}); });
}); });
function createFile(f) { function createFile(f): FileData {
return { file: f, ext: extname(f), hash: '' }; return { file: f, hash: '' };
} }
function runRule( function runRule(

View File

@ -51,7 +51,7 @@ export class Rule extends Lint.Rules.AbstractRule {
*/ */
try { try {
(global as any).projectGraph = mapProjectGraphFiles( (global as any).projectGraph = mapProjectGraphFiles(
readCachedProjectGraph() readCachedProjectGraph('4.0')
); );
} catch {} } catch {}
} }

View File

@ -6,5 +6,5 @@ import { createProjectGraph } from '../core/project-graph/project-graph';
* @deprecated This method is deprecated and `await {@link createProjectGraphAsync}()` should be used instead * @deprecated This method is deprecated and `await {@link createProjectGraphAsync}()` should be used instead
*/ */
export function createProjectGraphFromTree(tree: Tree) { export function createProjectGraphFromTree(tree: Tree) {
return createProjectGraph(undefined, undefined, undefined); return createProjectGraph(undefined, undefined, undefined, '3.0');
} }

View File

@ -17,7 +17,7 @@ export function createGlobPatternsForDependencies(
fileGlobPattern: string fileGlobPattern: string
): string[] { ): string[] {
const filenameRelativeToWorkspaceRoot = relative(appRootPath, dirPath); const filenameRelativeToWorkspaceRoot = relative(appRootPath, dirPath);
const projectGraph = readCachedProjectGraph(); const projectGraph = readCachedProjectGraph('4.0');
// find the project // find the project
let projectName; let projectName;

View File

@ -20,7 +20,7 @@ export function projectHasTargetAndConfiguration(
export function getSourceDirOfDependentProjects( export function getSourceDirOfDependentProjects(
projectName: string, projectName: string,
projectGraph = readCachedProjectGraph() projectGraph = readCachedProjectGraph('4.0')
): string[] { ): string[] {
if (!projectGraph.nodes[projectName]) { if (!projectGraph.nodes[projectName]) {
throw new Error( throw new Error(
@ -41,7 +41,7 @@ export function getSourceDirOfDependentProjects(
*/ */
export function getProjectNameFromDirPath( export function getProjectNameFromDirPath(
projRelativeDirPath: string, projRelativeDirPath: string,
projectGraph = readCachedProjectGraph() projectGraph = readCachedProjectGraph('4.0')
) { ) {
let parentNodeName = null; let parentNodeName = null;
for (const [nodeName, node] of Object.entries(projectGraph.nodes)) { for (const [nodeName, node] of Object.entries(projectGraph.nodes)) {
@ -75,7 +75,7 @@ export function getProjectNameFromDirPath(
*/ */
function findAllProjectNodeDependencies( function findAllProjectNodeDependencies(
parentNodeName: string, parentNodeName: string,
projectGraph = readCachedProjectGraph() projectGraph = readCachedProjectGraph('4.0')
): string[] { ): string[] {
const dependencyNodeNames = new Set<string>(); const dependencyNodeNames = new Set<string>();

View File

@ -367,7 +367,9 @@ export function readJsonInTree<T extends object = any>(
* 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(createProjectGraph()); return onlyWorkspaceProjects(
createProjectGraph(undefined, undefined, undefined, '3.0')
);
} }
// TODO(v13): remove this deprecated method // TODO(v13): remove this deprecated method
@ -375,7 +377,7 @@ export function getProjectGraphFromHost(host: Tree): ProjectGraph {
* @deprecated This method is deprecated and `await {@link createProjectGraphAsync}()` should be used instead * @deprecated This method is deprecated and `await {@link createProjectGraphAsync}()` should be used instead
*/ */
export function getFullProjectGraphFromHost(host: Tree): ProjectGraph { export function getFullProjectGraphFromHost(host: Tree): ProjectGraph {
return createProjectGraph(undefined, undefined, undefined); return createProjectGraph(undefined, undefined, undefined, '3.0');
} }
// TODO(v13): remove this deprecated method // TODO(v13): remove this deprecated method

View File

@ -42,7 +42,7 @@ function hasTag(proj: ProjectGraphNode, tag: string) {
} }
function removeExt(file: string): string { function removeExt(file: string): string {
return file.replace(/\.[^/.]+$/, ''); return file.replace(/(?<!(^|\/))\.[^/.]+$/, '');
} }
export function matchImportWithWildcard( export function matchImportWithWildcard(
@ -200,8 +200,8 @@ export function mapProjectGraphFiles<T>(
const nodes: Record<string, MappedProjectGraphNode> = {}; const nodes: Record<string, MappedProjectGraphNode> = {};
Object.entries(projectGraph.nodes).forEach(([name, node]) => { Object.entries(projectGraph.nodes).forEach(([name, node]) => {
const files: Record<string, FileData> = {}; const files: Record<string, FileData> = {};
node.data.files.forEach(({ file, hash, ext }) => { node.data.files.forEach(({ file, hash }) => {
files[file.slice(0, -ext.length)] = { file, hash, ext }; files[removeExt(file)] = { file, hash };
}); });
const data = { ...node.data, files }; const data = { ...node.data, files };