nx-lifecycle 1.0.0 → 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/README.md +42 -4
- package/WHY-NX-LIFECYCLE.md +1 -1
- package/dist/bin.d.ts +1 -605
- package/dist/bin.js +1 -15
- 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 +1 -11
- package/dist/commands/lifecycle-command.js +13 -22
- package/dist/executors/lifecycle/index.d.ts +1 -4
- package/dist/executors/lifecycle/index.js +1 -4
- 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 +92 -109
- package/dist/lifecycle/normalizer.d.ts +13 -7
- package/dist/lifecycle/normalizer.js +29 -36
- package/dist/lifecycle/processor.d.ts +1 -3
- package/dist/lifecycle/processor.js +0 -2
- package/dist/plugin/index.d.ts +1 -277
- package/dist/plugin/index.js +1 -3
- package/dist/plugin/lifecycle-plugin.d.ts +18 -15
- package/dist/plugin/lifecycle-plugin.js +76 -89
- package/dist/plugin/schema.d.ts +2 -279
- package/dist/plugin/schema.js +0 -2
- package/dist/schemas/nx-json.d.ts +2 -153
- package/dist/schemas/nx-json.js +0 -2
- package/dist/schemas/project-json.d.ts +2 -153
- package/dist/schemas/project-json.js +0 -2
- package/package.json +16 -13
- package/dist/commands/index.d.ts +0 -755
- 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/container.d.ts +0 -603
- package/dist/executors/lifecycle/container.js +0 -8
- package/dist/lifecycle/dependencies.d.ts +0 -16
- package/dist/lifecycle/dependencies.js +0 -14
- package/dist/lifecycle/index.d.ts +0 -756
- package/dist/lifecycle/index.js +0 -25
- package/dist/plugin/container.d.ts +0 -855
- package/dist/plugin/container.js +0 -13
- package/dist/plugin/dependencies.d.ts +0 -860
- package/dist/plugin/dependencies.js +0 -9
package/dist/cli.js
CHANGED
|
@@ -1,43 +1,30 @@
|
|
|
1
1
|
import yargs from 'yargs';
|
|
2
2
|
import { EntryScript } from "entry-script";
|
|
3
|
+
import { explainCommand } from './commands/explain-command.js';
|
|
4
|
+
import { lifecycleCommand } from './commands/lifecycle-command.js';
|
|
3
5
|
export class LifecycleCli extends EntryScript {
|
|
4
|
-
|
|
5
|
-
#logger;
|
|
6
|
-
#errorLogger;
|
|
7
|
-
#exitCode;
|
|
8
|
-
constructor(getCommands, logger, errorLogger, exitCode){
|
|
9
|
-
super();
|
|
10
|
-
this.#getCommands = getCommands;
|
|
11
|
-
this.#logger = logger;
|
|
12
|
-
this.#errorLogger = errorLogger;
|
|
13
|
-
this.#exitCode = exitCode;
|
|
14
|
-
}
|
|
15
|
-
async main(argv) {
|
|
6
|
+
static async main(argv) {
|
|
16
7
|
const packageJson = await import('../package.json', {
|
|
17
8
|
with: {
|
|
18
9
|
type: 'json'
|
|
19
10
|
}
|
|
20
11
|
});
|
|
21
|
-
|
|
12
|
+
await yargs().scriptName('lifecycle').option({
|
|
22
13
|
cwd: {
|
|
23
14
|
type: 'string',
|
|
24
15
|
default: '.',
|
|
25
16
|
describe: 'Directory to resolve all other paths from'
|
|
26
17
|
}
|
|
27
|
-
}).strict().help().alias('help', 'info').version(packageJson.default.version);
|
|
28
|
-
for (const command of this.#getCommands()){
|
|
29
|
-
yarg.command(command);
|
|
30
|
-
}
|
|
31
|
-
await yarg.parseAsync(argv, {}, this.#yargsOutput.bind(this));
|
|
18
|
+
}).strict().help().alias('help', 'info').version(packageJson.default.version).command(lifecycleCommand).command(explainCommand).parseAsync(argv, {}, LifecycleCli.#yargsOutput);
|
|
32
19
|
}
|
|
33
|
-
#yargsOutput(e, _argv, log) {
|
|
20
|
+
static #yargsOutput(e, _argv, log) {
|
|
34
21
|
if (e) {
|
|
35
|
-
|
|
22
|
+
process.exitCode = 1;
|
|
36
23
|
if (log) {
|
|
37
|
-
|
|
24
|
+
console.error(log);
|
|
38
25
|
}
|
|
39
26
|
} else if (log) {
|
|
40
|
-
|
|
27
|
+
console.log(log);
|
|
41
28
|
}
|
|
42
29
|
}
|
|
43
30
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Command, LifecycleCommandInput } from './lib/types.js';
|
|
2
|
+
interface ExplainCommandExtendedInput extends LifecycleCommandInput {
|
|
3
|
+
project: string;
|
|
4
|
+
stage: string | undefined;
|
|
5
|
+
configFile: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Prints the stages of a project in the order they run, with the targets bound to each hook.
|
|
9
|
+
*/
|
|
10
|
+
export declare const explainCommand: Command<ExplainCommandExtendedInput>;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=explain-command.d.ts.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import Path from 'node:path';
|
|
2
|
+
import { createProjectGraphAsync, readJsonFile, workspaceRoot } from '@nx/devkit';
|
|
3
|
+
import { explainLifecycle, formatExplanation } from '../lifecycle/explain.js';
|
|
4
|
+
import { loadOptions } from '../lifecycle/normalizer.js';
|
|
5
|
+
import { planLifecycle } from '../lifecycle/processor.js';
|
|
6
|
+
import { planPluginOptions } from '../plugin/lifecycle-plugin.js';
|
|
7
|
+
const loadPlan = async ({ cwd, configFile })=>{
|
|
8
|
+
const { plugins = [] } = readJsonFile(Path.join(workspaceRoot, 'nx.json'));
|
|
9
|
+
const plugin = plugins.find((entry)=>typeof entry !== 'string' && entry.plugin === 'nx-lifecycle/plugin');
|
|
10
|
+
if (plugin) {
|
|
11
|
+
return planPluginOptions(plugin.options);
|
|
12
|
+
}
|
|
13
|
+
return planLifecycle(await loadOptions({
|
|
14
|
+
cwd,
|
|
15
|
+
configFile
|
|
16
|
+
}));
|
|
17
|
+
};
|
|
18
|
+
export const explainCommand = {
|
|
19
|
+
command: 'explain <project> [stage]',
|
|
20
|
+
describe: 'Print what runs, in which order, for the stages of a project',
|
|
21
|
+
builder: (yargs)=>yargs.positional('project', {
|
|
22
|
+
describe: 'Name of the Nx project',
|
|
23
|
+
type: 'string',
|
|
24
|
+
demandOption: true
|
|
25
|
+
}).positional('stage', {
|
|
26
|
+
describe: 'Only explain this stage, and the stages it runs after',
|
|
27
|
+
type: 'string'
|
|
28
|
+
}).options({
|
|
29
|
+
configFile: {
|
|
30
|
+
describe: 'Lifecycle config file, used when nx.json does not register the plugin',
|
|
31
|
+
type: 'string',
|
|
32
|
+
default: 'lifecycle.json'
|
|
33
|
+
}
|
|
34
|
+
}).strict(),
|
|
35
|
+
handler: async (options)=>{
|
|
36
|
+
const graph = await createProjectGraphAsync();
|
|
37
|
+
const plan = await loadPlan(options);
|
|
38
|
+
let explanation;
|
|
39
|
+
try {
|
|
40
|
+
explanation = explainLifecycle({
|
|
41
|
+
plan,
|
|
42
|
+
graph,
|
|
43
|
+
project: options.project,
|
|
44
|
+
...options.stage === undefined ? {} : {
|
|
45
|
+
stage: options.stage
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
} catch (err) {
|
|
49
|
+
console.error(err.message);
|
|
50
|
+
process.exitCode = 1;
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
console.log(formatExplanation(explanation));
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
//# sourceMappingURL=explain-command.js.map
|
|
@@ -3,7 +3,4 @@ export interface LifecycleCommandInput {
|
|
|
3
3
|
cwd: string;
|
|
4
4
|
}
|
|
5
5
|
export type Command<ExtendedInput extends LifecycleCommandInput> = Pick<CommandModule<LifecycleCommandInput, ExtendedInput>, 'builder' | 'command' | 'describe' | 'handler'>;
|
|
6
|
-
export interface AbstractCommand extends Pick<CommandModule<LifecycleCommandInput, LifecycleCommandInput>, 'builder' | 'command' | 'describe'> {
|
|
7
|
-
handler: (args: any) => Promise<void>;
|
|
8
|
-
}
|
|
9
6
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import type { ProjectGraph } from '@nx/devkit';
|
|
2
|
-
import type { Argv } from 'yargs';
|
|
3
|
-
import type { ILifecycleInternal } from '../lifecycle/lifecycle-internal.js';
|
|
4
1
|
import type { Command, LifecycleCommandInput } from './lib/types.js';
|
|
5
2
|
interface LifecycleCommandExtendedInput extends LifecycleCommandInput {
|
|
6
3
|
configFile: string;
|
|
@@ -10,13 +7,6 @@ interface LifecycleCommandExtendedInput extends LifecycleCommandInput {
|
|
|
10
7
|
/**
|
|
11
8
|
* Main `nx-lifecycle` command
|
|
12
9
|
*/
|
|
13
|
-
export declare
|
|
14
|
-
#private;
|
|
15
|
-
readonly command: string[];
|
|
16
|
-
readonly describe = "Inject Nx targets as high level workflows";
|
|
17
|
-
constructor(getProjectGraph: () => Promise<ProjectGraph>, workspaceRoot: string, lifecycleInternal: ILifecycleInternal);
|
|
18
|
-
builder(this: void, yargs: Argv<LifecycleCommandInput>): Argv<LifecycleCommandExtendedInput>;
|
|
19
|
-
handler(options: LifecycleCommandExtendedInput): Promise<void>;
|
|
20
|
-
}
|
|
10
|
+
export declare const lifecycleCommand: Command<LifecycleCommandExtendedInput>;
|
|
21
11
|
export {};
|
|
22
12
|
//# sourceMappingURL=lifecycle-command.d.ts.map
|
|
@@ -1,21 +1,13 @@
|
|
|
1
|
+
import { createProjectGraphAsync, workspaceRoot } from '@nx/devkit';
|
|
1
2
|
import { isCI } from 'ci-info';
|
|
2
|
-
|
|
3
|
-
|
|
3
|
+
import { lifecycleInternal } from '../lifecycle/lifecycle-internal.js';
|
|
4
|
+
export const lifecycleCommand = {
|
|
5
|
+
command: [
|
|
4
6
|
'$0',
|
|
5
7
|
'lifecycle'
|
|
6
|
-
]
|
|
7
|
-
describe
|
|
8
|
-
|
|
9
|
-
#workspaceRoot;
|
|
10
|
-
#lifecycleInternal;
|
|
11
|
-
constructor(getProjectGraph, workspaceRoot, lifecycleInternal){
|
|
12
|
-
this.#getProjectGraph = getProjectGraph;
|
|
13
|
-
this.#workspaceRoot = workspaceRoot;
|
|
14
|
-
this.#lifecycleInternal = lifecycleInternal;
|
|
15
|
-
this.handler = this.handler.bind(this);
|
|
16
|
-
}
|
|
17
|
-
builder(yargs) {
|
|
18
|
-
return yargs.options({
|
|
8
|
+
],
|
|
9
|
+
describe: 'Inject Nx targets as high level workflows',
|
|
10
|
+
builder: (yargs)=>yargs.options({
|
|
19
11
|
configFile: {
|
|
20
12
|
describe: 'File that exports data content to populate',
|
|
21
13
|
type: 'string',
|
|
@@ -32,23 +24,22 @@ export class LifecycleCommand {
|
|
|
32
24
|
type: 'boolean',
|
|
33
25
|
default: false
|
|
34
26
|
}
|
|
35
|
-
}).strict()
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
await this.#lifecycleInternal({
|
|
27
|
+
}).strict(),
|
|
28
|
+
handler: async (options)=>{
|
|
29
|
+
const projectGraph = await createProjectGraphAsync();
|
|
30
|
+
await lifecycleInternal({
|
|
40
31
|
configFile: options.configFile,
|
|
41
32
|
cwd: options.cwd,
|
|
42
33
|
check: options.ci,
|
|
43
34
|
dryRun: options.dryRun
|
|
44
35
|
}, {
|
|
45
|
-
root:
|
|
36
|
+
root: workspaceRoot,
|
|
46
37
|
projects: Object.values(projectGraph.nodes).map((node)=>({
|
|
47
38
|
name: node.name,
|
|
48
39
|
root: node.data.root
|
|
49
40
|
}))
|
|
50
41
|
});
|
|
51
42
|
}
|
|
52
|
-
}
|
|
43
|
+
};
|
|
53
44
|
|
|
54
45
|
//# sourceMappingURL=lifecycle-command.js.map
|
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
success: boolean;
|
|
3
|
-
}>;
|
|
4
|
-
export default _default;
|
|
1
|
+
export { lifecycle as default } from './lifecycle.js';
|
|
5
2
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
import { Lifecycle } from './lifecycle.js';
|
|
3
|
-
const lifecycle = lifecycleContainer.get(Lifecycle);
|
|
4
|
-
export default lifecycle.lifecycle;
|
|
1
|
+
export { lifecycle as default } from './lifecycle.js';
|
|
5
2
|
|
|
6
3
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import type { ExecutorContext } from '@nx/devkit';
|
|
2
|
-
import type { ILifecycleInternal } from '../../lifecycle/lifecycle-internal.js';
|
|
3
2
|
import type { LifecycleOptionsOrConfig } from '../../lifecycle/schema.js';
|
|
4
3
|
export type SimpleExecutorContext = Pick<ExecutorContext, 'projectsConfigurations' | 'root'>;
|
|
5
4
|
/**
|
|
6
|
-
*
|
|
5
|
+
* Nx executor for lifecycle file management.
|
|
7
6
|
*
|
|
8
7
|
* Loads the `nx.json` + `project.json`s for all projects,
|
|
9
8
|
* calculates the new targets and dependencies,
|
|
10
9
|
* and re-writes files as appropriate.
|
|
10
|
+
*
|
|
11
|
+
* @param options - options provided directly, or where to load them from
|
|
12
|
+
* @param context - Nx executor context
|
|
13
|
+
* @returns success, as failures throw
|
|
11
14
|
*/
|
|
12
|
-
export declare
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
success: boolean;
|
|
16
|
-
}>;
|
|
17
|
-
constructor(lifecycleInternal: ILifecycleInternal);
|
|
18
|
-
}
|
|
15
|
+
export declare const lifecycle: (options: LifecycleOptionsOrConfig, context: SimpleExecutorContext) => Promise<{
|
|
16
|
+
success: boolean;
|
|
17
|
+
}>;
|
|
19
18
|
//# sourceMappingURL=lifecycle.d.ts.map
|
|
@@ -1,22 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}))
|
|
15
|
-
});
|
|
16
|
-
return {
|
|
17
|
-
success: true
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
}
|
|
1
|
+
import { lifecycleInternal } from '../../lifecycle/lifecycle-internal.js';
|
|
2
|
+
export const lifecycle = async (options, context)=>{
|
|
3
|
+
await lifecycleInternal(options, {
|
|
4
|
+
root: context.root,
|
|
5
|
+
projects: Object.values(context.projectsConfigurations.projects).map((projectConfig)=>({
|
|
6
|
+
name: projectConfig.name,
|
|
7
|
+
root: projectConfig.root
|
|
8
|
+
}))
|
|
9
|
+
});
|
|
10
|
+
return {
|
|
11
|
+
success: true
|
|
12
|
+
};
|
|
13
|
+
};
|
|
21
14
|
|
|
22
15
|
//# sourceMappingURL=lifecycle.js.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { ProjectGraph } from '@nx/devkit';
|
|
2
|
+
import type { LifecyclePlan } from './processor.js';
|
|
3
|
+
export interface DependencyExplanation {
|
|
4
|
+
/**
|
|
5
|
+
* Dependency as written, e.g. `prepare`, `^build` or `my-server:build`.
|
|
6
|
+
*/
|
|
7
|
+
label: string;
|
|
8
|
+
/**
|
|
9
|
+
* For a `^` dependency, the upstream projects it runs the target of.
|
|
10
|
+
*/
|
|
11
|
+
upstream?: readonly string[];
|
|
12
|
+
}
|
|
13
|
+
export interface BoundTargetExplanation {
|
|
14
|
+
name: string;
|
|
15
|
+
/**
|
|
16
|
+
* Dependencies besides the hook the target is bound after.
|
|
17
|
+
*/
|
|
18
|
+
dependsOn: readonly DependencyExplanation[];
|
|
19
|
+
}
|
|
20
|
+
export interface HookExplanation {
|
|
21
|
+
name: string;
|
|
22
|
+
targets: readonly BoundTargetExplanation[];
|
|
23
|
+
}
|
|
24
|
+
export interface StageExplanation {
|
|
25
|
+
name: string;
|
|
26
|
+
dependsOn: readonly DependencyExplanation[];
|
|
27
|
+
/**
|
|
28
|
+
* Hooks in order. A stage without hooks has a single entry, the stage itself.
|
|
29
|
+
*/
|
|
30
|
+
hooks: readonly HookExplanation[];
|
|
31
|
+
hasHooks: boolean;
|
|
32
|
+
}
|
|
33
|
+
export interface LifecycleExplanation {
|
|
34
|
+
project: string;
|
|
35
|
+
/**
|
|
36
|
+
* Stages in the order they run, each after the stages it depends on.
|
|
37
|
+
*/
|
|
38
|
+
stages: readonly StageExplanation[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Describes what runs, and in which order, for the stages of one project.
|
|
42
|
+
*
|
|
43
|
+
* Stage dependencies come from the lifecycle configuration.
|
|
44
|
+
* Bound targets, and their other dependencies, come from the merged project configuration,
|
|
45
|
+
* so they match what Nx runs.
|
|
46
|
+
*
|
|
47
|
+
* @param params - required
|
|
48
|
+
* @param params.plan - lifecycle targets and bindings
|
|
49
|
+
* @param params.graph - project graph, with merged project configurations
|
|
50
|
+
* @param params.project - name of the project to explain
|
|
51
|
+
* @param [params.stage] - only explain this stage, and the stages it runs after
|
|
52
|
+
* @returns stages in run order
|
|
53
|
+
* @throws {Error} when the project or stage does not exist
|
|
54
|
+
*/
|
|
55
|
+
export declare const explainLifecycle: ({ plan, graph, project, stage, }: {
|
|
56
|
+
plan: LifecyclePlan;
|
|
57
|
+
graph: ProjectGraph;
|
|
58
|
+
project: string;
|
|
59
|
+
stage?: string;
|
|
60
|
+
}) => LifecycleExplanation;
|
|
61
|
+
/**
|
|
62
|
+
* Prints an explanation as an indented outline.
|
|
63
|
+
*
|
|
64
|
+
* @param explanation - stages of a project
|
|
65
|
+
* @returns human readable outline
|
|
66
|
+
*/
|
|
67
|
+
export declare const formatExplanation: ({ project, stages }: LifecycleExplanation) => string;
|
|
68
|
+
//# sourceMappingURL=explain.d.ts.map
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
const normalizeDependency = (dependency)=>{
|
|
2
|
+
if (typeof dependency !== 'string') {
|
|
3
|
+
return dependency;
|
|
4
|
+
}
|
|
5
|
+
if (dependency.startsWith('^')) {
|
|
6
|
+
return {
|
|
7
|
+
target: dependency.slice(1),
|
|
8
|
+
dependencies: true
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
target: dependency
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
const resolveUpstream = (graph, projectName, target)=>{
|
|
16
|
+
const upstream = new Set();
|
|
17
|
+
const visited = new Set([
|
|
18
|
+
projectName
|
|
19
|
+
]);
|
|
20
|
+
const visit = (name)=>{
|
|
21
|
+
for (const dependency of graph.dependencies[name] ?? []){
|
|
22
|
+
const node = graph.nodes[dependency.target];
|
|
23
|
+
if (!node || visited.has(dependency.target)) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
visited.add(dependency.target);
|
|
27
|
+
if (node.data.targets && target in node.data.targets) {
|
|
28
|
+
upstream.add(dependency.target);
|
|
29
|
+
} else {
|
|
30
|
+
visit(dependency.target);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
visit(projectName);
|
|
35
|
+
return [
|
|
36
|
+
...upstream
|
|
37
|
+
];
|
|
38
|
+
};
|
|
39
|
+
const explainDependency = (graph, projectName, dependency)=>{
|
|
40
|
+
const { target, dependencies, projects } = normalizeDependency(dependency);
|
|
41
|
+
if (dependencies) {
|
|
42
|
+
return {
|
|
43
|
+
label: `^${target}`,
|
|
44
|
+
upstream: resolveUpstream(graph, projectName, target)
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
if (projects !== undefined) {
|
|
48
|
+
return {
|
|
49
|
+
label: [
|
|
50
|
+
projects
|
|
51
|
+
].flat().map((project)=>`${project}:${target}`).join(', ')
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
label: target
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
const orderStages = (plan, stageDependencies, stage)=>{
|
|
59
|
+
const ordered = [];
|
|
60
|
+
const visited = new Set();
|
|
61
|
+
const visit = (name)=>{
|
|
62
|
+
if (visited.has(name)) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
visited.add(name);
|
|
66
|
+
for (const dependency of stageDependencies.get(name)){
|
|
67
|
+
visit(dependency);
|
|
68
|
+
}
|
|
69
|
+
ordered.push(name);
|
|
70
|
+
};
|
|
71
|
+
if (stage === undefined) {
|
|
72
|
+
for (const [name, target] of plan.lifecycleTargets){
|
|
73
|
+
if (target.kind === 'base') {
|
|
74
|
+
visit(name);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
} else {
|
|
78
|
+
visit(stage);
|
|
79
|
+
}
|
|
80
|
+
return ordered;
|
|
81
|
+
};
|
|
82
|
+
export const explainLifecycle = ({ plan, graph, project, stage })=>{
|
|
83
|
+
const node = graph.nodes[project];
|
|
84
|
+
if (!node) {
|
|
85
|
+
throw new Error(`Project ${project} not found`);
|
|
86
|
+
}
|
|
87
|
+
const targets = node.data.targets ?? {};
|
|
88
|
+
const stageNames = [
|
|
89
|
+
...plan.lifecycleTargets.values()
|
|
90
|
+
].filter((target)=>target.kind === 'base').map((target)=>target.name);
|
|
91
|
+
if (stage !== undefined && !stageNames.includes(stage)) {
|
|
92
|
+
throw new Error(`Stage ${stage} not found. Stages: ${stageNames.join(', ')}`);
|
|
93
|
+
}
|
|
94
|
+
const stageDependencies = new Map();
|
|
95
|
+
for (const stageName of stageNames){
|
|
96
|
+
const anchor = plan.lifecycleTargets.get(`${stageName}:_`);
|
|
97
|
+
stageDependencies.set(stageName, anchor.dependsOn.map((dependency)=>normalizeDependency(dependency)).filter(({ target, dependencies, projects })=>!dependencies && projects === undefined && stageNames.includes(target)).map(({ target })=>target));
|
|
98
|
+
}
|
|
99
|
+
const explainTarget = (targetName, previousHook)=>({
|
|
100
|
+
name: targetName,
|
|
101
|
+
dependsOn: (targets[targetName]?.dependsOn ?? []).filter((dependency)=>{
|
|
102
|
+
const normalized = normalizeDependency(dependency);
|
|
103
|
+
return normalized.target !== previousHook || normalized.dependencies !== undefined || normalized.projects !== undefined;
|
|
104
|
+
}).map((dependency)=>explainDependency(graph, project, dependency))
|
|
105
|
+
});
|
|
106
|
+
const stages = orderStages(plan, stageDependencies, stage).map((stageName)=>{
|
|
107
|
+
const base = plan.lifecycleTargets.get(stageName);
|
|
108
|
+
const anchor = plan.lifecycleTargets.get(`${stageName}:_`);
|
|
109
|
+
const hookTargets = [
|
|
110
|
+
...plan.lifecycleTargets.values()
|
|
111
|
+
].filter((target)=>target.stage === stageName && (target.kind === 'hook' || target.kind === 'base' && !target.hasHooks));
|
|
112
|
+
return {
|
|
113
|
+
name: stageName,
|
|
114
|
+
dependsOn: anchor.dependsOn.map((dependency)=>explainDependency(graph, project, dependency)),
|
|
115
|
+
hooks: hookTargets.map((hook)=>({
|
|
116
|
+
name: hook.name,
|
|
117
|
+
targets: [
|
|
118
|
+
...plan.registeredTargets
|
|
119
|
+
].filter(([targetName, lifecycleTarget])=>lifecycleTarget.name === hook.name && targetName in targets).map(([targetName, lifecycleTarget])=>explainTarget(targetName, lifecycleTarget.previousHook))
|
|
120
|
+
})),
|
|
121
|
+
hasHooks: base.kind === 'base' && base.hasHooks
|
|
122
|
+
};
|
|
123
|
+
});
|
|
124
|
+
return {
|
|
125
|
+
project,
|
|
126
|
+
stages
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
const formatDependencies = (dependencies)=>dependencies.map(({ label, upstream })=>{
|
|
130
|
+
if (!upstream) {
|
|
131
|
+
return label;
|
|
132
|
+
}
|
|
133
|
+
return `${label} (${upstream.length > 0 ? upstream.join(', ') : 'no upstream projects'})`;
|
|
134
|
+
}).join('; ');
|
|
135
|
+
const STAGE_INDENT = ' '.repeat('1. '.length);
|
|
136
|
+
const HOOK_TARGET_INDENT = `${STAGE_INDENT} `;
|
|
137
|
+
export const formatExplanation = ({ project, stages })=>{
|
|
138
|
+
const lines = [
|
|
139
|
+
project
|
|
140
|
+
];
|
|
141
|
+
for (const [index, stage] of stages.entries()){
|
|
142
|
+
lines.push('', `${index + 1}. ${stage.name}`);
|
|
143
|
+
if (stage.dependsOn.length > 0) {
|
|
144
|
+
lines.push(`${STAGE_INDENT}after: ${formatDependencies(stage.dependsOn)}`);
|
|
145
|
+
}
|
|
146
|
+
for (const hook of stage.hooks){
|
|
147
|
+
const indent = stage.hasHooks ? HOOK_TARGET_INDENT : STAGE_INDENT;
|
|
148
|
+
if (stage.hasHooks) {
|
|
149
|
+
lines.push(`${STAGE_INDENT}${hook.name}${hook.targets.length > 0 ? '' : ' (nothing bound)'}`);
|
|
150
|
+
}
|
|
151
|
+
for (const target of hook.targets){
|
|
152
|
+
const after = target.dependsOn.length > 0 ? ` (also after: ${formatDependencies(target.dependsOn)})` : '';
|
|
153
|
+
lines.push(`${indent}${target.name}${after}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return lines.join('\n');
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
//# sourceMappingURL=explain.js.map
|
|
@@ -1,22 +1,14 @@
|
|
|
1
|
-
import type { readFile as ReadFile, writeFile as WriteFile } from 'node:fs/promises';
|
|
2
|
-
import type { FilesFormatter } from 'format-file';
|
|
3
|
-
import type { AssertNxJson, AssertProjectJson } from '#schemas';
|
|
4
|
-
import type { Logger } from './dependencies.js';
|
|
5
|
-
import type { Normalizer } from './normalizer.js';
|
|
6
|
-
import type { NxAndProjectJsonProcessor } from './processor.js';
|
|
7
1
|
import type { LifecycleOptionsOrConfig } from './schema.js';
|
|
8
2
|
import type { NxContext } from './types.js';
|
|
9
|
-
export type ILifecycleInternal = (options: LifecycleOptionsOrConfig, context: NxContext) => Promise<void>;
|
|
10
3
|
/**
|
|
11
4
|
* Main logic for lifecycle file management.
|
|
12
5
|
*
|
|
13
6
|
* Loads the `nx.json` + `project.json`s for all projects,
|
|
14
7
|
* calculates the new targets and dependencies,
|
|
15
8
|
* and re-writes files as appropriate.
|
|
9
|
+
*
|
|
10
|
+
* @param options - options provided directly, or where to load them from
|
|
11
|
+
* @param context - workspace root and projects
|
|
16
12
|
*/
|
|
17
|
-
export declare
|
|
18
|
-
#private;
|
|
19
|
-
readonly lifecycleInternal: ILifecycleInternal;
|
|
20
|
-
constructor(normalizer: Normalizer, readFile: typeof ReadFile, writeFile: typeof WriteFile, formatFiles: FilesFormatter, processNxAndProjectJsons: NxAndProjectJsonProcessor, assertNxJson: AssertNxJson, assertProjectJson: AssertProjectJson, logger: Logger);
|
|
21
|
-
}
|
|
13
|
+
export declare const lifecycleInternal: (options: LifecycleOptionsOrConfig, context: NxContext) => Promise<void>;
|
|
22
14
|
//# sourceMappingURL=lifecycle-internal.d.ts.map
|