@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.
- package/executors.json +2 -2
- package/package.json +8 -7
- package/src/executors/docs-generate/executor.d.ts +14 -13
- package/src/executors/docs-generate/executor.js +24 -22
- package/src/executors/docs-generate/executor.js.map +1 -1
- package/src/executors/docs-generate/schema.json +3 -3
- package/src/executors/openapi-generate/executor.d.ts +23 -18
- package/src/executors/openapi-generate/executor.js +30 -24
- package/src/executors/openapi-generate/executor.js.map +1 -1
- package/src/executors/openapi-generate/schema.json +2 -2
- package/src/executors/validate-nx-wiring/executor.d.ts +4 -0
- package/src/executors/validate-nx-wiring/executor.js +14 -1
- package/src/executors/validate-nx-wiring/executor.js.map +1 -1
- package/src/generate-targets.d.ts +59 -0
- package/src/generate-targets.js +118 -0
- package/src/generate-targets.js.map +1 -0
- package/src/lib/api-docs/consumer-bin-resolver.d.ts +62 -0
- package/src/lib/api-docs/consumer-bin-resolver.js +148 -0
- package/src/lib/api-docs/consumer-bin-resolver.js.map +1 -0
- package/src/lib/api-docs/generate-wiring.d.ts +61 -0
- package/src/lib/api-docs/generate-wiring.js +163 -0
- package/src/lib/api-docs/generate-wiring.js.map +1 -0
- package/src/lib/api-docs/generator-package.d.ts +23 -0
- package/src/lib/api-docs/generator-package.js +32 -0
- package/src/lib/api-docs/generator-package.js.map +1 -0
- package/src/lib/api-docs/generator-runner.d.ts +21 -0
- package/src/lib/api-docs/generator-runner.js +38 -0
- package/src/lib/api-docs/generator-runner.js.map +1 -0
- package/src/lib/{generated-docs → api-docs}/generator-target.d.ts +19 -12
- package/src/lib/{generated-docs → api-docs}/generator-target.js +40 -24
- package/src/lib/api-docs/generator-target.js.map +1 -0
- package/src/lib/api-docs/json-value.d.ts +6 -0
- package/src/lib/api-docs/json-value.js +3 -0
- package/src/lib/api-docs/json-value.js.map +1 -0
- package/src/plugin.d.ts +2 -0
- package/src/plugin.js +15 -2
- package/src/plugin.js.map +1 -1
- 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
|
|
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
|
|
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.
|
|
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.
|
|
22
|
-
"@webpieces/api-doc-model": "0.4.
|
|
23
|
-
"@webpieces/code-rules": "0.4.
|
|
24
|
-
"@webpieces/
|
|
25
|
-
"@webpieces/
|
|
26
|
-
"@webpieces/
|
|
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
|
-
*
|
|
6
|
-
*
|
|
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
|
-
*
|
|
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
|
-
* "
|
|
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
|
|
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
|
|
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
|
-
*
|
|
7
|
-
*
|
|
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
|
-
*
|
|
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
|
-
* "
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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(
|
|
55
|
+
target.assertDependsOn(core_util_1.GeneratedApiDocsLayout.OPENAPI_TARGET);
|
|
53
56
|
const document = target.requiredOption(options.document, 'document');
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
const spec = path.join(
|
|
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,
|
|
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
|
|
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
|
|
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":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;;;
|
|
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
|
|
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
|
|
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
|
|
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
|
|
5
|
-
* `
|
|
6
|
-
*
|
|
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
|
-
*
|
|
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
|
-
* "
|
|
11
|
-
*
|
|
12
|
-
* "
|
|
13
|
-
*
|
|
14
|
-
* "
|
|
15
|
-
*
|
|
16
|
-
* "{
|
|
17
|
-
*
|
|
18
|
-
*
|
|
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
|
-
*
|
|
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
|
|
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
|
|
6
|
-
* `
|
|
7
|
-
*
|
|
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
|
-
*
|
|
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
|
-
* "
|
|
12
|
-
*
|
|
13
|
-
* "
|
|
14
|
-
*
|
|
15
|
-
* "
|
|
16
|
-
*
|
|
17
|
-
* "{
|
|
18
|
-
*
|
|
19
|
-
*
|
|
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
|
-
*
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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.
|
|
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
|
|
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":";AAAA
|
|
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
|
|
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
|