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
): Observable<BuilderOutput> {
const { target, dependencies } = calculateProjectDependencies(
readCachedProjectGraph(),
readCachedProjectGraph('4.0'),
context
);

View File

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

View File

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

View File

@ -45,7 +45,7 @@ function addHTMLPatternToBuilderConfig(
async function updateProjectESLintConfigsAndBuilders(
host: Tree
): 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

View File

@ -9,7 +9,8 @@ import type {
export interface FileData {
file: string;
hash: string;
ext: string;
/** @deprecated this field will be removed in v13. Use {@link path.extname} to parse extension */
ext?: 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
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 {
for (const sourceProject of Object.keys(this.graph.nodes)) {
const alreadySetTargetProjects =

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -7,7 +7,7 @@ import { hasDependentAppUsingWebBuild } from './utils';
export async function createBabelrcForWorkspaceLibs(host: Tree) {
const projects = getProjects(host);
const graph = reverse(await createProjectGraphAsync());
const graph = reverse(await createProjectGraphAsync('4.0'));
for (const [name, p] of projects.entries()) {
if (!hasDependentAppUsingWebBuild(name, graph, projects)) {

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@ import { output } from '../utilities/output';
import * as path from 'path';
export async function workspaceLint(): Promise<void> {
const graph = onlyWorkspaceProjects(await createProjectGraphAsync());
const graph = onlyWorkspaceProjects(await createProjectGraphAsync('4.0'));
const cliErrorOutputConfigs = new WorkspaceIntegrityChecks(
graph,
@ -25,7 +25,7 @@ export async function workspaceLint(): Promise<void> {
function readAllFilesFromAppsAndLibs() {
const wl = workspaceLayout();
return readWorkspaceFiles()
return readWorkspaceFiles('4.0')
.map((f) => f.file)
.filter(
(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);
const projectGraph = await createProjectGraphAsync();
const projectGraph = await createProjectGraphAsync('4.0');
const projects = projectsToRun(nxArgs, projectGraph);
const projectsNotExcluded = applyExclude(projects, nxArgs);
const env = readEnvironment(nxArgs.target, projectsNotExcluded);

View File

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

View File

@ -1,7 +1,6 @@
import { WorkspaceIntegrityChecks } from './workspace-integrity-checks';
import * as chalk from 'chalk';
import { ProjectType } from '../core/project-graph';
import { extname } from 'path';
describe('WorkspaceIntegrityChecks', () => {
describe('workspace.json is in sync with the filesystem', () => {
@ -106,5 +105,5 @@ describe('WorkspaceIntegrityChecks', () => {
});
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, [
{
file: 'something-for-api.txt',
ext: '.txt',
hash: 'some-hash',
getChanges: () => [new WholeFileChange()],
},
{
file: 'libs/ui/src/index.ts',
ext: '.ts',
hash: 'some-hash',
getChanges: () => [new WholeFileChange()],
},
@ -182,7 +180,6 @@ describe('project graph', () => {
const affected = filterAffected(graph, [
{
file: 'package.json',
ext: '.json',
hash: 'some-hash',
getChanges: () => jsonDiff(packageJson, updatedPackageJson),
},
@ -238,7 +235,6 @@ describe('project graph', () => {
const affected = filterAffected(graph, [
{
file: 'package.json',
ext: '.json',
hash: 'some-hash',
getChanges: () => jsonDiff(packageJson, updatedPackageJson),
},
@ -259,7 +255,6 @@ describe('project graph', () => {
const affected = filterAffected(graph, [
{
file: 'package.json',
ext: '.json',
hash: 'some-hash',
getChanges: () => jsonDiff(packageJson, updatedPackageJson),
},

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

@ -44,7 +44,7 @@ describe('Hasher', () => {
type: 'lib',
data: {
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.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({
'yarn.lock': 'yarn.lock.hash',
@ -99,7 +99,7 @@ describe('Hasher', () => {
type: 'lib',
data: {
root: '',
files: [{ file: '/file', ext: '.ts', hash: 'some-hash' }],
files: [{ file: '/file.ts', hash: 'some-hash' }],
},
},
},
@ -143,7 +143,7 @@ describe('Hasher', () => {
type: 'lib',
data: {
root: '',
files: [{ file: '/filea', ext: '.ts', hash: 'a.hash' }],
files: [{ file: '/filea.ts', hash: 'a.hash' }],
},
},
child: {
@ -151,7 +151,7 @@ describe('Hasher', () => {
type: 'lib',
data: {
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!
expect(hash.details.nodes).toEqual({
parent: '/filea|a.hash|""|""',
child: '/fileb|b.hash|""|""',
parent: '/filea.ts|a.hash|""|""',
child: '/fileb.ts|b.hash|""|""',
});
});
@ -188,7 +188,7 @@ describe('Hasher', () => {
type: 'lib',
data: {
root: '',
files: [{ file: '/filea', ext: '.ts', hash: 'a.hash' }],
files: [{ file: '/filea.ts', hash: 'a.hash' }],
},
},
projb: {
@ -196,7 +196,7 @@ describe('Hasher', () => {
type: 'lib',
data: {
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('build'); //target
expect(tasksHash.details.nodes).toEqual({
proja: '/filea|a.hash|""|""',
projb: '/fileb|b.hash|""|""',
proja: '/filea.ts|a.hash|""|""',
projb: '/fileb.ts|b.hash|""|""',
});
const hashb = await hasher.hashTaskWithDepsAndContext({
@ -240,8 +240,8 @@ describe('Hasher', () => {
expect(hashb.value).toContain('proj'); //project
expect(hashb.value).toContain('build'); //target
expect(hashb.details.nodes).toEqual({
proja: '/filea|a.hash|""|""',
projb: '/fileb|b.hash|""|""',
proja: '/filea.ts|a.hash|""|""',
projb: '/fileb.ts|b.hash|""|""',
});
});
@ -265,12 +265,10 @@ describe('Hasher', () => {
{
file: 'global1',
hash: 'hash1',
ext: '',
},
{
file: 'global2',
hash: 'hash2',
ext: '',
},
],
},

View File

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

View File

@ -92,7 +92,7 @@ export function writeCache(
version: packageJsonDeps[p],
}));
const newValue: ProjectGraphCache = {
version: '3.0',
version: projectGraph.version || '4.0',
deps: packageJsonDeps,
pathMappings: tsConfig.compilerOptions.paths || {},
nxJsonPlugins,
@ -119,7 +119,9 @@ export function shouldRecomputeWholeGraph(
if (
Object.keys(cache.nodes).some(
(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]
)
) {

View File

@ -4,7 +4,12 @@ jest.mock('fs', () => require('memfs').fs);
jest.mock('@nrwl/tao/src/utils/app-root', () => ({
appRootPath: '/root',
}));
import { createProjectGraphAsync } from './project-graph';
import {
createProjectGraphAsync,
projectFileDataCompatAdapter,
projectGraphMigrate3to4,
projectGraphCompat4to3,
} from './project-graph';
import {
NxJsonConfiguration,
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,
ProjectFileMap,
ProjectGraph,
ProjectGraphNode,
ProjectGraphProcessorContext,
WorkspaceJsonConfiguration,
} from '@nrwl/devkit';
import { ProjectGraphBuilder, readJsonFile, logger } from '@nrwl/devkit';
import { appRootPath } from '@nrwl/tao/src/utils/app-root';
import { join } from 'path';
import { join, extname } from 'path';
import { performance } from 'perf_hooks';
import { assertWorkspaceValidity } from '../assert-workspace-validity';
import { createProjectFileMap } from '../file-graph';
@ -41,27 +42,127 @@ import {
/**
* Synchronously reads the latest cached copy of the workspace's ProjectGraph.
* @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();
if (!projectGraphCache) {
throw new Error(`
[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
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
`);
}
return {
let projectGraph: ProjectGraph = {
version: projectGraphCache.version,
nodes: projectGraphCache.nodes,
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() {
@ -74,10 +175,16 @@ function readCombinedDeps() {
* @deprecated This function is deprecated in favor of the new asynchronous version {@link createProjectGraphAsync}
*/
export function createProjectGraph(
workspaceJson = readWorkspaceJson(),
nxJson = readNxJson(),
workspaceFiles = readWorkspaceFiles()
workspaceJson?: WorkspaceJsonConfiguration,
nxJson?: NxJsonConfiguration,
workspaceFiles?: FileData[],
projectGraphVersion?: string
): ProjectGraph {
projectGraphVersion = projectGraphVersion || '3.0';
workspaceJson = workspaceJson || readWorkspaceJson();
nxJson = nxJson || readNxJson();
workspaceFiles = workspaceFiles || readWorkspaceFiles(projectGraphVersion);
const cacheEnabled = process.env.NX_CACHE_PROJECT_GRAPH !== 'false';
let cache = cacheEnabled ? readCache() : false;
assertWorkspaceValidity(workspaceJson, nxJson);
@ -90,15 +197,14 @@ export function createProjectGraph(
let cachedFileData = {};
if (
cache &&
cache.version === '3.0' &&
(cache.version === '3.0' || cache.version === '4.0') &&
!shouldRecomputeWholeGraph(
cache,
packageJsonDeps,
workspaceJson,
normalizedNxJson,
rootTsConfig
) &&
cacheEnabled
)
) {
const fromCache = extractCachedFileData(projectFileMap, cache);
filesToProcess = fromCache.filesToProcess;
@ -110,7 +216,17 @@ export function createProjectGraph(
projectFileMap,
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) {
writeCache(packageJsonDeps, nxJson, rootTsConfig, projectGraph);
}
@ -135,7 +251,8 @@ function addWorkspaceFiles(
function buildProjectGraph(
ctx: ProjectGraphProcessorContext,
cachedFileData: { [project: string]: { [file: string]: FileData } }
cachedFileData: { [project: string]: { [file: string]: FileData } },
projectGraphVersion: string
) {
performance.mark('build project graph:start');
@ -155,6 +272,7 @@ function buildProjectGraph(
buildExplicitTypeScriptDependencies(ctx, builder);
buildExplicitPackageJsonDependencies(ctx, builder);
buildImplicitProjectDependencies(ctx, builder);
builder.setVersion(projectGraphVersion);
const initProjectGraph = builder.getUpdatedProjectGraph();
const r = updateProjectGraphWithPlugins(ctx, initProjectGraph);
@ -175,16 +293,16 @@ function createContext(
fileMap: ProjectFileMap,
filesToProcess: ProjectFileMap
): ProjectGraphProcessorContext {
const projects = Object.keys(workspaceJson.projects).reduce(
(map, projectName) => {
map[projectName] = {
...workspaceJson.projects[projectName],
...nxJson.projects[projectName],
};
return map;
},
{} as Record<string, ProjectConfiguration & NxJsonProjectConfiguration>
);
const projects: Record<
string,
ProjectConfiguration & NxJsonProjectConfiguration
> = Object.keys(workspaceJson.projects).reduce((map, projectName) => {
map[projectName] = {
...workspaceJson.projects[projectName],
...nxJson.projects[projectName],
};
return map;
}, {});
return {
workspace: {
...workspaceJson,

View File

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

View File

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

View File

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

View File

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

View File

@ -51,7 +51,7 @@ export class Rule extends Lint.Rules.AbstractRule {
*/
try {
(global as any).projectGraph = mapProjectGraphFiles(
readCachedProjectGraph()
readCachedProjectGraph('4.0')
);
} 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
*/
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
): string[] {
const filenameRelativeToWorkspaceRoot = relative(appRootPath, dirPath);
const projectGraph = readCachedProjectGraph();
const projectGraph = readCachedProjectGraph('4.0');
// find the project
let projectName;

View File

@ -20,7 +20,7 @@ export function projectHasTargetAndConfiguration(
export function getSourceDirOfDependentProjects(
projectName: string,
projectGraph = readCachedProjectGraph()
projectGraph = readCachedProjectGraph('4.0')
): string[] {
if (!projectGraph.nodes[projectName]) {
throw new Error(
@ -41,7 +41,7 @@ export function getSourceDirOfDependentProjects(
*/
export function getProjectNameFromDirPath(
projRelativeDirPath: string,
projectGraph = readCachedProjectGraph()
projectGraph = readCachedProjectGraph('4.0')
) {
let parentNodeName = null;
for (const [nodeName, node] of Object.entries(projectGraph.nodes)) {
@ -75,7 +75,7 @@ export function getProjectNameFromDirPath(
*/
function findAllProjectNodeDependencies(
parentNodeName: string,
projectGraph = readCachedProjectGraph()
projectGraph = readCachedProjectGraph('4.0')
): 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
*/
export function getProjectGraphFromHost(host: Tree): ProjectGraph {
return onlyWorkspaceProjects(createProjectGraph());
return onlyWorkspaceProjects(
createProjectGraph(undefined, undefined, undefined, '3.0')
);
}
// 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
*/
export function getFullProjectGraphFromHost(host: Tree): ProjectGraph {
return createProjectGraph(undefined, undefined, undefined);
return createProjectGraph(undefined, undefined, undefined, '3.0');
}
// TODO(v13): remove this deprecated method

View File

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