@webpieces/nx-webpieces-rules 0.4.811 → 0.4.812

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 +23 -18
  8. package/src/executors/openapi-generate/executor.js +30 -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 +4 -0
  12. package/src/executors/validate-nx-wiring/executor.js +14 -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 +61 -0
  21. package/src/lib/api-docs/generate-wiring.js +163 -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
package/executors.json CHANGED
@@ -153,12 +153,12 @@
153
153
  "openapi-generate": {
154
154
  "implementation": "./src/executors/openapi-generate/executor",
155
155
  "schema": "./src/executors/openapi-generate/schema.json",
156
- "description": "Per-project: render the contracts to OpenAPI + mcp-tools.json into the build outputPath, with the consumer's own @webpieces/openapi-generator"
156
+ "description": "Per-project, inferred from the generate:openapi tag: render the contracts to OpenAPI + one mcp-<ContractClass>-tools.json per MCP contract into the compile target outputPath, with the consumer's own @webpieces/openapi-generator"
157
157
  },
158
158
  "docs-generate": {
159
159
  "implementation": "./src/executors/docs-generate/executor",
160
160
  "schema": "./src/executors/docs-generate/schema.json",
161
- "description": "Per-project: render the static API reference site from a generated document into the build outputPath, with the consumer's own @webpieces/docs-site"
161
+ "description": "Per-project, inferred from the generate:docs-site tag: render the static API reference site from a generated document into <projectRoot>/<siteDir>, with the consumer's own @webpieces/docs-site"
162
162
  },
163
163
  "validate-nx-wiring": {
164
164
  "implementation": "./src/executors/validate-nx-wiring/executor",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/nx-webpieces-rules",
3
- "version": "0.4.811",
3
+ "version": "0.4.812",
4
4
  "description": "Nx-specific webpieces validation rules and graph tooling. Bundles all @webpieces rule packages with Nx graph validators and an inference plugin.",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -18,12 +18,13 @@
18
18
  "README.md"
19
19
  ],
20
20
  "dependencies": {
21
- "@webpieces/ai-hook-rules": "0.4.811",
22
- "@webpieces/api-doc-model": "0.4.811",
23
- "@webpieces/code-rules": "0.4.811",
24
- "@webpieces/eslint-rules": "0.4.811",
25
- "@webpieces/pr-gate": "0.4.811",
26
- "@webpieces/rules-config": "0.4.811",
21
+ "@webpieces/ai-hook-rules": "0.4.812",
22
+ "@webpieces/api-doc-model": "0.4.812",
23
+ "@webpieces/code-rules": "0.4.812",
24
+ "@webpieces/core-util": "0.4.812",
25
+ "@webpieces/eslint-rules": "0.4.812",
26
+ "@webpieces/pr-gate": "0.4.812",
27
+ "@webpieces/rules-config": "0.4.812",
27
28
  "madge": "8.0.0"
28
29
  },
