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.
Files changed (57) hide show
  1. package/.npmignore +20 -0
  2. package/README.md +242 -120
  3. package/WHY-NX-LIFECYCLE.md +64 -0
  4. package/dist/bin.d.ts +1 -2
  5. package/dist/bin.js +1 -14
  6. package/dist/cli.d.ts +1 -5
  7. package/dist/cli.js +9 -22
  8. package/dist/commands/explain-command.d.ts +12 -0
  9. package/dist/commands/explain-command.js +57 -0
  10. package/dist/commands/lib/types.d.ts +0 -3
  11. package/dist/commands/lifecycle-command.d.ts +2 -12
  12. package/dist/commands/lifecycle-command.js +13 -22
  13. package/dist/executors/lifecycle/index.d.ts +1 -4
  14. package/dist/executors/lifecycle/index.js +1 -8
  15. package/dist/executors/lifecycle/lifecycle.d.ts +8 -9
  16. package/dist/executors/lifecycle/lifecycle.js +13 -20
  17. package/dist/lifecycle/explain.d.ts +68 -0
  18. package/dist/lifecycle/explain.js +160 -0
  19. package/dist/lifecycle/lifecycle-internal.d.ts +4 -12
  20. package/dist/lifecycle/lifecycle-internal.js +93 -93
  21. package/dist/lifecycle/normalizer.d.ts +14 -8
  22. package/dist/lifecycle/normalizer.js +29 -36
  23. package/dist/lifecycle/processor.d.ts +41 -5
  24. package/dist/lifecycle/processor.js +36 -35
  25. package/dist/lifecycle/schema.d.ts +468 -66
  26. package/dist/lifecycle/schema.js +30 -21
  27. package/dist/plugin/index.d.ts +7 -0
  28. package/dist/plugin/index.js +4 -0
  29. package/dist/plugin/lifecycle-plugin.d.ts +24 -0
  30. package/dist/plugin/lifecycle-plugin.js +145 -0
  31. package/dist/{executors/lifecycle/index.d.cts → plugin/schema.d.ts} +32 -55
  32. package/dist/plugin/schema.js +19 -0
  33. package/dist/schemas/configurations.d.ts +5 -5
  34. package/dist/schemas/depend-on.d.ts +39 -9
  35. package/dist/schemas/depend-on.js +4 -2
  36. package/dist/schemas/empty.d.ts +2 -2
  37. package/dist/schemas/empty.js +2 -2
  38. package/dist/schemas/nx-json.d.ts +42 -20
  39. package/dist/schemas/nx-json.js +2 -4
  40. package/dist/schemas/project-json.d.ts +42 -20
  41. package/dist/schemas/project-json.js +2 -4
  42. package/dist/schemas/target.d.ts +79 -25
  43. package/executors.json +2 -2
  44. package/out/nx-executor/schema.json +148 -0
  45. package/out/schema.json +114 -0
  46. package/package.json +43 -41
  47. package/dist/commands/index.d.ts +0 -5
  48. package/dist/commands/index.js +0 -14
  49. package/dist/commands/lib/dependencies.d.ts +0 -10
  50. package/dist/commands/lib/dependencies.js +0 -12
  51. package/dist/executors/lifecycle/index.cjs +0 -15
  52. package/dist/lifecycle/depedencies.d.ts +0 -15
  53. package/dist/lifecycle/depedencies.js +0 -14
  54. package/dist/lifecycle/index.d.ts +0 -5
  55. package/dist/lifecycle/index.js +0 -25
  56. package/dist/schemas/lib/ajv.d.ts +0 -3
  57. package/dist/schemas/lib/ajv.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
- #getCommands;
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
- const yarg = yargs().scriptName('lifecycle').option({
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
- this.#exitCode(1);
22
+ process.exitCode = 1;
36
23
  if (log) {
37
- this.#errorLogger(log);
24
+ console.error(log);
38
25
  }
39
26
  } else if (log) {
40
- this.#logger(log);
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;
@@ -8,15 +5,8 @@ interface LifecycleCommandExtendedInput extends LifecycleCommandInput {
8
5
  dryRun: boolean;
9
6
  }
10
7
  /**
11
- * Main `load-populate-files` command
8
+ * Main `nx-lifecycle` command
12
9
  */
13
- export declare class LifecycleCommand implements Command<LifecycleCommandExtendedInput> {
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
- export class LifecycleCommand {
3
- command = [
3
+ import { lifecycleInternal } from '../lifecycle/lifecycle-internal.js';
4
+ export const lifecycleCommand = {
5
+ command: [
4
6
  '$0',
5
7
  'lifecycle'
6
- ];
7
- describe = 'Inject Nx targets as high level workflows';
8
- #getProjectGraph;
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
- async handler(options) {
38
- const projectGraph = await this.#getProjectGraph();
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: this.#workspaceRoot,
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
- declare const _default: (options: import("../../lifecycle/schema.js").LifecycleOptionsOrConfig, context: import("./lifecycle.js").SimpleExecutorContext) => Promise<{
2
- success: boolean;
3
- }>;
4
- export default _default;
1
+ export { lifecycle as default } from './lifecycle.js';
5
2
  //# sourceMappingURL=index.d.ts.map
@@ -1,10 +1,3 @@
1
- import { bind, createContainer } from 'haywire';
2
- import { lifecycleInternalId, lifecycleInternalModule } from '../../lifecycle/index.js';
3
- import { Lifecycle } from './lifecycle.js';
4
- const lifecycleModule = lifecycleInternalModule.addBinding(bind(Lifecycle).withDependencies([
5
- lifecycleInternalId
6
- ]).withConstructorProvider());
7
- const lifecycle = createContainer(lifecycleModule).get(Lifecycle);
8
- export default lifecycle.lifecycle;
1
+ export { lifecycle as default } from './lifecycle.js';
9
2
 
10
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
- * Main logic for lifecycle file management.
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 class Lifecycle {
13
- #private;
14
- readonly lifecycle: (options: LifecycleOptionsOrConfig, context: SimpleExecutorContext) => Promise<{
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
- export class Lifecycle {
2
- #lifecycleInternal;
3
- lifecycle;
4
- constructor(lifecycleInternal){
5
- this.#lifecycleInternal = lifecycleInternal;
6
- this.lifecycle = this.#lifecycle.bind(this);
7
- }
8
- async #lifecycle(options, context) {
9
- await this.#lifecycleInternal(options, {
10
- root: context.root,
11
- projects: Object.values(context.projectsConfigurations.projects).map((projectConfig)=>({
12
- name: projectConfig.name,
13
- root: projectConfig.root
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 { IsNxJson, IsProjectJson } from '#schemas';
4
- import type { Logger } from './depedencies.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 class LifecycleInternal {
18
- #private;
19
- readonly lifecycleInternal: ILifecycleInternal;
20
- constructor(normalizer: Normalizer, readFile: typeof ReadFile, writeFile: typeof WriteFile, formatFiles: FilesFormatter, processNxAndProjectJsons: NxAndProjectJsonProcessor, isNxJson: IsNxJson, isProjectJson: IsProjectJson, logger: Logger);
21
- }
13
+ export declare const lifecycleInternal: (options: LifecycleOptionsOrConfig, context: NxContext) => Promise<void>;
22
14
  //# sourceMappingURL=lifecycle-internal.d.ts.map