@webpieces/nx-webpieces-rules 0.4.811 → 0.4.813

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 (38) hide show
  1. package/executors.json +2 -2
  2. package/package.json +8 -7
  3. package/src/executors/docs-generate/executor.d.ts +14 -13
  4. package/src/executors/docs-generate/executor.js +24 -22
  5. package/src/executors/docs-generate/executor.js.map +1 -1
  6. package/src/executors/docs-generate/schema.json +3 -3
  7. package/src/executors/openapi-generate/executor.d.ts +25 -18
  8. package/src/executors/openapi-generate/executor.js +32 -24
  9. package/src/executors/openapi-generate/executor.js.map +1 -1
  10. package/src/executors/openapi-generate/schema.json +2 -2
  11. package/src/executors/validate-nx-wiring/executor.d.ts +6 -0
  12. package/src/executors/validate-nx-wiring/executor.js +17 -1
  13. package/src/executors/validate-nx-wiring/executor.js.map +1 -1
  14. package/src/generate-targets.d.ts +59 -0
  15. package/src/generate-targets.js +118 -0
  16. package/src/generate-targets.js.map +1 -0
  17. package/src/lib/api-docs/consumer-bin-resolver.d.ts +62 -0
  18. package/src/lib/api-docs/consumer-bin-resolver.js +148 -0
  19. package/src/lib/api-docs/consumer-bin-resolver.js.map +1 -0
  20. package/src/lib/api-docs/generate-wiring.d.ts +124 -0
  21. package/src/lib/api-docs/generate-wiring.js +328 -0
  22. package/src/lib/api-docs/generate-wiring.js.map +1 -0
  23. package/src/lib/api-docs/generator-package.d.ts +23 -0
  24. package/src/lib/api-docs/generator-package.js +32 -0
  25. package/src/lib/api-docs/generator-package.js.map +1 -0
  26. package/src/lib/api-docs/generator-runner.d.ts +21 -0
  27. package/src/lib/api-docs/generator-runner.js +38 -0
  28. package/src/lib/api-docs/generator-runner.js.map +1 -0
  29. package/src/lib/{generated-docs → api-docs}/generator-target.d.ts +19 -12
  30. package/src/lib/{generated-docs → api-docs}/generator-target.js +40 -24
  31. package/src/lib/api-docs/generator-target.js.map +1 -0
  32. package/src/lib/api-docs/json-value.d.ts +6 -0
  33. package/src/lib/api-docs/json-value.js +3 -0
  34. package/src/lib/api-docs/json-value.js.map +1 -0
  35. package/src/plugin.d.ts +2 -0
  36. package/src/plugin.js +15 -2
  37. package/src/plugin.js.map +1 -1
  38. package/src/lib/generated-docs/generator-target.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator-runner.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/api-docs/generator-runner.ts"],"names":[],"mappings":";;;AAAA,iDAA0C;AAG1C,iDAAiD;AACjD,MAAa,YAAY;IAER;IAEA;IAHb,YACa,QAAgB;IACzB,uFAAuF;IAC9E,MAAc;QAFd,aAAQ,GAAR,QAAQ,CAAQ;QAEhB,WAAM,GAAN,MAAM,CAAQ;IACxB,CAAC;IAEJ,IAAI,EAAE;QACF,OAAO,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC;IAC/B,CAAC;CACJ;AAVD,oCAUC;AAED;;;;;;GAMG;AACH,MAAa,eAAe;IACxB,GAAG,CAAC,GAAgB,EAAE,IAAuB,EAAE,GAAW;QACtD,MAAM,MAAM,GAAG,IAAA,yBAAS,EAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;QAC9F,MAAM,MAAM,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE,EAAE,MAAM,CAAC,KAAK,EAAE,OAAO,IAAI,EAAE,CAAC;aACjF,MAAM,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;aAC5C,IAAI,CAAC,IAAI,CAAC;aACV,IAAI,EAAE,CAAC;QACZ,OAAO,IAAI,YAAY,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;IACxD,CAAC;CACJ;AATD,0CASC","sourcesContent":["import { spawnSync } from 'child_process';\nimport { ConsumerBin } from './consumer-bin-resolver';\n\n/** One finished generator process. Data-only. */\nexport class GeneratorRun {\n constructor(\n readonly exitCode: number,\n /** stdout and stderr, in that order — the generator reports its refusals on stdout. */\n readonly output: string,\n ) {}\n\n get ok(): boolean {\n return this.exitCode === 0;\n }\n}\n\n/**\n * Runs a resolved {@link ConsumerBin} with the node that is running US, so the generator gets the\n * consumer's `node_modules` (it lives there) without depending on a `.bin` shim or on `PATH`.\n *\n * It REPORTS the outcome rather than throwing on a non-zero exit, so the executor that ran it decides\n * how to word the refusal (it names the manifest or the document it was rendering).\n */\nexport class GeneratorRunner {\n run(bin: ConsumerBin, args: readonly string[], cwd: string): GeneratorRun {\n const result = spawnSync(process.execPath, [bin.binPath, ...args], { cwd, encoding: 'utf8' });\n const output = [result.stdout ?? '', result.stderr ?? '', result.error?.message ?? '']\n .filter((part: string) => part.trim() !== '')\n .join('\\n')\n .trim();\n return new GeneratorRun(result.status ?? 1, output);\n }\n}\n"]}
@@ -4,16 +4,18 @@
4
4
  *
5
5
  * Both halves read the project's own declarations and never supply a value of their own:
6
6
  *
7
- * - the output directory is the project's `build` target's `options.outputPath` — the directory tsc
8
- * writes and the package is packed from, so the documents ship INSIDE the published package. It is
9
- * ASKED of nx, never assumed: this repo builds into a workspace-root `dist/apps/...`, another
10
- * consumer builds into a project-local `<project>/dist`, and hardcoding either one generates the
7
+ * - the documents' directory is the `outputPath` of the target `openapi-generate` dependsOn — the api
8
+ * library's `build` (tsc) step, which writes the directory the package is packed from, so the
9
+ * documents ship INSIDE the published package. It is ASKED of nx through `GeneratedApiDocsLayout`
10
+ * (`@webpieces/core-util`), the same lookup `McpToolCatalog.fromPackages` reads with, and never
11
+ * assumed: this repo builds into a workspace-root `dist/apps/...`, another consumer builds into a
12
+ * project-local `<project>/dist`, and hardcoding either one — or the target's NAME — generates the
11
13
  * document somewhere the package is not packed from;
12
14
  * - the ordering and the cache are the target's own `dependsOn` and `outputs`, which the executor
13
- * checks rather than trusts, because both failures are silent: a missing `dependsOn: ["build"]`
14
- * lets tsc's clean of `outputPath` race the write (the document vanishes and a dependent test dies on
15
- * ENOENT, intermittently, only in CI), and `outputs` that miss a written file make every cache hit
16
- * restore a package without that file.
15
+ * checks rather than trusts, because both failures are silent: without the `dependsOn` edge, tsc's
16
+ * clean of `outputPath` races the write (the document vanishes and a dependent test dies on ENOENT,
17
+ * intermittently, only in CI), and `outputs` that miss a written file make every cache hit restore a
18
+ * package without that file.
17
19
  */
18
20
  import type { ExecutorContext, TargetConfiguration } from '@nx/devkit';
19
21
  export declare class GeneratorTarget {
@@ -25,15 +27,20 @@ export declare class GeneratorTarget {
25
27
  readonly projectRoot: string;
26
28
  readonly targetName: string;
27
29
  readonly target: TargetConfiguration;
28
- readonly build: TargetConfiguration | undefined;
30
+ readonly targets: Record<string, TargetConfiguration>;
29
31
  constructor(
30
32
  /** The executor's name, which is what every refusal is reported under. */
31
33
  ruleName: string, workspaceRoot: string, projectName: string,
32
34
  /** Workspace-relative. */
33
- projectRoot: string, targetName: string, target: TargetConfiguration, build: TargetConfiguration | undefined);
35
+ projectRoot: string, targetName: string, target: TargetConfiguration, targets: Record<string, TargetConfiguration>);
34
36
  static of(ruleName: string, context: ExecutorContext): GeneratorTarget;
35
- /** Absolute path to the project's declared `build` `outputPath` — the directory the package is packed from. */
36
- buildOutputDir(): string;
37
+ /**
38
+ * Absolute path to the directory the documents live in: the `outputPath` of the target
39
+ * `openapi-generate` dependsOn — the directory the package is packed from.
40
+ */
41
+ documentsDir(): string;
42
+ /** Absolute `<projectRoot>/<dir>`, refusing anything that is not strictly inside the project. */
43
+ insideProject(dir: string, optionName: string): string;
37
44
  /** Refuse unless this target `dependsOn` the sibling `required` target. */
38
45
  assertDependsOn(required: string): void;
39
46
  /** Refuse unless every written file is covered by the target's declared `outputs`, so a cache hit restores it. */
@@ -5,20 +5,23 @@
5
5
  *
6
6
  * Both halves read the project's own declarations and never supply a value of their own:
7
7
  *
8
- * - the output directory is the project's `build` target's `options.outputPath` — the directory tsc
9
- * writes and the package is packed from, so the documents ship INSIDE the published package. It is
10
- * ASKED of nx, never assumed: this repo builds into a workspace-root `dist/apps/...`, another
11
- * consumer builds into a project-local `<project>/dist`, and hardcoding either one generates the
8
+ * - the documents' directory is the `outputPath` of the target `openapi-generate` dependsOn — the api
9
+ * library's `build` (tsc) step, which writes the directory the package is packed from, so the
10
+ * documents ship INSIDE the published package. It is ASKED of nx through `GeneratedApiDocsLayout`
11
+ * (`@webpieces/core-util`), the same lookup `McpToolCatalog.fromPackages` reads with, and never
12
+ * assumed: this repo builds into a workspace-root `dist/apps/...`, another consumer builds into a
13
+ * project-local `<project>/dist`, and hardcoding either one — or the target's NAME — generates the
12
14
  * document somewhere the package is not packed from;
13
15
  * - the ordering and the cache are the target's own `dependsOn` and `outputs`, which the executor
14
- * checks rather than trusts, because both failures are silent: a missing `dependsOn: ["build"]`
15
- * lets tsc's clean of `outputPath` race the write (the document vanishes and a dependent test dies on
16
- * ENOENT, intermittently, only in CI), and `outputs` that miss a written file make every cache hit
17
- * restore a package without that file.
16
+ * checks rather than trusts, because both failures are silent: without the `dependsOn` edge, tsc's
17
+ * clean of `outputPath` races the write (the document vanishes and a dependent test dies on ENOENT,
18
+ * intermittently, only in CI), and `outputs` that miss a written file make every cache hit restore a
19
+ * package without that file.
18
20
  */
