Skip to content

Commit

Permalink
feat(core): move target defaults handling to nx plugin (#21104)
Browse files Browse the repository at this point in the history
  • Loading branch information
AgentEnder committed Jan 19, 2024
1 parent 2e2dada commit 06717de
Show file tree
Hide file tree
Showing 23 changed files with 353 additions and 357 deletions.
2 changes: 1 addition & 1 deletion packages/jest/src/plugins/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { existsSync, readdirSync } from 'fs';
import { readConfig } from 'jest-config';
import { projectGraphCacheDirectory } from 'nx/src/utils/cache-directory';
import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes';
import { getGlobPatternsFromPackageManagerWorkspaces } from 'nx/plugins/package-json-workspaces';
import { getGlobPatternsFromPackageManagerWorkspaces } from 'nx/src/plugins/package-json-workspaces';
import { combineGlobPatterns } from 'nx/src/utils/globs';
import { minimatch } from 'minimatch';

Expand Down
2 changes: 1 addition & 1 deletion packages/nx/plugins/package-json.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { NxPluginV2 } from '../src/utils/nx-plugin';
import { workspaceRoot } from '../src/utils/workspace-root';
import { createNodeFromPackageJson } from './package-json-workspaces';
import { createNodeFromPackageJson } from '../src/plugins/package-json-workspaces';

const plugin: NxPluginV2 = {
name: 'nx-all-package-jsons-plugin',
Expand Down
21 changes: 13 additions & 8 deletions packages/nx/src/generators/utils/project-configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ import { basename, join, relative } from 'path';
import {
buildProjectConfigurationFromPackageJson,
getGlobPatternsFromPackageManagerWorkspaces,
} from '../../../plugins/package-json-workspaces';
import { buildProjectFromProjectJson } from '../../plugins/project-json/build-nodes/project-json';
import { getDefaultPluginsSync } from '../../utils/nx-plugin.deprecated';
getNxPackageJsonWorkspacesPlugin,
} from '../../plugins/package-json-workspaces';
import {
buildProjectFromProjectJson,
ProjectJsonProjectsPlugin,
} from '../../plugins/project-json/build-nodes/project-json';
import { renamePropertyWithStableKeys } from '../../adapter/angular-json';
import {
ProjectConfiguration,
Expand All @@ -16,7 +19,8 @@ import {
mergeProjectConfigurationIntoRootMap,
readProjectConfigurationsFromRootMap,
} from '../../project-graph/utils/project-configuration-utils';
import { retrieveProjectConfigurationPaths } from '../../project-graph/utils/retrieve-workspace-files';
import { configurationGlobs } from '../../project-graph/utils/retrieve-workspace-files';
import { globWithWorkspaceContext } from '../../utils/workspace-context';
import { output } from '../../utils/output';
import { PackageJson } from '../../utils/package-json';
import { joinPathFragments, normalizePath } from '../../utils/path';
Expand Down Expand Up @@ -191,10 +195,11 @@ function readAndCombineAllProjectConfigurations(tree: Tree): {
readJson(tree, p)
),
];
const globbedFiles = retrieveProjectConfigurationPaths(
tree.root,
getDefaultPluginsSync(tree.root)
);
const projectGlobPatterns = configurationGlobs([
{ plugin: ProjectJsonProjectsPlugin },
{ plugin: getNxPackageJsonWorkspacesPlugin(tree.root) },
]);
const globbedFiles = globWithWorkspaceContext(tree.root, projectGlobPatterns);
const createdFiles = findCreatedProjectFiles(tree, patterns);
const deletedFiles = findDeletedProjectFiles(tree, patterns);
const projectFiles = [...globbedFiles, ...createdFiles].filter(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@ export function assertRunsAgainstNxRepo(
let resultOrPromise: void | Promise<void> = migrateFn(tree);

if (resultOrPromise && 'then' in resultOrPromise) {
try {
await resultOrPromise;
} catch (e) {
fail(e);
}
await resultOrPromise;
}
});
}
2 changes: 1 addition & 1 deletion packages/nx/src/plugins/js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { detectPackageManager } from '../../utils/package-manager';
import { workspaceRoot } from '../../utils/workspace-root';
import { nxVersion } from '../../utils/versions';

export const name = 'nx-js-graph-plugin';
export const name = 'nx/js/dependencies-and-lockfile';

