nx-lifecycle 0.2.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.npmignore +20 -0
- package/README.md +242 -120
- package/WHY-NX-LIFECYCLE.md +64 -0
- package/dist/bin.d.ts +1 -2
- package/dist/bin.js +1 -14
- package/dist/cli.d.ts +1 -5
- package/dist/cli.js +9 -22
- package/dist/commands/explain-command.d.ts +12 -0
- package/dist/commands/explain-command.js +57 -0
- package/dist/commands/lib/types.d.ts +0 -3
- package/dist/commands/lifecycle-command.d.ts +2 -12
- package/dist/commands/lifecycle-command.js +13 -22
- package/dist/executors/lifecycle/index.d.ts +1 -4
- package/dist/executors/lifecycle/index.js +1 -8
- package/dist/executors/lifecycle/lifecycle.d.ts +8 -9
- package/dist/executors/lifecycle/lifecycle.js +13 -20
- package/dist/lifecycle/explain.d.ts +68 -0
- package/dist/lifecycle/explain.js +160 -0
- package/dist/lifecycle/lifecycle-internal.d.ts +4 -12
- package/dist/lifecycle/lifecycle-internal.js +93 -93
- package/dist/lifecycle/normalizer.d.ts +14 -8
- package/dist/lifecycle/normalizer.js +29 -36
- package/dist/lifecycle/processor.d.ts +41 -5
- package/dist/lifecycle/processor.js +36 -35
- package/dist/lifecycle/schema.d.ts +468 -66
- package/dist/lifecycle/schema.js +30 -21
- package/dist/plugin/index.d.ts +7 -0
- package/dist/plugin/index.js +4 -0
- package/dist/plugin/lifecycle-plugin.d.ts +24 -0
- package/dist/plugin/lifecycle-plugin.js +145 -0
- package/dist/{executors/lifecycle/index.d.cts → plugin/schema.d.ts} +32 -55
- package/dist/plugin/schema.js +19 -0
- package/dist/schemas/configurations.d.ts +5 -5
- package/dist/schemas/depend-on.d.ts +39 -9
- package/dist/schemas/depend-on.js +4 -2
- package/dist/schemas/empty.d.ts +2 -2
- package/dist/schemas/empty.js +2 -2
- package/dist/schemas/nx-json.d.ts +42 -20
- package/dist/schemas/nx-json.js +2 -4
- package/dist/schemas/project-json.d.ts +42 -20
- package/dist/schemas/project-json.js +2 -4
- package/dist/schemas/target.d.ts +79 -25
- package/executors.json +2 -2
- package/out/nx-executor/schema.json +148 -0
- package/out/schema.json +114 -0
- package/package.json +43 -41
- package/dist/commands/index.d.ts +0 -5
- package/dist/commands/index.js +0 -14
- package/dist/commands/lib/dependencies.d.ts +0 -10
- package/dist/commands/lib/dependencies.js +0 -12
- package/dist/executors/lifecycle/index.cjs +0 -15
- package/dist/lifecycle/depedencies.d.ts +0 -15
- package/dist/lifecycle/depedencies.js +0 -14
- package/dist/lifecycle/index.d.ts +0 -5
- package/dist/lifecycle/index.js +0 -25
- package/dist/schemas/lib/ajv.d.ts +0 -3
- package/dist/schemas/lib/ajv.js +0 -9
|
@@ -1,102 +1,102 @@
|
|
|
1
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
1
2
|
import { deepEqual } from 'fast-equals';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
this.lifecycleInternal = this.#lifecycleInternal.bind(this);
|
|
22
|
-
}
|
|
23
|
-
async #lifecycleInternal(options, context) {
|
|
24
|
-
const normalized = await this.#normalizer.normalizeOptions(options, context);
|
|
25
|
-
const { nxJson, projectJsons } = await this.#loadJsonConfigs(normalized);
|
|
26
|
-
const { processedNxJson, processedProjectJsons } = this.#processNxAndProjectJsons({
|
|
27
|
-
nxJson: nxJson.data,
|
|
28
|
-
projectJsons: projectJsons.map(({ data })=>data),
|
|
29
|
-
options: normalized
|
|
30
|
-
});
|
|
31
|
-
await this.#saveJsonConfigs({
|
|
32
|
-
jsons: [
|
|
33
|
-
{
|
|
34
|
-
...nxJson,
|
|
35
|
-
processed: processedNxJson
|
|
36
|
-
},
|
|
37
|
-
...projectJsons.map((projectJson, i)=>({
|
|
38
|
-
...projectJson,
|
|
39
|
-
processed: processedProjectJsons[i]
|
|
40
|
-
}))
|
|
41
|
-
],
|
|
42
|
-
options: normalized
|
|
3
|
+
import { formatFiles } from 'format-file';
|
|
4
|
+
import { assertNxJson, assertProjectJson } from '#schemas';
|
|
5
|
+
import { normalizeOptions } from './normalizer.js';
|
|
6
|
+
import { processNxAndProjectJsons } from './processor.js';
|
|
7
|
+
const loadJsonConfigs = async ({ nxJsonPath, packageJsonPaths })=>{
|
|
8
|
+
const [rawNxJson, ...rawProjectJsons] = await Promise.all([
|
|
9
|
+
readFile(nxJsonPath, 'utf8'),
|
|
10
|
+
...packageJsonPaths.map(async ({ name, path })=>({
|
|
11
|
+
name,
|
|
12
|
+
path,
|
|
13
|
+
rawData: await readFile(path, 'utf8')
|
|
14
|
+
}))
|
|
15
|
+
]);
|
|
16
|
+
const parsedNxJson = JSON.parse(rawNxJson);
|
|
17
|
+
try {
|
|
18
|
+
assertNxJson(parsedNxJson);
|
|
19
|
+
} catch (err) {
|
|
20
|
+
throw new Error('Failed to parse nx.json', {
|
|
21
|
+
cause: err
|
|
43
22
|
});
|
|
44
23
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
nxJson: {
|
|
60
|
-
name: 'nx.json',
|
|
61
|
-
path: nxJsonPath,
|
|
62
|
-
data: parsedNxJson
|
|
63
|
-
},
|
|
64
|
-
projectJsons: rawProjectJsons.map(({ name, path, rawData })=>{
|
|
65
|
-
const data = JSON.parse(rawData);
|
|
66
|
-
if (!this.#isProjectJson(data)) {
|
|
67
|
-
throw new Error(`Failed to parse ${path}: ${JSON.stringify(this.#isProjectJson.errors, null, 2)}`);
|
|
68
|
-
}
|
|
69
|
-
return {
|
|
70
|
-
name,
|
|
71
|
-
path,
|
|
72
|
-
data
|
|
73
|
-
};
|
|
74
|
-
})
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
async #saveJsonConfigs({ jsons, options }) {
|
|
78
|
-
const filesToUpdate = [];
|
|
79
|
-
for (const { path, data, processed } of jsons){
|
|
80
|
-
if (deepEqual(data, processed)) {
|
|
81
|
-
continue;
|
|
24
|
+
return {
|
|
25
|
+
nxJson: {
|
|
26
|
+
name: 'nx.json',
|
|
27
|
+
path: nxJsonPath,
|
|
28
|
+
data: parsedNxJson
|
|
29
|
+
},
|
|
30
|
+
projectJsons: rawProjectJsons.map(({ name, path, rawData })=>{
|
|
31
|
+
const data = JSON.parse(rawData);
|
|
32
|
+
try {
|
|
33
|
+
assertProjectJson(data);
|
|
34
|
+
} catch (err) {
|
|
35
|
+
throw new Error(`Failed to parse ${path}`, {
|
|
36
|
+
cause: err
|
|
37
|
+
});
|
|
82
38
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
filesToUpdate.push({
|
|
39
|
+
return {
|
|
40
|
+
name,
|
|
87
41
|
path,
|
|
88
|
-
|
|
89
|
-
}
|
|
42
|
+
data
|
|
43
|
+
};
|
|
44
|
+
})
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
const warnUndeclaredBindings = (bindings, projectJsons)=>{
|
|
48
|
+
const declaredTargets = new Set(projectJsons.flatMap((projectJson)=>Object.keys(projectJson.targets ?? {})));
|
|
49
|
+
for (const targetName of Object.keys(bindings)){
|
|
50
|
+
if (!declaredTargets.has(targetName)) {
|
|
51
|
+
console.warn(`Bound target ${targetName} is not declared in any project.json. Is it a typo?`);
|
|
90
52
|
}
|
|
91
|
-
await Promise.all(filesToUpdate.map(async ({ path, processed })=>{
|
|
92
|
-
this.#logger.info(`Updating ${path}`);
|
|
93
|
-
if (options.dryRun) {
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
return this.#writeFile(path, JSON.stringify(processed), 'utf8');
|
|
97
|
-
}));
|
|
98
|
-
await this.#formatFiles(filesToUpdate.map((file)=>file.path));
|
|
99
53
|
}
|
|
100
|
-
}
|
|
54
|
+
};
|
|
55
|
+
const saveJsonConfigs = async ({ jsons, options })=>{
|
|
56
|
+
const filesToUpdate = [];
|
|
57
|
+
for (const { path, data, processed } of jsons){
|
|
58
|
+
if (deepEqual(data, processed)) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (options.check) {
|
|
62
|
+
throw new Error(`File ${path} is not up to date`);
|
|
63
|
+
}
|
|
64
|
+
filesToUpdate.push({
|
|
65
|
+
path,
|
|
66
|
+
processed
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
for (const { path } of filesToUpdate){
|
|
70
|
+
console.info(`Updating ${path}`);
|
|
71
|
+
}
|
|
72
|
+
if (options.dryRun) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
await Promise.all(filesToUpdate.map(async ({ path, processed })=>writeFile(path, JSON.stringify(processed), 'utf8')));
|
|
76
|
+
await formatFiles(filesToUpdate.map((file)=>file.path));
|
|
77
|
+
};
|
|
78
|
+
export const lifecycleInternal = async (options, context)=>{
|
|
79
|
+
const normalized = await normalizeOptions(options, context);
|
|
80
|
+
const { nxJson, projectJsons } = await loadJsonConfigs(normalized);
|
|
81
|
+
warnUndeclaredBindings(normalized.bindings, projectJsons.map(({ data })=>data));
|
|
82
|
+
const { processedNxJson, processedProjectJsons } = processNxAndProjectJsons({
|
|
83
|
+
nxJson: nxJson.data,
|
|
84
|
+
projectJsons: projectJsons.map(({ data })=>data),
|
|
85
|
+
options: normalized
|
|
86
|
+
});
|
|
87
|
+
await saveJsonConfigs({
|
|
88
|
+
jsons: [
|
|
89
|
+
{
|
|
90
|
+
...nxJson,
|
|
91
|
+
processed: processedNxJson
|
|
92
|
+
},
|
|
93
|
+
...projectJsons.map((projectJson, i)=>({
|
|
94
|
+
...projectJson,
|
|
95
|
+
processed: processedProjectJsons[i]
|
|
96
|
+
}))
|
|
97
|
+
],
|
|
98
|
+
options: normalized
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
101
|
|
|
102
102
|
//# sourceMappingURL=lifecycle-internal.js.map
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { ParseCwd } from 'parse-cwd';
|
|
3
|
-
import { type LifecycleOptions, type LifecycleOptionsOrConfig } from './schema.js';
|
|
1
|
+
import type { LifecycleOptions, LifecycleOptionsOrConfig } from './schema.js';
|
|
4
2
|
import type { NxContext } from './types.js';
|
|
5
3
|
export interface NormalizedOptions {
|
|
6
4
|
check: boolean;
|
|
@@ -13,13 +11,21 @@ export interface NormalizedOptions {
|
|
|
13
11
|
stages: LifecycleOptions['stages'];
|
|
14
12
|
bindings: LifecycleOptions['bindings'];
|
|
15
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Options passed directly, or loaded from a config file.
|
|
16
|
+
*
|
|
17
|
+
* @param options - options, or where to load them from
|
|
18
|
+
* @returns stages and bindings, with any options passed directly
|
|
19
|
+
* @throws {Error} when the config file is invalid
|
|
20
|
+
*/
|
|
21
|
+
export declare const loadOptions: (options: LifecycleOptionsOrConfig) => Promise<LifecycleOptions>;
|
|
16
22
|
/**
|
|
17
23
|
* Standardizes the options passed to this executor,
|
|
18
24
|
* based on input, reasonable defaults, and project state.
|
|
25
|
+
*
|
|
26
|
+
* @param options - options provided directly, or where to load them from
|
|
27
|
+
* @param context - workspace root and projects
|
|
28
|
+
* @returns options with defaults and file paths resolved
|
|
19
29
|
*/
|
|
20
|
-
export declare
|
|
21
|
-
#private;
|
|
22
|
-
constructor(isCI: () => boolean, parseCwd: ParseCwd, readFile: typeof ReadFile);
|
|
23
|
-
normalizeOptions(options: LifecycleOptionsOrConfig, context: NxContext): Promise<NormalizedOptions>;
|
|
24
|
-
}
|
|
30
|
+
export declare const normalizeOptions: (options: LifecycleOptionsOrConfig, context: NxContext) => Promise<NormalizedOptions>;
|
|
25
31
|
//# sourceMappingURL=normalizer.d.ts.map
|
|
@@ -1,44 +1,37 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
1
2
|
import Path from 'node:path';
|
|
3
|
+
import { isCI } from 'ci-info';
|
|
4
|
+
import { parseCwd } from 'parse-cwd';
|
|
2
5
|
import { isLifecycleOptions } from './schema.js';
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
#readFile;
|
|
7
|
-
constructor(isCI, parseCwd, readFile){
|
|
8
|
-
this.#isCI = isCI;
|
|
9
|
-
this.#parseCwd = parseCwd;
|
|
10
|
-
this.#readFile = readFile;
|
|
6
|
+
export const loadOptions = async (options)=>{
|
|
7
|
+
if ('stages' in options) {
|
|
8
|
+
return options;
|
|
11
9
|
}
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
const cwd = await parseCwd(options.cwd);
|
|
11
|
+
const configFile = Path.join(cwd, options.configFile ?? './lifecycle.json');
|
|
12
|
+
const loadedConfig = await readFile(configFile, 'utf8');
|
|
13
|
+
const parsedConfig = JSON.parse(loadedConfig);
|
|
14
|
+
if (isLifecycleOptions(parsedConfig)) {
|
|
14
15
|
return {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
nxJsonPath: Path.join(context.root, 'nx.json'),
|
|
18
|
-
packageJsonPaths: context.projects.map((project)=>({
|
|
19
|
-
name: project.name,
|
|
20
|
-
path: Path.join(context.root, project.root, 'project.json')
|
|
21
|
-
})),
|
|
22
|
-
stages: loadedOptions.stages,
|
|
23
|
-
bindings: loadedOptions.bindings
|
|
16
|
+
...parsedConfig,
|
|
17
|
+
...options
|
|
24
18
|
};
|
|
25
19
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
20
|
+
throw new Error(`Invalid config loaded from ${configFile}`);
|
|
21
|
+
};
|
|
22
|
+
export const normalizeOptions = async (options, context)=>{
|
|
23
|
+
const loadedOptions = await loadOptions(options);
|
|
24
|
+
return {
|
|
25
|
+
check: loadedOptions.check ?? isCI,
|
|
26
|
+
dryRun: loadedOptions.dryRun ?? false,
|
|
27
|
+
nxJsonPath: Path.join(context.root, 'nx.json'),
|
|
28
|
+
packageJsonPaths: context.projects.map((project)=>({
|
|
29
|
+
name: project.name,
|
|
30
|
+
path: Path.join(context.root, project.root, 'project.json')
|
|
31
|
+
})),
|
|
32
|
+
stages: loadedOptions.stages,
|
|
33
|
+
bindings: loadedOptions.bindings
|
|
34
|
+
};
|
|
35
|
+
};
|
|
43
36
|
|
|
44
37
|
//# sourceMappingURL=normalizer.js.map
|
|
@@ -1,7 +1,45 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { DependsOn, NxJson, ProjectJson } from '#schemas';
|
|
2
2
|
import type { NormalizedOptions } from './normalizer.js';
|
|
3
|
-
type ProcessorOptions = Pick<NormalizedOptions, 'bindings' | 'stages'>;
|
|
4
|
-
export type
|
|
3
|
+
export type ProcessorOptions = Pick<NormalizedOptions, 'bindings' | 'stages'>;
|
|
4
|
+
export type LifecycleTarget = {
|
|
5
|
+
name: string;
|
|
6
|
+
stage: string;
|
|
7
|
+
dependsOn: DependsOn;
|
|
8
|
+
} & ({
|
|
9
|
+
kind: 'anchor';
|
|
10
|
+
} | ({
|
|
11
|
+
previousHook: string;
|
|
12
|
+
} & ({
|
|
13
|
+
kind: 'base';
|
|
14
|
+
hasHooks: boolean;
|
|
15
|
+
} | {
|
|
16
|
+
kind: 'hook';
|
|
17
|
+
})));
|
|
18
|
+
export type LifecycleTargets = Map<string, LifecycleTarget>;
|
|
19
|
+
type LifecycleTargetWithHooks = Extract<LifecycleTarget, {
|
|
20
|
+
previousHook: string;
|
|
21
|
+
}>;
|
|
22
|
+
export type RegisteredTargets = Map<string, LifecycleTargetWithHooks>;
|
|
23
|
+
export interface LifecyclePlan {
|
|
24
|
+
/**
|
|
25
|
+
* Every anchor, hook and stage target by name, with the dependencies its stage declares.
|
|
26
|
+
*/
|
|
27
|
+
lifecycleTargets: LifecycleTargets;
|
|
28
|
+
/**
|
|
29
|
+
* Bound target names mapped to the lifecycle target they run in.
|
|
30
|
+
*/
|
|
31
|
+
registeredTargets: RegisteredTargets;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Calculates the lifecycle targets, and the hook each bound target runs in.
|
|
35
|
+
* Shared by the executor, which writes the result to files, and the plugin, which infers it.
|
|
36
|
+
*
|
|
37
|
+
* @param options - stages and bindings
|
|
38
|
+
* @returns lifecycle targets and bound targets
|
|
39
|
+
* @throws if stages or bindings are inconsistent
|
|
40
|
+
*/
|
|
41
|
+
export declare const planLifecycle: (options: ProcessorOptions) => LifecyclePlan;
|
|
42
|
+
export declare const processNxAndProjectJsons: ({ nxJson, projectJsons, options, }: {
|
|
5
43
|
nxJson: NxJson;
|
|
6
44
|
projectJsons: ProjectJson[];
|
|
7
45
|
options: ProcessorOptions;
|
|
@@ -9,7 +47,5 @@ export type NxAndProjectJsonProcessor = ({ nxJson, projectJsons, options, }: {
|
|
|
9
47
|
processedNxJson: NxJson;
|
|
10
48
|
processedProjectJsons: ProjectJson[];
|
|
11
49
|
};
|
|
12
|
-
export declare const nxAndProjectJsonProcessorIdentifier: import("haywire").HaywireId<NxAndProjectJsonProcessor, null, null, false, false, false, false>;
|
|
13
|
-
export declare const processNxAndProjectJsons: NxAndProjectJsonProcessor;
|
|
14
50
|
export {};
|
|
15
51
|
//# sourceMappingURL=processor.d.ts.map
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { identifier } from 'haywire';
|
|
2
1
|
import { isEmpty } from '#schemas';
|
|
3
2
|
import { NOOP_EXECUTOR } from './constants.js';
|
|
4
3
|
const calculateTargets = ({ stages })=>{
|
|
@@ -7,6 +6,7 @@ const calculateTargets = ({ stages })=>{
|
|
|
7
6
|
const prefixHook = `${stageName}:_`;
|
|
8
7
|
lifecycleTargets.set(prefixHook, {
|
|
9
8
|
name: prefixHook,
|
|
9
|
+
stage: stageName,
|
|
10
10
|
kind: 'anchor',
|
|
11
11
|
dependsOn: stage.dependsOn ?? []
|
|
12
12
|
});
|
|
@@ -16,6 +16,7 @@ const calculateTargets = ({ stages })=>{
|
|
|
16
16
|
const hookName = `${stageName}:${hook}`;
|
|
17
17
|
lifecycleTargets.set(hookName, {
|
|
18
18
|
name: hookName,
|
|
19
|
+
stage: stageName,
|
|
19
20
|
kind: 'hook',
|
|
20
21
|
dependsOn: [
|
|
21
22
|
previousHook
|
|
@@ -26,6 +27,7 @@ const calculateTargets = ({ stages })=>{
|
|
|
26
27
|
}
|
|
27
28
|
lifecycleTargets.set(stageName, {
|
|
28
29
|
name: stageName,
|
|
30
|
+
stage: stageName,
|
|
29
31
|
kind: 'base',
|
|
30
32
|
dependsOn: [
|
|
31
33
|
previousHook
|
|
@@ -70,39 +72,46 @@ const calculateTargetsToRemove = ({ lifecycleTargets, nxJson })=>{
|
|
|
70
72
|
}
|
|
71
73
|
return targetsToRemove;
|
|
72
74
|
};
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
75
|
+
const getDependencyTarget = (dependency)=>typeof dependency === 'string' ? dependency : dependency.target;
|
|
76
|
+
const normalizeDependencyTarget = (dependencyTarget)=>dependencyTarget.replace(/^\^/u, '');
|
|
77
|
+
const removeDependencyTargets = ({ target, targetsToRemove })=>(target.dependsOn ?? []).filter((dependency)=>!targetsToRemove.has(normalizeDependencyTarget(getDependencyTarget(dependency))));
|
|
78
|
+
const validateLifecycleDependencies = ({ lifecycleTargets, options })=>{
|
|
79
|
+
for (const [stageName, { dependsOn }] of Object.entries(options.stages)){
|
|
80
|
+
for (const dependency of dependsOn ?? []){
|
|
81
|
+
const dependencyTarget = getDependencyTarget(dependency);
|
|
82
|
+
const normalized = normalizeDependencyTarget(dependencyTarget);
|
|
81
83
|
const lifecycleTarget = lifecycleTargets.get(normalized);
|
|
82
|
-
if (lifecycleTarget) {
|
|
83
|
-
|
|
84
|
+
if (lifecycleTarget && lifecycleTarget.kind !== 'base') {
|
|
85
|
+
const suggested = dependencyTarget.replace(normalized, lifecycleTarget.stage);
|
|
86
|
+
throw new Error(`Lifecycle stage ${stageName} cannot depend on ${dependencyTarget}, which is internal to stage ${lifecycleTarget.stage}. Depend on ${suggested} instead`);
|
|
84
87
|
}
|
|
85
|
-
|
|
86
|
-
});
|
|
88
|
+
}
|
|
87
89
|
}
|
|
88
|
-
return [];
|
|
89
90
|
};
|
|
90
|
-
const
|
|
91
|
+
const validateStaleDependencies = ({ options, targetsToRemove })=>{
|
|
91
92
|
for (const [stageName, { dependsOn }] of Object.entries(options.stages)){
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
},
|
|
97
|
-
lifecycleTargets,
|
|
98
|
-
targetsToRemove
|
|
99
|
-
});
|
|
100
|
-
if (filtered.length !== dependsOn.length) {
|
|
101
|
-
throw new Error(`Invalid dependency detected on lifecycle stage ${stageName}`);
|
|
93
|
+
for (const dependency of dependsOn ?? []){
|
|
94
|
+
const dependencyTarget = getDependencyTarget(dependency);
|
|
95
|
+
if (targetsToRemove.has(normalizeDependencyTarget(dependencyTarget))) {
|
|
96
|
+
throw new Error(`Lifecycle stage ${stageName} cannot depend on ${dependencyTarget}, which is a stale lifecycle target in nx.json`);
|
|
102
97
|
}
|
|
103
98
|
}
|
|
104
99
|
}
|
|
105
100
|
};
|
|
101
|
+
export const planLifecycle = (options)=>{
|
|
102
|
+
const lifecycleTargets = calculateTargets(options);
|
|
103
|
+
validateLifecycleDependencies({
|
|
104
|
+
lifecycleTargets,
|
|
105
|
+
options
|
|
106
|
+
});
|
|
107
|
+
return {
|
|
108
|
+
lifecycleTargets,
|
|
109
|
+
registeredTargets: registerTargets({
|
|
110
|
+
options,
|
|
111
|
+
lifecycleTargets
|
|
112
|
+
})
|
|
113
|
+
};
|
|
114
|
+
};
|
|
106
115
|
const processNxJson = ({ nxJson, lifecycleTargets, registeredTargets, targetsToRemove })=>{
|
|
107
116
|
const originalTargets = nxJson.targetDefaults ?? {};
|
|
108
117
|
const targetDefaults = {
|
|
@@ -132,7 +141,6 @@ const processNxJson = ({ nxJson, lifecycleTargets, registeredTargets, targetsToR
|
|
|
132
141
|
...originalTarget,
|
|
133
142
|
dependsOn: removeDependencyTargets({
|
|
134
143
|
target: originalTarget,
|
|
135
|
-
lifecycleTargets,
|
|
136
144
|
targetsToRemove
|
|
137
145
|
})
|
|
138
146
|
};
|
|
@@ -178,7 +186,6 @@ const processProjectJson = ({ projectJson, lifecycleTargets, registeredTargets,
|
|
|
178
186
|
targets[targetName] = processedTarget;
|
|
179
187
|
processedTarget.dependsOn = removeDependencyTargets({
|
|
180
188
|
target,
|
|
181
|
-
lifecycleTargets,
|
|
182
189
|
targetsToRemove
|
|
183
190
|
});
|
|
184
191
|
const lifecycleTarget = registeredTargets.get(targetName);
|
|
@@ -199,22 +206,16 @@ const processProjectJson = ({ projectJson, lifecycleTargets, registeredTargets,
|
|
|
199
206
|
targets: processedTargets
|
|
200
207
|
};
|
|
201
208
|
};
|
|
202
|
-
export const nxAndProjectJsonProcessorIdentifier = identifier();
|
|
203
209
|
export const processNxAndProjectJsons = ({ nxJson, projectJsons, options })=>{
|
|
204
|
-
const lifecycleTargets =
|
|
210
|
+
const { lifecycleTargets, registeredTargets } = planLifecycle(options);
|
|
205
211
|
const targetsToRemove = calculateTargetsToRemove({
|
|
206
212
|
lifecycleTargets,
|
|
207
213
|
nxJson
|
|
208
214
|
});
|
|
209
|
-
|
|
210
|
-
lifecycleTargets,
|
|
215
|
+
validateStaleDependencies({
|
|
211
216
|
options,
|
|
212
217
|
targetsToRemove
|
|
213
218
|
});
|
|
214
|
-
const registeredTargets = registerTargets({
|
|
215
|
-
options,
|
|
216
|
-
lifecycleTargets
|
|
217
|
-
});
|
|
218
219
|
const processedNxJson = processNxJson({
|
|
219
220
|
nxJson,
|
|
220
221
|
lifecycleTargets,
|