19
21
  Object.defineProperty(exports, "__esModule", { value: true });
20
22
  exports.StagedOutput = exports.GeneratorTarget = void 0;
21
23
  const tslib_1 = require("tslib");
24
+ const core_util_1 = require("@webpieces/core-util");
22
25
  const rules_config_1 = require("@webpieces/rules-config");
23
26
  const fs = tslib_1.__importStar(require("fs"));
24
27
  const path = tslib_1.__importStar(require("path"));
@@ -29,19 +32,19 @@ class GeneratorTarget {
29
32
  projectRoot;
30
33
  targetName;
31
34
  target;
32
- build;
35
+ targets;
33
36
  constructor(
34
37
  /** The executor's name, which is what every refusal is reported under. */
35
38
  ruleName, workspaceRoot, projectName,
36
39
  /** Workspace-relative. */
37
- projectRoot, targetName, target, build) {
40
+ projectRoot, targetName, target, targets) {
38
41
  this.ruleName = ruleName;
39
42
  this.workspaceRoot = workspaceRoot;
40
43
  this.projectName = projectName;
41
44
  this.projectRoot = projectRoot;
42
45
  this.targetName = targetName;
43
46
  this.target = target;
44
- this.build = build;
47
+ this.targets = targets;
45
48
  }
46
49
  // webpieces-disable no-function-outside-class -- static factory of this class
47
50
  static of(ruleName, context) {
@@ -53,27 +56,40 @@ class GeneratorTarget {
53
56
  // nx hands every executor its own project and target; their absence is our bug, not the consumer's.
54
57
  throw new Error(`${ruleName}: nx did not describe project '${projectName}' target '${targetName}'`);
55
58
  }
56
- return new GeneratorTarget(ruleName, context.root, projectName, project.root, targetName, target, project.targets?.['build']);
59
+ return new GeneratorTarget(ruleName, context.root, projectName, project.root, targetName, target, project.targets ?? {});
57
60
  }
58
- /** Absolute path to the project's declared `build` `outputPath` — the directory the package is packed from. */
59
- buildOutputDir() {
60
- const declared = this.build?.options?.['outputPath'];
61
- if (typeof declared !== 'string' || declared.trim() === '') {
62
- throw new rules_config_1.RuleFailError(this.ruleName, `${this.projectName} has no build target with an options.outputPath, so ${this.ruleName} has ` +
63
- `nowhere to write that gets published. The documents go into the build's own output ` +
64
- `directory — the one the package is packed from — and are never assumed to be ./dist.`, undefined, undefined, [new rules_config_1.Option(`Declare targets.build.options.outputPath in ${this.projectRoot}/project.json`, true)]);
61
+ /**
62
+ * Absolute path to the directory the documents live in: the `outputPath` of the target
63
+ * `openapi-generate` dependsOn — the directory the package is packed from.
64
+ */
65
+ documentsDir() {
66
+ const lookup = new core_util_1.GeneratedApiDocsLayout(this.projectRoot, this.projectName, this.targets).outputTarget();
67
+ if (lookup.found === undefined) {
68
+ throw new rules_config_1.RuleFailError(this.ruleName, `${lookup.problem.problem} The documents go into the build's own output directory — the ` +
69
+ 'one the package is packed from — and are never assumed to be ./dist.', undefined, undefined, [new rules_config_1.Option(lookup.problem.cure, true)]);
65
70
  }
66
- return path.resolve(this.workspaceRoot, this.interpolate(declared));
71
+ return path.resolve(this.workspaceRoot, lookup.found.outputPath);
72
+ }
73
+ /** Absolute `<projectRoot>/<dir>`, refusing anything that is not strictly inside the project. */
74
+ insideProject(dir, optionName) {
75
+ const projectAbs = path.resolve(this.workspaceRoot, this.projectRoot);
76
+ const resolved = path.resolve(projectAbs, dir);
77
+ const relative = path.relative(projectAbs, resolved);
78
+ if (relative !== '' && !relative.startsWith('..') && !path.isAbsolute(relative))
79
+ return resolved;
80
+ throw new rules_config_1.RuleFailError(this.ruleName, `${this.projectName}:${this.targetName} options.${optionName} is '${dir}', which is not a directory ` +
81
+ `strictly inside ${this.projectRoot}. It is emptied and rewritten on every run, so it may only ` +
82
+ 'name a directory of the project\'s own.', undefined, undefined, [new rules_config_1.Option(`Set options.${optionName} to a project-relative directory, e.g. "generated-docs"`, true)]);
67
83
  }
68
84
  /** Refuse unless this target `dependsOn` the sibling `required` target. */
69
85
  assertDependsOn(required) {
70
86
  const entries = this.target.dependsOn ?? [];
71
87
  if (entries.some((entry) => this.namesSibling(entry, required)))
72
88
  return;
73
- throw new rules_config_1.RuleFailError(this.ruleName, `${this.projectName}:${this.targetName} does not declare dependsOn "${required}". It writes into ` +
74
- `the build's outputPath, so without that edge nx may run it before or alongside ${required} ` +
75
- `— and ${required}'s clean of that directory deletes the document it just wrote. That ` +
76
- `fails intermittently and mostly in CI, which is why it is refused here instead.`, undefined, undefined, [new rules_config_1.Option(`Add "dependsOn": ["${required}"] to the ${this.targetName} target in ${this.projectRoot}/project.json`, true)]);
89
+ throw new rules_config_1.RuleFailError(this.ruleName, `${this.projectName}:${this.targetName} does not declare dependsOn "${required}". It reads what ` +
90
+ `${required} writes, so without that edge nx may run it before or alongside ${required} and ` +
91
+ `render a stale or missing document. That fails intermittently and mostly in CI, which is ` +
92
+ `why it is refused here instead.`, undefined, undefined, [new rules_config_1.Option(`Add "dependsOn": ["${required}"] to the ${this.targetName} target in ${this.projectRoot}/project.json`, true)]);
77
93
  }
78
94
  /** Refuse unless every written file is covered by the target's declared `outputs`, so a cache hit restores it. */
79
95
  assertOutputsCover(writtenAbs) {
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator-target.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/api-docs/generator-target.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The shared half of the `openapi-generate` and `docs-generate` executors: WHERE a generated document\n * goes, and the proof that the target is wired so that nx both orders and caches it correctly.\n *\n * Both halves read the project's own declarations and never supply a value of their own:\n *\n * - the documents' directory is the `outputPath` of the target `openapi-generate` dependsOn — the api\n * library's `build` (tsc) step, which writes the directory the package is packed from, so the\n * documents ship INSIDE the published package. It is ASKED of nx through `GeneratedApiDocsLayout`\n * (`@webpieces/core-util`), the same lookup `McpToolCatalog.fromPackages` reads with, and never\n * assumed: this repo builds into a workspace-root `dist/apps/...`, another consumer builds into a\n * project-local `<project>/dist`, and hardcoding either one — or the target's NAME — generates the\n * document somewhere the package is not packed from;\n * - the ordering and the cache are the target's own `dependsOn` and `outputs`, which the executor\n * checks rather than trusts, because both failures are silent: without the `dependsOn` edge, tsc's\n * clean of `outputPath` races the write (the document vanishes and a dependent test dies on ENOENT,\n * intermittently, only in CI), and `outputs` that miss a written file make every cache hit restore a\n * package without that file.\n */\n\nimport type { ExecutorContext, TargetConfiguration, TargetDependencyConfig } from '@nx/devkit';\nimport { GeneratedApiDocsLayout } from '@webpieces/core-util';\nimport { Option, RuleFailError, matchesAnyGlob } from '@webpieces/rules-config';\nimport * as fs from 'fs';\nimport * as path from 'path';\n\n/** What `dependsOn` may name: a sibling target by name, or nx's object form of the same. */\ntype DependsOnEntry = string | TargetDependencyConfig;\n\nexport class GeneratorTarget {\n constructor(\n /** The executor's name, which is what every refusal is reported under. */\n readonly ruleName: string,\n readonly workspaceRoot: string,\n readonly projectName: string,\n /** Workspace-relative. */\n readonly projectRoot: string,\n readonly targetName: string,\n readonly target: TargetConfiguration,\n readonly targets: Record<string, TargetConfiguration>,\n ) {}\n\n // webpieces-disable no-function-outside-class -- static factory of this class\n static of(ruleName: string, context: ExecutorContext): GeneratorTarget {\n const projectName = context.projectName ?? '';\n const project = context.projectsConfigurations?.projects[projectName];\n const targetName = context.targetName ?? '';\n const target = project?.targets?.[targetName];\n if (project === undefined || target === undefined) {\n // nx hands every executor its own project and target; their absence is our bug, not the consumer's.\n throw new Error(`${ruleName}: nx did not describe project '${projectName}' target '${targetName}'`);\n }\n return new GeneratorTarget(\n ruleName, context.root, projectName, project.root, targetName, target, project.targets ?? {});\n }\n\n /**\n * Absolute path to the directory the documents live in: the `outputPath` of the target\n * `openapi-generate` dependsOn — the directory the package is packed from.\n */\n documentsDir(): string {\n const lookup = new GeneratedApiDocsLayout(this.projectRoot, this.projectName, this.targets).outputTarget();\n if (lookup.found === undefined) {\n throw new RuleFailError(\n this.ruleName,\n `${lookup.problem!.problem} The documents go into the build's own output directory — the ` +\n 'one the package is packed from — and are never assumed to be ./dist.',\n undefined,\n undefined,\n [new Option(lookup.problem!.cure, true)],\n );\n }\n return path.resolve(this.workspaceRoot, lookup.found.outputPath);\n }\n\n /** Absolute `<projectRoot>/<dir>`, refusing anything that is not strictly inside the project. */\n insideProject(dir: string, optionName: string): string {\n const projectAbs = path.resolve(this.workspaceRoot, this.projectRoot);\n const resolved = path.resolve(projectAbs, dir);\n const relative = path.relative(projectAbs, resolved);\n if (relative !== '' && !relative.startsWith('..') && !path.isAbsolute(relative)) return resolved;\n throw new RuleFailError(\n this.ruleName,\n `${this.projectName}:${this.targetName} options.${optionName} is '${dir}', which is not a directory ` +\n `strictly inside ${this.projectRoot}. It is emptied and rewritten on every run, so it may only ` +\n 'name a directory of the project\\'s own.',\n undefined,\n undefined,\n [new Option(`Set options.${optionName} to a project-relative directory, e.g. \"generated-docs\"`, true)],\n );\n }\n\n /** Refuse unless this target `dependsOn` the sibling `required` target. */\n assertDependsOn(required: string): void {\n const entries: readonly DependsOnEntry[] = this.target.dependsOn ?? [];\n if (entries.some((entry: DependsOnEntry) => this.namesSibling(entry, required))) return;\n throw new RuleFailError(\n this.ruleName,\n `${this.projectName}:${this.targetName} does not declare dependsOn \"${required}\". It reads what ` +\n `${required} writes, so without that edge nx may run it before or alongside ${required} and ` +\n `render a stale or missing document. That fails intermittently and mostly in CI, which is ` +\n `why it is refused here instead.`,\n undefined,\n undefined,\n [new Option(`Add \"dependsOn\": [\"${required}\"] to the ${this.targetName} target in ${this.projectRoot}/project.json`, true)],\n );\n }\n\n /** Refuse unless every written file is covered by the target's declared `outputs`, so a cache hit restores it. */\n assertOutputsCover(writtenAbs: readonly string[]): void {\n const patterns = (this.target.outputs ?? []).map((output: string) => this.interpolate(output));\n const uncovered = writtenAbs\n .map((file: string) => path.relative(this.workspaceRoot, file).split(path.sep).join('/'))\n .filter((file: string) => !matchesAnyGlob(file, patterns));\n if (uncovered.length === 0) return;\n throw new RuleFailError(\n this.ruleName,\n `${this.projectName}:${this.targetName} wrote files its declared outputs do not cover, so a ` +\n `cache hit would restore a package WITHOUT them:\\n` +\n uncovered.map((file: string) => ` ${file}`).join('\\n'),\n undefined,\n undefined,\n [new Option(\n `Cover them in the ${this.targetName} target's \"outputs\" in ${this.projectRoot}/project.json, ` +\n `e.g. \"{workspaceRoot}/${path.posix.dirname(uncovered[0]!)}/<the files>\"`,\n true,\n )],\n );\n }\n\n /** A workspace-relative path the consumer stated, from `options`, required and never defaulted. */\n requiredOption(value: string | undefined, name: string): string {\n if (typeof value === 'string' && value.trim() !== '') return value;\n throw new RuleFailError(\n this.ruleName,\n `${this.projectName}:${this.targetName} has no options.${name}. It is required and has no default.`,\n undefined,\n undefined,\n [new Option(`Set options.${name} on the ${this.targetName} target in ${this.projectRoot}/project.json`, true)],\n );\n }\n\n private namesSibling(entry: DependsOnEntry, required: string): boolean {\n if (typeof entry === 'string') return entry === required;\n const projects = entry.projects;\n const self = projects === undefined || projects === 'self' ||\n (Array.isArray(projects) && projects.length === 1 && projects[0] === this.projectName);\n return entry.target === required && entry.dependencies !== true && self;\n }\n\n /** nx's own tokens, so a path written the way nx accepts it resolves the way nx resolves it. */\n private interpolate(text: string): string {\n return text\n .replace(/\\{workspaceRoot\\}\\/?/g, '')\n .replace(/\\{projectRoot\\}/g, this.projectRoot)\n .replace(/\\{projectName\\}/g, this.projectName)\n .replace(/\\{options\\.([A-Za-z0-9_]+)\\}/g, (whole: string, key: string): string => {\n const value = this.target.options?.[key];\n return typeof value === 'string' ? value : whole;\n });\n }\n}\n\n/**\n * Generate into a STAGING directory, then publish into the output directory — so the executor knows\n * exactly which files the run produced (for {@link GeneratorTarget.assertOutputsCover}) without\n * parsing a generator's console output, and a failed run leaves the output directory untouched.\n */\nexport class StagedOutput {\n publish(stagingDir: string, destDir: string): string[] {\n const written: string[] = [];\n const copy = (from: string, to: string): void => {\n fs.mkdirSync(to, { recursive: true });\n for (const entry of fs.readdirSync(from, { withFileTypes: true })) {\n const source = path.join(from, entry.name);\n const target = path.join(to, entry.name);\n if (entry.isDirectory()) {\n copy(source, target);\n } else {\n fs.copyFileSync(source, target);\n written.push(target);\n }\n }\n };\n copy(stagingDir, destDir);\n return written.sort();\n }\n}\n"]}
@@ -0,0 +1,6 @@
1
+ /** Everything a JSON document can hold — a parsed OpenAPI document or package.json is exactly this. */
2
+ export type JsonValue = string | number | boolean | null | JsonValue[] | JsonObject;
3
+ /** The object case of {@link JsonValue}, named so the recursive alias can refer to it. */
4
+ export type JsonObject = {
5
+ [key: string]: JsonValue;
6
+ };
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=json-value.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-value.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/api-docs/json-value.ts"],"names":[],"mappings":"","sourcesContent":["/** Everything a JSON document can hold — a parsed OpenAPI document or package.json is exactly this. */\nexport type JsonValue = string | number | boolean | null | JsonValue[] | JsonObject;\n\n/** The object case of {@link JsonValue}, named so the recursive alias can refer to it. */\nexport type JsonObject = { [key: string]: JsonValue };\n"]}
package/src/plugin.d.ts CHANGED
@@ -4,6 +4,8 @@
4
4
  * This plugin automatically creates targets for:
5
5
  * 1. Workspace-level architecture validation (generate, visualize, validate-*)
6
6
  * 2. Per-project circular dependency checking
7
+ * 3. Per-project API documents, opted into with a TAG: `generate:openapi` infers `openapi-generate`,
8
+ * `generate:docs-site` infers `openapi-generate` + `docs-generate` (see generate-targets.ts)
7
9
  *
8
10
  * Install with: nx add @webpieces/nx-webpieces-rules
9
11
  *
package/src/plugin.js CHANGED
@@ -5,6 +5,8 @@
5
5
  * This plugin automatically creates targets for:
6
6
  * 1. Workspace-level architecture validation (generate, visualize, validate-*)
7
7
  * 2. Per-project circular dependency checking
8
+ * 3. Per-project API documents, opted into with a TAG: `generate:openapi` infers `openapi-generate`,
9
+ * `generate:docs-site` infers `openapi-generate` + `docs-generate` (see generate-targets.ts)
8
10
  *
9
11
  * Install with: nx add @webpieces/nx-webpieces-rules
10
12
  *
@@ -26,6 +28,7 @@ const runtime_targets_1 = require("./runtime-targets");
26
28
  const branch_identity_inputs_1 = require("./branch-identity-inputs");
27
29
  const validation_targets_1 = require("./validation-targets");
28
30
  const di_graph_targets_1 = require("./di-graph-targets");
31
+ const generate_targets_1 = require("./generate-targets");
29
32
  const DEFAULT_OPTIONS = {
30
33
  circularDeps: {
31
34
  enabled: true,
@@ -161,7 +164,7 @@ function addPerProjectTargets(results, projectFiles, opts, context) {
161
164
  processedRoots.add(projectRoot);
162
165
  const architectureEnabled = opts.workspace.enabled === true &&
163
166
  (0, fs_1.existsSync)((0, path_1.join)(context.workspaceRoot, 'architecture'));
164
- const targets = buildPerProjectTargets(isProjectJson, projectRoot, opts, architectureEnabled);
167
+ const targets = buildPerProjectTargets(isProjectJson, projectRoot, opts, architectureEnabled, isProjectJson ? new generate_targets_1.RawProjectJsonReader().read(context.workspaceRoot, projectFile, projectRoot) : undefined);
165
168
  if (Object.keys(targets).length === 0)
166
169
  continue;
167
170
  const result = {
@@ -178,7 +181,7 @@ function addPerProjectTargets(results, projectFiles, opts, context) {
178
181
  * Build the target map for one project. Most targets are project.json-only
179
182
  * (package.json-only projects may not have TypeScript source); `ci` goes on all.
180
183
  */
181
- function buildPerProjectTargets(isProjectJson, projectRoot, opts, architectureEnabled) {
184
+ function buildPerProjectTargets(isProjectJson, projectRoot, opts, architectureEnabled, rawProject) {
182
185
  const targets = {};
183
186
  // Per-project validation gates that `ci` must depend on. Collected as they are added
184
187
  // so `ci` references only gates that actually exist on THIS project (a package.json-only
@@ -202,6 +205,16 @@ function buildPerProjectTargets(isProjectJson, projectRoot, opts, architectureEn
202
205
  targets['di-graph-generate'] = (0, di_graph_targets_1.createDiGraphGenerateTarget)();
203
206
  validationTargets.push('di-graph-generate');
204
207
  }
208
+ // API documents, opted into with a TAG (generate:openapi / generate:docs-site). An untagged project
209
+ // costs this one in-memory tag check. They ride ci like every other build step — generation is
210
+ // ordinary BUILD work, not a side channel (#1021).
211
+ if (rawProject !== undefined) {
212
+ const generated = new generate_targets_1.GenerateTargets(projectRoot, rawProject).infer();
213
+ for (const [name, target] of Object.entries(generated)) {
214
+ targets[name] = target;
215
+ validationTargets.push(name);
216
+ }
217
+ }
205
218
  // Add ci target to ALL projects (both project.json and package.json). ci aggregates
206
219
  // lint + build + test + the validation gates that formerly rode on the compile
207
220
  // executor's targetDefaults, so a bare `build` stays a fast compile-only step.
package/src/plugin.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../../../packages/tooling/nx-webpieces-rules/src/plugin.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Unified Nx Inference Plugin for @webpieces/nx-webpieces-rules\n *\n * This plugin automatically creates targets for:\n * 1. Workspace-level architecture validation (generate, visualize, validate-*)\n * 2. Per-project circular dependency checking\n *\n * Install with: nx add @webpieces/nx-webpieces-rules\n *\n * Usage:\n * Add to nx.json plugins array:\n * {\n * \"plugins\": [\"@webpieces/nx-webpieces-rules\"]\n * }\n *\n * Then all targets appear automatically without manual project.json configuration.\n */\n\nimport { dirname, join } from 'path';\nimport { existsSync } from 'fs';\nimport type {\n CreateNodesV2,\n CreateNodesContextV2,\n CreateNodesResultV2,\n CreateNodesResult,\n TargetConfiguration,\n} from '@nx/devkit';\nimport {\n createVisualizeRuntimeTarget,\n createValidateRuntimeArchitectureTarget,\n} from './runtime-targets';\nimport { BRANCH_IDENTITY_INPUTS } from './branch-identity-inputs';\nimport { ValidationTargets } from './validation-targets';\nimport { createDiGraphGenerateTarget } from './di-graph-targets';\n\n/**\n * Circular dependency checking options\n */\nexport interface CircularDepsOptions {\n enabled?: boolean;\n targetName?: string;\n excludePatterns?: string[];\n}\n\n/**\n * Validation options for architecture checks\n */\nexport interface ValidationOptions {\n noCycles?: boolean;\n architectureUnchanged?: boolean;\n validatePackageJson?: boolean;\n validateNewMethods?: boolean;\n validateModifiedMethods?: boolean;\n validateModifiedFiles?: boolean;\n validateVersionsLocked?: boolean;\n validateTsInSrc?: boolean;\n validateNxWiring?: boolean;\n runtimeArchitecture?: boolean;\n validateApiRelations?: boolean;\n validateApiLibTag?: boolean;\n diGraph?: boolean;\n newMethodsMaxLines?: number;\n modifiedAndNewMethodsMaxLines?: number;\n modifiedFilesMaxLines?: number;\n /**\n * Validation mode for method/file size limits:\n * - STRICT: All limits enforced, disable comments ignored\n * - NORMAL: Limits enforced, disable comments with dates work\n * - OFF: Skip size validations entirely (for fast iteration)\n */\n validationMode?: 'STRICT' | 'NORMAL' | 'OFF';\n}\n\n/**\n * Feature flags for workspace targets\n */\nexport interface FeatureOptions {\n generate?: boolean;\n visualize?: boolean;\n visualizeRuntime?: boolean;\n}\n\n/**\n * Workspace-level configuration options\n */\nexport interface WorkspaceOptions {\n enabled?: boolean;\n targetPrefix?: string;\n graphPath?: string;\n validations?: ValidationOptions;\n features?: FeatureOptions;\n}\n\n/**\n * Configuration for @webpieces/nx-webpieces-rules Nx plugin\n */\nexport interface ArchitecturePluginOptions {\n circularDeps?: CircularDepsOptions;\n workspace?: WorkspaceOptions;\n}\n\nconst DEFAULT_OPTIONS: Required<ArchitecturePluginOptions> = {\n circularDeps: {\n enabled: true,\n targetName: 'validate-no-file-import-cycles',\n excludePatterns: [],\n },\n workspace: {\n enabled: true,\n targetPrefix: 'arch:',\n graphPath: 'architecture/dependencies.json',\n validations: {\n noCycles: true,\n architectureUnchanged: true,\n validatePackageJson: true,\n validateNewMethods: true,\n validateModifiedMethods: true,\n validateModifiedFiles: true,\n validateVersionsLocked: true,\n validateTsInSrc: true,\n validateNxWiring: true,\n runtimeArchitecture: true,\n validateApiRelations: true,\n validateApiLibTag: true,\n diGraph: true,\n newMethodsMaxLines: 30,\n modifiedAndNewMethodsMaxLines: 80,\n modifiedFilesMaxLines: 900,\n validationMode: 'NORMAL',\n },\n features: {\n generate: true,\n visualize: true,\n visualizeRuntime: true,\n },\n },\n};\n\nfunction normalizeOptions(\n options: ArchitecturePluginOptions | undefined,\n): Required<ArchitecturePluginOptions> {\n const circularDeps = {\n ...DEFAULT_OPTIONS.circularDeps,\n ...options?.circularDeps,\n };\n\n const workspace = {\n ...DEFAULT_OPTIONS.workspace,\n ...options?.workspace,\n validations: {\n ...DEFAULT_OPTIONS.workspace.validations,\n ...options?.workspace?.validations,\n },\n features: {\n ...DEFAULT_OPTIONS.workspace.features,\n ...options?.workspace?.features,\n },\n };\n\n return {\n circularDeps,\n workspace,\n } as Required<ArchitecturePluginOptions>;\n}\n\nasync function createNodesFunction(\n projectFiles: readonly string[],\n options: ArchitecturePluginOptions | undefined,\n context: CreateNodesContextV2,\n): Promise<CreateNodesResultV2> {\n const opts = normalizeOptions(options);\n const results: CreateNodesResultV2 = [];\n\n // Add workspace-level architecture targets\n addArchitectureProject(results, projectFiles, opts, context);\n\n // Add per-project targets (circular-deps, ci, di-graph)\n addPerProjectTargets(results, projectFiles, opts, context);\n\n return results;\n}\n\nfunction addArchitectureProject(\n results: CreateNodesResultV2,\n projectFiles: readonly string[],\n opts: Required<ArchitecturePluginOptions>,\n context: CreateNodesContextV2,\n): void {\n if (!opts.workspace.enabled) return;\n\n const archDirPath = join(context.workspaceRoot, 'architecture');\n if (!existsSync(archDirPath)) return;\n\n const workspaceTargets = createWorkspaceTargetsWithoutPrefix(opts);\n if (Object.keys(workspaceTargets).length === 0) return;\n\n const result: CreateNodesResult = {\n projects: {\n architecture: {\n name: 'architecture',\n root: 'architecture',\n targets: workspaceTargets,\n },\n },\n };\n\n const firstProjectFile = projectFiles[0];\n if (firstProjectFile) {\n results.push([firstProjectFile, result] as const);\n }\n}\n\n\n// A project sits inside a NESTED git repo (e.g. a clone under repositories/) when any of its\n// ancestor dirs — up to but NOT including the workspace root — contains a `.git`. Such projects are\n// separate repos, not part of THIS workspace's graph, so they must not get inferred targets (that is\n// what drags foreign clones into `nx affected`). Same repo-boundary signal the AI guards use.\nexport function isInsideNestedGitRepo(workspaceRoot: string, projectRoot: string): boolean {\n let dir = projectRoot;\n while (dir && dir !== '.' && dir !== '/') {\n if (existsSync(join(workspaceRoot, dir, '.git'))) return true;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return false;\n}\n\nfunction addPerProjectTargets(\n results: CreateNodesResultV2,\n projectFiles: readonly string[],\n opts: Required<ArchitecturePluginOptions>,\n context: CreateNodesContextV2,\n): void {\n // Track processed project roots to avoid duplicates when both files exist\n const processedRoots = new Set<string>();\n\n for (const projectFile of projectFiles) {\n const isProjectJson = projectFile.endsWith('project.json');\n const isPackageJson = projectFile.endsWith('package.json');\n\n if (!isProjectJson && !isPackageJson) continue;\n\n const projectRoot = dirname(projectFile);\n\n // Skip root (workspace manifest, not a project)\n if (projectRoot === '.') continue;\n\n // Skip projects inside a nested git repo (vendored clones under repositories/): they are\n // separate repos and must not be swept into this workspace's `nx affected` graph.\n if (isInsideNestedGitRepo(context.workspaceRoot, projectRoot)) continue;\n\n // Skip if we've already processed this project root\n if (processedRoots.has(projectRoot)) continue;\n\n // For package.json, skip if project.json also exists in same directory\n // (prefer project.json - it will be processed separately)\n if (isPackageJson) {\n const projectJsonPath = join(context.workspaceRoot, projectRoot, 'project.json');\n if (existsSync(projectJsonPath)) continue;\n }\n\n processedRoots.add(projectRoot);\n\n const architectureEnabled =\n opts.workspace.enabled === true &&\n existsSync(join(context.workspaceRoot, 'architecture'));\n const targets = buildPerProjectTargets(\n isProjectJson,\n projectRoot,\n opts,\n architectureEnabled,\n );\n\n if (Object.keys(targets).length === 0) continue;\n\n const result: CreateNodesResult = {\n projects: {\n [projectRoot]: {\n targets,\n },\n },\n };\n\n results.push([projectFile, result] as const);\n }\n}\n\n/**\n * Build the target map for one project. Most targets are project.json-only\n * (package.json-only projects may not have TypeScript source); `ci` goes on all.\n */\nfunction buildPerProjectTargets(\n isProjectJson: boolean,\n projectRoot: string,\n opts: Required<ArchitecturePluginOptions>,\n architectureEnabled: boolean,\n): Record<string, TargetConfiguration> {\n const targets: Record<string, TargetConfiguration> = {};\n\n // Per-project validation gates that `ci` must depend on. Collected as they are added\n // so `ci` references only gates that actually exist on THIS project (a package.json-only\n // project has none).\n const validationTargets: string[] = [];\n\n // Add circular-deps target ONLY for project.json projects\n if (isProjectJson && opts.circularDeps.enabled) {\n if (!isExcluded(projectRoot, opts.circularDeps.excludePatterns!)) {\n const targetName = opts.circularDeps.targetName!;\n targets[targetName] = createCircularDepsTarget(projectRoot, targetName);\n validationTargets.push(targetName);\n }\n }\n\n // Per-project DI design DAG: regenerate design.json/design.md/design.html on every build.\n //\n // `di-graph-generate` is itself pushed onto validationTargets so `ci` still RUNS it — it used to ride\n // in only as the `dependsOn` of the deleted `validate-di-graph-unchanged` gate. There is no staleness\n // gate here any more: \"the regenerated design files are committed\" is now one repo-wide check in\n // `wp-review-upsert-pr` (see di-graph-targets.ts for why the per-project gate could not work).\n if (isProjectJson && opts.workspace.validations!.diGraph) {\n targets['di-graph-generate'] = createDiGraphGenerateTarget();\n validationTargets.push('di-graph-generate');\n }\n\n // Add ci target to ALL projects (both project.json and package.json). ci aggregates\n // lint + build + test + the validation gates that formerly rode on the compile\n // executor's targetDefaults, so a bare `build` stays a fast compile-only step.\n targets['ci'] = createCiTarget(validationTargets, architectureEnabled);\n\n return targets;\n}\n\n/**\n * Nx V2 Inference Plugin\n * Matches project.json and package.json files to create targets\n */\nexport const createNodesV2: CreateNodesV2<ArchitecturePluginOptions> = [\n // Pattern to match project.json and package.json files\n '**/{project,package}.json',\n\n // Inference function\n createNodesFunction,\n];\n\n/**\n * Build list of enabled validation target names for validate-complete dependency chain\n */\nfunction buildValidationTargetsList(\n validations: Required<ArchitecturePluginOptions>['workspace']['validations'],\n): string[] {\n const targets: string[] = [];\n if (validations!.noCycles) targets.push('validate-no-architecture-cycles');\n if (validations!.architectureUnchanged) targets.push('validate-architecture-unchanged');\n if (validations!.validatePackageJson) targets.push('validate-packagejson');\n // Use combined validate-code instead of 3 separate targets\n if (\n validations!.validateNewMethods ||\n validations!.validateModifiedMethods ||\n validations!.validateModifiedFiles\n ) {\n targets.push('validate-code');\n }\n if (validations!.validateVersionsLocked) targets.push('validate-versions-locked');\n if (validations!.validateTsInSrc) targets.push('validate-ts-in-src');\n if (validations!.validateNxWiring) targets.push('validate-nx-wiring');\n if (validations!.runtimeArchitecture) targets.push('validate-runtime-architecture');\n if (validations!.validateApiRelations) targets.push('validate-api-relations');\n if (validations!.validateApiLibTag) targets.push('validate-api-lib-tag');\n return targets;\n}\n\n/**\n * Create workspace-level architecture validation targets WITHOUT prefix\n * Used for virtual 'architecture' project\n */\nfunction createWorkspaceTargetsWithoutPrefix(\n opts: Required<ArchitecturePluginOptions>,\n): Record<string, TargetConfiguration> {\n const targets: Record<string, TargetConfiguration> = {};\n const graphPath = opts.workspace.graphPath!;\n const validations = opts.workspace.validations!;\n // One ValidationTargets instance, injected below to build each target config.\n const targetFactory = new ValidationTargets();\n\n // Add help target (always available)\n targets['help'] = createHelpTarget();\n\n if (opts.workspace.features!.generate) {\n targets['generate'] = createGenerateTarget(graphPath);\n }\n if (opts.workspace.features!.visualize) {\n targets['visualize'] = createVisualizeTargetWithoutPrefix(graphPath);\n }\n if (opts.workspace.features!.visualizeRuntime) {\n targets['visualize-runtime'] = createVisualizeRuntimeTarget();\n }\n if (validations.noCycles) {\n targets['validate-no-architecture-cycles'] = targetFactory.noCycles();\n }\n if (validations.architectureUnchanged) {\n targets['validate-architecture-unchanged'] = createValidateUnchangedTarget(graphPath);\n }\n if (validations.validatePackageJson) {\n targets['validate-packagejson'] = targetFactory.packageJson();\n }\n // Always available (cheap; success when a repo has no checklists). Kept out of the validate-complete /\n // ci aggregate so it does not change existing gate behavior — consumers point a required check at it.\n targets['validate-checklist-docs'] = targetFactory.checklistDocs();\n // Use combined validate-code instead of 3 separate targets\n // Options come from webpieces.config.json at the workspace root\n // (loaded via @webpieces/rules-config; same source of truth as @webpieces/ai-hook-rules)\n if (\n validations.validateNewMethods ||\n validations.validateModifiedMethods ||\n validations.validateModifiedFiles\n ) {\n targets['validate-code'] = targetFactory.code();\n }\n if (validations.validateVersionsLocked) {\n targets['validate-versions-locked'] = targetFactory.versionsLocked();\n }\n if (validations.validateTsInSrc) {\n targets['validate-ts-in-src'] = targetFactory.tsInSrc();\n }\n if (validations.validateNxWiring) {\n targets['validate-nx-wiring'] = targetFactory.nxWiring();\n }\n if (validations.runtimeArchitecture) {\n targets['validate-runtime-architecture'] = createValidateRuntimeArchitectureTarget();\n }\n if (validations.validateApiRelations) {\n targets['validate-api-relations'] = targetFactory.apiRelations();\n }\n if (validations.validateApiLibTag) {\n targets['validate-api-lib-tag'] = targetFactory.apiLibTag();\n }\n\n // Add validate-complete target that runs all enabled validations\n const validationTargets = buildValidationTargetsList(validations);\n if (validationTargets.length > 0) {\n targets['validate-complete'] = createValidateCompleteTarget(validationTargets);\n }\n\n return targets;\n}\n\nfunction createGenerateTarget(graphPath: string): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:generate',\n cache: false,\n outputs: [\n '{workspaceRoot}/architecture/dependencies.json',\n '{workspaceRoot}/architecture/dependencies.html',\n '{workspaceRoot}/architecture/apis',\n '{workspaceRoot}/architecture/runtime-dependencies.json',\n ],\n options: { graphPath },\n metadata: {\n technologies: ['nx'],\n description:\n 'Generate the architecture dependency graph (+ clickable dependencies.html) and the runtime microservice graph',\n },\n };\n}\n\nfunction createVisualizeTargetWithoutPrefix(graphPath: string): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:visualize',\n dependsOn: ['generate'],\n options: { graphPath },\n metadata: {\n technologies: ['nx'],\n description: 'Generate visual representations of the architecture graph',\n },\n };\n}\n\nfunction createValidateUnchangedTarget(graphPath: string): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:validate-architecture-unchanged',\n cache: false,\n inputs: ['default', '{workspaceRoot}/architecture/dependencies.json'],\n options: { graphPath },\n metadata: {\n technologies: ['nx'],\n description: 'Validate the architecture matches the saved blessed graph',\n },\n };\n}\n\nfunction createValidateNewMethodsTarget(\n maxLines: number,\n mode: 'STRICT' | 'NORMAL' | 'OFF',\n): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:validate-new-methods',\n cache: false, // Don't cache - depends on git state\n inputs: ['default'],\n options: { max: maxLines, mode },\n metadata: {\n technologies: ['nx'],\n description: `Validate new methods do not exceed ${maxLines} lines (only runs in affected mode)`,\n },\n };\n}\n\nfunction createValidateModifiedMethodsTarget(\n maxLines: number,\n mode: 'STRICT' | 'NORMAL' | 'OFF',\n): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:validate-modified-methods',\n cache: false, // Don't cache - depends on git state\n inputs: ['default'],\n options: { max: maxLines, mode },\n metadata: {\n technologies: ['nx'],\n description: `Validate new and modified methods do not exceed ${maxLines} lines (encourages gradual cleanup)`,\n },\n };\n}\n\nfunction createValidateModifiedFilesTarget(\n maxLines: number,\n mode: 'STRICT' | 'NORMAL' | 'OFF',\n): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:validate-modified-files',\n cache: false, // Don't cache - depends on git state\n inputs: ['default'],\n options: { max: maxLines, mode },\n metadata: {\n technologies: ['nx'],\n description: `Validate modified files do not exceed ${maxLines} lines (encourages keeping files small)`,\n },\n };\n}\n\nfunction createValidateCompleteTarget(validationTargets: string[]): TargetConfiguration {\n return {\n executor: 'nx:noop',\n cache: true,\n dependsOn: validationTargets,\n metadata: {\n technologies: ['nx'],\n description: 'Run all architecture validations (cycles, unchanged, package.json, code rules)',\n },\n };\n}\n\n/**\n * Create per-project ci target - Gradle-style composite target\n * Composite CI target: runs lint, build, test, and every validation gate.\n *\n * Validation (architecture graph completeness, per-project file-import cycles, DI-graph\n * unchanged) lives HERE, not on the build/compile target. That keeps `nx build` a fast\n * compile-only step for local iteration while `nx ci` is the full gate the PR check runs.\n *\n * The per-project gates are passed in because they exist only on project.json projects;\n * `architecture:validate-complete` is a cross-project dep added only when the workspace\n * `architecture` project exists.\n *\n * NOTE: Type checking is done by the build target (@nx/js:tsc) during compilation.\n */\n// webpieces-disable no-function-outside-class -- Nx inference plugin: createNodes invokes these as module-scope target factories; the entire plugin is intentionally functional (matching the surrounding 18 factories), a DI class is not how the Nx plugin API is called.\nexport function createCiTarget(\n perProjectValidation: string[],\n architectureEnabled: boolean,\n): TargetConfiguration {\n const dependsOn: string[] = ['lint', 'build', 'test', ...perProjectValidation];\n if (architectureEnabled) {\n dependsOn.push('architecture:validate-complete');\n }\n return {\n executor: 'nx:noop',\n cache: true,\n // The branch is part of what `ci` asserts, because the rules it aggregates can be switched off by\n // turnOffRuleWhileOnBranch. Its own cache entry is a noop, but a `ci` hash that ignores the branch\n // is a green claim about a branch that was never checked. See branch-identity-inputs.ts.\n inputs: ['default', ...BRANCH_IDENTITY_INPUTS],\n dependsOn,\n metadata: {\n technologies: ['nx'],\n description:\n 'Run all CI checks: lint, build, test, and validation (Gradle-style composite target)',\n },\n };\n}\n\nfunction createHelpTarget(): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:help',\n cache: false, // Never cache - always show help output\n metadata: {\n technologies: ['nx'],\n description: 'Display help for @webpieces/nx-webpieces-rules commands and targets',\n },\n };\n}\n\n/**\n * Create per-project circular dependency checking target.\n *\n * Uses the `validate-no-file-import-cycles` executor (which bundles madge as a\n * dependency) rather than a runtime `npx madge` fetch. The executor reads\n * webpieces.config.json so the gate can be turned on/off (`mode`) and\n * time-boxed (`turnOffRuleUntilEpoch`) like every other webpieces rule.\n *\n * Note `projectRoot` is intentionally unused now — the executor derives the\n * project root from the Nx context — but the param is kept for call-site\n * symmetry with the rest of the per-project target factories.\n */\nfunction createCircularDepsTarget(_projectRoot: string, _targetName: string): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:validate-no-file-import-cycles',\n cache: true,\n // BRANCH_IDENTITY_INPUTS: this gate honors turnOffRuleWhileOnBranch, and it is CACHED, so without\n // the branch in its hash a hatched green replays onto branches the hatch never covered.\n inputs: ['default', ...BRANCH_IDENTITY_INPUTS],\n outputs: [] as string[],\n metadata: {\n technologies: ['madge'],\n description: 'Check for circular file-import dependencies using madge',\n },\n };\n}\n\n/**\n * Check if a project should be excluded based on patterns\n */\nfunction isExcluded(projectRoot: string, excludePatterns: string[]): boolean {\n if (excludePatterns.length === 0) {\n return false;\n }\n\n // Simple glob matching (could be enhanced with minimatch if needed)\n return excludePatterns.some((pattern) => {\n // Convert glob pattern to regex\n const regexPattern = pattern\n .replace(/\\*\\*/g, '.*') // ** matches any path\n .replace(/\\*/g, '[^/]*'); // * matches any string except /\n\n const regex = new RegExp(`^${regexPattern}$`);\n return regex.test(projectRoot);\n });\n}\n\n/**\n * Export plugin as default for Nx\n */\nexport default { createNodesV2 };\n"]}
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../../../packages/tooling/nx-webpieces-rules/src/plugin.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Unified Nx Inference Plugin for @webpieces/nx-webpieces-rules\n *\n * This plugin automatically creates targets for:\n * 1. Workspace-level architecture validation (generate, visualize, validate-*)\n * 2. Per-project circular dependency checking\n * 3. Per-project API documents, opted into with a TAG: `generate:openapi` infers `openapi-generate`,\n * `generate:docs-site` infers `openapi-generate` + `docs-generate` (see generate-targets.ts)\n *\n * Install with: nx add @webpieces/nx-webpieces-rules\n *\n * Usage:\n * Add to nx.json plugins array:\n * {\n * \"plugins\": [\"@webpieces/nx-webpieces-rules\"]\n * }\n *\n * Then all targets appear automatically without manual project.json configuration.\n */\n\nimport { dirname, join } from 'path';\nimport { existsSync } from 'fs';\nimport type {\n CreateNodesV2,\n CreateNodesContextV2,\n CreateNodesResultV2,\n CreateNodesResult,\n TargetConfiguration,\n} from '@nx/devkit';\nimport {\n createVisualizeRuntimeTarget,\n createValidateRuntimeArchitectureTarget,\n} from './runtime-targets';\nimport { BRANCH_IDENTITY_INPUTS } from './branch-identity-inputs';\nimport { ValidationTargets } from './validation-targets';\nimport { createDiGraphGenerateTarget } from './di-graph-targets';\nimport { GenerateTargets, RawProjectJson, RawProjectJsonReader } from './generate-targets';\n\n/**\n * Circular dependency checking options\n */\nexport interface CircularDepsOptions {\n enabled?: boolean;\n targetName?: string;\n excludePatterns?: string[];\n}\n\n/**\n * Validation options for architecture checks\n */\nexport interface ValidationOptions {\n noCycles?: boolean;\n architectureUnchanged?: boolean;\n validatePackageJson?: boolean;\n validateNewMethods?: boolean;\n validateModifiedMethods?: boolean;\n validateModifiedFiles?: boolean;\n validateVersionsLocked?: boolean;\n validateTsInSrc?: boolean;\n validateNxWiring?: boolean;\n runtimeArchitecture?: boolean;\n validateApiRelations?: boolean;\n validateApiLibTag?: boolean;\n diGraph?: boolean;\n newMethodsMaxLines?: number;\n modifiedAndNewMethodsMaxLines?: number;\n modifiedFilesMaxLines?: number;\n /**\n * Validation mode for method/file size limits:\n * - STRICT: All limits enforced, disable comments ignored\n * - NORMAL: Limits enforced, disable comments with dates work\n * - OFF: Skip size validations entirely (for fast iteration)\n */\n validationMode?: 'STRICT' | 'NORMAL' | 'OFF';\n}\n\n/**\n * Feature flags for workspace targets\n */\nexport interface FeatureOptions {\n generate?: boolean;\n visualize?: boolean;\n visualizeRuntime?: boolean;\n}\n\n/**\n * Workspace-level configuration options\n */\nexport interface WorkspaceOptions {\n enabled?: boolean;\n targetPrefix?: string;\n graphPath?: string;\n validations?: ValidationOptions;\n features?: FeatureOptions;\n}\n\n/**\n * Configuration for @webpieces/nx-webpieces-rules Nx plugin\n */\nexport interface ArchitecturePluginOptions {\n circularDeps?: CircularDepsOptions;\n workspace?: WorkspaceOptions;\n}\n\nconst DEFAULT_OPTIONS: Required<ArchitecturePluginOptions> = {\n circularDeps: {\n enabled: true,\n targetName: 'validate-no-file-import-cycles',\n excludePatterns: [],\n },\n workspace: {\n enabled: true,\n targetPrefix: 'arch:',\n graphPath: 'architecture/dependencies.json',\n validations: {\n noCycles: true,\n architectureUnchanged: true,\n validatePackageJson: true,\n validateNewMethods: true,\n validateModifiedMethods: true,\n validateModifiedFiles: true,\n validateVersionsLocked: true,\n validateTsInSrc: true,\n validateNxWiring: true,\n runtimeArchitecture: true,\n validateApiRelations: true,\n validateApiLibTag: true,\n diGraph: true,\n newMethodsMaxLines: 30,\n modifiedAndNewMethodsMaxLines: 80,\n modifiedFilesMaxLines: 900,\n validationMode: 'NORMAL',\n },\n features: {\n generate: true,\n visualize: true,\n visualizeRuntime: true,\n },\n },\n};\n\nfunction normalizeOptions(\n options: ArchitecturePluginOptions | undefined,\n): Required<ArchitecturePluginOptions> {\n const circularDeps = {\n ...DEFAULT_OPTIONS.circularDeps,\n ...options?.circularDeps,\n };\n\n const workspace = {\n ...DEFAULT_OPTIONS.workspace,\n ...options?.workspace,\n validations: {\n ...DEFAULT_OPTIONS.workspace.validations,\n ...options?.workspace?.validations,\n },\n features: {\n ...DEFAULT_OPTIONS.workspace.features,\n ...options?.workspace?.features,\n },\n };\n\n return {\n circularDeps,\n workspace,\n } as Required<ArchitecturePluginOptions>;\n}\n\nasync function createNodesFunction(\n projectFiles: readonly string[],\n options: ArchitecturePluginOptions | undefined,\n context: CreateNodesContextV2,\n): Promise<CreateNodesResultV2> {\n const opts = normalizeOptions(options);\n const results: CreateNodesResultV2 = [];\n\n // Add workspace-level architecture targets\n addArchitectureProject(results, projectFiles, opts, context);\n\n // Add per-project targets (circular-deps, ci, di-graph)\n addPerProjectTargets(results, projectFiles, opts, context);\n\n return results;\n}\n\nfunction addArchitectureProject(\n results: CreateNodesResultV2,\n projectFiles: readonly string[],\n opts: Required<ArchitecturePluginOptions>,\n context: CreateNodesContextV2,\n): void {\n if (!opts.workspace.enabled) return;\n\n const archDirPath = join(context.workspaceRoot, 'architecture');\n if (!existsSync(archDirPath)) return;\n\n const workspaceTargets = createWorkspaceTargetsWithoutPrefix(opts);\n if (Object.keys(workspaceTargets).length === 0) return;\n\n const result: CreateNodesResult = {\n projects: {\n architecture: {\n name: 'architecture',\n root: 'architecture',\n targets: workspaceTargets,\n },\n },\n };\n\n const firstProjectFile = projectFiles[0];\n if (firstProjectFile) {\n results.push([firstProjectFile, result] as const);\n }\n}\n\n\n// A project sits inside a NESTED git repo (e.g. a clone under repositories/) when any of its\n// ancestor dirs — up to but NOT including the workspace root — contains a `.git`. Such projects are\n// separate repos, not part of THIS workspace's graph, so they must not get inferred targets (that is\n// what drags foreign clones into `nx affected`). Same repo-boundary signal the AI guards use.\nexport function isInsideNestedGitRepo(workspaceRoot: string, projectRoot: string): boolean {\n let dir = projectRoot;\n while (dir && dir !== '.' && dir !== '/') {\n if (existsSync(join(workspaceRoot, dir, '.git'))) return true;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return false;\n}\n\nfunction addPerProjectTargets(\n results: CreateNodesResultV2,\n projectFiles: readonly string[],\n opts: Required<ArchitecturePluginOptions>,\n context: CreateNodesContextV2,\n): void {\n // Track processed project roots to avoid duplicates when both files exist\n const processedRoots = new Set<string>();\n\n for (const projectFile of projectFiles) {\n const isProjectJson = projectFile.endsWith('project.json');\n const isPackageJson = projectFile.endsWith('package.json');\n\n if (!isProjectJson && !isPackageJson) continue;\n\n const projectRoot = dirname(projectFile);\n\n // Skip root (workspace manifest, not a project)\n if (projectRoot === '.') continue;\n\n // Skip projects inside a nested git repo (vendored clones under repositories/): they are\n // separate repos and must not be swept into this workspace's `nx affected` graph.\n if (isInsideNestedGitRepo(context.workspaceRoot, projectRoot)) continue;\n\n // Skip if we've already processed this project root\n if (processedRoots.has(projectRoot)) continue;\n\n // For package.json, skip if project.json also exists in same directory\n // (prefer project.json - it will be processed separately)\n if (isPackageJson) {\n const projectJsonPath = join(context.workspaceRoot, projectRoot, 'project.json');\n if (existsSync(projectJsonPath)) continue;\n }\n\n processedRoots.add(projectRoot);\n\n const architectureEnabled =\n opts.workspace.enabled === true &&\n existsSync(join(context.workspaceRoot, 'architecture'));\n const targets = buildPerProjectTargets(\n isProjectJson,\n projectRoot,\n opts,\n architectureEnabled,\n isProjectJson ? new RawProjectJsonReader().read(context.workspaceRoot, projectFile, projectRoot) : undefined,\n );\n\n if (Object.keys(targets).length === 0) continue;\n\n const result: CreateNodesResult = {\n projects: {\n [projectRoot]: {\n targets,\n },\n },\n };\n\n results.push([projectFile, result] as const);\n }\n}\n\n/**\n * Build the target map for one project. Most targets are project.json-only\n * (package.json-only projects may not have TypeScript source); `ci` goes on all.\n */\nfunction buildPerProjectTargets(\n isProjectJson: boolean,\n projectRoot: string,\n opts: Required<ArchitecturePluginOptions>,\n architectureEnabled: boolean,\n rawProject: RawProjectJson | undefined,\n): Record<string, TargetConfiguration> {\n const targets: Record<string, TargetConfiguration> = {};\n\n // Per-project validation gates that `ci` must depend on. Collected as they are added\n // so `ci` references only gates that actually exist on THIS project (a package.json-only\n // project has none).\n const validationTargets: string[] = [];\n\n // Add circular-deps target ONLY for project.json projects\n if (isProjectJson && opts.circularDeps.enabled) {\n if (!isExcluded(projectRoot, opts.circularDeps.excludePatterns!)) {\n const targetName = opts.circularDeps.targetName!;\n targets[targetName] = createCircularDepsTarget(projectRoot, targetName);\n validationTargets.push(targetName);\n }\n }\n\n // Per-project DI design DAG: regenerate design.json/design.md/design.html on every build.\n //\n // `di-graph-generate` is itself pushed onto validationTargets so `ci` still RUNS it — it used to ride\n // in only as the `dependsOn` of the deleted `validate-di-graph-unchanged` gate. There is no staleness\n // gate here any more: \"the regenerated design files are committed\" is now one repo-wide check in\n // `wp-review-upsert-pr` (see di-graph-targets.ts for why the per-project gate could not work).\n if (isProjectJson && opts.workspace.validations!.diGraph) {\n targets['di-graph-generate'] = createDiGraphGenerateTarget();\n validationTargets.push('di-graph-generate');\n }\n\n // API documents, opted into with a TAG (generate:openapi / generate:docs-site). An untagged project\n // costs this one in-memory tag check. They ride ci like every other build step — generation is\n // ordinary BUILD work, not a side channel (#1021).\n if (rawProject !== undefined) {\n const generated = new GenerateTargets(projectRoot, rawProject).infer();\n for (const [name, target] of Object.entries(generated)) {\n targets[name] = target;\n validationTargets.push(name);\n }\n }\n\n // Add ci target to ALL projects (both project.json and package.json). ci aggregates\n // lint + build + test + the validation gates that formerly rode on the compile\n // executor's targetDefaults, so a bare `build` stays a fast compile-only step.\n targets['ci'] = createCiTarget(validationTargets, architectureEnabled);\n\n return targets;\n}\n\n/**\n * Nx V2 Inference Plugin\n * Matches project.json and package.json files to create targets\n */\nexport const createNodesV2: CreateNodesV2<ArchitecturePluginOptions> = [\n // Pattern to match project.json and package.json files\n '**/{project,package}.json',\n\n // Inference function\n createNodesFunction,\n];\n\n/**\n * Build list of enabled validation target names for validate-complete dependency chain\n */\nfunction buildValidationTargetsList(\n validations: Required<ArchitecturePluginOptions>['workspace']['validations'],\n): string[] {\n const targets: string[] = [];\n if (validations!.noCycles) targets.push('validate-no-architecture-cycles');\n if (validations!.architectureUnchanged) targets.push('validate-architecture-unchanged');\n if (validations!.validatePackageJson) targets.push('validate-packagejson');\n // Use combined validate-code instead of 3 separate targets\n if (\n validations!.validateNewMethods ||\n validations!.validateModifiedMethods ||\n validations!.validateModifiedFiles\n ) {\n targets.push('validate-code');\n }\n if (validations!.validateVersionsLocked) targets.push('validate-versions-locked');\n if (validations!.validateTsInSrc) targets.push('validate-ts-in-src');\n if (validations!.validateNxWiring) targets.push('validate-nx-wiring');\n if (validations!.runtimeArchitecture) targets.push('validate-runtime-architecture');\n if (validations!.validateApiRelations) targets.push('validate-api-relations');\n if (validations!.validateApiLibTag) targets.push('validate-api-lib-tag');\n return targets;\n}\n\n/**\n * Create workspace-level architecture validation targets WITHOUT prefix\n * Used for virtual 'architecture' project\n */\nfunction createWorkspaceTargetsWithoutPrefix(\n opts: Required<ArchitecturePluginOptions>,\n): Record<string, TargetConfiguration> {\n const targets: Record<string, TargetConfiguration> = {};\n const graphPath = opts.workspace.graphPath!;\n const validations = opts.workspace.validations!;\n // One ValidationTargets instance, injected below to build each target config.\n const targetFactory = new ValidationTargets();\n\n // Add help target (always available)\n targets['help'] = createHelpTarget();\n\n if (opts.workspace.features!.generate) {\n targets['generate'] = createGenerateTarget(graphPath);\n }\n if (opts.workspace.features!.visualize) {\n targets['visualize'] = createVisualizeTargetWithoutPrefix(graphPath);\n }\n if (opts.workspace.features!.visualizeRuntime) {\n targets['visualize-runtime'] = createVisualizeRuntimeTarget();\n }\n if (validations.noCycles) {\n targets['validate-no-architecture-cycles'] = targetFactory.noCycles();\n }\n if (validations.architectureUnchanged) {\n targets['validate-architecture-unchanged'] = createValidateUnchangedTarget(graphPath);\n }\n if (validations.validatePackageJson) {\n targets['validate-packagejson'] = targetFactory.packageJson();\n }\n // Always available (cheap; success when a repo has no checklists). Kept out of the validate-complete /\n // ci aggregate so it does not change existing gate behavior — consumers point a required check at it.\n targets['validate-checklist-docs'] = targetFactory.checklistDocs();\n // Use combined validate-code instead of 3 separate targets\n // Options come from webpieces.config.json at the workspace root\n // (loaded via @webpieces/rules-config; same source of truth as @webpieces/ai-hook-rules)\n if (\n validations.validateNewMethods ||\n validations.validateModifiedMethods ||\n validations.validateModifiedFiles\n ) {\n targets['validate-code'] = targetFactory.code();\n }\n if (validations.validateVersionsLocked) {\n targets['validate-versions-locked'] = targetFactory.versionsLocked();\n }\n if (validations.validateTsInSrc) {\n targets['validate-ts-in-src'] = targetFactory.tsInSrc();\n }\n if (validations.validateNxWiring) {\n targets['validate-nx-wiring'] = targetFactory.nxWiring();\n }\n if (validations.runtimeArchitecture) {\n targets['validate-runtime-architecture'] = createValidateRuntimeArchitectureTarget();\n }\n if (validations.validateApiRelations) {\n targets['validate-api-relations'] = targetFactory.apiRelations();\n }\n if (validations.validateApiLibTag) {\n targets['validate-api-lib-tag'] = targetFactory.apiLibTag();\n }\n\n // Add validate-complete target that runs all enabled validations\n const validationTargets = buildValidationTargetsList(validations);\n if (validationTargets.length > 0) {\n targets['validate-complete'] = createValidateCompleteTarget(validationTargets);\n }\n\n return targets;\n}\n\nfunction createGenerateTarget(graphPath: string): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:generate',\n cache: false,\n outputs: [\n '{workspaceRoot}/architecture/dependencies.json',\n '{workspaceRoot}/architecture/dependencies.html',\n '{workspaceRoot}/architecture/apis',\n '{workspaceRoot}/architecture/runtime-dependencies.json',\n ],\n options: { graphPath },\n metadata: {\n technologies: ['nx'],\n description:\n 'Generate the architecture dependency graph (+ clickable dependencies.html) and the runtime microservice graph',\n },\n };\n}\n\nfunction createVisualizeTargetWithoutPrefix(graphPath: string): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:visualize',\n dependsOn: ['generate'],\n options: { graphPath },\n metadata: {\n technologies: ['nx'],\n description: 'Generate visual representations of the architecture graph',\n },\n };\n}\n\nfunction createValidateUnchangedTarget(graphPath: string): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:validate-architecture-unchanged',\n cache: false,\n inputs: ['default', '{workspaceRoot}/architecture/dependencies.json'],\n options: { graphPath },\n metadata: {\n technologies: ['nx'],\n description: 'Validate the architecture matches the saved blessed graph',\n },\n };\n}\n\nfunction createValidateNewMethodsTarget(\n maxLines: number,\n mode: 'STRICT' | 'NORMAL' | 'OFF',\n): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:validate-new-methods',\n cache: false, // Don't cache - depends on git state\n inputs: ['default'],\n options: { max: maxLines, mode },\n metadata: {\n technologies: ['nx'],\n description: `Validate new methods do not exceed ${maxLines} lines (only runs in affected mode)`,\n },\n };\n}\n\nfunction createValidateModifiedMethodsTarget(\n maxLines: number,\n mode: 'STRICT' | 'NORMAL' | 'OFF',\n): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:validate-modified-methods',\n cache: false, // Don't cache - depends on git state\n inputs: ['default'],\n options: { max: maxLines, mode },\n metadata: {\n technologies: ['nx'],\n description: `Validate new and modified methods do not exceed ${maxLines} lines (encourages gradual cleanup)`,\n },\n };\n}\n\nfunction createValidateModifiedFilesTarget(\n maxLines: number,\n mode: 'STRICT' | 'NORMAL' | 'OFF',\n): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:validate-modified-files',\n cache: false, // Don't cache - depends on git state\n inputs: ['default'],\n options: { max: maxLines, mode },\n metadata: {\n technologies: ['nx'],\n description: `Validate modified files do not exceed ${maxLines} lines (encourages keeping files small)`,\n },\n };\n}\n\nfunction createValidateCompleteTarget(validationTargets: string[]): TargetConfiguration {\n return {\n executor: 'nx:noop',\n cache: true,\n dependsOn: validationTargets,\n metadata: {\n technologies: ['nx'],\n description: 'Run all architecture validations (cycles, unchanged, package.json, code rules)',\n },\n };\n}\n\n/**\n * Create per-project ci target - Gradle-style composite target\n * Composite CI target: runs lint, build, test, and every validation gate.\n *\n * Validation (architecture graph completeness, per-project file-import cycles, DI-graph\n * unchanged) lives HERE, not on the build/compile target. That keeps `nx build` a fast\n * compile-only step for local iteration while `nx ci` is the full gate the PR check runs.\n *\n * The per-project gates are passed in because they exist only on project.json projects;\n * `architecture:validate-complete` is a cross-project dep added only when the workspace\n * `architecture` project exists.\n *\n * NOTE: Type checking is done by the build target (@nx/js:tsc) during compilation.\n */\n// webpieces-disable no-function-outside-class -- Nx inference plugin: createNodes invokes these as module-scope target factories; the entire plugin is intentionally functional (matching the surrounding 18 factories), a DI class is not how the Nx plugin API is called.\nexport function createCiTarget(\n perProjectValidation: string[],\n architectureEnabled: boolean,\n): TargetConfiguration {\n const dependsOn: string[] = ['lint', 'build', 'test', ...perProjectValidation];\n if (architectureEnabled) {\n dependsOn.push('architecture:validate-complete');\n }\n return {\n executor: 'nx:noop',\n cache: true,\n // The branch is part of what `ci` asserts, because the rules it aggregates can be switched off by\n // turnOffRuleWhileOnBranch. Its own cache entry is a noop, but a `ci` hash that ignores the branch\n // is a green claim about a branch that was never checked. See branch-identity-inputs.ts.\n inputs: ['default', ...BRANCH_IDENTITY_INPUTS],\n dependsOn,\n metadata: {\n technologies: ['nx'],\n description:\n 'Run all CI checks: lint, build, test, and validation (Gradle-style composite target)',\n },\n };\n}\n\nfunction createHelpTarget(): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:help',\n cache: false, // Never cache - always show help output\n metadata: {\n technologies: ['nx'],\n description: 'Display help for @webpieces/nx-webpieces-rules commands and targets',\n },\n };\n}\n\n/**\n * Create per-project circular dependency checking target.\n *\n * Uses the `validate-no-file-import-cycles` executor (which bundles madge as a\n * dependency) rather than a runtime `npx madge` fetch. The executor reads\n * webpieces.config.json so the gate can be turned on/off (`mode`) and\n * time-boxed (`turnOffRuleUntilEpoch`) like every other webpieces rule.\n *\n * Note `projectRoot` is intentionally unused now — the executor derives the\n * project root from the Nx context — but the param is kept for call-site\n * symmetry with the rest of the per-project target factories.\n */\nfunction createCircularDepsTarget(_projectRoot: string, _targetName: string): TargetConfiguration {\n return {\n executor: '@webpieces/nx-webpieces-rules:validate-no-file-import-cycles',\n cache: true,\n // BRANCH_IDENTITY_INPUTS: this gate honors turnOffRuleWhileOnBranch, and it is CACHED, so without\n // the branch in its hash a hatched green replays onto branches the hatch never covered.\n inputs: ['default', ...BRANCH_IDENTITY_INPUTS],\n outputs: [] as string[],\n metadata: {\n technologies: ['madge'],\n description: 'Check for circular file-import dependencies using madge',\n },\n };\n}\n\n/**\n * Check if a project should be excluded based on patterns\n */\nfunction isExcluded(projectRoot: string, excludePatterns: string[]): boolean {\n if (excludePatterns.length === 0) {\n return false;\n }\n\n // Simple glob matching (could be enhanced with minimatch if needed)\n return excludePatterns.some((pattern) => {\n // Convert glob pattern to regex\n const regexPattern = pattern\n .replace(/\\*\\*/g, '.*') // ** matches any path\n .replace(/\\*/g, '[^/]*'); // * matches any string except /\n\n const regex = new RegExp(`^${regexPattern}$`);\n return regex.test(projectRoot);\n });\n}\n\n/**\n * Export plugin as default for Nx\n */\nexport default { createNodesV2 };\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"generator-target.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/generated-docs/generator-target.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The shared half of the `openapi-generate` and `docs-generate` executors: WHERE a generated document\n * goes, and the proof that the target is wired so that nx both orders and caches it correctly.\n *\n * Both halves read the project's own declarations and never supply a value of their own:\n *\n * - the output directory is the project's `build` target's `options.outputPath` — the directory tsc\n * writes and the package is packed from, so the documents ship INSIDE the published package. It is\n * ASKED of nx, never assumed: this repo builds into a workspace-root `dist/apps/...`, another\n * consumer builds into a project-local `<project>/dist`, and hardcoding either one generates the\n * document somewhere the package is not packed from;\n * - the ordering and the cache are the target's own `dependsOn` and `outputs`, which the executor\n * checks rather than trusts, because both failures are silent: a missing `dependsOn: [\"build\"]`\n * lets tsc's clean of `outputPath` race the write (the document vanishes and a dependent test dies on\n * ENOENT, intermittently, only in CI), and `outputs` that miss a written file make every cache hit\n * restore a package without that file.\n */\n\nimport type { ExecutorContext, TargetConfiguration, TargetDependencyConfig } from '@nx/devkit';\nimport { Option, RuleFailError, matchesAnyGlob } from '@webpieces/rules-config';\nimport * as fs from 'fs';\nimport * as path from 'path';\n\n/** What `dependsOn` may name: a sibling target by name, or nx's object form of the same. */\ntype DependsOnEntry = string | TargetDependencyConfig;\n\nexport class GeneratorTarget {\n constructor(\n /** The executor's name, which is what every refusal is reported under. */\n readonly ruleName: string,\n readonly workspaceRoot: string,\n readonly projectName: string,\n /** Workspace-relative. */\n readonly projectRoot: string,\n readonly targetName: string,\n readonly target: TargetConfiguration,\n readonly build: TargetConfiguration | undefined,\n ) {}\n\n // webpieces-disable no-function-outside-class -- static factory of this class\n static of(ruleName: string, context: ExecutorContext): GeneratorTarget {\n const projectName = context.projectName ?? '';\n const project = context.projectsConfigurations?.projects[projectName];\n const targetName = context.targetName ?? '';\n const target = project?.targets?.[targetName];\n if (project === undefined || target === undefined) {\n // nx hands every executor its own project and target; their absence is our bug, not the consumer's.\n throw new Error(`${ruleName}: nx did not describe project '${projectName}' target '${targetName}'`);\n }\n return new GeneratorTarget(\n ruleName, context.root, projectName, project.root, targetName, target, project.targets?.['build']);\n }\n\n /** Absolute path to the project's declared `build` `outputPath` — the directory the package is packed from. */\n buildOutputDir(): string {\n const declared = this.build?.options?.['outputPath'];\n if (typeof declared !== 'string' || declared.trim() === '') {\n throw new RuleFailError(\n this.ruleName,\n `${this.projectName} has no build target with an options.outputPath, so ${this.ruleName} has ` +\n `nowhere to write that gets published. The documents go into the build's own output ` +\n `directory — the one the package is packed from — and are never assumed to be ./dist.`,\n undefined,\n undefined,\n [new Option(`Declare targets.build.options.outputPath in ${this.projectRoot}/project.json`, true)],\n );\n }\n return path.resolve(this.workspaceRoot, this.interpolate(declared));\n }\n\n /** Refuse unless this target `dependsOn` the sibling `required` target. */\n assertDependsOn(required: string): void {\n const entries: readonly DependsOnEntry[] = this.target.dependsOn ?? [];\n if (entries.some((entry: DependsOnEntry) => this.namesSibling(entry, required))) return;\n throw new RuleFailError(\n this.ruleName,\n `${this.projectName}:${this.targetName} does not declare dependsOn \"${required}\". It writes into ` +\n `the build's outputPath, so without that edge nx may run it before or alongside ${required} ` +\n `— and ${required}'s clean of that directory deletes the document it just wrote. That ` +\n `fails intermittently and mostly in CI, which is why it is refused here instead.`,\n undefined,\n undefined,\n [new Option(`Add \"dependsOn\": [\"${required}\"] to the ${this.targetName} target in ${this.projectRoot}/project.json`, true)],\n );\n }\n\n /** Refuse unless every written file is covered by the target's declared `outputs`, so a cache hit restores it. */\n assertOutputsCover(writtenAbs: readonly string[]): void {\n const patterns = (this.target.outputs ?? []).map((output: string) => this.interpolate(output));\n const uncovered = writtenAbs\n .map((file: string) => path.relative(this.workspaceRoot, file).split(path.sep).join('/'))\n .filter((file: string) => !matchesAnyGlob(file, patterns));\n if (uncovered.length === 0) return;\n throw new RuleFailError(\n this.ruleName,\n `${this.projectName}:${this.targetName} wrote files its declared outputs do not cover, so a ` +\n `cache hit would restore a package WITHOUT them:\\n` +\n uncovered.map((file: string) => ` ${file}`).join('\\n'),\n undefined,\n undefined,\n [new Option(\n `Cover them in the ${this.targetName} target's \"outputs\" in ${this.projectRoot}/project.json, ` +\n `e.g. \"{workspaceRoot}/${path.posix.dirname(uncovered[0]!)}/<the files>\"`,\n true,\n )],\n );\n }\n\n /** A workspace-relative path the consumer stated, from `options`, required and never defaulted. */\n requiredOption(value: string | undefined, name: string): string {\n if (typeof value === 'string' && value.trim() !== '') return value;\n throw new RuleFailError(\n this.ruleName,\n `${this.projectName}:${this.targetName} has no options.${name}. It is required and has no default.`,\n undefined,\n undefined,\n [new Option(`Set options.${name} on the ${this.targetName} target in ${this.projectRoot}/project.json`, true)],\n );\n }\n\n private namesSibling(entry: DependsOnEntry, required: string): boolean {\n if (typeof entry === 'string') return entry === required;\n const projects = entry.projects;\n const self = projects === undefined || projects === 'self' ||\n (Array.isArray(projects) && projects.length === 1 && projects[0] === this.projectName);\n return entry.target === required && entry.dependencies !== true && self;\n }\n\n /** nx's own tokens, so a path written the way nx accepts it resolves the way nx resolves it. */\n private interpolate(text: string): string {\n return text\n .replace(/\\{workspaceRoot\\}\\/?/g, '')\n .replace(/\\{projectRoot\\}/g, this.projectRoot)\n .replace(/\\{projectName\\}/g, this.projectName)\n .replace(/\\{options\\.([A-Za-z0-9_]+)\\}/g, (whole: string, key: string): string => {\n const value = this.target.options?.[key];\n return typeof value === 'string' ? value : whole;\n });\n }\n}\n\n/**\n * Generate into a STAGING directory, then publish into the output directory — so the executor knows\n * exactly which files the run produced (for {@link GeneratorTarget.assertOutputsCover}) without\n * parsing a generator's console output, and a failed run leaves the output directory untouched.\n */\nexport class StagedOutput {\n publish(stagingDir: string, destDir: string): string[] {\n const written: string[] = [];\n const copy = (from: string, to: string): void => {\n fs.mkdirSync(to, { recursive: true });\n for (const entry of fs.readdirSync(from, { withFileTypes: true })) {\n const source = path.join(from, entry.name);\n const target = path.join(to, entry.name);\n if (entry.isDirectory()) {\n copy(source, target);\n } else {\n fs.copyFileSync(source, target);\n written.push(target);\n }\n }\n };\n copy(stagingDir, destDir);\n return written.sort();\n }\n}\n"]}