interface ParsedLockFile {
externalNodes?: ProjectGraph['externalNodes'];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as memfs from 'memfs';

import '../src/internal-testing-utils/mock-fs';
import { createNodeFromPackageJson } from './package-json-workspaces';
import '../../internal-testing-utils/mock-fs';
import { createNodeFromPackageJson } from './create-nodes';

describe('nx package.json workspaces plugin', () => {
it('should build projects from package.json files', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import { existsSync } from 'node:fs';
import { dirname, join } from 'node:path';

import { NxJsonConfiguration, readNxJson } from '../src/config/nx-json';
import { ProjectConfiguration } from '../src/config/workspace-json-project-json';
import { toProjectName } from '../src/config/workspaces';
import { readJsonFile, readYamlFile } from '../src/utils/fileutils';
import { combineGlobPatterns } from '../src/utils/globs';
import { NX_PREFIX } from '../src/utils/logger';
import { NxPluginV2 } from '../src/utils/nx-plugin';
import { output } from '../src/utils/output';
import { NxJsonConfiguration, readNxJson } from '../../config/nx-json';
import { ProjectConfiguration } from '../../config/workspace-json-project-json';
import { toProjectName } from '../../config/workspaces';
import { readJsonFile, readYamlFile } from '../../utils/fileutils';
import { combineGlobPatterns } from '../../utils/globs';
import { NX_PREFIX } from '../../utils/logger';
import { NxPluginV2 } from '../../utils/nx-plugin';
import { output } from '../../utils/output';
import {
PackageJson,
readTargetsFromPackageJson,
} from '../src/utils/package-json';
import { joinPathFragments } from '../src/utils/path';
} from '../../utils/package-json';
import { joinPathFragments } from '../../utils/path';

export function getNxPackageJsonWorkspacesPlugin(root: string): NxPluginV2 {
const readJson = (f) => readJsonFile(join(root, f));
return {
name: 'nx-core-build-package-json-nodes',
name: 'nx/core/package-json-workspaces',
createNodes: [
combineGlobPatterns(
getGlobPatternsFromPackageManagerWorkspaces(root, readJson)
Expand Down
1 change: 1 addition & 0 deletions packages/nx/src/plugins/package-json-workspaces/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './create-nodes';
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import * as memfs from 'memfs';

import '../../../internal-testing-utils/mock-fs';

import { CreatePackageJsonProjectsNextToProjectJson } from './package-json-next-to-project-json';
import { PackageJsonProjectsNextToProjectJsonPlugin } from './package-json-next-to-project-json';
import { CreateNodesContext } from '../../../utils/nx-plugin';
const { createNodes } = CreatePackageJsonProjectsNextToProjectJson;
const { createNodes } = PackageJsonProjectsNextToProjectJsonPlugin;

describe('nx project.json plugin', () => {
let context: CreateNodesContext;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import {

// TODO: Remove this one day, this should not need to be done.

export const CreatePackageJsonProjectsNextToProjectJson: NxPluginV2 = {
name: 'nx-core-build-package-json-nodes-next-to-project-json-nodes',
export const PackageJsonProjectsNextToProjectJsonPlugin: NxPluginV2 = {
// Its not a problem if plugins happen to have same name, and this
// will look least confusing in the source map.
name: 'nx/core/package-json',
createNodes: [
'{project.json,**/project.json}',
(file, _, { workspaceRoot }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import * as memfs from 'memfs';

import '../../../internal-testing-utils/mock-fs';

import { CreateProjectJsonProjectsPlugin } from './project-json';
import { ProjectJsonProjectsPlugin } from './project-json';
import { CreateNodesContext } from '../../../utils/nx-plugin';
const { createNodes } = CreateProjectJsonProjectsPlugin;
const { createNodes } = ProjectJsonProjectsPlugin;

describe('nx project.json plugin', () => {
let context: CreateNodesContext;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { toProjectName } from '../../../config/workspaces';
import { readJsonFile } from '../../../utils/fileutils';
import { NxPluginV2 } from '../../../utils/nx-plugin';

export const CreateProjectJsonProjectsPlugin: NxPluginV2 = {
name: 'nx-core-build-project-json-nodes',
export const ProjectJsonProjectsPlugin: NxPluginV2 = {
name: 'nx/core/project-json',
createNodes: [
'{project.json,**/project.json}',
(file, _, { workspaceRoot }) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import * as memfs from 'memfs';

import '../../../src/internal-testing-utils/mock-fs';

import { TargetDefaultsPlugin } from './target-defaults-plugin';
import { CreateNodesContext } from '../../utils/nx-plugin';
const {
createNodes: [, createNodesFn],
} = TargetDefaultsPlugin;

describe('nx project.json plugin', () => {
let context: CreateNodesContext;
beforeEach(() => {
context = {
nxJsonConfiguration: {
targetDefaults: {
build: {
dependsOn: ['^build'],
},
},
},
workspaceRoot: '/root',
};
});

it('should add target default info to project json projects', () => {
memfs.vol.fromJSON(
{
'project.json': JSON.stringify({
name: 'root',
targets: { echo: { command: 'echo root project' } },
}),
'packages/lib-a/project.json': JSON.stringify({
name: 'lib-a',
targets: {
build: {
executor: 'nx:run-commands',
options: {},
},
},
}),
},
'/root'
);

expect(createNodesFn('project.json', undefined, context))
.toMatchInlineSnapshot(`
{
"projects": {
".": {
"targets": {
"build": {
"dependsOn": [
"^build",
],
Symbol(ONLY_MODIFIES_EXISTING_TARGET): true,
},
},
},
},
}
`);
expect(createNodesFn('packages/lib-a/project.json', undefined, context))
.toMatchInlineSnapshot(`
{
"projects": {
"packages/lib-a": {
"targets": {
"build": {
"dependsOn": [
"^build",
],
},
},
},
},
}
`);
});
});
129 changes: 129 additions & 0 deletions packages/nx/src/plugins/target-defaults/target-defaults-plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import { minimatch } from 'minimatch';
import { existsSync } from 'node:fs';
import { basename, dirname, join } from 'node:path';

import {
ProjectConfiguration,
TargetConfiguration,
} from '../../config/workspace-json-project-json';
import { readJsonFile } from '../../utils/fileutils';
import { combineGlobPatterns } from '../../utils/globs';
import { NxPluginV2 } from '../../utils/nx-plugin';
import { PackageJson } from '../../utils/package-json';
import { getGlobPatternsFromPackageManagerWorkspaces } from '../package-json-workspaces';

/**
* This symbol marks that a target provides information which should modify a target already registered
* on the project via other plugins. If the target has not already been registered, and this symbol is true,
* the information provided by it will be discarded.
*/
export const ONLY_MODIFIES_EXISTING_TARGET = Symbol(
'ONLY_MODIFIES_EXISTING_TARGET'
);

export const TargetDefaultsPlugin: NxPluginV2 = {
name: 'nx/core/target-defaults',
createNodes: [
'{package.json,**/package.json,project.json,**/project.json}',
(configFile, _, ctx) => {
const fileName = basename(configFile);
const root = dirname(configFile);

const packageManagerWorkspacesGlob = combineGlobPatterns(
getGlobPatternsFromPackageManagerWorkspaces(ctx.workspaceRoot)
);

// Only process once if package.json + project.json both exist
if (
fileName === 'package.json' &&
existsSync(join(ctx.workspaceRoot, root, 'project.json'))
) {
return {};
} else if (
fileName === 'package.json' &&
!minimatch(configFile, packageManagerWorkspacesGlob)
) {
return {};
}

// If no target defaults, this does nothing
const targetDefaults = ctx.nxJsonConfiguration?.targetDefaults;
if (!targetDefaults) {
return {};
}

const projectJson = readJsonOrNull<ProjectConfiguration>(
join(ctx.workspaceRoot, root, 'project.json')
);
const packageJson = readJsonOrNull<PackageJson>(
join(ctx.workspaceRoot, root, 'package.json')
);
const projectDefinedTargets = new Set(
Object.keys({
...packageJson?.scripts,
...projectJson?.targets,
})
);

const executorToTargetMap = getExecutorToTargetMap(
packageJson,
projectJson
);

const newTargets: Record<
string,
TargetConfiguration & { [ONLY_MODIFIES_EXISTING_TARGET]?: boolean }
> = {};
for (const defaultSpecifier in targetDefaults) {
const targetName =
executorToTargetMap.get(defaultSpecifier) ?? defaultSpecifier;
newTargets[targetName] = structuredClone(
targetDefaults[defaultSpecifier]
);
// TODO: Remove this after we figure out a way to define new targets
// in target defaults
if (!projectDefinedTargets.has(targetName)) {
newTargets[targetName][ONLY_MODIFIES_EXISTING_TARGET] = true;
}
}

return {
projects: {
[root]: {
targets: newTargets,
},
},
};
},
],
};

function getExecutorToTargetMap(
packageJson: PackageJson,
projectJson: ProjectConfiguration
) {
const executorToTargetMap = new Map<string, string>();
if (packageJson?.scripts) {
for (const script in packageJson.scripts) {
executorToTargetMap.set('nx:run-script', script);
}
}
if (projectJson?.targets) {
for (const target in projectJson.targets) {
if (projectJson.targets[target].executor) {
executorToTargetMap.set(projectJson.targets[target].executor, target);
} else if (projectJson.targets[target].command) {
executorToTargetMap.set('nx:run-commands', target);
}
}
}
return executorToTargetMap;
}

function readJsonOrNull<T extends Object = any>(path: string) {
if (existsSync(path)) {
return readJsonFile<T>(path);
} else {
return null;
}
}
2 changes: 1 addition & 1 deletion packages/nx/src/project-graph/build-project-graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ async function buildProjectGraphUsingContext(
builder.addExternalNode(knownExternalNodes[node]);
}

await normalizeProjectNodes(ctx, builder, nxJson);
await normalizeProjectNodes(ctx, builder);
const initProjectGraph = builder.getUpdatedProjectGraph();

const r = await updateProjectGraphWithPlugins(ctx, initProjectGraph);
Expand Down
Loading

0 comments on commit 06717de

Please sign in to comment.