29
30
  "peerDependencies": {
@@ -1,21 +1,21 @@
1
1
  /**
2
2
  * docs-generate Executor
3
3
  *
4
- * Renders the static API reference site from a document `openapi-generate` already wrote into the
5
- * project's build `outputPath`, and writes the site into `<outputPath>/<siteDir>` — build output,
6
- * published with the package, never committed.
4
+ * Renders the static API reference site from a document `openapi-generate` already wrote into the api
5
+ * library's build output, and writes the site into `<projectRoot>/<siteDir>` — a gitignored directory
6
+ * of the project, for HOSTING. It is deliberately not written into the package: a docs site is
7
+ * something you deploy, not something an npm consumer installs.
7
8
  *
8
- * Usage (project.json):
9
+ * Consumers do not declare this executor. The nx-webpieces-rules plugin INFERS the target on a project
10
+ * tagged `generate:docs-site` (which implies `generate:openapi`), with `dependsOn: ["openapi-generate"]`;
11
+ * project.json states only the options, under the same target name:
9
12
  *
10
13
  * "docs-generate": {
11
- * "executor": "@webpieces/nx-webpieces-rules:docs-generate",
12
- * "dependsOn": ["openapi-generate"],
13
- * "cache": true,
14
- * "inputs": ["default", "^default"],
15
- * "outputs": ["{workspaceRoot}/dist/<project>/docs-site"],
16
- * "options": { "document": "public-openapi.json", "siteDir": "docs-site", "prose": "<project>/docs" }
14
+ * "options": { "document": "public-openapi.json", "siteDir": "generated-docs", "prose": "<project>/docs" }
17
15
  * }
18
16
  *
17
+ * and the repo's .gitignore carries `generated-docs/`.
18
+ *
19
19
  * `document` should be the PARTNER-facing document: a site built from `full-private-openapi.json`
20
20
  * publishes exactly the operations somebody decided not to publish. `prose` is optional because a site
21
21
  * with no prose pages is a legal site; `document` and `siteDir` are required and have no defaults.
@@ -24,13 +24,14 @@
24
24
  * version-checked; this plugin bundles no copy of it.
25
25
  */
26
26
  import type { ExecutorContext } from '@nx/devkit';
27
- import { ConsumerBinResolver, GeneratorRunner } from '@webpieces/pr-gate';
28
27
  import { RepoScratchDirs } from '@webpieces/rules-config';
29
28
  import { ExecutorResult } from '../../executor-result';
29
+ import { ConsumerBinResolver } from '../../lib/api-docs/consumer-bin-resolver';
30
+ import { GeneratorRunner } from '../../lib/api-docs/generator-runner';
30
31
  export interface DocsGenerateOptions {
31
- /** A document name inside the build outputPath, e.g. `public-openapi.json`. Required. */
32
+ /** A document name inside the api library's build output, e.g. `public-openapi.json`. Required. */
32
33
  document?: string;
33
- /** The site's directory name inside the build outputPath, e.g. `docs-site`. Required. */
34
+ /** The site's directory, relative to the project root, e.g. `generated-docs`. Required. */
34
35
  siteDir?: string;
35
36
  /** Workspace-relative directory holding `docs.manifest.json` and its markdown. Optional. */
36
37
  prose?: string;
@@ -2,21 +2,21 @@
2
2
  /**
3
3
  * docs-generate Executor
4
4
  *
5
- * Renders the static API reference site from a document `openapi-generate` already wrote into the
6
- * project's build `outputPath`, and writes the site into `<outputPath>/<siteDir>` — build output,
7
- * published with the package, never committed.
5
+ * Renders the static API reference site from a document `openapi-generate` already wrote into the api
6
+ * library's build output, and writes the site into `<projectRoot>/<siteDir>` — a gitignored directory
7
+ * of the project, for HOSTING. It is deliberately not written into the package: a docs site is
8
+ * something you deploy, not something an npm consumer installs.
8
9
  *
9
- * Usage (project.json):
10
+ * Consumers do not declare this executor. The nx-webpieces-rules plugin INFERS the target on a project
11
+ * tagged `generate:docs-site` (which implies `generate:openapi`), with `dependsOn: ["openapi-generate"]`;
12
+ * project.json states only the options, under the same target name:
10
13
  *
11
14
  * "docs-generate": {
12
- * "executor": "@webpieces/nx-webpieces-rules:docs-generate",
13
- * "dependsOn": ["openapi-generate"],
14
- * "cache": true,
15
- * "inputs": ["default", "^default"],
16
- * "outputs": ["{workspaceRoot}/dist/<project>/docs-site"],
17
- * "options": { "document": "public-openapi.json", "siteDir": "docs-site", "prose": "<project>/docs" }
15
+ * "options": { "document": "public-openapi.json", "siteDir": "generated-docs", "prose": "<project>/docs" }
18
16
  * }
19
17
  *
18
+ * and the repo's .gitignore carries `generated-docs/`.
19
+ *
20
20
  * `document` should be the PARTNER-facing document: a site built from `full-private-openapi.json`
21
21
  * publishes exactly the operations somebody decided not to publish. `prose` is optional because a site
22
22
  * with no prose pages is a legal site; `document` and `siteDir` are required and have no defaults.
@@ -28,20 +28,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
28
28
  exports.DocsGenerate = void 0;
29
29
  exports.default = runExecutor;
30
30
  const tslib_1 = require("tslib");
31
- const pr_gate_1 = require("@webpieces/pr-gate");
31
+ const core_util_1 = require("@webpieces/core-util");
32
32
  const rules_config_1 = require("@webpieces/rules-config");
33
33
  const fs = tslib_1.__importStar(require("fs"));
34
34
  const path = tslib_1.__importStar(require("path"));
35
35
  const executor_result_1 = require("../../executor-result");
36
- const generator_target_1 = require("../../lib/generated-docs/generator-target");
36
+ const consumer_bin_resolver_1 = require("../../lib/api-docs/consumer-bin-resolver");
37
+ const generator_package_1 = require("../../lib/api-docs/generator-package");
38
+ const generator_runner_1 = require("../../lib/api-docs/generator-runner");
39
+ const generator_target_1 = require("../../lib/api-docs/generator-target");
37
40
  const toError_1 = require("../../toError");
38
- const RULE_NAME = 'docs-generate';
41
+ const RULE_NAME = core_util_1.GeneratedApiDocsLayout.DOCS_TARGET;
39
42
  /** Everything except the process-facing reporting, so the suite drives it exactly as nx does. */
40
43
  class DocsGenerate {
41
44
  resolver;
42
45
  runner;
43
46
  scratch;
44
- constructor(resolver = new pr_gate_1.ConsumerBinResolver(), runner = new pr_gate_1.GeneratorRunner(), scratch = new rules_config_1.RepoScratchDirs()) {
47
+ constructor(resolver = new consumer_bin_resolver_1.ConsumerBinResolver(), runner = new generator_runner_1.GeneratorRunner(), scratch = new rules_config_1.RepoScratchDirs()) {
45
48
  this.resolver = resolver;
46
49
  this.runner = runner;
47
50
  this.scratch = scratch;
@@ -49,16 +52,16 @@ class DocsGenerate {
49
52
  /** @returns the files written, absolute. Throws RuleFailError on every refusal. */
50
53
  run(options, context) {
51
54
  const target = generator_target_1.GeneratorTarget.of(RULE_NAME, context);
52
- target.assertDependsOn('openapi-generate');
55
+ target.assertDependsOn(core_util_1.GeneratedApiDocsLayout.OPENAPI_TARGET);
53
56
  const document = target.requiredOption(options.document, 'document');
54
- const siteDir = target.requiredOption(options.siteDir, 'siteDir');
55
- const outDir = target.buildOutputDir();
56
- const spec = path.join(outDir, document);
57
+ const siteOut = target.insideProject(target.requiredOption(options.siteDir, 'siteDir'), 'siteDir');
58
+ const documentsDir = target.documentsDir();
59
+ const spec = path.join(documentsDir, document);
57
60
  if (!fs.existsSync(spec)) {
58
61
  throw new rules_config_1.RuleFailError(RULE_NAME, `${path.relative(context.root, spec)} does not exist, so there is nothing to render. ` +
59
- `openapi-generate writes only the documents the contracts' @ApiType(...) ask for.`, undefined, undefined, [new rules_config_1.Option(`Set options.document to a file openapi-generate writes into ${path.relative(context.root, outDir)}`, true)]);
62
+ `openapi-generate writes only the documents the contracts' @ApiType(...) ask for.`, undefined, undefined, [new rules_config_1.Option(`Set options.document to a file openapi-generate writes into ${path.relative(context.root, documentsDir)}`, true)]);
60
63
  }
61
- const bin = this.resolver.resolve(new pr_gate_1.ConsumerBinRequest(RULE_NAME, pr_gate_1.DOCS_SITE, [path.join(context.root, target.projectRoot), context.root]));
64
+ const bin = this.resolver.resolve(new consumer_bin_resolver_1.ConsumerBinRequest(RULE_NAME, generator_package_1.DOCS_SITE, [path.join(context.root, target.projectRoot), context.root]));
62
65
  const staging = this.scratch.make(context.root, 'wp-docs-generate-');
63
66
  // webpieces-disable no-unmanaged-exceptions -- try/FINALLY only, nothing is caught: the staging
64
67
  // directory is removed however this ends, and every throw still reaches runExecutor below
@@ -72,8 +75,7 @@ class DocsGenerate {
72
75
  throw new rules_config_1.RuleFailError(RULE_NAME, `${bin.packageName} ${bin.version} refused ${document}:\n${run.output}`);
73
76
  }
74
77
  // The site REPLACES the previous one: a page for an operation that no longer exists must not
75
- // survive into the published package.
76
- const siteOut = path.join(outDir, siteDir);
78
+ // survive into what gets hosted.
77
79
  fs.rmSync(siteOut, { recursive: true, force: true });
78
80
  const written = new generator_target_1.StagedOutput().publish(staging, siteOut);
79
81
  target.assertOutputsCover(written);
@@ -1 +1 @@
1
- {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/docs-generate/executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * docs-generate Executor\n *\n * Renders the static API reference site from a document `openapi-generate` already wrote into the\n * project's build `outputPath`, and writes the site into `<outputPath>/<siteDir>` — build output,\n * published with the package, never committed.\n *\n * Usage (project.json):\n *\n * \"docs-generate\": {\n * \"executor\": \"@webpieces/nx-webpieces-rules:docs-generate\",\n * \"dependsOn\": [\"openapi-generate\"],\n * \"cache\": true,\n * \"inputs\": [\"default\", \"^default\"],\n * \"outputs\": [\"{workspaceRoot}/dist/<project>/docs-site\"],\n * \"options\": { \"document\": \"public-openapi.json\", \"siteDir\": \"docs-site\", \"prose\": \"<project>/docs\" }\n * }\n *\n * `document` should be the PARTNER-facing document: a site built from `full-private-openapi.json`\n * publishes exactly the operations somebody decided not to publish. `prose` is optional because a site\n * with no prose pages is a legal site; `document` and `siteDir` are required and have no defaults.\n *\n * The renderer is the CONSUMER's `@webpieces/docs-site`, resolved from its node_modules and\n * version-checked; this plugin bundles no copy of it.\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport { ConsumerBinRequest, ConsumerBinResolver, DOCS_SITE, GeneratorRunner } from '@webpieces/pr-gate';\nimport { Option, RepoScratchDirs, RuleFailError, renderRuleFailForHuman } from '@webpieces/rules-config';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { ExecutorResult } from '../../executor-result';\nimport { GeneratorTarget, StagedOutput } from '../../lib/generated-docs/generator-target';\nimport { toError } from '../../toError';\n\nexport interface DocsGenerateOptions {\n /** A document name inside the build outputPath, e.g. `public-openapi.json`. Required. */\n document?: string;\n /** The site's directory name inside the build outputPath, e.g. `docs-site`. Required. */\n siteDir?: string;\n /** Workspace-relative directory holding `docs.manifest.json` and its markdown. Optional. */\n prose?: string;\n}\n\nconst RULE_NAME = 'docs-generate';\n\n/** Everything except the process-facing reporting, so the suite drives it exactly as nx does. */\nexport class DocsGenerate {\n constructor(\n private readonly resolver: ConsumerBinResolver = new ConsumerBinResolver(),\n private readonly runner: GeneratorRunner = new GeneratorRunner(),\n private readonly scratch: RepoScratchDirs = new RepoScratchDirs(),\n ) {}\n\n /** @returns the files written, absolute. Throws RuleFailError on every refusal. */\n run(options: DocsGenerateOptions, context: ExecutorContext): string[] {\n const target = GeneratorTarget.of(RULE_NAME, context);\n target.assertDependsOn('openapi-generate');\n const document = target.requiredOption(options.document, 'document');\n const siteDir = target.requiredOption(options.siteDir, 'siteDir');\n const outDir = target.buildOutputDir();\n const spec = path.join(outDir, document);\n if (!fs.existsSync(spec)) {\n throw new RuleFailError(\n RULE_NAME,\n `${path.relative(context.root, spec)} does not exist, so there is nothing to render. ` +\n `openapi-generate writes only the documents the contracts' @ApiType(...) ask for.`,\n undefined,\n undefined,\n [new Option(`Set options.document to a file openapi-generate writes into ${path.relative(context.root, outDir)}`, true)],\n );\n }\n const bin = this.resolver.resolve(new ConsumerBinRequest(\n RULE_NAME, DOCS_SITE, [path.join(context.root, target.projectRoot), context.root]));\n\n const staging = this.scratch.make(context.root, 'wp-docs-generate-');\n // webpieces-disable no-unmanaged-exceptions -- try/FINALLY only, nothing is caught: the staging\n // directory is removed however this ends, and every throw still reaches runExecutor below\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const args = ['--spec', spec, '--out', staging];\n if (options.prose !== undefined) args.push('--prose', path.resolve(context.root, options.prose));\n const run = this.runner.run(bin, args, context.root);\n if (!run.ok) {\n throw new RuleFailError(RULE_NAME, `${bin.packageName} ${bin.version} refused ${document}:\\n${run.output}`);\n }\n // The site REPLACES the previous one: a page for an operation that no longer exists must not\n // survive into the published package.\n const siteOut = path.join(outDir, siteDir);\n fs.rmSync(siteOut, { recursive: true, force: true });\n const written = new StagedOutput().publish(staging, siteOut);\n target.assertOutputsCover(written);\n return written;\n } finally {\n fs.rmSync(staging, { recursive: true, force: true });\n }\n }\n}\n\n// webpieces-disable no-function-outside-class -- nx executor module: nx resolves a default-export function here\nexport default async function runExecutor(\n options: DocsGenerateOptions,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- this IS the executor's single top-level handler\n try {\n const written = new DocsGenerate().run(options, context);\n console.log(`wrote ${written.length} file(s) of the docs site for ${context.projectName ?? ''}`);\n return new ExecutorResult(true);\n } catch (err: unknown) {\n const error = toError(err);\n console.error(`❌ ${RULE_NAME}: ${error instanceof RuleFailError ? renderRuleFailForHuman(error) : error.message}`);\n return new ExecutorResult(false);\n }\n}\n"]}
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/docs-generate/executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * docs-generate Executor\n *\n * Renders the static API reference site from a document `openapi-generate` already wrote into the api\n * library's build output, and writes the site into `<projectRoot>/<siteDir>` — a gitignored directory\n * of the project, for HOSTING. It is deliberately not written into the package: a docs site is\n * something you deploy, not something an npm consumer installs.\n *\n * Consumers do not declare this executor. The nx-webpieces-rules plugin INFERS the target on a project\n * tagged `generate:docs-site` (which implies `generate:openapi`), with `dependsOn: [\"openapi-generate\"]`;\n * project.json states only the options, under the same target name:\n *\n * \"docs-generate\": {\n * \"options\": { \"document\": \"public-openapi.json\", \"siteDir\": \"generated-docs\", \"prose\": \"<project>/docs\" }\n * }\n *\n * and the repo's .gitignore carries `generated-docs/`.\n *\n * `document` should be the PARTNER-facing document: a site built from `full-private-openapi.json`\n * publishes exactly the operations somebody decided not to publish. `prose` is optional because a site\n * with no prose pages is a legal site; `document` and `siteDir` are required and have no defaults.\n *\n * The renderer is the CONSUMER's `@webpieces/docs-site`, resolved from its node_modules and\n * version-checked; this plugin bundles no copy of it.\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport { GeneratedApiDocsLayout } from '@webpieces/core-util';\nimport { Option, RepoScratchDirs, RuleFailError, renderRuleFailForHuman } from '@webpieces/rules-config';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { ExecutorResult } from '../../executor-result';\nimport { ConsumerBinRequest, ConsumerBinResolver } from '../../lib/api-docs/consumer-bin-resolver';\nimport { DOCS_SITE } from '../../lib/api-docs/generator-package';\nimport { GeneratorRunner } from '../../lib/api-docs/generator-runner';\nimport { GeneratorTarget, StagedOutput } from '../../lib/api-docs/generator-target';\nimport { toError } from '../../toError';\n\nexport interface DocsGenerateOptions {\n /** A document name inside the api library's build output, e.g. `public-openapi.json`. Required. */\n document?: string;\n /** The site's directory, relative to the project root, e.g. `generated-docs`. Required. */\n siteDir?: string;\n /** Workspace-relative directory holding `docs.manifest.json` and its markdown. Optional. */\n prose?: string;\n}\n\nconst RULE_NAME = GeneratedApiDocsLayout.DOCS_TARGET;\n\n/** Everything except the process-facing reporting, so the suite drives it exactly as nx does. */\nexport class DocsGenerate {\n constructor(\n private readonly resolver: ConsumerBinResolver = new ConsumerBinResolver(),\n private readonly runner: GeneratorRunner = new GeneratorRunner(),\n private readonly scratch: RepoScratchDirs = new RepoScratchDirs(),\n ) {}\n\n /** @returns the files written, absolute. Throws RuleFailError on every refusal. */\n run(options: DocsGenerateOptions, context: ExecutorContext): string[] {\n const target = GeneratorTarget.of(RULE_NAME, context);\n target.assertDependsOn(GeneratedApiDocsLayout.OPENAPI_TARGET);\n const document = target.requiredOption(options.document, 'document');\n const siteOut = target.insideProject(target.requiredOption(options.siteDir, 'siteDir'), 'siteDir');\n const documentsDir = target.documentsDir();\n const spec = path.join(documentsDir, document);\n if (!fs.existsSync(spec)) {\n throw new RuleFailError(\n RULE_NAME,\n `${path.relative(context.root, spec)} does not exist, so there is nothing to render. ` +\n `openapi-generate writes only the documents the contracts' @ApiType(...) ask for.`,\n undefined,\n undefined,\n [new Option(`Set options.document to a file openapi-generate writes into ${path.relative(context.root, documentsDir)}`, true)],\n );\n }\n const bin = this.resolver.resolve(new ConsumerBinRequest(\n RULE_NAME, DOCS_SITE, [path.join(context.root, target.projectRoot), context.root]));\n\n const staging = this.scratch.make(context.root, 'wp-docs-generate-');\n // webpieces-disable no-unmanaged-exceptions -- try/FINALLY only, nothing is caught: the staging\n // directory is removed however this ends, and every throw still reaches runExecutor below\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const args = ['--spec', spec, '--out', staging];\n if (options.prose !== undefined) args.push('--prose', path.resolve(context.root, options.prose));\n const run = this.runner.run(bin, args, context.root);\n if (!run.ok) {\n throw new RuleFailError(RULE_NAME, `${bin.packageName} ${bin.version} refused ${document}:\\n${run.output}`);\n }\n // The site REPLACES the previous one: a page for an operation that no longer exists must not\n // survive into what gets hosted.\n fs.rmSync(siteOut, { recursive: true, force: true });\n const written = new StagedOutput().publish(staging, siteOut);\n target.assertOutputsCover(written);\n return written;\n } finally {\n fs.rmSync(staging, { recursive: true, force: true });\n }\n }\n}\n\n// webpieces-disable no-function-outside-class -- nx executor module: nx resolves a default-export function here\nexport default async function runExecutor(\n options: DocsGenerateOptions,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- this IS the executor's single top-level handler\n try {\n const written = new DocsGenerate().run(options, context);\n console.log(`wrote ${written.length} file(s) of the docs site for ${context.projectName ?? ''}`);\n return new ExecutorResult(true);\n } catch (err: unknown) {\n const error = toError(err);\n console.error(`❌ ${RULE_NAME}: ${error instanceof RuleFailError ? renderRuleFailForHuman(error) : error.message}`);\n return new ExecutorResult(false);\n }\n}\n"]}
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/schema",
3
3
  "title": "Docs Generate Executor",
4
- "description": "Render the static API reference site from a document openapi-generate wrote into the build outputPath, with the consumer's own @webpieces/docs-site, into <outputPath>/<siteDir>. The target must dependsOn openapi-generate and declare outputs covering the site.",
4
+ "description": "Inferred on a project tagged generate:docs-site. Render the static API reference site from a document openapi-generate wrote, with the consumer's own @webpieces/docs-site, into <projectRoot>/<siteDir> (gitignored, for hosting — not packed into the package).",
5
5
  "type": "object",
6
6
  "properties": {
7
7
  "document": {
8
8
  "type": "string",
9
- "description": "The document inside the build outputPath to render, e.g. public-openapi.json. No default."
9
+ "description": "The document openapi-generate wrote to render, e.g. public-openapi.json. No default."
10
10
  },
11
11
  "siteDir": {
12
12
  "type": "string",
13
- "description": "The site's directory name inside the build outputPath, e.g. docs-site. No default."
13
+ "description": "The site's directory relative to the project root, e.g. generated-docs. Emptied and rewritten on every run; gitignore it. No default."
14
14
  },
15
15
  "prose": {
16
16
  "type": "string",
@@ -1,33 +1,38 @@
1
1
  /**
2
2
  * openapi-generate Executor
3
3
  *
4
- * Renders a project's contracts to OpenAPI (and `mcp-tools.json`) INTO the project's own build
5
- * `outputPath`, so the documents are packed and published inside the api library's npm package: a
6
- * consumer installs the library and has the contract. They are build output — never committed.
4
+ * Renders a project's contracts to OpenAPI, plus ONE MCP tool catalog per contract
5
+ * (`mcp-<ContractClass>-tools.json`), INTO the outputPath of the target it dependsOn — the api
6
+ * library's compile step — so the documents are packed and published inside the api library's npm
7
+ * package: a consumer installs the library and has the contract. They are build output, never
8
+ * committed.
7
9
  *
8
- * Usage (project.json):
10
+ * Consumers do not declare this executor. The nx-webpieces-rules plugin INFERS the target on a project
11
+ * tagged `generate:openapi` (executor, cache, inputs, outputs); project.json states only what is the
12
+ * consumer's to decide, under the same target name:
9
13
  *
10
- * "openapi-generate": {
11
- * "executor": "@webpieces/nx-webpieces-rules:openapi-generate",
12
- * "dependsOn": ["build"],
13
- * "cache": true,
14
- * "inputs": ["default", "^default"],
15
- * "outputs": [
16
- * "{workspaceRoot}/dist/<project>/*openapi.json",
17
- * "{workspaceRoot}/dist/<project>/*openapi.yaml",
18
- * "{workspaceRoot}/dist/<project>/mcp-tools.json"
19
- * ],
20
- * "options": { "manifest": "<project>/openapi.manifest.json", "format": "both" }
14
+ * "tags": ["generate:openapi"],
15
+ * "targets": {
16
+ * "compile": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"],
17
+ * "options": { "outputPath": "dist/<project>", ... } },
18
+ * "openapi-generate": {
19
+ * "dependsOn": ["compile"],
20
+ * "options": { "manifest": "<project>/openapi.manifest.json", "format": "both" }
21
+ * },
22
+ * "build": { "executor": "nx:noop", "dependsOn": ["compile", "openapi-generate"] }
21
23
  * }
22
24
  *
23
- * `dependsOn: ["build"]` and `outputs` are CHECKED, not merely recommended — see GeneratorTarget. The
25
+ * The output directory is the outputPath of the ONE target `dependsOn` names (GeneratedApiDocsLayout
26
+ * in @webpieces/core-util — the same lookup the MCP server reads with), never a hardcoded target name
27
+ * and never an assumed dist/. `outputs` are CHECKED against what a run wrote — see GeneratorTarget. The
24
28
  * generator itself is the CONSUMER's `@webpieces/openapi-generator`, resolved from its node_modules and
25
- * version-checked; this plugin bundles no copy of it (see ConsumerBinResolver in @webpieces/pr-gate).
29
+ * version-checked; this plugin bundles no copy of it (see ConsumerBinResolver).
26
30
  */
27
31
  import type { ExecutorContext } from '@nx/devkit';
28
- import { ConsumerBinResolver, GeneratorRunner } from '@webpieces/pr-gate';
29
32
  import { RepoScratchDirs } from '@webpieces/rules-config';
30
33
  import { ExecutorResult } from '../../executor-result';
34
+ import { ConsumerBinResolver } from '../../lib/api-docs/consumer-bin-resolver';
35
+ import { GeneratorRunner } from '../../lib/api-docs/generator-runner';
31
36
  export interface OpenApiGenerateOptions {
32
37
  /** Workspace-relative path to the project's `openapi.manifest.json`. Required; no default. */
33
38
  manifest?: string;
@@ -2,47 +2,54 @@
2
2
  /**
3
3
  * openapi-generate Executor
4
4
  *
5
- * Renders a project's contracts to OpenAPI (and `mcp-tools.json`) INTO the project's own build
6
- * `outputPath`, so the documents are packed and published inside the api library's npm package: a
7
- * consumer installs the library and has the contract. They are build output — never committed.
5
+ * Renders a project's contracts to OpenAPI, plus ONE MCP tool catalog per contract
6
+ * (`mcp-<ContractClass>-tools.json`), INTO the outputPath of the target it dependsOn — the api
7
+ * library's compile step — so the documents are packed and published inside the api library's npm
8
+ * package: a consumer installs the library and has the contract. They are build output, never
9
+ * committed.
8
10
  *
9
- * Usage (project.json):
11
+ * Consumers do not declare this executor. The nx-webpieces-rules plugin INFERS the target on a project
12
+ * tagged `generate:openapi` (executor, cache, inputs, outputs); project.json states only what is the
13
+ * consumer's to decide, under the same target name:
10
14
  *
11
- * "openapi-generate": {
12
- * "executor": "@webpieces/nx-webpieces-rules:openapi-generate",
13
- * "dependsOn": ["build"],
14
- * "cache": true,
15
- * "inputs": ["default", "^default"],
16
- * "outputs": [
17
- * "{workspaceRoot}/dist/<project>/*openapi.json",
18
- * "{workspaceRoot}/dist/<project>/*openapi.yaml",
19
- * "{workspaceRoot}/dist/<project>/mcp-tools.json"
20
- * ],
21
- * "options": { "manifest": "<project>/openapi.manifest.json", "format": "both" }
15
+ * "tags": ["generate:openapi"],
16
+ * "targets": {
17
+ * "compile": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"],
18
+ * "options": { "outputPath": "dist/<project>", ... } },
19
+ * "openapi-generate": {
20
+ * "dependsOn": ["compile"],
21
+ * "options": { "manifest": "<project>/openapi.manifest.json", "format": "both" }
22
+ * },
23
+ * "build": { "executor": "nx:noop", "dependsOn": ["compile", "openapi-generate"] }
22
24
  * }
23
25
  *
24
- * `dependsOn: ["build"]` and `outputs` are CHECKED, not merely recommended — see GeneratorTarget. The
26
+ * The output directory is the outputPath of the ONE target `dependsOn` names (GeneratedApiDocsLayout
27
+ * in @webpieces/core-util — the same lookup the MCP server reads with), never a hardcoded target name
28
+ * and never an assumed dist/. `outputs` are CHECKED against what a run wrote — see GeneratorTarget. The
25
29
  * generator itself is the CONSUMER's `@webpieces/openapi-generator`, resolved from its node_modules and
26
- * version-checked; this plugin bundles no copy of it (see ConsumerBinResolver in @webpieces/pr-gate).
30
+ * version-checked; this plugin bundles no copy of it (see ConsumerBinResolver).
27
31
  */
28
32
  Object.defineProperty(exports, "__esModule", { value: true });
29
33
  exports.OpenApiGenerate = void 0;
30
34
  exports.default = runExecutor;
31
35
  const tslib_1 = require("tslib");
32
- const pr_gate_1 = require("@webpieces/pr-gate");
36
+ const core_util_1 = require("@webpieces/core-util");
33
37
  const rules_config_1 = require("@webpieces/rules-config");
34
38
  const fs = tslib_1.__importStar(require("fs"));
35
39
  const path = tslib_1.__importStar(require("path"));
36
40
  const executor_result_1 = require("../../executor-result");
37
- const generator_target_1 = require("../../lib/generated-docs/generator-target");
41
+ const consumer_bin_resolver_1 = require("../../lib/api-docs/consumer-bin-resolver");
42
+ const generator_package_1 = require("../../lib/api-docs/generator-package");
43
+ const generator_runner_1 = require("../../lib/api-docs/generator-runner");
44
+ const generator_target_1 = require("../../lib/api-docs/generator-target");
38
45
  const toError_1 = require("../../toError");
39
- const RULE_NAME = 'openapi-generate';
46
+ const RULE_NAME = core_util_1.GeneratedApiDocsLayout.OPENAPI_TARGET;
40
47
  /** Everything except the process-facing reporting, so the suite drives it exactly as nx does. */
41
48
  class OpenApiGenerate {
42
49
  resolver;
43
50
  runner;
44
51
  scratch;
45
- constructor(resolver = new pr_gate_1.ConsumerBinResolver(), runner = new pr_gate_1.GeneratorRunner(), scratch = new rules_config_1.RepoScratchDirs()) {
52
+ constructor(resolver = new consumer_bin_resolver_1.ConsumerBinResolver(), runner = new generator_runner_1.GeneratorRunner(), scratch = new rules_config_1.RepoScratchDirs()) {
46
53
  this.resolver = resolver;
47
54
  this.runner = runner;
48
55
  this.scratch = scratch;
@@ -50,11 +57,10 @@ class OpenApiGenerate {
50
57
  /** @returns the files written, absolute. Throws RuleFailError on every refusal. */
51
58
  run(options, context) {
52
59
  const target = generator_target_1.GeneratorTarget.of(RULE_NAME, context);
53
- target.assertDependsOn('build');
60
+ const outDir = target.documentsDir();
54
61
  const manifest = target.requiredOption(options.manifest, 'manifest');
55
62
  const format = target.requiredOption(options.format, 'format');
56
- const outDir = target.buildOutputDir();
57
- const bin = this.resolver.resolve(new pr_gate_1.ConsumerBinRequest(RULE_NAME, pr_gate_1.OPENAPI_GENERATOR, [path.join(context.root, target.projectRoot), context.root]));
63
+ const bin = this.resolver.resolve(new consumer_bin_resolver_1.ConsumerBinRequest(RULE_NAME, generator_package_1.OPENAPI_GENERATOR, [path.join(context.root, target.projectRoot), context.root]));
58
64
  const staging = this.scratch.make(context.root, 'wp-openapi-generate-');
59
65
  // webpieces-disable no-unmanaged-exceptions -- try/FINALLY only, nothing is caught: the staging
60
66
  // directory is removed however this ends, and every throw still reaches runExecutor below
@@ -1 +1 @@
1
- {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/openapi-generate/executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * openapi-generate Executor\n *\n * Renders a project's contracts to OpenAPI (and `mcp-tools.json`) INTO the project's own build\n * `outputPath`, so the documents are packed and published inside the api library's npm package: a\n * consumer installs the library and has the contract. They are build output — never committed.\n *\n * Usage (project.json):\n *\n * \"openapi-generate\": {\n * \"executor\": \"@webpieces/nx-webpieces-rules:openapi-generate\",\n * \"dependsOn\": [\"build\"],\n * \"cache\": true,\n * \"inputs\": [\"default\", \"^default\"],\n * \"outputs\": [\n * \"{workspaceRoot}/dist/<project>/*openapi.json\",\n * \"{workspaceRoot}/dist/<project>/*openapi.yaml\",\n * \"{workspaceRoot}/dist/<project>/mcp-tools.json\"\n * ],\n * \"options\": { \"manifest\": \"<project>/openapi.manifest.json\", \"format\": \"both\" }\n * }\n *\n * `dependsOn: [\"build\"]` and `outputs` are CHECKED, not merely recommended — see GeneratorTarget. The\n * generator itself is the CONSUMER's `@webpieces/openapi-generator`, resolved from its node_modules and\n * version-checked; this plugin bundles no copy of it (see ConsumerBinResolver in @webpieces/pr-gate).\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport {\n ConsumerBinRequest, ConsumerBinResolver, GeneratorRunner, OPENAPI_GENERATOR,\n} from '@webpieces/pr-gate';\nimport { RepoScratchDirs, RuleFailError, renderRuleFailForHuman } from '@webpieces/rules-config';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { ExecutorResult } from '../../executor-result';\nimport { GeneratorTarget, StagedOutput } from '../../lib/generated-docs/generator-target';\nimport { toError } from '../../toError';\n\nexport interface OpenApiGenerateOptions {\n /** Workspace-relative path to the project's `openapi.manifest.json`. Required; no default. */\n manifest?: string;\n /** `json`, `yaml` or `both`. Required; no default — it decides what the package ships. */\n format?: string;\n}\n\nconst RULE_NAME = 'openapi-generate';\n\n/** Everything except the process-facing reporting, so the suite drives it exactly as nx does. */\nexport class OpenApiGenerate {\n constructor(\n private readonly resolver: ConsumerBinResolver = new ConsumerBinResolver(),\n private readonly runner: GeneratorRunner = new GeneratorRunner(),\n private readonly scratch: RepoScratchDirs = new RepoScratchDirs(),\n ) {}\n\n /** @returns the files written, absolute. Throws RuleFailError on every refusal. */\n run(options: OpenApiGenerateOptions, context: ExecutorContext): string[] {\n const target = GeneratorTarget.of(RULE_NAME, context);\n target.assertDependsOn('build');\n const manifest = target.requiredOption(options.manifest, 'manifest');\n const format = target.requiredOption(options.format, 'format');\n const outDir = target.buildOutputDir();\n const bin = this.resolver.resolve(new ConsumerBinRequest(\n RULE_NAME, OPENAPI_GENERATOR, [path.join(context.root, target.projectRoot), context.root]));\n\n const staging = this.scratch.make(context.root, 'wp-openapi-generate-');\n // webpieces-disable no-unmanaged-exceptions -- try/FINALLY only, nothing is caught: the staging\n // directory is removed however this ends, and every throw still reaches runExecutor below\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const run = this.runner.run(bin, [\n '--manifest', path.resolve(context.root, manifest), '--out', staging, '--format', format,\n ], context.root);\n if (!run.ok) {\n throw new RuleFailError(\n RULE_NAME,\n `${bin.packageName} ${bin.version} refused ${manifest}:\\n${run.output}`,\n );\n }\n const written = new StagedOutput().publish(staging, outDir);\n target.assertOutputsCover(written);\n return written;\n } finally {\n fs.rmSync(staging, { recursive: true, force: true });\n }\n }\n}\n\n// webpieces-disable no-function-outside-class -- nx executor module: nx resolves a default-export function here\nexport default async function runExecutor(\n options: OpenApiGenerateOptions,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- this IS the executor's single top-level handler\n try {\n const written = new OpenApiGenerate().run(options, context);\n for (const file of written) console.log(`wrote ${path.relative(context.root, file)}`);\n return new ExecutorResult(true);\n } catch (err: unknown) {\n const error = toError(err);\n console.error(`❌ ${RULE_NAME}: ${error instanceof RuleFailError ? renderRuleFailForHuman(error) : error.message}`);\n return new ExecutorResult(false);\n }\n}\n"]}
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/executors/openapi-generate/executor.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * openapi-generate Executor\n *\n * Renders a project's contracts to OpenAPI, plus ONE MCP tool catalog per contract\n * (`mcp-<ContractClass>-tools.json`), INTO the outputPath of the target it dependsOn — the api\n * library's compile step — so the documents are packed and published inside the api library's npm\n * package: a consumer installs the library and has the contract. They are build output, never\n * committed.\n *\n * Consumers do not declare this executor. The nx-webpieces-rules plugin INFERS the target on a project\n * tagged `generate:openapi` (executor, cache, inputs, outputs); project.json states only what is the\n * consumer's to decide, under the same target name:\n *\n * \"tags\": [\"generate:openapi\"],\n * \"targets\": {\n * \"compile\": { \"executor\": \"@nx/js:tsc\", \"outputs\": [\"{options.outputPath}\"],\n * \"options\": { \"outputPath\": \"dist/<project>\", ... } },\n * \"openapi-generate\": {\n * \"dependsOn\": [\"compile\"],\n * \"options\": { \"manifest\": \"<project>/openapi.manifest.json\", \"format\": \"both\" }\n * },\n * \"build\": { \"executor\": \"nx:noop\", \"dependsOn\": [\"compile\", \"openapi-generate\"] }\n * }\n *\n * The output directory is the outputPath of the ONE target `dependsOn` names (GeneratedApiDocsLayout\n * in @webpieces/core-util — the same lookup the MCP server reads with), never a hardcoded target name\n * and never an assumed dist/. `outputs` are CHECKED against what a run wrote — see GeneratorTarget. The\n * generator itself is the CONSUMER's `@webpieces/openapi-generator`, resolved from its node_modules and\n * version-checked; this plugin bundles no copy of it (see ConsumerBinResolver).\n */\n\nimport type { ExecutorContext } from '@nx/devkit';\nimport { GeneratedApiDocsLayout } from '@webpieces/core-util';\nimport { RepoScratchDirs, RuleFailError, renderRuleFailForHuman } from '@webpieces/rules-config';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { ExecutorResult } from '../../executor-result';\nimport { ConsumerBinRequest, ConsumerBinResolver } from '../../lib/api-docs/consumer-bin-resolver';\nimport { OPENAPI_GENERATOR } from '../../lib/api-docs/generator-package';\nimport { GeneratorRunner } from '../../lib/api-docs/generator-runner';\nimport { GeneratorTarget, StagedOutput } from '../../lib/api-docs/generator-target';\nimport { toError } from '../../toError';\n\nexport interface OpenApiGenerateOptions {\n /** Workspace-relative path to the project's `openapi.manifest.json`. Required; no default. */\n manifest?: string;\n /** `json`, `yaml` or `both`. Required; no default — it decides what the package ships. */\n format?: string;\n}\n\nconst RULE_NAME = GeneratedApiDocsLayout.OPENAPI_TARGET;\n\n/** Everything except the process-facing reporting, so the suite drives it exactly as nx does. */\nexport class OpenApiGenerate {\n constructor(\n private readonly resolver: ConsumerBinResolver = new ConsumerBinResolver(),\n private readonly runner: GeneratorRunner = new GeneratorRunner(),\n private readonly scratch: RepoScratchDirs = new RepoScratchDirs(),\n ) {}\n\n /** @returns the files written, absolute. Throws RuleFailError on every refusal. */\n run(options: OpenApiGenerateOptions, context: ExecutorContext): string[] {\n const target = GeneratorTarget.of(RULE_NAME, context);\n const outDir = target.documentsDir();\n const manifest = target.requiredOption(options.manifest, 'manifest');\n const format = target.requiredOption(options.format, 'format');\n const bin = this.resolver.resolve(new ConsumerBinRequest(\n RULE_NAME, OPENAPI_GENERATOR, [path.join(context.root, target.projectRoot), context.root]));\n\n const staging = this.scratch.make(context.root, 'wp-openapi-generate-');\n // webpieces-disable no-unmanaged-exceptions -- try/FINALLY only, nothing is caught: the staging\n // directory is removed however this ends, and every throw still reaches runExecutor below\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const run = this.runner.run(bin, [\n '--manifest', path.resolve(context.root, manifest), '--out', staging, '--format', format,\n ], context.root);\n if (!run.ok) {\n throw new RuleFailError(\n RULE_NAME,\n `${bin.packageName} ${bin.version} refused ${manifest}:\\n${run.output}`,\n );\n }\n const written = new StagedOutput().publish(staging, outDir);\n target.assertOutputsCover(written);\n return written;\n } finally {\n fs.rmSync(staging, { recursive: true, force: true });\n }\n }\n}\n\n// webpieces-disable no-function-outside-class -- nx executor module: nx resolves a default-export function here\nexport default async function runExecutor(\n options: OpenApiGenerateOptions,\n context: ExecutorContext,\n): Promise<ExecutorResult> {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- this IS the executor's single top-level handler\n try {\n const written = new OpenApiGenerate().run(options, context);\n for (const file of written) console.log(`wrote ${path.relative(context.root, file)}`);\n return new ExecutorResult(true);\n } catch (err: unknown) {\n const error = toError(err);\n console.error(`❌ ${RULE_NAME}: ${error instanceof RuleFailError ? renderRuleFailForHuman(error) : error.message}`);\n return new ExecutorResult(false);\n }\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/schema",
3
3
  "title": "OpenAPI Generate Executor",
4
- "description": "Render the project's contracts to OpenAPI (and mcp-tools.json) into the project's build outputPath, with the consumer's own @webpieces/openapi-generator. The target must dependsOn build and declare outputs covering what it writes.",
4
+ "description": "Inferred on a project tagged generate:openapi. Render the project's contracts to OpenAPI plus one mcp-<ContractClass>-tools.json per MCP contract, with the consumer's own @webpieces/openapi-generator, into the outputPath of the ONE target this target dependsOn (the compile step).",
5
5
  "type": "object",
6
6
  "properties": {
7
7
  "manifest": {
@@ -11,7 +11,7 @@
11
11
  "format": {
12
12
  "type": "string",
13
13
  "enum": ["json", "yaml", "both"],
14
- "description": "Which serializations to write, and therefore publish. No default."
14
+ "description": "Which serializations of the OpenAPI documents to write, and therefore publish. No default."
15
15
  }
16
16
  },
17
17
  "required": ["manifest", "format"]
@@ -18,6 +18,10 @@
18
18
  * fast compile-only step while `nx ci` runs the full gate. This executor therefore only
19
19
  * guards build ORDER (`^build`), not the validators — those are guaranteed by the plugin.
20
20
  *
21
+ * 3. Generated API documents (#1021) — a project tagged `generate:openapi` / `generate:docs-site` has the
22
+ * `compile` → `openapi-generate` → `build` (nx:noop) shape, and every project depending on one has
23
+ * `test` dependsOn `^build`. See GenerateWiring for why.
24
+ *
21
25
  * Conservative by design: only REQUIRES wiring on compile executors actually in use
22
26
  * (@nx/js:tsc, @angular/build:application). A repo that uses neither passes.
23
27
  *
@@ -19,6 +19,10 @@
19
19
  * fast compile-only step while `nx ci` runs the full gate. This executor therefore only
20
20
  * guards build ORDER (`^build`), not the validators — those are guaranteed by the plugin.
21
21
  *
22
+ * 3. Generated API documents (#1021) — a project tagged `generate:openapi` / `generate:docs-site` has the
23
+ * `compile` → `openapi-generate` → `build` (nx:noop) shape, and every project depending on one has
24
+ * `test` dependsOn `^build`. See GenerateWiring for why.
25
+ *
22
26
  * Conservative by design: only REQUIRES wiring on compile executors actually in use
23
27
  * (@nx/js:tsc, @angular/build:application). A repo that uses neither passes.
24
28
  *
@@ -31,6 +35,7 @@ exports.default = runExecutor;
31
35
  const tslib_1 = require("tslib");
32
36
  const devkit_1 = require("@nx/devkit");
33
37
  const rules_config_1 = require("@webpieces/rules-config");
38
+ const generate_wiring_1 = require("../../lib/api-docs/generate-wiring");
34
39
  const fs = tslib_1.__importStar(require("fs"));
35
40
  const path = tslib_1.__importStar(require("path"));
36
41
  // Compile executors (and any per-project build override) must keep `^build` so build order
@@ -183,16 +188,22 @@ async function runExecutor(options, context) {
183
188
  console.log('\n🔌 Validating webpieces validators are wired into the build\n');
184
189
  const projectGraph = await (0, devkit_1.createProjectGraphAsync)();
185
190
  const projectsConfig = (0, devkit_1.readProjectsConfigurationFromProjectGraph)(projectGraph);
191
+ const generateWiring = new generate_wiring_1.GenerateWiring(projectsConfig.projects, projectGraph.dependencies);
192
+ const generateProblems = generateWiring.problems();
186
193
  const inUse = findCompileExecutorsInUse(projectsConfig, compileExecutors);
187
194
  const relevantExecutors = compileExecutors.filter((executorName) => inUse.has(executorName));
188
195
  if (relevantExecutors.length === 0) {
196
+ if (generateProblems.length > 0) {
197
+ generateWiring.report(generateProblems);
198
+ return { success: false };
199
+ }
189
200
  console.log('✅ No known compile executors in use — nothing to gate\n');
190
201
  return { success: true };
191
202
  }
192
203
  const targetDefaults = readTargetDefaults(context.root);
193
204
  const wiringProblems = findProblems(relevantExecutors, targetDefaults, requiredDeps);
194
205
  const gateProblems = findProjectGateProblems(projectsConfig, inUse, requiredDeps);
195
- if (wiringProblems.length === 0 && gateProblems.length === 0) {
206
+ if (wiringProblems.length === 0 && gateProblems.length === 0 && generateProblems.length === 0) {
196
207
  console.log('✅ Validators are wired into the build (targetDefaults + every project)\n');
197
208
  return { success: true };
198
209
  }
@@ -200,6 +211,8 @@ async function runExecutor(options, context) {
200
211
  reportFailure(wiringProblems, requiredDeps);
201
212
  if (gateProblems.length > 0)
202
213
  reportProjectGateFailure(gateProblems);
214
+ if (generateProblems.length > 0)
215
+ generateWiring.report(generateProblems);
203
216
  return { success: false };
204
217
  }
205
218
  //# sourceMappingURL=executor.js.map