nx-lifecycle 0.2.1 → 1.0.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 +203 -119
- package/WHY-NX-LIFECYCLE.md +64 -0
- package/dist/bin.d.ts +603 -0
- package/dist/bin.js +3 -2
- package/dist/cli.d.ts +1 -1
- package/dist/commands/index.d.ts +752 -2
- package/dist/commands/lib/dependencies.d.ts +7 -7
- package/dist/commands/lib/dependencies.js +1 -1
- package/dist/commands/lifecycle-command.d.ts +1 -1
- package/dist/executors/lifecycle/container.d.ts +603 -0
- package/dist/executors/lifecycle/container.js +8 -0
- package/dist/executors/lifecycle/index.js +2 -6
- package/dist/lifecycle/dependencies.d.ts +16 -0
- package/dist/lifecycle/{depedencies.js → dependencies.js} +1 -1
- package/dist/lifecycle/index.d.ts +754 -3
- package/dist/lifecycle/index.js +5 -5
- package/dist/lifecycle/lifecycle-internal.d.ts +3 -3
- package/dist/lifecycle/lifecycle-internal.js +26 -9
- package/dist/lifecycle/normalizer.d.ts +1 -1
- package/dist/lifecycle/processor.d.ts +41 -3
- package/dist/lifecycle/processor.js +36 -33
- package/dist/lifecycle/schema.d.ts +468 -66
- package/dist/lifecycle/schema.js +30 -21
- package/dist/plugin/container.d.ts +855 -0
- package/dist/plugin/container.js +13 -0
- package/dist/plugin/dependencies.d.ts +860 -0
- package/dist/plugin/dependencies.js +9 -0
- package/dist/plugin/index.d.ts +283 -0
- package/dist/plugin/index.js +6 -0
- package/dist/plugin/lifecycle-plugin.d.ts +21 -0
- package/dist/plugin/lifecycle-plugin.js +158 -0
- package/dist/plugin/schema.d.ts +353 -0
- package/dist/plugin/schema.js +21 -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 +191 -18
- package/dist/schemas/nx-json.js +3 -3
- package/dist/schemas/project-json.d.ts +191 -18
- package/dist/schemas/project-json.js +3 -3
- 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 +39 -40
- package/dist/executors/lifecycle/index.cjs +0 -15
- package/dist/executors/lifecycle/index.d.cts +0 -99
- package/dist/lifecycle/depedencies.d.ts +0 -15
- package/dist/schemas/lib/ajv.d.ts +0 -3
- package/dist/schemas/lib/ajv.js +0 -9
package/dist/lifecycle/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { bind, identifier } from 'haywire';
|
|
2
|
-
import {
|
|
3
|
-
import { dependenciesModule, formatFileIdentifier, isCiIdentifier, loggerIdentifier, parseCwdId, readFileIdentifier, writeFileIdentifier } from './
|
|
2
|
+
import { assertNxJson, assertNxJsonIdentifier, assertProjectJson, assertProjectJsonIdentifier } from '#schemas';
|
|
3
|
+
import { dependenciesModule, formatFileIdentifier, isCiIdentifier, loggerIdentifier, parseCwdId, readFileIdentifier, writeFileIdentifier } from './dependencies.js';
|
|
4
4
|
import { LifecycleInternal } from './lifecycle-internal.js';
|
|
5
5
|
import { Normalizer } from './normalizer.js';
|
|
6
6
|
import { nxAndProjectJsonProcessorIdentifier, processNxAndProjectJsons } from './processor.js';
|
|
@@ -13,13 +13,13 @@ export const lifecycleInternalModule = dependenciesModule.addBinding(bind(lifecy
|
|
|
13
13
|
writeFileIdentifier,
|
|
14
14
|
formatFileIdentifier,
|
|
15
15
|
nxAndProjectJsonProcessorIdentifier,
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
assertNxJsonIdentifier,
|
|
17
|
+
assertProjectJsonIdentifier,
|
|
18
18
|
loggerIdentifier
|
|
19
19
|
])).addBinding(bind(Normalizer).withDependencies([
|
|
20
20
|
isCiIdentifier.supplier(),
|
|
21
21
|
parseCwdId,
|
|
22
22
|
readFileIdentifier
|
|
23
|
-
]).withConstructorProvider()).addBinding(bind(nxAndProjectJsonProcessorIdentifier).withInstance(processNxAndProjectJsons)).addBinding(bind(
|
|
23
|
+
]).withConstructorProvider()).addBinding(bind(nxAndProjectJsonProcessorIdentifier).withInstance(processNxAndProjectJsons)).addBinding(bind(assertNxJsonIdentifier).withInstance(assertNxJson)).addBinding(bind(assertProjectJsonIdentifier).withInstance(assertProjectJson));
|
|
24
24
|
|
|
25
25
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { readFile as ReadFile, writeFile as WriteFile } from 'node:fs/promises';
|
|
2
2
|
import type { FilesFormatter } from 'format-file';
|
|
3
|
-
import type {
|
|
4
|
-
import type { Logger } from './
|
|
3
|
+
import type { AssertNxJson, AssertProjectJson } from '#schemas';
|
|
4
|
+
import type { Logger } from './dependencies.js';
|
|
5
5
|
import type { Normalizer } from './normalizer.js';
|
|
6
6
|
import type { NxAndProjectJsonProcessor } from './processor.js';
|
|
7
7
|
import type { LifecycleOptionsOrConfig } from './schema.js';
|
|
@@ -17,6 +17,6 @@ export type ILifecycleInternal = (options: LifecycleOptionsOrConfig, context: Nx
|
|
|
17
17
|
export declare class LifecycleInternal {
|
|
18
18
|
#private;
|
|
19
19
|
readonly lifecycleInternal: ILifecycleInternal;
|
|
20
|
-
constructor(normalizer: Normalizer, readFile: typeof ReadFile, writeFile: typeof WriteFile, formatFiles: FilesFormatter, processNxAndProjectJsons: NxAndProjectJsonProcessor,
|
|
20
|
+
constructor(normalizer: Normalizer, readFile: typeof ReadFile, writeFile: typeof WriteFile, formatFiles: FilesFormatter, processNxAndProjectJsons: NxAndProjectJsonProcessor, assertNxJson: AssertNxJson, assertProjectJson: AssertProjectJson, logger: Logger);
|
|
21
21
|
}
|
|
22
22
|
//# sourceMappingURL=lifecycle-internal.d.ts.map
|
|
@@ -5,24 +5,25 @@ export class LifecycleInternal {
|
|
|
5
5
|
#writeFile;
|
|
6
6
|
#formatFiles;
|
|
7
7
|
#processNxAndProjectJsons;
|
|
8
|
-
#
|
|
9
|
-
#
|
|
8
|
+
#assertNxJson;
|
|
9
|
+
#assertProjectJson;
|
|
10
10
|
#logger;
|
|
11
11
|
lifecycleInternal;
|
|
12
|
-
constructor(normalizer, readFile, writeFile, formatFiles, processNxAndProjectJsons,
|
|
12
|
+
constructor(normalizer, readFile, writeFile, formatFiles, processNxAndProjectJsons, assertNxJson, assertProjectJson, logger){
|
|
13
13
|
this.#normalizer = normalizer;
|
|
14
14
|
this.#readFile = readFile;
|
|
15
15
|
this.#writeFile = writeFile;
|
|
16
16
|
this.#formatFiles = formatFiles;
|
|
17
17
|
this.#processNxAndProjectJsons = processNxAndProjectJsons;
|
|
18
|
-
this.#
|
|
19
|
-
this.#
|
|
18
|
+
this.#assertNxJson = assertNxJson;
|
|
19
|
+
this.#assertProjectJson = assertProjectJson;
|
|
20
20
|
this.#logger = logger;
|
|
21
21
|
this.lifecycleInternal = this.#lifecycleInternal.bind(this);
|
|
22
22
|
}
|
|
23
23
|
async #lifecycleInternal(options, context) {
|
|
24
24
|
const normalized = await this.#normalizer.normalizeOptions(options, context);
|
|
25
25
|
const { nxJson, projectJsons } = await this.#loadJsonConfigs(normalized);
|
|
26
|
+
this.#warnUndeclaredBindings(normalized.bindings, projectJsons.map(({ data })=>data));
|
|
26
27
|
const { processedNxJson, processedProjectJsons } = this.#processNxAndProjectJsons({
|
|
27
28
|
nxJson: nxJson.data,
|
|
28
29
|
projectJsons: projectJsons.map(({ data })=>data),
|
|
@@ -52,8 +53,12 @@ export class LifecycleInternal {
|
|
|
52
53
|
}))
|
|
53
54
|
]);
|
|
54
55
|
const parsedNxJson = JSON.parse(rawNxJson);
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
try {
|
|
57
|
+
this.#assertNxJson(parsedNxJson);
|
|
58
|
+
} catch (err) {
|
|
59
|
+
throw new Error('Failed to parse nx.json', {
|
|
60
|
+
cause: err
|
|
61
|
+
});
|
|
57
62
|
}
|
|
58
63
|
return {
|
|
59
64
|
nxJson: {
|
|
@@ -63,8 +68,12 @@ export class LifecycleInternal {
|
|
|
63
68
|
},
|
|
64
69
|
projectJsons: rawProjectJsons.map(({ name, path, rawData })=>{
|
|
65
70
|
const data = JSON.parse(rawData);
|
|
66
|
-
|
|
67
|
-
|
|
71
|
+
try {
|
|
72
|
+
this.#assertProjectJson(data);
|
|
73
|
+
} catch (err) {
|
|
74
|
+
throw new Error(`Failed to parse ${path}`, {
|
|
75
|
+
cause: err
|
|
76
|
+
});
|
|
68
77
|
}
|
|
69
78
|
return {
|
|
70
79
|
name,
|
|
@@ -74,6 +83,14 @@ export class LifecycleInternal {
|
|
|
74
83
|
})
|
|
75
84
|
};
|
|
76
85
|
}
|
|
86
|
+
#warnUndeclaredBindings(bindings, projectJsons) {
|
|
87
|
+
const declaredTargets = new Set(projectJsons.flatMap((projectJson)=>Object.keys(projectJson.targets ?? {})));
|
|
88
|
+
for (const targetName of Object.keys(bindings)){
|
|
89
|
+
if (!declaredTargets.has(targetName)) {
|
|
90
|
+
this.#logger.warn(`Bound target ${targetName} is not declared in any project.json. Is it a typo?`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
77
94
|
async #saveJsonConfigs({ jsons, options }) {
|
|
78
95
|
const filesToUpdate = [];
|
|
79
96
|
for (const { path, data, processed } of jsons){
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { readFile as ReadFile } from 'node:fs/promises';
|
|
2
2
|
import type { ParseCwd } from 'parse-cwd';
|
|
3
|
-
import {
|
|
3
|
+
import type { LifecycleOptions, LifecycleOptionsOrConfig } from './schema.js';
|
|
4
4
|
import type { NxContext } from './types.js';
|
|
5
5
|
export interface NormalizedOptions {
|
|
6
6
|
check: boolean;
|
|
@@ -1,6 +1,44 @@
|
|
|
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'>;
|
|
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;
|
|
4
42
|
export type NxAndProjectJsonProcessor = ({ nxJson, projectJsons, options, }: {
|
|
5
43
|
nxJson: NxJson;
|
|
6
44
|
projectJsons: ProjectJson[];
|
|
@@ -9,7 +47,7 @@ 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>;
|
|
50
|
+
export declare const nxAndProjectJsonProcessorIdentifier: import("haywire").HaywireId<NxAndProjectJsonProcessor, null, null, false, false, false, false, false>;
|
|
13
51
|
export declare const processNxAndProjectJsons: NxAndProjectJsonProcessor;
|
|
14
52
|
export {};
|
|
15
53
|
//# sourceMappingURL=processor.d.ts.map
|
|
@@ -7,6 +7,7 @@ const calculateTargets = ({ stages })=>{
|
|
|
7
7
|
const prefixHook = `${stageName}:_`;
|
|
8
8
|
lifecycleTargets.set(prefixHook, {
|
|
9
9
|
name: prefixHook,
|
|
10
|
+
stage: stageName,
|
|
10
11
|
kind: 'anchor',
|
|
11
12
|
dependsOn: stage.dependsOn ?? []
|
|
12
13
|
});
|
|
@@ -16,6 +17,7 @@ const calculateTargets = ({ stages })=>{
|
|
|
16
17
|
const hookName = `${stageName}:${hook}`;
|
|
17
18
|
lifecycleTargets.set(hookName, {
|
|
18
19
|
name: hookName,
|
|
20
|
+
stage: stageName,
|
|
19
21
|
kind: 'hook',
|
|
20
22
|
dependsOn: [
|
|
21
23
|
previousHook
|
|
@@ -26,6 +28,7 @@ const calculateTargets = ({ stages })=>{
|
|
|
26
28
|
}
|
|
27
29
|
lifecycleTargets.set(stageName, {
|
|
28
30
|
name: stageName,
|
|
31
|
+
stage: stageName,
|
|
29
32
|
kind: 'base',
|
|
30
33
|
dependsOn: [
|
|
31
34
|
previousHook
|
|
@@ -70,39 +73,46 @@ const calculateTargetsToRemove = ({ lifecycleTargets, nxJson })=>{
|
|
|
70
73
|
}
|
|
71
74
|
return targetsToRemove;
|
|
72
75
|
};
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
const getDependencyTarget = (dependency)=>typeof dependency === 'string' ? dependency : dependency.target;
|
|
77
|
+
const normalizeDependencyTarget = (dependencyTarget)=>dependencyTarget.replace(/^\^/u, '');
|
|
78
|
+
const removeDependencyTargets = ({ target, targetsToRemove })=>(target.dependsOn ?? []).filter((dependency)=>!targetsToRemove.has(normalizeDependencyTarget(getDependencyTarget(dependency))));
|
|
79
|
+
const validateLifecycleDependencies = ({ lifecycleTargets, options })=>{
|
|
80
|
+
for (const [stageName, { dependsOn }] of Object.entries(options.stages)){
|
|
81
|
+
for (const dependency of dependsOn ?? []){
|
|
82
|
+
const dependencyTarget = getDependencyTarget(dependency);
|
|
83
|
+
const normalized = normalizeDependencyTarget(dependencyTarget);
|
|
81
84
|
const lifecycleTarget = lifecycleTargets.get(normalized);
|
|
82
|
-
if (lifecycleTarget) {
|
|
83
|
-
|
|
85
|
+
if (lifecycleTarget && lifecycleTarget.kind !== 'base') {
|
|
86
|
+
const suggested = dependencyTarget.replace(normalized, lifecycleTarget.stage);
|
|
87
|
+
throw new Error(`Lifecycle stage ${stageName} cannot depend on ${dependencyTarget}, which is internal to stage ${lifecycleTarget.stage}. Depend on ${suggested} instead`);
|
|
84
88
|
}
|
|
85
|
-
|
|
86
|
-
});
|
|
89
|
+
}
|
|
87
90
|
}
|
|
88
|
-
return [];
|
|
89
91
|
};
|
|
90
|
-
const
|
|
92
|
+
const validateStaleDependencies = ({ options, targetsToRemove })=>{
|
|
91
93
|
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}`);
|
|
94
|
+
for (const dependency of dependsOn ?? []){
|
|
95
|
+
const dependencyTarget = getDependencyTarget(dependency);
|
|
96
|
+
if (targetsToRemove.has(normalizeDependencyTarget(dependencyTarget))) {
|
|
97
|
+
throw new Error(`Lifecycle stage ${stageName} cannot depend on ${dependencyTarget}, which is a stale lifecycle target in nx.json`);
|
|
102
98
|
}
|
|
103
99
|
}
|
|
104
100
|
}
|
|
105
101
|
};
|
|
102
|
+
export const planLifecycle = (options)=>{
|
|
103
|
+
const lifecycleTargets = calculateTargets(options);
|
|
104
|
+
validateLifecycleDependencies({
|
|
105
|
+
lifecycleTargets,
|
|
106
|
+
options
|
|
107
|
+
});
|
|
108
|
+
return {
|
|
109
|
+
lifecycleTargets,
|
|
110
|
+
registeredTargets: registerTargets({
|
|
111
|
+
options,
|
|
112
|
+
lifecycleTargets
|
|
113
|
+
})
|
|
114
|
+
};
|
|
115
|
+
};
|
|
106
116
|
const processNxJson = ({ nxJson, lifecycleTargets, registeredTargets, targetsToRemove })=>{
|
|
107
117
|
const originalTargets = nxJson.targetDefaults ?? {};
|
|
108
118
|
const targetDefaults = {
|
|
@@ -132,7 +142,6 @@ const processNxJson = ({ nxJson, lifecycleTargets, registeredTargets, targetsToR
|
|
|
132
142
|
...originalTarget,
|
|
133
143
|
dependsOn: removeDependencyTargets({
|
|
134
144
|
target: originalTarget,
|
|
135
|
-
lifecycleTargets,
|
|
136
145
|
targetsToRemove
|
|
137
146
|
})
|
|
138
147
|
};
|
|
@@ -178,7 +187,6 @@ const processProjectJson = ({ projectJson, lifecycleTargets, registeredTargets,
|
|
|
178
187
|
targets[targetName] = processedTarget;
|
|
179
188
|
processedTarget.dependsOn = removeDependencyTargets({
|
|
180
189
|
target,
|
|
181
|
-
lifecycleTargets,
|
|
182
190
|
targetsToRemove
|
|
183
191
|
});
|
|
184
192
|
const lifecycleTarget = registeredTargets.get(targetName);
|
|
@@ -201,20 +209,15 @@ const processProjectJson = ({ projectJson, lifecycleTargets, registeredTargets,
|
|
|
201
209
|
};
|
|
202
210
|
export const nxAndProjectJsonProcessorIdentifier = identifier();
|
|
203
211
|
export const processNxAndProjectJsons = ({ nxJson, projectJsons, options })=>{
|
|
204
|
-
const lifecycleTargets =
|
|
212
|
+
const { lifecycleTargets, registeredTargets } = planLifecycle(options);
|
|
205
213
|
const targetsToRemove = calculateTargetsToRemove({
|
|
206
214
|
lifecycleTargets,
|
|
207
215
|
nxJson
|
|
208
216
|
});
|
|
209
|
-
|
|
210
|
-
lifecycleTargets,
|
|
217
|
+
validateStaleDependencies({
|
|
211
218
|
options,
|
|
212
219
|
targetsToRemove
|
|
213
220
|
});
|
|
214
|
-
const registeredTargets = registerTargets({
|
|
215
|
-
options,
|
|
216
|
-
lifecycleTargets
|
|
217
|
-
});
|
|
218
221
|
const processedNxJson = processNxJson({
|
|
219
222
|
nxJson,
|
|
220
223
|
lifecycleTargets,
|