@webpieces/api-doc-model 0.4.808 → 0.4.809
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/package.json +2 -2
- package/src/extract/ApiDocExtractor.d.ts +8 -9
- package/src/extract/ApiDocExtractor.js +20 -23
- package/src/extract/ApiDocExtractor.js.map +1 -1
- package/src/extract/McpMembership.d.ts +19 -0
- package/src/extract/McpMembership.js +66 -0
- package/src/extract/McpMembership.js.map +1 -0
- package/src/extract/TypeResolver.js +1 -1
- package/src/extract/TypeResolver.js.map +1 -1
- package/src/model/ApiDocModel.d.ts +43 -1
- package/src/model/ApiDocModel.js +26 -1
- package/src/model/ApiDocModel.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpieces/api-doc-model",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.809",
|
|
4
4
|
"description": "TypeScript-compiler-API extractor producing one in-memory ApiDocModel from a webpieces API contract. No renderer, no runtime, no app-specific import.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"access": "public"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@webpieces/core-util": "0.4.
|
|
26
|
+
"@webpieces/core-util": "0.4.809",
|
|
27
27
|
"typescript": "5.9.3"
|
|
28
28
|
}
|
|
29
29
|
}
|
|
@@ -90,15 +90,6 @@ export declare class ApiDocExtractor {
|
|
|
90
90
|
* like a contract somebody deliberately kept internal.
|
|
91
91
|
*/
|
|
92
92
|
private declaredApiTypes;
|
|
93
|
-
/**
|
|
94
|
-
* MCP membership has exactly ONE spelling, and this is the build-time half of enforcing it
|
|
95
|
-
* (`assertApiTypeMatchesMcpTools` in `@webpieces/core-util` is the wiring-time half).
|
|
96
|
-
*
|
|
97
|
-
* Declared in two places, the two can disagree — and the disagreement is invisible, because each
|
|
98
|
-
* declaration is individually valid. That is the defect this whole epic exists to remove, so it
|
|
99
|
-
* fails the DOCUMENT build rather than producing one that quietly lists the wrong tools.
|
|
100
|
-
*/
|
|
101
|
-
private assertApiTypeMatchesMcpTools;
|
|
102
93
|
/** The FIRST parameter's declared type. An endpoint with no parameter has no request document. */
|
|
103
94
|
private requestOf;
|
|
104
95
|
/** The declared return type, unwrapped from `Promise<...>` by the resolver. */
|
|
@@ -125,6 +116,14 @@ export declare class ApiDocExtractor {
|
|
|
125
116
|
* {@link DocumentedMcpTool}.
|
|
126
117
|
*/
|
|
127
118
|
private static mcpToolOf;
|
|
119
|
+
/**
|
|
120
|
+
* `@InvalidEndpointForMcp('<reason>')`'s reason, or undefined.
|
|
121
|
+
*
|
|
122
|
+
* A reason that will not fold is read as the EMPTY STRING rather than as "no decorator": the
|
|
123
|
+
* method is still permanently outside MCP, and losing that fact because the argument was written
|
|
124
|
+
* as a cross-module constant would silently put the endpoint back in the candidate set.
|
|
125
|
+
*/
|
|
126
|
+
private static invalidForMcpOf;
|
|
128
127
|
/** `@MaskLog({ refreshToken: 'full' })` -> field name -> mask mode. */
|
|
129
128
|
private static maskLogOf;
|
|
130
129
|
private static booleanProperty;
|
|
@@ -9,6 +9,7 @@ const ApiDocExtractionError_1 = require("./ApiDocExtractionError");
|
|
|
9
9
|
const ConstantFolder_1 = require("./ConstantFolder");
|
|
10
10
|
const JsDoc_1 = require("./JsDoc");
|
|
11
11
|
const SourceLocation_1 = require("./SourceLocation");
|
|
12
|
+
const McpMembership_1 = require("./McpMembership");
|
|
12
13
|
const TypeResolver_1 = require("./TypeResolver");
|
|
13
14
|
/**
|
|
14
15
|
* The decorator names this extractor matches on, taken from the REAL SYMBOLS rather than re-typed as
|
|
@@ -38,6 +39,7 @@ const API_PATH = core_util_1.ApiPath.name;
|
|
|
38
39
|
const ENDPOINT = core_util_1.Endpoint.name;
|
|
39
40
|
const MASK_LOG = core_util_1.MaskLog.name;
|
|
40
41
|
const MCP_TOOL = core_util_1.WpMcpTool.name;
|
|
42
|
+
const MCP_INVALID = core_util_1.InvalidEndpointForMcp.name;
|
|
41
43
|
const MCP_AUTH = core_util_1.WpMcpAuthJwt.name;
|
|
42
44
|
const API_KEY_AUTH = core_util_1.WpAuthApiKey.name;
|
|
43
45
|
const API_TYPE = core_util_1.ApiType.name;
|
|
@@ -171,7 +173,7 @@ class ApiDocExtractor {
|
|
|
171
173
|
endpoints.push(endpoint);
|
|
172
174
|
}
|
|
173
175
|
}
|
|
174
|
-
|
|
176
|
+
(0, McpMembership_1.assertApiTypeMatchesMcpTools)(contract, apiTypes, endpoints);
|
|
175
177
|
return new ApiDocModel_1.ApiDocModel(contract.name?.text ?? '<anonymous>', apiTypes, basePath, JsDoc_1.JsDoc.read(contract).description, endpoints, resolver.collectedTypes(), resolver.collectedUnmapped());
|
|
176
178
|
}
|
|
177
179
|
/**
|
|
@@ -243,7 +245,7 @@ class ApiDocExtractor {
|
|
|
243
245
|
const literal = options !== undefined && ts.isObjectLiteralExpression(options) ? options : undefined;
|
|
244
246
|
const doc = JsDoc_1.JsDoc.read(member);
|
|
245
247
|
const mcpTool = ApiDocExtractor.mcpToolOf(member, folder);
|
|
246
|
-
return new ApiDocModel_1.DocumentedEndpoint(methodName, httpMethod, path, operation, kind, ApiDocExtractor.booleanProperty(literal, 'hidden'), ApiDocExtractor.booleanProperty(literal, 'openWorld'), new ApiDocModel_1.DocumentedEndpointOptions(ApiDocExtractor.booleanProperty(literal, 'formPost'), ApiDocExtractor.stringProperty(literal, 'calledBy', folder), ApiDocExtractor.stringProperty(literal, 'callerKind', folder)), ApiDocExtractor.authOf(member, folder), mcpTool, ApiDocExtractor.decoratorCall(member, MCP_AUTH)?.arguments[0]?.getText(), ApiDocExtractor.maskLogOf(member), doc.description, doc.mcp, this.requestOf(member, methodName, resolver), this.responseOf(member, methodName, resolver));
|
|
248
|
+
return new ApiDocModel_1.DocumentedEndpoint(methodName, httpMethod, path, operation, kind, ApiDocExtractor.booleanProperty(literal, 'hidden'), ApiDocExtractor.booleanProperty(literal, 'openWorld'), new ApiDocModel_1.DocumentedEndpointOptions(ApiDocExtractor.booleanProperty(literal, 'formPost'), ApiDocExtractor.stringProperty(literal, 'calledBy', folder), ApiDocExtractor.stringProperty(literal, 'callerKind', folder)), ApiDocExtractor.authOf(member, folder), mcpTool, ApiDocExtractor.invalidForMcpOf(member, folder), ApiDocExtractor.decoratorCall(member, MCP_AUTH)?.arguments[0]?.getText(), ApiDocExtractor.maskLogOf(member), doc.description, doc.mcp, this.requestOf(member, methodName, resolver), this.responseOf(member, methodName, resolver));
|
|
247
249
|
}
|
|
248
250
|
/**
|
|
249
251
|
* One REQUIRED positional argument of `@Endpoint`, folded to the string it denotes.
|
|
@@ -287,27 +289,6 @@ class ApiDocExtractor {
|
|
|
287
289
|
}
|
|
288
290
|
return declared.length === 0 ? DEFAULT_API_TYPES : declared;
|
|
289
291
|
}
|
|
290
|
-
/**
|
|
291
|
-
* MCP membership has exactly ONE spelling, and this is the build-time half of enforcing it
|
|
292
|
-
* (`assertApiTypeMatchesMcpTools` in `@webpieces/core-util` is the wiring-time half).
|
|
293
|
-
*
|
|
294
|
-
* Declared in two places, the two can disagree — and the disagreement is invisible, because each
|
|
295
|
-
* declaration is individually valid. That is the defect this whole epic exists to remove, so it
|
|
296
|
-
* fails the DOCUMENT build rather than producing one that quietly lists the wrong tools.
|
|
297
|
-
*/
|
|
298
|
-
assertApiTypeMatchesMcpTools(contract, apiTypes, endpoints) {
|
|
299
|
-
const tools = endpoints.filter((e) => e.mcpTool !== undefined);
|
|
300
|
-
const declaresMcp = apiTypes.includes(core_util_1.MCP);
|
|
301
|
-
if (declaresMcp && tools.length === 0) {
|
|
302
|
-
throw new ApiDocExtractionError_1.ApiDocExtractionError(`@${API_TYPE} names MCP but no method carries @${MCP_TOOL}`, SourceLocation_1.SourceLocation.of(contract), `Add @${MCP_TOOL}({name, description, openWorldHint}) to the methods agents may ` +
|
|
303
|
-
`call, or drop MCP from the @${API_TYPE} list.`);
|
|
304
|
-
}
|
|
305
|
-
if (!declaresMcp && tools.length > 0) {
|
|
306
|
-
const named = tools.map((e) => e.methodName).join(', ');
|
|
307
|
-
throw new ApiDocExtractionError_1.ApiDocExtractionError(`@${MCP_TOOL} is on ${named} but @${API_TYPE} does not name MCP`, SourceLocation_1.SourceLocation.of(contract), `Add MCP to the @${API_TYPE} list — membership has ONE spelling, so a tool on a ` +
|
|
308
|
-
'contract nobody published to agents is a contradiction, not a hint.');
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
292
|
/** The FIRST parameter's declared type. An endpoint with no parameter has no request document. */
|
|
312
293
|
requestOf(member, methodName, resolver) {
|
|
313
294
|
const parameter = member.parameters[0];
|
|
@@ -398,6 +379,22 @@ class ApiDocExtractor {
|
|
|
398
379
|
}
|
|
399
380
|
return new ApiDocModel_1.DocumentedMcpTool(folder.tryFoldString(argument) ?? '');
|
|
400
381
|
}
|
|
382
|
+
/**
|
|
383
|
+
* `@InvalidEndpointForMcp('<reason>')`'s reason, or undefined.
|
|
384
|
+
*
|
|
385
|
+
* A reason that will not fold is read as the EMPTY STRING rather than as "no decorator": the
|
|
386
|
+
* method is still permanently outside MCP, and losing that fact because the argument was written
|
|
387
|
+
* as a cross-module constant would silently put the endpoint back in the candidate set.
|
|
388
|
+
*/
|
|
389
|
+
// webpieces-disable no-function-outside-class -- private static reader of this class
|
|
390
|
+
static invalidForMcpOf(member, folder) {
|
|
391
|
+
const call = ApiDocExtractor.decoratorCall(member, MCP_INVALID);
|
|
392
|
+
if (call === undefined) {
|
|
393
|
+
return undefined;
|
|
394
|
+
}
|
|
395
|
+
const argument = call.arguments[0];
|
|
396
|
+
return argument === undefined ? '' : (folder.tryFoldString(argument) ?? '');
|
|
397
|
+
}
|
|
401
398
|
/** `@MaskLog({ refreshToken: 'full' })` -> field name -> mask mode. */
|
|
402
399
|
// webpieces-disable no-function-outside-class -- private static reader of this class
|
|
403
400
|
static maskLogOf(member) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApiDocExtractor.js","sourceRoot":"","sources":["../../../../../../packages/docs/api-doc-model/src/extract/ApiDocExtractor.ts"],"names":[],"mappings":"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","sourcesContent":["import * as ts from 'typescript';\nimport {\n ApiPath,\n CLOUDTASKS,\n CRON,\n Endpoint,\n EXTERNAL,\n GET,\n MaskLog,\n POST,\n READ,\n RPC,\n WRITE,\n WRITE_IDEMPOTENT,\n WpAuthApiKey,\n WpAuthJwt,\n WpAuthLocalOnly,\n WpAuthOidc,\n WpAuthPublic,\n WpAuthSharedSecret,\n WpAuthWebhook,\n ApiType,\n EXTERNAL_CUSTOMER,\n MCP,\n SVC_TO_SVC,\n WpMcpAuthJwt,\n WpMcpTool,\n} from '@webpieces/core-util';\nimport {\n ApiDocModel,\n DocumentedApiKey,\n DocumentedApiKeyCredential,\n DocumentedAuth,\n DocumentedEndpoint,\n DocumentedEndpointOptions,\n DocumentedMcpTool,\n} from '../model/ApiDocModel';\nimport { TypeRef } from '../model/TypeRef';\nimport { ApiDocExtractionError } from './ApiDocExtractionError';\nimport { ConstantFolder } from './ConstantFolder';\nimport { JsDoc } from './JsDoc';\nimport { SourceLocation } from './SourceLocation';\nimport { TypeResolver } from './TypeResolver';\n\n/**\n * The decorator names this extractor matches on, taken from the REAL SYMBOLS rather than re-typed as\n * string literals.\n *\n * ## Why `.name` and not `'Endpoint'`\n *\n * The extractor matches decorators by NAME on the syntax — it must, because it reads a contract with\n * the compiler and never executes it. The question is only where that name comes from, and a literal\n * has a silent failure mode that a symbol does not: rename `@WpMcpTool` in `core-util` and a literal\n * simply stops matching. The extractor then finds zero MCP tools, the MCP document is correctly not\n * written because it has no tools in it, and the BUILD IS GREEN. A partner-facing document silently\n * loses a section with nothing red anywhere (issue #1001).\n *\n * `Endpoint.name` makes that rename a COMPILE ERROR here, which in this repo is the delivery\n * mechanism for a migration rather than an obstacle to one: a compile break names the new spelling\n * and an agent applies it in one pass, where a green build teaches nobody anything.\n *\n * ## Why importing `@webpieces/core-util` is not the coupling it looks like\n *\n * Any contract carrying `@Endpoint` already depends on `core-util` by definition, so there is no\n * upstream project this import could shut out. It is build-time only, it creates no cycle, and it\n * costs a browser bundle nothing because nothing in a bundle imports this package. The direction that\n * WOULD be fatal is `core-util` depending on the TypeScript compiler, and that is not this.\n */\nconst API_PATH = ApiPath.name;\nconst ENDPOINT = Endpoint.name;\nconst MASK_LOG = MaskLog.name;\nconst MCP_TOOL = WpMcpTool.name;\nconst MCP_AUTH = WpMcpAuthJwt.name;\nconst API_KEY_AUTH = WpAuthApiKey.name;\nconst API_TYPE = ApiType.name;\n\n/**\n * The prefix shared by every credential decorator. A PREFIX genuinely has no symbol to take a name\n * from, so it stays a literal — but the set it selects is pinned below, which is what stops it\n * quietly matching nothing.\n */\nconst AUTH_PREFIX = 'WpAuth';\n\n/** Every credential decorator, by real symbol, so a rename of any of them fails to compile here. */\nconst AUTH_DECORATORS = new Set([\n WpAuthPublic.name,\n WpAuthJwt.name,\n WpAuthOidc.name,\n WpAuthSharedSecret.name,\n WpAuthWebhook.name,\n WpAuthApiKey.name,\n WpAuthLocalOnly.name,\n]);\n\n/** The REAL trigger kinds and side-effect contracts, so a contract cannot declare one that is not. */\nconst ENDPOINT_KINDS: readonly string[] = [RPC, CLOUDTASKS, CRON, EXTERNAL];\nconst ENDPOINT_OPERATIONS: readonly string[] = [READ, WRITE_IDEMPOTENT, WRITE];\nconst HTTP_METHODS: readonly string[] = [GET, POST];\n\n/** `@Endpoint`'s four required positions, named so a failure can say which one is missing. */\nconst ARGUMENT_NAMES = ['http method', 'path', 'operation', 'trigger kind'];\n\n/** The allowed values of each required position, in the same order, for the same failure. */\nconst ARGUMENT_VALUES: readonly (readonly string[])[] = [\n HTTP_METHODS,\n [],\n ENDPOINT_OPERATIONS,\n ENDPOINT_KINDS,\n];\n\n/** The REAL document types, so a contract cannot name a document that does not exist. */\nconst API_TYPES: readonly string[] = [SVC_TO_SVC, EXTERNAL_CUSTOMER, MCP];\n\n/** The fail-closed default: a contract that declares nothing feeds only the internal document. */\nconst DEFAULT_API_TYPES: readonly string[] = [SVC_TO_SVC];\n\n/**\n * ONE contract file -> ONE {@link ApiDocModel}. The single extraction pass both the OpenAPI documents\n * and the MCP tool list (#982) are rendered from.\n *\n * ## Why the compiler API at all\n *\n * A DTO field's TYPE IS ERASED AT RUNTIME. Reflection can see that `save` takes one argument; it\n * cannot see that the argument has a `deliveryWindow` that is a discriminated union of two shapes,\n * one of which carries an ISO timestamp. Those are precisely the shapes a partner-grade document is\n * made of, so the only place they exist is the source, and the only honest way to read the source is\n * the compiler.\n *\n * ## Why it IMPORTS `@webpieces/core-util`\n *\n * Decorators are matched BY NAME on the syntax — they must be, because this reads a contract and\n * never executes it. The NAMES come from the real symbols (`Endpoint.name`), so a rename in\n * `core-util` is a compile error here instead of a literal that quietly stops matching. The full\n * argument, and why the import is not the coupling it looks like, is at those constants.\n *\n * ## What it does NOT do\n *\n * It emits nothing. No OpenAPI, no MCP tool definitions, no file — that is #982, and keeping the\n * render out means the two renderers cannot drift apart about what the contract SAYS.\n */\nexport class ApiDocExtractor {\n /**\n * Extract the contract in `entryFile`.\n *\n * @param entryFile absolute path to the `.ts` file holding the `@ApiPath` class.\n * @param compilerOptions handed straight to `ts.createProgram`; the caller owns them because\n * only the caller knows its own `paths` / `lib` setup.\n * @throws ApiDocExtractionError when the file holds no `@ApiPath` class, or when something that\n * must be exact (a path constant, a numeric bound) cannot be established.\n */\n extractFile(entryFile: string, compilerOptions: ts.CompilerOptions = {}): ApiDocModel {\n const program = ts.createProgram([entryFile], compilerOptions);\n const source = program.getSourceFile(entryFile);\n if (source === undefined) {\n throw new ApiDocExtractionError(\n 'entry file is not part of the program',\n entryFile,\n 'Pass an absolute path to a .ts file that exists.',\n );\n }\n return this.extract(program, source);\n }\n\n /**\n * EVERY `@ApiPath` contract in one file, in declaration order.\n *\n * {@link extractFile} answers \"what is THE contract in this file\", which is the shape a manifest\n * entry and a generated document have: one contract, one file. This answers a different question\n * — \"what does this file declare\" — and it exists because a REPO does not obey that convention.\n * `McpRemoteFixtures.ts` in `@webpieces/mcp-server` declares seven contracts, and the runtime\n * registers MCP tools from all seven; a sweep that read only the first would report green while\n * six contracts' worth of tools had never been looked at, which is the exact shape of silent miss\n * this epic exists to remove.\n *\n * A file with no contract yields an EMPTY list rather than throwing: \"this file has none\" is an\n * ordinary answer to this question, where it is a failure to answer {@link extractFile}'s.\n */\n extractAll(\n entryFile: string,\n compilerOptions: ts.CompilerOptions = {},\n ): readonly ApiDocModel[] {\n const program = ts.createProgram([entryFile], compilerOptions);\n const source = program.getSourceFile(entryFile);\n if (source === undefined) {\n throw new ApiDocExtractionError(\n 'entry file is not part of the program',\n entryFile,\n 'Pass an absolute path to a .ts file that exists.',\n );\n }\n return this.extractAllFrom(program, source);\n }\n\n /** {@link extractAll} against a program the caller already built. */\n extractAllFrom(program: ts.Program, source: ts.SourceFile): readonly ApiDocModel[] {\n const models: ApiDocModel[] = [];\n for (const statement of source.statements) {\n if (\n ts.isClassDeclaration(statement) &&\n ApiDocExtractor.decoratorCall(statement, API_PATH) !== undefined\n ) {\n models.push(this.extractContract(program, statement));\n }\n }\n return models;\n }\n\n /** The same extraction against a program the caller already built. */\n extract(program: ts.Program, source: ts.SourceFile): ApiDocModel {\n return this.extractContract(program, this.findContract(source));\n }\n\n /** ONE contract class -> ONE model. The single place the walk actually happens. */\n private extractContract(program: ts.Program, contract: ts.ClassDeclaration): ApiDocModel {\n const checker = program.getTypeChecker();\n const folder = new ConstantFolder(checker);\n const resolver = new TypeResolver(checker);\n\n const pathDecorator = ApiDocExtractor.decoratorCall(contract, API_PATH)!;\n const basePathArgument = pathDecorator.arguments[0];\n const basePath =\n basePathArgument === undefined\n ? ''\n : folder.foldString(basePathArgument, '@ApiPath argument');\n\n const apiTypes = this.declaredApiTypes(contract, folder);\n const endpoints: DocumentedEndpoint[] = [];\n for (const member of contract.members) {\n const endpoint = this.endpointOf(member, folder, resolver);\n if (endpoint !== undefined) {\n endpoints.push(endpoint);\n }\n }\n this.assertApiTypeMatchesMcpTools(contract, apiTypes, endpoints);\n\n return new ApiDocModel(\n contract.name?.text ?? '<anonymous>',\n apiTypes,\n basePath,\n JsDoc.read(contract).description,\n endpoints,\n resolver.collectedTypes(),\n resolver.collectedUnmapped(),\n );\n }\n\n /**\n * Extract ONE named type and everything it reaches, from a file that holds NO contract.\n *\n * This exists for a type nothing in a contract points at but a document still publishes — the\n * document-wide error body a renderer's manifest names. Reading it with the SAME resolver is the\n * point: a second reader would be a second answer to \"what shape is this type\", and the two\n * would drift the first time a field changed.\n *\n * @throws ApiDocExtractionError when the file does not declare that name.\n */\n extractType(\n entryFile: string,\n typeName: string,\n compilerOptions: ts.CompilerOptions = {},\n ): ApiDocModel {\n const program = ts.createProgram([entryFile], compilerOptions);\n const source = program.getSourceFile(entryFile);\n if (source === undefined) {\n throw new ApiDocExtractionError(\n 'entry file is not part of the program',\n entryFile,\n 'Pass an absolute path to a .ts file that exists.',\n );\n }\n const resolver = new TypeResolver(program.getTypeChecker());\n const declaration = ApiDocExtractor.declarationNamed(source, typeName);\n if (declaration === undefined) {\n throw new ApiDocExtractionError(\n `no type named '${typeName}' is declared in this file`,\n entryFile,\n `Declare and export '${typeName}' there, or name the file that does.`,\n );\n }\n resolver.resolveDeclaration(typeName, declaration, typeName);\n return new ApiDocModel(\n typeName,\n DEFAULT_API_TYPES,\n '',\n '',\n [],\n resolver.collectedTypes(),\n resolver.collectedUnmapped(),\n );\n }\n\n /** The interface / class / type alias / enum declared under `name` at the file's top level. */\n // webpieces-disable no-function-outside-class -- private static reader of this class\n private static declarationNamed(\n source: ts.SourceFile,\n name: string,\n ): ts.Declaration | undefined {\n for (const statement of source.statements) {\n const named =\n ts.isInterfaceDeclaration(statement) ||\n ts.isClassDeclaration(statement) ||\n ts.isTypeAliasDeclaration(statement) ||\n ts.isEnumDeclaration(statement);\n if (named && statement.name?.text === name) {\n return statement;\n }\n }\n return undefined;\n }\n\n /** The one `@ApiPath` class in the file. Zero is a hard failure; the FIRST wins if there are two. */\n private findContract(source: ts.SourceFile): ts.ClassDeclaration {\n for (const statement of source.statements) {\n if (\n ts.isClassDeclaration(statement) &&\n ApiDocExtractor.decoratorCall(statement, API_PATH) !== undefined\n ) {\n return statement;\n }\n }\n throw new ApiDocExtractionError(\n 'no @ApiPath class in this file',\n source.fileName,\n 'Point the extractor at the contract file — the one whose class carries @ApiPath.',\n );\n }\n\n /** One `@Endpoint` method. Members without the decorator are not part of the contract. */\n private endpointOf(\n member: ts.ClassElement,\n folder: ConstantFolder,\n resolver: TypeResolver,\n ): DocumentedEndpoint | undefined {\n if (!ts.isMethodDeclaration(member) || !ts.isIdentifier(member.name)) {\n return undefined;\n }\n const call = ApiDocExtractor.decoratorCall(member, ENDPOINT);\n if (call === undefined) {\n return undefined;\n }\n const methodName = member.name.text;\n\n // `@Endpoint(httpMethod, path, operation, kind, options?)` — METHOD-FIRST, five positions.\n // The positions are read here and nowhere else, so the one place that has to change when the\n // decorator changes is this block plus `ARGUMENT_NAMES` beside it.\n const httpMethod = this.requiredArgument(call, methodName, 0, folder);\n const path = this.requiredArgument(call, methodName, 1, folder);\n const operation = this.requiredArgument(call, methodName, 2, folder);\n const kind = this.requiredArgument(call, methodName, 3, folder);\n\n const options = call.arguments[4];\n const literal =\n options !== undefined && ts.isObjectLiteralExpression(options) ? options : undefined;\n\n const doc = JsDoc.read(member);\n const mcpTool = ApiDocExtractor.mcpToolOf(member, folder);\n return new DocumentedEndpoint(\n methodName,\n httpMethod,\n path,\n operation,\n kind,\n ApiDocExtractor.booleanProperty(literal, 'hidden'),\n ApiDocExtractor.booleanProperty(literal, 'openWorld'),\n new DocumentedEndpointOptions(\n ApiDocExtractor.booleanProperty(literal, 'formPost'),\n ApiDocExtractor.stringProperty(literal, 'calledBy', folder),\n ApiDocExtractor.stringProperty(literal, 'callerKind', folder),\n ),\n ApiDocExtractor.authOf(member, folder),\n mcpTool,\n ApiDocExtractor.decoratorCall(member, MCP_AUTH)?.arguments[0]?.getText(),\n ApiDocExtractor.maskLogOf(member),\n doc.description,\n doc.mcp,\n this.requestOf(member, methodName, resolver),\n this.responseOf(member, methodName, resolver),\n );\n }\n\n /**\n * One REQUIRED positional argument of `@Endpoint`, folded to the string it denotes.\n *\n * Every one of the four is an enum member (`POST`, `READ`, `RPC`) as often as it is a literal,\n * and the folder resolves both — a document that printed `RPC` where the trigger goes would be\n * worse than no document. A missing one is a hard failure naming the position, because the\n * alternative is a document quietly missing a verb.\n */\n private requiredArgument(\n call: ts.CallExpression,\n methodName: string,\n index: number,\n folder: ConstantFolder,\n ): string {\n const argument = call.arguments[index];\n const what = ARGUMENT_NAMES[index];\n if (argument === undefined) {\n throw new ApiDocExtractionError(\n `@Endpoint on '${methodName}' declares no ${what}`,\n SourceLocation.of(call),\n \"Write all four: @Endpoint(POST, '/thing', READ, RPC).\",\n );\n }\n const value = folder.foldString(argument, `@Endpoint ${what} on '${methodName}'`);\n const allowed = ARGUMENT_VALUES[index]!;\n if (allowed.length > 0 && !allowed.includes(value)) {\n throw new ApiDocExtractionError(\n `@Endpoint on '${methodName}' declares ${what} '${value}', which is not one of ` +\n allowed.join(', '),\n SourceLocation.of(argument),\n `Use one of the exported constants: ${allowed.join(', ')}.`,\n );\n }\n return value;\n }\n\n /**\n * `@ApiType(...)` on the contract, folded to the real values.\n *\n * A value that is not one of the three documents is a HARD FAILURE rather than a silent drop: a\n * contract that named `CUSTOMER` by mistake would otherwise feed nothing, which looks exactly\n * like a contract somebody deliberately kept internal.\n */\n private declaredApiTypes(node: ts.Node, folder: ConstantFolder): readonly string[] {\n const call = ApiDocExtractor.decoratorCall(node, API_TYPE);\n if (call === undefined) {\n return DEFAULT_API_TYPES;\n }\n const declared = call.arguments.map((argument: ts.Expression) =>\n folder.foldString(argument, `@${API_TYPE} argument`),\n );\n for (const apiType of declared) {\n if (!API_TYPES.includes(apiType)) {\n throw new ApiDocExtractionError(\n `@${API_TYPE} names '${apiType}', which is not a generated document`,\n SourceLocation.of(call),\n `Use one of the exported constants: ${API_TYPES.join(', ')}.`,\n );\n }\n }\n return declared.length === 0 ? DEFAULT_API_TYPES : declared;\n }\n\n /**\n * MCP membership has exactly ONE spelling, and this is the build-time half of enforcing it\n * (`assertApiTypeMatchesMcpTools` in `@webpieces/core-util` is the wiring-time half).\n *\n * Declared in two places, the two can disagree — and the disagreement is invisible, because each\n * declaration is individually valid. That is the defect this whole epic exists to remove, so it\n * fails the DOCUMENT build rather than producing one that quietly lists the wrong tools.\n */\n private assertApiTypeMatchesMcpTools(\n contract: ts.ClassDeclaration,\n apiTypes: readonly string[],\n endpoints: readonly DocumentedEndpoint[],\n ): void {\n const tools = endpoints.filter((e: DocumentedEndpoint) => e.mcpTool !== undefined);\n const declaresMcp = apiTypes.includes(MCP);\n if (declaresMcp && tools.length === 0) {\n throw new ApiDocExtractionError(\n `@${API_TYPE} names MCP but no method carries @${MCP_TOOL}`,\n SourceLocation.of(contract),\n `Add @${MCP_TOOL}({name, description, openWorldHint}) to the methods agents may ` +\n `call, or drop MCP from the @${API_TYPE} list.`,\n );\n }\n if (!declaresMcp && tools.length > 0) {\n const named = tools.map((e: DocumentedEndpoint) => e.methodName).join(', ');\n throw new ApiDocExtractionError(\n `@${MCP_TOOL} is on ${named} but @${API_TYPE} does not name MCP`,\n SourceLocation.of(contract),\n `Add MCP to the @${API_TYPE} list — membership has ONE spelling, so a tool on a ` +\n 'contract nobody published to agents is a contradiction, not a hint.',\n );\n }\n }\n\n /** The FIRST parameter's declared type. An endpoint with no parameter has no request document. */\n private requestOf(\n member: ts.MethodDeclaration,\n methodName: string,\n resolver: TypeResolver,\n ): TypeRef | undefined {\n const parameter = member.parameters[0];\n if (parameter?.type === undefined) {\n return undefined;\n }\n return resolver.resolve(parameter.type, `${methodName}.request`);\n }\n\n /** The declared return type, unwrapped from `Promise<...>` by the resolver. */\n private responseOf(\n member: ts.MethodDeclaration,\n methodName: string,\n resolver: TypeResolver,\n ): TypeRef | undefined {\n if (member.type === undefined) {\n return undefined;\n }\n return resolver.resolve(member.type, `${methodName}.response`);\n }\n\n /** `@WpAuthPublic()`, `@WpAuthJwt({...})`, … — recorded verbatim; this package rules on nothing. */\n // webpieces-disable no-function-outside-class -- private static reader of this class\n private static authOf(member: ts.Node, folder: ConstantFolder): DocumentedAuth | undefined {\n const decorators = ts.canHaveDecorators(member) ? (ts.getDecorators(member) ?? []) : [];\n for (const decorator of decorators) {\n const call = decorator.expression;\n if (!ts.isCallExpression(call) || !ts.isIdentifier(call.expression)) {\n continue;\n }\n const name = call.expression.text;\n if (name.startsWith(AUTH_PREFIX) && AUTH_DECORATORS.has(name)) {\n return new DocumentedAuth(\n name,\n call.arguments.map((argument: ts.Expression) => argument.getText()),\n name === API_KEY_AUTH ? ApiDocExtractor.apiKeyOf(call, folder) : undefined,\n );\n }\n }\n return undefined;\n }\n\n /**\n * `@WpAuthApiKey(regime, [{in: 'header', name: 'x-api-key', description: '…'}, …])`, parsed.\n *\n * A malformed declaration FAILS rather than yielding a half-parsed regime: the credentials are\n * what a published document's security block is made of, and a document that silently omitted\n * one would tell a partner they need fewer credentials than the running hook demands.\n */\n // webpieces-disable no-function-outside-class -- private static reader of this class\n private static apiKeyOf(call: ts.CallExpression, folder: ConstantFolder): DocumentedApiKey {\n const regimeArgument = call.arguments[0];\n const credentialsArgument = call.arguments[1];\n if (regimeArgument === undefined || credentialsArgument === undefined) {\n throw new ApiDocExtractionError(\n '@WpAuthApiKey needs a regime AND its credentials',\n SourceLocation.of(call),\n \"Write both: @WpAuthApiKey('partner', [{ in: 'header', name: 'x-api-key' }]).\",\n );\n }\n const regime = folder.foldString(regimeArgument, '@WpAuthApiKey regime');\n // FOLLOW a name first: a credential list shared by every method of a contract is written\n // once as a `const` and named per method, which is better source than a copy per method.\n const credentialsLiteral = folder.follow(credentialsArgument);\n if (!ts.isArrayLiteralExpression(credentialsLiteral)) {\n throw new ApiDocExtractionError(\n '@WpAuthApiKey credentials is not an array literal',\n SourceLocation.of(credentialsArgument),\n 'Write the credentials as an array literal, inline or in a `const`; a value ' +\n 'assembled at runtime cannot appear in a published security scheme.',\n );\n }\n const credentials: DocumentedApiKeyCredential[] = [];\n for (const element of credentialsLiteral.elements) {\n credentials.push(ApiDocExtractor.credentialOf(element, folder));\n }\n return new DocumentedApiKey(regime, credentials);\n }\n\n /** ONE `{ in: …, name?: …, description?: … }` credential. */\n // webpieces-disable no-function-outside-class -- private static reader of this class\n private static credentialOf(\n expression: ts.Expression,\n folder: ConstantFolder,\n ): DocumentedApiKeyCredential {\n const element = folder.follow(expression);\n if (!ts.isObjectLiteralExpression(element)) {\n throw new ApiDocExtractionError(\n 'an @WpAuthApiKey credential is not an object literal',\n SourceLocation.of(element),\n \"Write it inline: { in: 'header', name: 'x-api-key' }.\",\n );\n }\n const location = ApiDocExtractor.stringProperty(element, 'in', folder);\n if (location === undefined) {\n throw new ApiDocExtractionError(\n 'an @WpAuthApiKey credential declares no `in`',\n SourceLocation.of(element),\n \"Say where it rides: `in: 'header'` with a name, or `in: 'bearer'`.\",\n );\n }\n return new DocumentedApiKeyCredential(\n location,\n ApiDocExtractor.stringProperty(element, 'name', folder),\n ApiDocExtractor.stringProperty(element, 'description', folder),\n );\n }\n\n /**\n * `@WpMcpTool('search_stores')` — the stable protocol name, which is the ONE fact the source\n * cannot otherwise state.\n *\n * Nothing else is read because nothing else is declared there any more (#984): the method's JSDoc\n * is the description for the agent and the partner alike, the three side-effect hints are computed\n * from the endpoint's `operation`, and `openWorldHint` is `@Endpoint`'s `openWorld`. See\n * {@link DocumentedMcpTool}.\n */\n // webpieces-disable no-function-outside-class -- private static reader of this class\n private static mcpToolOf(\n member: ts.Node,\n folder: ConstantFolder,\n ): DocumentedMcpTool | undefined {\n const call = ApiDocExtractor.decoratorCall(member, MCP_TOOL);\n const argument = call?.arguments[0];\n if (argument === undefined) {\n return undefined;\n }\n return new DocumentedMcpTool(folder.tryFoldString(argument) ?? '');\n }\n\n /** `@MaskLog({ refreshToken: 'full' })` -> field name -> mask mode. */\n // webpieces-disable no-function-outside-class -- private static reader of this class\n private static maskLogOf(member: ts.Node): ReadonlyMap<string, string> {\n const fields = new Map<string, string>();\n const argument = ApiDocExtractor.decoratorCall(member, MASK_LOG)?.arguments[0];\n if (argument === undefined || !ts.isObjectLiteralExpression(argument)) {\n return fields;\n }\n for (const property of argument.properties) {\n if (\n ts.isPropertyAssignment(property) &&\n (ts.isIdentifier(property.name) || ts.isStringLiteral(property.name)) &&\n ts.isStringLiteralLike(property.initializer)\n ) {\n fields.set(property.name.text, property.initializer.text);\n }\n }\n return fields;\n }\n\n // webpieces-disable no-function-outside-class -- private static reader of this class\n private static booleanProperty(\n literal: ts.ObjectLiteralExpression | undefined,\n name: string,\n ): boolean {\n const value =\n literal === undefined ? undefined : ApiDocExtractor.findProperty(literal, name);\n return value?.kind === ts.SyntaxKind.TrueKeyword;\n }\n\n // webpieces-disable no-function-outside-class -- private static reader of this class\n private static stringProperty(\n literal: ts.ObjectLiteralExpression | undefined,\n name: string,\n folder: ConstantFolder,\n ): string | undefined {\n const value =\n literal === undefined ? undefined : ApiDocExtractor.findProperty(literal, name);\n return value === undefined ? undefined : folder.tryFoldString(value);\n }\n\n // webpieces-disable no-function-outside-class -- private static reader of this class\n private static findProperty(\n literal: ts.ObjectLiteralExpression,\n name: string,\n ): ts.Expression | undefined {\n for (const property of literal.properties) {\n if (\n ts.isPropertyAssignment(property) &&\n (ts.isIdentifier(property.name) || ts.isStringLiteral(property.name)) &&\n property.name.text === name\n ) {\n return property.initializer;\n }\n }\n return undefined;\n }\n\n // webpieces-disable no-function-outside-class -- private static reader of this class\n private static decoratorCall(\n node: ts.Node,\n decoratorName: string,\n ): ts.CallExpression | undefined {\n const decorators = ts.canHaveDecorators(node) ? (ts.getDecorators(node) ?? []) : [];\n for (const decorator of decorators) {\n const call = decorator.expression;\n if (\n ts.isCallExpression(call) &&\n ts.isIdentifier(call.expression) &&\n call.expression.text === decoratorName\n ) {\n return call;\n }\n }\n return undefined;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ApiDocExtractor.js","sourceRoot":"","sources":["../../../../../../packages/docs/api-doc-model/src/extract/ApiDocExtractor.ts"],"names":[],"mappings":"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","sourcesContent":["import * as ts from 'typescript';\nimport {\n ApiPath,\n CLOUDTASKS,\n CRON,\n Endpoint,\n EXTERNAL,\n GET,\n MaskLog,\n POST,\n READ,\n RPC,\n WRITE,\n WRITE_IDEMPOTENT,\n WpAuthApiKey,\n WpAuthJwt,\n WpAuthLocalOnly,\n WpAuthOidc,\n WpAuthPublic,\n WpAuthSharedSecret,\n WpAuthWebhook,\n ApiType,\n EXTERNAL_CUSTOMER,\n MCP,\n SVC_TO_SVC,\n InvalidEndpointForMcp,\n WpMcpAuthJwt,\n WpMcpTool,\n} from '@webpieces/core-util';\nimport {\n ApiDocModel,\n DocumentedApiKey,\n DocumentedApiKeyCredential,\n DocumentedAuth,\n DocumentedEndpoint,\n DocumentedEndpointOptions,\n DocumentedMcpTool,\n} from '../model/ApiDocModel';\nimport { TypeRef } from '../model/TypeRef';\nimport { ApiDocExtractionError } from './ApiDocExtractionError';\nimport { ConstantFolder } from './ConstantFolder';\nimport { JsDoc } from './JsDoc';\nimport { SourceLocation } from './SourceLocation';\nimport { assertApiTypeMatchesMcpTools } from './McpMembership';\nimport { TypeResolver } from './TypeResolver';\n\n/**\n * The decorator names this extractor matches on, taken from the REAL SYMBOLS rather than re-typed as\n * string literals.\n *\n * ## Why `.name` and not `'Endpoint'`\n *\n * The extractor matches decorators by NAME on the syntax — it must, because it reads a contract with\n * the compiler and never executes it. The question is only where that name comes from, and a literal\n * has a silent failure mode that a symbol does not: rename `@WpMcpTool` in `core-util` and a literal\n * simply stops matching. The extractor then finds zero MCP tools, the MCP document is correctly not\n * written because it has no tools in it, and the BUILD IS GREEN. A partner-facing document silently\n * loses a section with nothing red anywhere (issue #1001).\n *\n * `Endpoint.name` makes that rename a COMPILE ERROR here, which in this repo is the delivery\n * mechanism for a migration rather than an obstacle to one: a compile break names the new spelling\n * and an agent applies it in one pass, where a green build teaches nobody anything.\n *\n * ## Why importing `@webpieces/core-util` is not the coupling it looks like\n *\n * Any contract carrying `@Endpoint` already depends on `core-util` by definition, so there is no\n * upstream project this import could shut out. It is build-time only, it creates no cycle, and it\n * costs a browser bundle nothing because nothing in a bundle imports this package. The direction that\n * WOULD be fatal is `core-util` depending on the TypeScript compiler, and that is not this.\n */\nconst API_PATH = ApiPath.name;\nconst ENDPOINT = Endpoint.name;\nconst MASK_LOG = MaskLog.name;\nconst MCP_TOOL = WpMcpTool.name;\nconst MCP_INVALID = InvalidEndpointForMcp.name;\nconst MCP_AUTH = WpMcpAuthJwt.name;\nconst API_KEY_AUTH = WpAuthApiKey.name;\nconst API_TYPE = ApiType.name;\n\n/**\n * The prefix shared by every credential decorator. A PREFIX genuinely has no symbol to take a name\n * from, so it stays a literal — but the set it selects is pinned below, which is what stops it\n * quietly matching nothing.\n */\nconst AUTH_PREFIX = 'WpAuth';\n\n/** Every credential decorator, by real symbol, so a rename of any of them fails to compile here. */\nconst AUTH_DECORATORS = new Set([\n WpAuthPublic.name,\n WpAuthJwt.name,\n WpAuthOidc.name,\n WpAuthSharedSecret.name,\n WpAuthWebhook.name,\n WpAuthApiKey.name,\n WpAuthLocalOnly.name,\n]);\n\n/** The REAL trigger kinds and side-effect contracts, so a contract cannot declare one that is not. */\nconst ENDPOINT_KINDS: readonly string[] = [RPC, CLOUDTASKS, CRON, EXTERNAL];\nconst ENDPOINT_OPERATIONS: readonly string[] = [READ, WRITE_IDEMPOTENT, WRITE];\nconst HTTP_METHODS: readonly string[] = [GET, POST];\n\n/** `@Endpoint`'s four required positions, named so a failure can say which one is missing. */\nconst ARGUMENT_NAMES = ['http method', 'path', 'operation', 'trigger kind'];\n\n/** The allowed values of each required position, in the same order, for the same failure. */\nconst ARGUMENT_VALUES: readonly (readonly string[])[] = [\n HTTP_METHODS,\n [],\n ENDPOINT_OPERATIONS,\n ENDPOINT_KINDS,\n];\n\n/** The REAL document types, so a contract cannot name a document that does not exist. */\nconst API_TYPES: readonly string[] = [SVC_TO_SVC, EXTERNAL_CUSTOMER, MCP];\n\n/** The fail-closed default: a contract that declares nothing feeds only the internal document. */\nconst DEFAULT_API_TYPES: readonly string[] = [SVC_TO_SVC];\n\n/**\n * ONE contract file -> ONE {@link ApiDocModel}. The single extraction pass both the OpenAPI documents\n * and the MCP tool list (#982) are rendered from.\n *\n * ## Why the compiler API at all\n *\n * A DTO field's TYPE IS ERASED AT RUNTIME. Reflection can see that `save` takes one argument; it\n * cannot see that the argument has a `deliveryWindow` that is a discriminated union of two shapes,\n * one of which carries an ISO timestamp. Those are precisely the shapes a partner-grade document is\n * made of, so the only place they exist is the source, and the only honest way to read the source is\n * the compiler.\n *\n * ## Why it IMPORTS `@webpieces/core-util`\n *\n * Decorators are matched BY NAME on the syntax — they must be, because this reads a contract and\n * never executes it. The NAMES come from the real symbols (`Endpoint.name`), so a rename in\n * `core-util` is a compile error here instead of a literal that quietly stops matching. The full\n * argument, and why the import is not the coupling it looks like, is at those constants.\n *\n * ## What it does NOT do\n *\n * It emits nothing. No OpenAPI, no MCP tool definitions, no file — that is #982, and keeping the\n * render out means the two renderers cannot drift apart about what the contract SAYS.\n */\nexport class ApiDocExtractor {\n /**\n * Extract the contract in `entryFile`.\n *\n * @param entryFile absolute path to the `.ts` file holding the `@ApiPath` class.\n * @param compilerOptions handed straight to `ts.createProgram`; the caller owns them because\n * only the caller knows its own `paths` / `lib` setup.\n * @throws ApiDocExtractionError when the file holds no `@ApiPath` class, or when something that\n * must be exact (a path constant, a numeric bound) cannot be established.\n */\n extractFile(entryFile: string, compilerOptions: ts.CompilerOptions = {}): ApiDocModel {\n const program = ts.createProgram([entryFile], compilerOptions);\n const source = program.getSourceFile(entryFile);\n if (source === undefined) {\n throw new ApiDocExtractionError(\n 'entry file is not part of the program',\n entryFile,\n 'Pass an absolute path to a .ts file that exists.',\n );\n }\n return this.extract(program, source);\n }\n\n /**\n * EVERY `@ApiPath` contract in one file, in declaration order.\n *\n * {@link extractFile} answers \"what is THE contract in this file\", which is the shape a manifest\n * entry and a generated document have: one contract, one file. This answers a different question\n * — \"what does this file declare\" — and it exists because a REPO does not obey that convention.\n * `McpRemoteFixtures.ts` in `@webpieces/mcp-server` declares seven contracts, and the runtime\n * registers MCP tools from all seven; a sweep that read only the first would report green while\n * six contracts' worth of tools had never been looked at, which is the exact shape of silent miss\n * this epic exists to remove.\n *\n * A file with no contract yields an EMPTY list rather than throwing: \"this file has none\" is an\n * ordinary answer to this question, where it is a failure to answer {@link extractFile}'s.\n */\n extractAll(\n entryFile: string,\n compilerOptions: ts.CompilerOptions = {},\n ): readonly ApiDocModel[] {\n const program = ts.createProgram([entryFile], compilerOptions);\n const source = program.getSourceFile(entryFile);\n if (source === undefined) {\n throw new ApiDocExtractionError(\n 'entry file is not part of the program',\n entryFile,\n 'Pass an absolute path to a .ts file that exists.',\n );\n }\n return this.extractAllFrom(program, source);\n }\n\n /** {@link extractAll} against a program the caller already built. */\n extractAllFrom(program: ts.Program, source: ts.SourceFile): readonly ApiDocModel[] {\n const models: ApiDocModel[] = [];\n for (const statement of source.statements) {\n if (\n ts.isClassDeclaration(statement) &&\n ApiDocExtractor.decoratorCall(statement, API_PATH) !== undefined\n ) {\n models.push(this.extractContract(program, statement));\n }\n }\n return models;\n }\n\n /** The same extraction against a program the caller already built. */\n extract(program: ts.Program, source: ts.SourceFile): ApiDocModel {\n return this.extractContract(program, this.findContract(source));\n }\n\n /** ONE contract class -> ONE model. The single place the walk actually happens. */\n private extractContract(program: ts.Program, contract: ts.ClassDeclaration): ApiDocModel {\n const checker = program.getTypeChecker();\n const folder = new ConstantFolder(checker);\n const resolver = new TypeResolver(checker);\n\n const pathDecorator = ApiDocExtractor.decoratorCall(contract, API_PATH)!;\n const basePathArgument = pathDecorator.arguments[0];\n const basePath =\n basePathArgument === undefined\n ? ''\n : folder.foldString(basePathArgument, '@ApiPath argument');\n\n const apiTypes = this.declaredApiTypes(contract, folder);\n const endpoints: DocumentedEndpoint[] = [];\n for (const member of contract.members) {\n const endpoint = this.endpointOf(member, folder, resolver);\n if (endpoint !== undefined) {\n endpoints.push(endpoint);\n }\n }\n assertApiTypeMatchesMcpTools(contract, apiTypes, endpoints);\n\n return new ApiDocModel(\n contract.name?.text ?? '<anonymous>',\n apiTypes,\n basePath,\n JsDoc.read(contract).description,\n endpoints,\n resolver.collectedTypes(),\n resolver.collectedUnmapped(),\n );\n }\n\n /**\n * Extract ONE named type and everything it reaches, from a file that holds NO contract.\n *\n * This exists for a type nothing in a contract points at but a document still publishes — the\n * document-wide error body a renderer's manifest names. Reading it with the SAME resolver is the\n * point: a second reader would be a second answer to \"what shape is this type\", and the two\n * would drift the first time a field changed.\n *\n * @throws ApiDocExtractionError when the file does not declare that name.\n */\n extractType(\n entryFile: string,\n typeName: string,\n compilerOptions: ts.CompilerOptions = {},\n ): ApiDocModel {\n const program = ts.createProgram([entryFile], compilerOptions);\n const source = program.getSourceFile(entryFile);\n if (source === undefined) {\n throw new ApiDocExtractionError(\n 'entry file is not part of the program',\n entryFile,\n 'Pass an absolute path to a .ts file that exists.',\n );\n }\n const resolver = new TypeResolver(program.getTypeChecker());\n const declaration = ApiDocExtractor.declarationNamed(source, typeName);\n if (declaration === undefined) {\n throw new ApiDocExtractionError(\n `no type named '${typeName}' is declared in this file`,\n entryFile,\n `Declare and export '${typeName}' there, or name the file that does.`,\n );\n }\n resolver.resolveDeclaration(typeName, declaration, typeName);\n return new ApiDocModel(\n typeName,\n DEFAULT_API_TYPES,\n '',\n '',\n [],\n resolver.collectedTypes(),\n resolver.collectedUnmapped(),\n );\n }\n\n /** The interface / class / type alias / enum declared under `name` at the file's top level. */\n // webpieces-disable no-function-outside-class -- private static reader of this class\n private static declarationNamed(\n source: ts.SourceFile,\n name: string,\n ): ts.Declaration | undefined {\n for (const statement of source.statements) {\n const named =\n ts.isInterfaceDeclaration(statement) ||\n ts.isClassDeclaration(statement) ||\n ts.isTypeAliasDeclaration(statement) ||\n ts.isEnumDeclaration(statement);\n if (named && statement.name?.text === name) {\n return statement;\n }\n }\n return undefined;\n }\n\n /** The one `@ApiPath` class in the file. Zero is a hard failure; the FIRST wins if there are two. */\n private findContract(source: ts.SourceFile): ts.ClassDeclaration {\n for (const statement of source.statements) {\n if (\n ts.isClassDeclaration(statement) &&\n ApiDocExtractor.decoratorCall(statement, API_PATH) !== undefined\n ) {\n return statement;\n }\n }\n throw new ApiDocExtractionError(\n 'no @ApiPath class in this file',\n source.fileName,\n 'Point the extractor at the contract file — the one whose class carries @ApiPath.',\n );\n }\n\n /** One `@Endpoint` method. Members without the decorator are not part of the contract. */\n private endpointOf(\n member: ts.ClassElement,\n folder: ConstantFolder,\n resolver: TypeResolver,\n ): DocumentedEndpoint | undefined {\n if (!ts.isMethodDeclaration(member) || !ts.isIdentifier(member.name)) {\n return undefined;\n }\n const call = ApiDocExtractor.decoratorCall(member, ENDPOINT);\n if (call === undefined) {\n return undefined;\n }\n const methodName = member.name.text;\n\n // `@Endpoint(httpMethod, path, operation, kind, options?)` — METHOD-FIRST, five positions.\n // The positions are read here and nowhere else, so the one place that has to change when the\n // decorator changes is this block plus `ARGUMENT_NAMES` beside it.\n const httpMethod = this.requiredArgument(call, methodName, 0, folder);\n const path = this.requiredArgument(call, methodName, 1, folder);\n const operation = this.requiredArgument(call, methodName, 2, folder);\n const kind = this.requiredArgument(call, methodName, 3, folder);\n\n const options = call.arguments[4];\n const literal =\n options !== undefined && ts.isObjectLiteralExpression(options) ? options : undefined;\n\n const doc = JsDoc.read(member);\n const mcpTool = ApiDocExtractor.mcpToolOf(member, folder);\n return new DocumentedEndpoint(\n methodName,\n httpMethod,\n path,\n operation,\n kind,\n ApiDocExtractor.booleanProperty(literal, 'hidden'),\n ApiDocExtractor.booleanProperty(literal, 'openWorld'),\n new DocumentedEndpointOptions(\n ApiDocExtractor.booleanProperty(literal, 'formPost'),\n ApiDocExtractor.stringProperty(literal, 'calledBy', folder),\n ApiDocExtractor.stringProperty(literal, 'callerKind', folder),\n ),\n ApiDocExtractor.authOf(member, folder),\n mcpTool,\n ApiDocExtractor.invalidForMcpOf(member, folder),\n ApiDocExtractor.decoratorCall(member, MCP_AUTH)?.arguments[0]?.getText(),\n ApiDocExtractor.maskLogOf(member),\n doc.description,\n doc.mcp,\n this.requestOf(member, methodName, resolver),\n this.responseOf(member, methodName, resolver),\n );\n }\n\n /**\n * One REQUIRED positional argument of `@Endpoint`, folded to the string it denotes.\n *\n * Every one of the four is an enum member (`POST`, `READ`, `RPC`) as often as it is a literal,\n * and the folder resolves both — a document that printed `RPC` where the trigger goes would be\n * worse than no document. A missing one is a hard failure naming the position, because the\n * alternative is a document quietly missing a verb.\n */\n private requiredArgument(\n call: ts.CallExpression,\n methodName: string,\n index: number,\n folder: ConstantFolder,\n ): string {\n const argument = call.arguments[index];\n const what = ARGUMENT_NAMES[index];\n if (argument === undefined) {\n throw new ApiDocExtractionError(\n `@Endpoint on '${methodName}' declares no ${what}`,\n SourceLocation.of(call),\n \"Write all four: @Endpoint(POST, '/thing', READ, RPC).\",\n );\n }\n const value = folder.foldString(argument, `@Endpoint ${what} on '${methodName}'`);\n const allowed = ARGUMENT_VALUES[index]!;\n if (allowed.length > 0 && !allowed.includes(value)) {\n throw new ApiDocExtractionError(\n `@Endpoint on '${methodName}' declares ${what} '${value}', which is not one of ` +\n allowed.join(', '),\n SourceLocation.of(argument),\n `Use one of the exported constants: ${allowed.join(', ')}.`,\n );\n }\n return value;\n }\n\n /**\n * `@ApiType(...)` on the contract, folded to the real values.\n *\n * A value that is not one of the three documents is a HARD FAILURE rather than a silent drop: a\n * contract that named `CUSTOMER` by mistake would otherwise feed nothing, which looks exactly\n * like a contract somebody deliberately kept internal.\n */\n private declaredApiTypes(node: ts.Node, folder: ConstantFolder): readonly string[] {\n const call = ApiDocExtractor.decoratorCall(node, API_TYPE);\n if (call === undefined) {\n return DEFAULT_API_TYPES;\n }\n const declared = call.arguments.map((argument: ts.Expression) =>\n folder.foldString(argument, `@${API_TYPE} argument`),\n );\n for (const apiType of declared) {\n if (!API_TYPES.includes(apiType)) {\n throw new ApiDocExtractionError(\n `@${API_TYPE} names '${apiType}', which is not a generated document`,\n SourceLocation.of(call),\n `Use one of the exported constants: ${API_TYPES.join(', ')}.`,\n );\n }\n }\n return declared.length === 0 ? DEFAULT_API_TYPES : declared;\n }\n\n /** The FIRST parameter's declared type. An endpoint with no parameter has no request document. */\n private requestOf(\n member: ts.MethodDeclaration,\n methodName: string,\n resolver: TypeResolver,\n ): TypeRef | undefined {\n const parameter = member.parameters[0];\n if (parameter?.type === undefined) {\n return undefined;\n }\n return resolver.resolve(parameter.type, `${methodName}.request`);\n }\n\n /** The declared return type, unwrapped from `Promise<...>` by the resolver. */\n private responseOf(\n member: ts.MethodDeclaration,\n methodName: string,\n resolver: TypeResolver,\n ): TypeRef | undefined {\n if (member.type === undefined) {\n return undefined;\n }\n return resolver.resolve(member.type, `${methodName}.response`);\n }\n\n /** `@WpAuthPublic()`, `@WpAuthJwt({...})`, … — recorded verbatim; this package rules on nothing. */\n // webpieces-disable no-function-outside-class -- private static reader of this class\n private static authOf(member: ts.Node, folder: ConstantFolder): DocumentedAuth | undefined {\n const decorators = ts.canHaveDecorators(member) ? (ts.getDecorators(member) ?? []) : [];\n for (const decorator of decorators) {\n const call = decorator.expression;\n if (!ts.isCallExpression(call) || !ts.isIdentifier(call.expression)) {\n continue;\n }\n const name = call.expression.text;\n if (name.startsWith(AUTH_PREFIX) && AUTH_DECORATORS.has(name)) {\n return new DocumentedAuth(\n name,\n call.arguments.map((argument: ts.Expression) => argument.getText()),\n name === API_KEY_AUTH ? ApiDocExtractor.apiKeyOf(call, folder) : undefined,\n );\n }\n }\n return undefined;\n }\n\n /**\n * `@WpAuthApiKey(regime, [{in: 'header', name: 'x-api-key', description: '…'}, …])`, parsed.\n *\n * A malformed declaration FAILS rather than yielding a half-parsed regime: the credentials are\n * what a published document's security block is made of, and a document that silently omitted\n * one would tell a partner they need fewer credentials than the running hook demands.\n */\n // webpieces-disable no-function-outside-class -- private static reader of this class\n private static apiKeyOf(call: ts.CallExpression, folder: ConstantFolder): DocumentedApiKey {\n const regimeArgument = call.arguments[0];\n const credentialsArgument = call.arguments[1];\n if (regimeArgument === undefined || credentialsArgument === undefined) {\n throw new ApiDocExtractionError(\n '@WpAuthApiKey needs a regime AND its credentials',\n SourceLocation.of(call),\n \"Write both: @WpAuthApiKey('partner', [{ in: 'header', name: 'x-api-key' }]).\",\n );\n }\n const regime = folder.foldString(regimeArgument, '@WpAuthApiKey regime');\n // FOLLOW a name first: a credential list shared by every method of a contract is written\n // once as a `const` and named per method, which is better source than a copy per method.\n const credentialsLiteral = folder.follow(credentialsArgument);\n if (!ts.isArrayLiteralExpression(credentialsLiteral)) {\n throw new ApiDocExtractionError(\n '@WpAuthApiKey credentials is not an array literal',\n SourceLocation.of(credentialsArgument),\n 'Write the credentials as an array literal, inline or in a `const`; a value ' +\n 'assembled at runtime cannot appear in a published security scheme.',\n );\n }\n const credentials: DocumentedApiKeyCredential[] = [];\n for (const element of credentialsLiteral.elements) {\n credentials.push(ApiDocExtractor.credentialOf(element, folder));\n }\n return new DocumentedApiKey(regime, credentials);\n }\n\n /** ONE `{ in: …, name?: …, description?: … }` credential. */\n // webpieces-disable no-function-outside-class -- private static reader of this class\n private static credentialOf(\n expression: ts.Expression,\n folder: ConstantFolder,\n ): DocumentedApiKeyCredential {\n const element = folder.follow(expression);\n if (!ts.isObjectLiteralExpression(element)) {\n throw new ApiDocExtractionError(\n 'an @WpAuthApiKey credential is not an object literal',\n SourceLocation.of(element),\n \"Write it inline: { in: 'header', name: 'x-api-key' }.\",\n );\n }\n const location = ApiDocExtractor.stringProperty(element, 'in', folder);\n if (location === undefined) {\n throw new ApiDocExtractionError(\n 'an @WpAuthApiKey credential declares no `in`',\n SourceLocation.of(element),\n \"Say where it rides: `in: 'header'` with a name, or `in: 'bearer'`.\",\n );\n }\n return new DocumentedApiKeyCredential(\n location,\n ApiDocExtractor.stringProperty(element, 'name', folder),\n ApiDocExtractor.stringProperty(element, 'description', folder),\n );\n }\n\n /**\n * `@WpMcpTool('search_stores')` — the stable protocol name, which is the ONE fact the source\n * cannot otherwise state.\n *\n * Nothing else is read because nothing else is declared there any more (#984): the method's JSDoc\n * is the description for the agent and the partner alike, the three side-effect hints are computed\n * from the endpoint's `operation`, and `openWorldHint` is `@Endpoint`'s `openWorld`. See\n * {@link DocumentedMcpTool}.\n */\n // webpieces-disable no-function-outside-class -- private static reader of this class\n private static mcpToolOf(\n member: ts.Node,\n folder: ConstantFolder,\n ): DocumentedMcpTool | undefined {\n const call = ApiDocExtractor.decoratorCall(member, MCP_TOOL);\n const argument = call?.arguments[0];\n if (argument === undefined) {\n return undefined;\n }\n return new DocumentedMcpTool(folder.tryFoldString(argument) ?? '');\n }\n\n /**\n * `@InvalidEndpointForMcp('<reason>')`'s reason, or undefined.\n *\n * A reason that will not fold is read as the EMPTY STRING rather than as \"no decorator\": the\n * method is still permanently outside MCP, and losing that fact because the argument was written\n * as a cross-module constant would silently put the endpoint back in the candidate set.\n */\n // webpieces-disable no-function-outside-class -- private static reader of this class\n private static invalidForMcpOf(\n member: ts.Node,\n folder: ConstantFolder,\n ): string | undefined {\n const call = ApiDocExtractor.decoratorCall(member, MCP_INVALID);\n if (call === undefined) {\n return undefined;\n }\n const argument = call.arguments[0];\n return argument === undefined ? '' : (folder.tryFoldString(argument) ?? '');\n }\n\n /** `@MaskLog({ refreshToken: 'full' })` -> field name -> mask mode. */\n // webpieces-disable no-function-outside-class -- private static reader of this class\n private static maskLogOf(member: ts.Node): ReadonlyMap<string, string> {\n const fields = new Map<string, string>();\n const argument = ApiDocExtractor.decoratorCall(member, MASK_LOG)?.arguments[0];\n if (argument === undefined || !ts.isObjectLiteralExpression(argument)) {\n return fields;\n }\n for (const property of argument.properties) {\n if (\n ts.isPropertyAssignment(property) &&\n (ts.isIdentifier(property.name) || ts.isStringLiteral(property.name)) &&\n ts.isStringLiteralLike(property.initializer)\n ) {\n fields.set(property.name.text, property.initializer.text);\n }\n }\n return fields;\n }\n\n // webpieces-disable no-function-outside-class -- private static reader of this class\n private static booleanProperty(\n literal: ts.ObjectLiteralExpression | undefined,\n name: string,\n ): boolean {\n const value =\n literal === undefined ? undefined : ApiDocExtractor.findProperty(literal, name);\n return value?.kind === ts.SyntaxKind.TrueKeyword;\n }\n\n // webpieces-disable no-function-outside-class -- private static reader of this class\n private static stringProperty(\n literal: ts.ObjectLiteralExpression | undefined,\n name: string,\n folder: ConstantFolder,\n ): string | undefined {\n const value =\n literal === undefined ? undefined : ApiDocExtractor.findProperty(literal, name);\n return value === undefined ? undefined : folder.tryFoldString(value);\n }\n\n // webpieces-disable no-function-outside-class -- private static reader of this class\n private static findProperty(\n literal: ts.ObjectLiteralExpression,\n name: string,\n ): ts.Expression | undefined {\n for (const property of literal.properties) {\n if (\n ts.isPropertyAssignment(property) &&\n (ts.isIdentifier(property.name) || ts.isStringLiteral(property.name)) &&\n property.name.text === name\n ) {\n return property.initializer;\n }\n }\n return undefined;\n }\n\n // webpieces-disable no-function-outside-class -- private static reader of this class\n private static decoratorCall(\n node: ts.Node,\n decoratorName: string,\n ): ts.CallExpression | undefined {\n const decorators = ts.canHaveDecorators(node) ? (ts.getDecorators(node) ?? []) : [];\n for (const decorator of decorators) {\n const call = decorator.expression;\n if (\n ts.isCallExpression(call) &&\n ts.isIdentifier(call.expression) &&\n call.expression.text === decoratorName\n ) {\n return call;\n }\n }\n return undefined;\n }\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { DocumentedEndpoint } from '../model/ApiDocModel';
|
|
3
|
+
/**
|
|
4
|
+
* MCP membership has exactly ONE spelling, and this is the BUILD-TIME half of enforcing it
|
|
5
|
+
* (`assertApiTypeMatchesMcpTools` in `@webpieces/core-util` is the wiring-time half).
|
|
6
|
+
*
|
|
7
|
+
* Declared in two places, the two can disagree — and the disagreement is invisible, because each
|
|
8
|
+
* declaration is individually valid. That is the defect this whole epic exists to remove, so it
|
|
9
|
+
* fails the DOCUMENT build rather than producing one that quietly lists the wrong tools.
|
|
10
|
+
*
|
|
11
|
+
* `@InvalidEndpointForMcp` (#1014) sits OUTSIDE the biconditional and is checked here too. A method
|
|
12
|
+
* declared permanently unusable as a tool is neither required to carry `@WpMcpTool` nor permitted
|
|
13
|
+
* to, and a contract whose every endpoint is so declared must not name MCP at all — the cure there
|
|
14
|
+
* is the opposite one, so it gets its own sentence rather than being folded into "no method carries
|
|
15
|
+
* @WpMcpTool".
|
|
16
|
+
*
|
|
17
|
+
* Split out of `ApiDocExtractor`, which owns the walk and is at its file-size limit.
|
|
18
|
+
*/
|
|
19
|
+
export declare function assertApiTypeMatchesMcpTools(contract: ts.ClassDeclaration, apiTypes: readonly string[], endpoints: readonly DocumentedEndpoint[]): void;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assertApiTypeMatchesMcpTools = assertApiTypeMatchesMcpTools;
|
|
4
|
+
const core_util_1 = require("@webpieces/core-util");
|
|
5
|
+
const ApiDocExtractionError_1 = require("./ApiDocExtractionError");
|
|
6
|
+
const SourceLocation_1 = require("./SourceLocation");
|
|
7
|
+
/**
|
|
8
|
+
* The decorator names, taken from the REAL SYMBOLS for the reason `ApiDocExtractor`'s constants give
|
|
9
|
+
* at length: a literal that stops matching after a rename empties a document with the build green.
|
|
10
|
+
*/
|
|
11
|
+
const API_TYPE = core_util_1.ApiType.name;
|
|
12
|
+
const MCP_TOOL = core_util_1.WpMcpTool.name;
|
|
13
|
+
const MCP_INVALID = core_util_1.InvalidEndpointForMcp.name;
|
|
14
|
+
/**
|
|
15
|
+
* MCP membership has exactly ONE spelling, and this is the BUILD-TIME half of enforcing it
|
|
16
|
+
* (`assertApiTypeMatchesMcpTools` in `@webpieces/core-util` is the wiring-time half).
|
|
17
|
+
*
|
|
18
|
+
* Declared in two places, the two can disagree — and the disagreement is invisible, because each
|
|
19
|
+
* declaration is individually valid. That is the defect this whole epic exists to remove, so it
|
|
20
|
+
* fails the DOCUMENT build rather than producing one that quietly lists the wrong tools.
|
|
21
|
+
*
|
|
22
|
+
* `@InvalidEndpointForMcp` (#1014) sits OUTSIDE the biconditional and is checked here too. A method
|
|
23
|
+
* declared permanently unusable as a tool is neither required to carry `@WpMcpTool` nor permitted
|
|
24
|
+
* to, and a contract whose every endpoint is so declared must not name MCP at all — the cure there
|
|
25
|
+
* is the opposite one, so it gets its own sentence rather than being folded into "no method carries
|
|
26
|
+
* @WpMcpTool".
|
|
27
|
+
*
|
|
28
|
+
* Split out of `ApiDocExtractor`, which owns the walk and is at its file-size limit.
|
|
29
|
+
*/
|
|
30
|
+
// webpieces-disable no-function-outside-class -- module entry point, mirrors the extractor's own split-out helpers
|
|
31
|
+
function assertApiTypeMatchesMcpTools(contract, apiTypes, endpoints) {
|
|
32
|
+
const tools = endpoints.filter((e) => e.mcpTool !== undefined);
|
|
33
|
+
const excluded = endpoints.filter((e) => e.invalidForMcp !== undefined);
|
|
34
|
+
const declaresMcp = apiTypes.includes(core_util_1.MCP);
|
|
35
|
+
assertNoToolIsAlsoExcluded(contract, tools);
|
|
36
|
+
if (declaresMcp && tools.length === 0 && excluded.length === endpoints.length) {
|
|
37
|
+
throw new ApiDocExtractionError_1.ApiDocExtractionError(`@${API_TYPE} names MCP but EVERY endpoint is @${MCP_INVALID}`, SourceLocation_1.SourceLocation.of(contract), `Drop MCP from the @${API_TYPE} list — a contract whose every method is permanently ` +
|
|
38
|
+
'outside MCP does not feed the MCP document.');
|
|
39
|
+
}
|
|
40
|
+
if (declaresMcp && tools.length === 0) {
|
|
41
|
+
throw new ApiDocExtractionError_1.ApiDocExtractionError(`@${API_TYPE} names MCP but no method carries @${MCP_TOOL}`, SourceLocation_1.SourceLocation.of(contract), `Add @${MCP_TOOL}('<stable_tool_name>') to the methods agents may call, or drop MCP ` +
|
|
42
|
+
`from the @${API_TYPE} list.`);
|
|
43
|
+
}
|
|
44
|
+
if (!declaresMcp && tools.length > 0) {
|
|
45
|
+
const named = tools.map((e) => e.methodName).join(', ');
|
|
46
|
+
throw new ApiDocExtractionError_1.ApiDocExtractionError(`@${MCP_TOOL} is on ${named} but @${API_TYPE} does not name MCP`, SourceLocation_1.SourceLocation.of(contract), `Add MCP to the @${API_TYPE} list — membership has ONE spelling, so a tool on a ` +
|
|
47
|
+
'contract nobody published to agents is a contradiction, not a hint.');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* `@WpMcpTool` and `@InvalidEndpointForMcp` on ONE method is a contradiction, not a precedence rule.
|
|
52
|
+
*
|
|
53
|
+
* Resolving it either way would make the pair a second spelling of a decision that already has one,
|
|
54
|
+
* and whichever way it resolved, half the readers of that method would be wrong about what it does.
|
|
55
|
+
*/
|
|
56
|
+
// webpieces-disable no-function-outside-class -- private assert of the entry point above, beside it
|
|
57
|
+
function assertNoToolIsAlsoExcluded(contract, tools) {
|
|
58
|
+
const both = tools
|
|
59
|
+
.filter((e) => e.invalidForMcp !== undefined)
|
|
60
|
+
.map((e) => e.methodName);
|
|
61
|
+
if (both.length === 0)
|
|
62
|
+
return;
|
|
63
|
+
throw new ApiDocExtractionError_1.ApiDocExtractionError(`@${MCP_TOOL} and @${MCP_INVALID} are BOTH on ${both.join(', ')}`, SourceLocation_1.SourceLocation.of(contract), 'They contradict each other — one publishes the method to agents and the other declares it ' +
|
|
64
|
+
'permanently unusable as a tool. Delete whichever one is wrong.');
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=McpMembership.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"McpMembership.js","sourceRoot":"","sources":["../../../../../../packages/docs/api-doc-model/src/extract/McpMembership.ts"],"names":[],"mappings":";;AA+BA,oEAkCC;AAhED,oDAAsF;AAEtF,mEAAgE;AAChE,qDAAkD;AAElD;;;GAGG;AACH,MAAM,QAAQ,GAAG,mBAAO,CAAC,IAAI,CAAC;AAC9B,MAAM,QAAQ,GAAG,qBAAS,CAAC,IAAI,CAAC;AAChC,MAAM,WAAW,GAAG,iCAAqB,CAAC,IAAI,CAAC;AAE/C;;;;;;;;;;;;;;;GAeG;AACH,mHAAmH;AACnH,SAAgB,4BAA4B,CACxC,QAA6B,EAC7B,QAA2B,EAC3B,SAAwC;IAExC,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAqB,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC;IACnF,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAqB,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC;IAC5F,MAAM,WAAW,GAAG,QAAQ,CAAC,QAAQ,CAAC,eAAG,CAAC,CAAC;IAC3C,0BAA0B,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC5C,IAAI,WAAW,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM,EAAE,CAAC;QAC5E,MAAM,IAAI,6CAAqB,CAC3B,IAAI,QAAQ,qCAAqC,WAAW,EAAE,EAC9D,+BAAc,CAAC,EAAE,CAAC,QAAQ,CAAC,EAC3B,sBAAsB,QAAQ,uDAAuD;YACjF,6CAA6C,CACpD,CAAC;IACN,CAAC;IACD,IAAI,WAAW,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,6CAAqB,CAC3B,IAAI,QAAQ,qCAAqC,QAAQ,EAAE,EAC3D,+BAAc,CAAC,EAAE,CAAC,QAAQ,CAAC,EAC3B,QAAQ,QAAQ,qEAAqE;YACjF,aAAa,QAAQ,QAAQ,CACpC,CAAC;IACN,CAAC;IACD,IAAI,CAAC,WAAW,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAqB,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5E,MAAM,IAAI,6CAAqB,CAC3B,IAAI,QAAQ,UAAU,KAAK,SAAS,QAAQ,oBAAoB,EAChE,+BAAc,CAAC,EAAE,CAAC,QAAQ,CAAC,EAC3B,mBAAmB,QAAQ,sDAAsD;YAC7E,qEAAqE,CAC5E,CAAC;IACN,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,oGAAoG;AACpG,SAAS,0BAA0B,CAC/B,QAA6B,EAC7B,KAAoC;IAEpC,MAAM,IAAI,GAAG,KAAK;SACb,MAAM,CAAC,CAAC,CAAqB,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,KAAK,SAAS,CAAC;SAChE,GAAG,CAAC,CAAC,CAAqB,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IAClD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAC9B,MAAM,IAAI,6CAAqB,CAC3B,IAAI,QAAQ,SAAS,WAAW,gBAAgB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EACjE,+BAAc,CAAC,EAAE,CAAC,QAAQ,CAAC,EAC3B,4FAA4F;QACxF,gEAAgE,CACvE,CAAC;AACN,CAAC","sourcesContent":["import * as ts from 'typescript';\nimport { ApiType, InvalidEndpointForMcp, MCP, WpMcpTool } from '@webpieces/core-util';\nimport { DocumentedEndpoint } from '../model/ApiDocModel';\nimport { ApiDocExtractionError } from './ApiDocExtractionError';\nimport { SourceLocation } from './SourceLocation';\n\n/**\n * The decorator names, taken from the REAL SYMBOLS for the reason `ApiDocExtractor`'s constants give\n * at length: a literal that stops matching after a rename empties a document with the build green.\n */\nconst API_TYPE = ApiType.name;\nconst MCP_TOOL = WpMcpTool.name;\nconst MCP_INVALID = InvalidEndpointForMcp.name;\n\n/**\n * MCP membership has exactly ONE spelling, and this is the BUILD-TIME half of enforcing it\n * (`assertApiTypeMatchesMcpTools` in `@webpieces/core-util` is the wiring-time half).\n *\n * Declared in two places, the two can disagree — and the disagreement is invisible, because each\n * declaration is individually valid. That is the defect this whole epic exists to remove, so it\n * fails the DOCUMENT build rather than producing one that quietly lists the wrong tools.\n *\n * `@InvalidEndpointForMcp` (#1014) sits OUTSIDE the biconditional and is checked here too. A method\n * declared permanently unusable as a tool is neither required to carry `@WpMcpTool` nor permitted\n * to, and a contract whose every endpoint is so declared must not name MCP at all — the cure there\n * is the opposite one, so it gets its own sentence rather than being folded into \"no method carries\n * @WpMcpTool\".\n *\n * Split out of `ApiDocExtractor`, which owns the walk and is at its file-size limit.\n */\n// webpieces-disable no-function-outside-class -- module entry point, mirrors the extractor's own split-out helpers\nexport function assertApiTypeMatchesMcpTools(\n contract: ts.ClassDeclaration,\n apiTypes: readonly string[],\n endpoints: readonly DocumentedEndpoint[],\n): void {\n const tools = endpoints.filter((e: DocumentedEndpoint) => e.mcpTool !== undefined);\n const excluded = endpoints.filter((e: DocumentedEndpoint) => e.invalidForMcp !== undefined);\n const declaresMcp = apiTypes.includes(MCP);\n assertNoToolIsAlsoExcluded(contract, tools);\n if (declaresMcp && tools.length === 0 && excluded.length === endpoints.length) {\n throw new ApiDocExtractionError(\n `@${API_TYPE} names MCP but EVERY endpoint is @${MCP_INVALID}`,\n SourceLocation.of(contract),\n `Drop MCP from the @${API_TYPE} list — a contract whose every method is permanently ` +\n 'outside MCP does not feed the MCP document.',\n );\n }\n if (declaresMcp && tools.length === 0) {\n throw new ApiDocExtractionError(\n `@${API_TYPE} names MCP but no method carries @${MCP_TOOL}`,\n SourceLocation.of(contract),\n `Add @${MCP_TOOL}('<stable_tool_name>') to the methods agents may call, or drop MCP ` +\n `from the @${API_TYPE} list.`,\n );\n }\n if (!declaresMcp && tools.length > 0) {\n const named = tools.map((e: DocumentedEndpoint) => e.methodName).join(', ');\n throw new ApiDocExtractionError(\n `@${MCP_TOOL} is on ${named} but @${API_TYPE} does not name MCP`,\n SourceLocation.of(contract),\n `Add MCP to the @${API_TYPE} list — membership has ONE spelling, so a tool on a ` +\n 'contract nobody published to agents is a contradiction, not a hint.',\n );\n }\n}\n\n/**\n * `@WpMcpTool` and `@InvalidEndpointForMcp` on ONE method is a contradiction, not a precedence rule.\n *\n * Resolving it either way would make the pair a second spelling of a decision that already has one,\n * and whichever way it resolved, half the readers of that method would be wrong about what it does.\n */\n// webpieces-disable no-function-outside-class -- private assert of the entry point above, beside it\nfunction assertNoToolIsAlsoExcluded(\n contract: ts.ClassDeclaration,\n tools: readonly DocumentedEndpoint[],\n): void {\n const both = tools\n .filter((e: DocumentedEndpoint) => e.invalidForMcp !== undefined)\n .map((e: DocumentedEndpoint) => e.methodName);\n if (both.length === 0) return;\n throw new ApiDocExtractionError(\n `@${MCP_TOOL} and @${MCP_INVALID} are BOTH on ${both.join(', ')}`,\n SourceLocation.of(contract),\n 'They contradict each other — one publishes the method to agents and the other declares it ' +\n 'permanently unusable as a tool. Delete whichever one is wrong.',\n );\n}\n"]}
|
|
@@ -380,7 +380,7 @@ class TypeResolver {
|
|
|
380
380
|
const min = this.numericArgument(member, MIN_DECORATOR);
|
|
381
381
|
const max = this.numericArgument(member, MAX_DECORATOR);
|
|
382
382
|
this.assertNumericConstraintsFit(member, name, type, min, max);
|
|
383
|
-
return new ApiDocModel_1.DocumentedField(name, type, optional, nullable, doc.description, doc.mcp, doc.format, min, max, doc.mcpHeader);
|
|
383
|
+
return new ApiDocModel_1.DocumentedField(name, type, optional, nullable, doc.description, doc.mcp, doc.format, min, max, doc.mcpHeader, SourceLocation_1.SourceLocation.of(member));
|
|
384
384
|
}
|
|
385
385
|
/**
|
|
386
386
|
* `@WpMin` / `@WpMax` on a non-numeric field is a BUILD FAILURE, not a warning. A minimum on a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TypeResolver.js","sourceRoot":"","sources":["../../../../../../packages/docs/api-doc-model/src/extract/TypeResolver.ts"],"names":[],"mappings":"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","sourcesContent":["import * as ts from 'typescript';\nimport { WpInt, WpMax, WpMin } from '@webpieces/core-util';\nimport {\n DocumentedField,\n DocumentedType,\n UnionDiscriminator,\n UnmappedType,\n} from '../model/ApiDocModel';\nimport { PrimitiveKind, TypeRef } from '../model/TypeRef';\nimport { ApiDocExtractionError } from './ApiDocExtractionError';\nimport { JsDoc } from './JsDoc';\nimport { SourceLocation } from './SourceLocation';\n\n/**\n * The decorators this resolver reads off a DTO property, named from the REAL SYMBOLS — a rename in\n * `core-util` is a compile error here rather than a literal that quietly stops matching. See\n * {@link ApiDocExtractor}'s constants for the full argument (issue #1001).\n */\nconst INT_DECORATOR = WpInt.name;\nconst MIN_DECORATOR = WpMin.name;\nconst MAX_DECORATOR = WpMax.name;\n\n/**\n * The type-alias name that DECLARES integer-ness.\n *\n * This one is a LITERAL and cannot be anything else: `Integer` is a TYPE ALIAS, so there is no\n * runtime symbol whose `.name` could be read — `.name` is a property of a function, and a type has\n * erased by then. It is the one name in this package that a rename in `core-util` would not break at\n * compile time; the cure if that ever bites is to make integer-ness a decorator here too, not to\n * pretend a type has a runtime identity. See {@link ApiDocExtractor}'s constants for the argument\n * everywhere else (issue #1001).\n */\nconst INTEGER_ALIAS = 'Integer';\n\n/**\n * Resolve declared TypeScript types into {@link TypeRef}s, registering every NAMED type it meets as\n * a {@link DocumentedType} a renderer can `$ref`.\n *\n * ## It walks TYPE NODES, not checker types, and that is load-bearing\n *\n * `type Integer = number` resolves, in the checker, to `number` — the alias is gone. Integer-ness is\n * therefore invisible to a checker-driven walk, and the whole reason `Integer` is the PREFERRED\n * spelling is that it COMPOSES: `Integer[]` and `Record<string, Integer>` say exactly which thing is\n * an integer, where a decorator on `counts?: number[]` cannot (the same ambiguity the deleted\n * `arrayItems` argument had). Walking the written syntax is what keeps that composition readable.\n *\n * ## Cycles terminate BY CONSTRUCTION\n *\n * Every named type is ONE entry in the model, registered before its fields are walked, so a type\n * that refers back to itself resolves to a `$ref` at the second visit and stops. There is NO depth\n * counter anywhere — a deep-but-finite graph of 7, 20 or 200 named hops is fully expanded, because\n * truncating one would silently publish an incomplete document. The ONLY thing that is cut is a\n * self-referential ANONYMOUS type, and it is cut by NODE IDENTITY (it has no name to `$ref`), with an\n * {@link UnmappedType} recorded so #982's guard has something to name.\n */\nexport class TypeResolver {\n private readonly types = new Map<string, DocumentedType>();\n private readonly unmapped: UnmappedType[] = [];\n /** Named types already registered (or mid-registration) — the cycle stop for the NAMED case. */\n private readonly registered = new Set<string>();\n /** Anonymous type literals currently being expanded — the cycle stop for the ANONYMOUS case. */\n private readonly expandingAnonymous = new Set<ts.TypeNode>();\n\n constructor(private readonly checker: ts.TypeChecker) {}\n\n /** Every named type reached so far, by name. */\n collectedTypes(): ReadonlyMap<string, DocumentedType> {\n return this.types;\n }\n\n /** Everything that could not be represented — recorded, never dropped. */\n collectedUnmapped(): readonly UnmappedType[] {\n return this.unmapped;\n }\n\n /** Resolve one written type, registering whatever named types it reaches. */\n resolve(node: ts.TypeNode, ownerName: string): TypeRef {\n if (ts.isParenthesizedTypeNode(node)) {\n return this.resolve(node.type, ownerName);\n }\n if (ts.isArrayTypeNode(node)) {\n return TypeRef.array(this.resolve(node.elementType, ownerName));\n }\n if (ts.isUnionTypeNode(node)) {\n return this.resolveUnion(node, ownerName);\n }\n if (ts.isTypeLiteralNode(node)) {\n return this.resolveAnonymousObject(node, ownerName);\n }\n if (ts.isLiteralTypeNode(node)) {\n return this.resolveLiteral(node);\n }\n if (ts.isTypeReferenceNode(node)) {\n return this.resolveReference(node, ownerName);\n }\n const primitive = TypeResolver.keywordOf(node.kind);\n if (primitive !== undefined) {\n return TypeRef.primitiveOf(primitive);\n }\n return this.recordUnmapped(node, 'no model representation for this type form');\n }\n\n /** `string` / `number` / `boolean` / `null` / `unknown`, or undefined for anything else. */\n // webpieces-disable no-function-outside-class -- private static lookup table of this class\n private static keywordOf(kind: ts.SyntaxKind): PrimitiveKind | undefined {\n switch (kind) {\n case ts.SyntaxKind.StringKeyword:\n return 'string';\n case ts.SyntaxKind.NumberKeyword:\n return 'number';\n case ts.SyntaxKind.BooleanKeyword:\n return 'boolean';\n case ts.SyntaxKind.NullKeyword:\n return 'null';\n case ts.SyntaxKind.UnknownKeyword:\n case ts.SyntaxKind.AnyKeyword:\n case ts.SyntaxKind.VoidKeyword:\n return 'unknown';\n default:\n return undefined;\n }\n }\n\n private resolveLiteral(node: ts.LiteralTypeNode): TypeRef {\n if (ts.isStringLiteral(node.literal)) {\n return TypeRef.enumOf([node.literal.text]);\n }\n if (node.literal.kind === ts.SyntaxKind.NullKeyword) {\n return TypeRef.primitiveOf('null');\n }\n if (\n node.literal.kind === ts.SyntaxKind.TrueKeyword ||\n node.literal.kind === ts.SyntaxKind.FalseKeyword\n ) {\n return TypeRef.primitiveOf('boolean');\n }\n if (ts.isNumericLiteral(node.literal)) {\n return TypeRef.primitiveOf('number');\n }\n return this.recordUnmapped(\n node,\n 'literal type is neither a string, a number nor a boolean',\n );\n }\n\n /**\n * A union, after `null` / `undefined` have been dropped (the FIELD records those as nullable /\n * optional — see {@link fieldOf} — because `{}` and `{x: null}` are different wire documents).\n *\n * Three outcomes, in this order:\n * - every branch a string literal -> an ENUM\n * - one branch left -> that branch\n * - every branch a named object -> a UNION, with a DERIVED discriminator when every branch\n * carries the same property typed as ONE string literal\n * - anything else -> an {@link UnmappedType}. No invented discriminator, ever:\n * a union TypeScript itself cannot narrow is not one a\n * renderer may claim to.\n */\n private resolveUnion(node: ts.UnionTypeNode, ownerName: string): TypeRef {\n const branches = node.types.filter((t: ts.TypeNode) => !TypeResolver.isNullish(t));\n\n const literals = branches.filter(\n (t: ts.TypeNode) => ts.isLiteralTypeNode(t) && ts.isStringLiteral(t.literal),\n );\n if (literals.length === branches.length && branches.length > 0) {\n return TypeRef.enumOf(\n literals.map(\n (t: ts.TypeNode) =>\n ((t as ts.LiteralTypeNode).literal as ts.StringLiteral).text,\n ),\n );\n }\n\n if (branches.length === 1) {\n return this.resolve(branches[0], ownerName);\n }\n if (branches.length === 0) {\n return TypeRef.primitiveOf('null');\n }\n\n const refs: TypeRef[] = branches.map((t: ts.TypeNode) => this.resolve(t, ownerName));\n if (!refs.every((r: TypeRef) => r.kind === 'ref')) {\n return this.recordUnmapped(\n node,\n 'a union whose branches are not all NAMED object types has no discriminator a renderer could narrow on',\n );\n }\n\n const names = refs.map((r: TypeRef) => r.refName!);\n const discriminator = this.deriveDiscriminator(names);\n if (discriminator === undefined) {\n return this.recordUnmapped(\n node,\n 'no property is typed as a single string literal on EVERY branch, so this union has no derivable discriminator',\n );\n }\n this.registerUnionAlias(node, names, discriminator);\n return TypeRef.union(names);\n }\n\n /** `null` and `undefined` branches — recorded as nullable/optional on the FIELD, not in the union. */\n // webpieces-disable no-function-outside-class -- private static predicate of this class\n private static isNullish(node: ts.TypeNode): boolean {\n if (\n node.kind === ts.SyntaxKind.UndefinedKeyword ||\n node.kind === ts.SyntaxKind.NullKeyword\n ) {\n return true;\n }\n return ts.isLiteralTypeNode(node) && node.literal.kind === ts.SyntaxKind.NullKeyword;\n }\n\n /**\n * The DERIVED discriminator: the property every branch declares as exactly ONE string literal,\n * with a value no two branches share. Derived, never invented — if the source does not narrow,\n * neither does the document.\n */\n private deriveDiscriminator(branchNames: readonly string[]): UnionDiscriminator | undefined {\n const branches = branchNames.map((name: string) => this.types.get(name));\n if (branches.some((b: DocumentedType | undefined) => b === undefined)) {\n return undefined;\n }\n const first = branches[0]!;\n for (const field of first.fields) {\n const values = new Map<string, string>();\n for (let i = 0; i < branches.length; i++) {\n const candidate = branches[i]!.fields.find(\n (f: DocumentedField) => f.name === field.name,\n );\n const literal =\n candidate !== undefined &&\n candidate.type.kind === 'enum' &&\n candidate.type.enumValues.length === 1\n ? candidate.type.enumValues[0]\n : undefined;\n if (literal === undefined) {\n values.clear();\n break;\n }\n values.set(branchNames[i], literal);\n }\n if (values.size === branches.length && new Set(values.values()).size === values.size) {\n return new UnionDiscriminator(field.name, values);\n }\n }\n return undefined;\n }\n\n /** A union written as a named `type X = A | B` becomes its own model entry, so #982 can `$ref` it. */\n private registerUnionAlias(\n node: ts.UnionTypeNode,\n branchNames: readonly string[],\n discriminator: UnionDiscriminator,\n ): void {\n const alias = node.parent;\n if (!ts.isTypeAliasDeclaration(alias)) {\n return;\n }\n const name = alias.name.text;\n if (this.registered.has(name)) {\n return;\n }\n this.registered.add(name);\n this.types.set(\n name,\n new DocumentedType(\n name,\n JsDoc.read(alias).description,\n [],\n [],\n branchNames,\n discriminator,\n undefined,\n ),\n );\n }\n\n /**\n * `Integer`, `Array<T>`, `Record<string, V>`, `Promise<T>`, and everything named — an interface,\n * a class, or a type alias. Anything else (a `Map`, a `Date`, a generic parameter) is recorded\n * rather than guessed at.\n */\n private resolveReference(node: ts.TypeReferenceNode, ownerName: string): TypeRef {\n const name = ts.isIdentifier(node.typeName) ? node.typeName.text : node.typeName.right.text;\n const args = node.typeArguments ?? [];\n\n if (name === INTEGER_ALIAS) {\n return TypeRef.primitiveOf('number', /*integer*/ true);\n }\n if ((name === 'Array' || name === 'ReadonlyArray') && args.length === 1) {\n return TypeRef.array(this.resolve(args[0], ownerName));\n }\n if ((name === 'Record' || name === 'Partial') && args.length === 2) {\n return TypeRef.openMap(this.resolve(args[1], ownerName));\n }\n if (name === 'Promise' && args.length === 1) {\n return this.resolve(args[0], ownerName);\n }\n\n const declaration = this.declarationOf(node.typeName);\n if (declaration === undefined) {\n return this.recordUnmapped(node, `no declaration found for '${name}'`);\n }\n return this.resolveDeclaration(name, declaration, ownerName);\n }\n\n /**\n * Resolve a type by its DECLARATION rather than by a reference to it.\n *\n * The reference path above is the normal one — a field says `Customer` and the resolver follows\n * it. This entry point exists for a type that is named from OUTSIDE the source: a manifest naming\n * the document-wide error body, which no field in the contract points at. Same registration, same\n * cycle story, so the two cannot disagree about what a type IS.\n */\n resolveDeclaration(name: string, declaration: ts.Declaration, ownerName: string): TypeRef {\n if (ts.isInterfaceDeclaration(declaration) || ts.isClassDeclaration(declaration)) {\n return this.registerNamedObject(name, declaration);\n }\n if (ts.isTypeAliasDeclaration(declaration)) {\n return this.resolveAlias(name, declaration, ownerName);\n }\n if (ts.isEnumDeclaration(declaration)) {\n return this.registerStringEnum(name, declaration);\n }\n return this.recordUnmapped(\n declaration,\n `'${name}' is declared as something with no document shape`,\n );\n }\n\n /** `type X = ...` — registered under X when it has a shape of its own, else transparent. */\n private resolveAlias(name: string, alias: ts.TypeAliasDeclaration, ownerName: string): TypeRef {\n if (this.registered.has(name)) {\n return this.types.get(name)?.unionRefNames.length\n ? TypeRef.union(this.types.get(name)!.unionRefNames)\n : TypeRef.ref(name);\n }\n\n if (ts.isUnionTypeNode(alias.type)) {\n const resolved = this.resolve(alias.type, ownerName);\n if (resolved.kind === 'enum') {\n this.registered.add(name);\n this.types.set(\n name,\n new DocumentedType(\n name,\n JsDoc.read(alias).description,\n [],\n resolved.enumValues,\n [],\n undefined,\n undefined,\n ),\n );\n return TypeRef.ref(name);\n }\n return resolved;\n }\n\n if (ts.isTypeLiteralNode(alias.type)) {\n return this.registerNamedObject(name, alias.type, alias);\n }\n return this.resolve(alias.type, ownerName);\n }\n\n /** A TS `enum` of string members — the one non-union enum shape a document can carry. */\n private registerStringEnum(name: string, declaration: ts.EnumDeclaration): TypeRef {\n if (this.registered.has(name)) {\n return TypeRef.ref(name);\n }\n const values: string[] = [];\n for (const member of declaration.members) {\n if (member.initializer && ts.isStringLiteral(member.initializer)) {\n values.push(member.initializer.text);\n }\n }\n if (values.length !== declaration.members.length) {\n return this.recordUnmapped(\n declaration,\n `enum '${name}' has members that are not string literals`,\n );\n }\n this.registered.add(name);\n this.types.set(\n name,\n new DocumentedType(\n name,\n JsDoc.read(declaration).description,\n [],\n values,\n [],\n undefined,\n undefined,\n ),\n );\n return TypeRef.ref(name);\n }\n\n /**\n * Register a named object shape, RESERVING THE NAME BEFORE walking its fields. That order is the\n * whole cycle story: a type that refers back to itself meets `registered.has(name)` on the second\n * visit and resolves to a `$ref`, so the walk terminates with no counter and no truncation.\n */\n private registerNamedObject(\n name: string,\n shape: ts.InterfaceDeclaration | ts.ClassDeclaration | ts.TypeLiteralNode,\n docSource?: ts.Node,\n ): TypeRef {\n if (this.registered.has(name)) {\n return TypeRef.ref(name);\n }\n this.registered.add(name);\n\n const fields: DocumentedField[] = [];\n let indexSignature: TypeRef | undefined;\n for (const member of shape.members) {\n if (ts.isIndexSignatureDeclaration(member)) {\n indexSignature = this.resolve(member.type, name);\n continue;\n }\n const field = this.fieldOf(member, name);\n if (field !== undefined) {\n fields.push(field);\n }\n }\n\n this.types.set(\n name,\n new DocumentedType(\n name,\n JsDoc.read(docSource ?? shape).description,\n fields,\n [],\n [],\n undefined,\n indexSignature,\n ),\n );\n return TypeRef.ref(name);\n }\n\n /**\n * An inline `{ ... }`. It has no name to `$ref`, so it is registered under an OWNER-DERIVED one\n * (`Parent.field`) — a renderer needs a target, and a name derived from where the shape is\n * written is the only honest one available.\n *\n * A self-referential anonymous type is cut HERE, by NODE IDENTITY. It cannot be a `$ref` (there\n * is no declared name to point at) and it cannot be expanded (it would never end), so it is\n * recorded as unmapped and the walk returns.\n */\n private resolveAnonymousObject(node: ts.TypeLiteralNode, ownerName: string): TypeRef {\n if (this.expandingAnonymous.has(node)) {\n return this.recordUnmapped(\n node,\n 'a self-referential ANONYMOUS object type has no name a renderer could $ref; give it a name',\n );\n }\n const indexOnly =\n node.members.length === 1 && ts.isIndexSignatureDeclaration(node.members[0]);\n if (indexOnly) {\n const signature = node.members[0] as ts.IndexSignatureDeclaration;\n return TypeRef.openMap(this.resolve(signature.type, ownerName));\n }\n\n this.expandingAnonymous.add(node);\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- the stack entry must be dropped whatever the walk does\n try {\n return this.registerNamedObject(ownerName, node);\n } finally {\n this.expandingAnonymous.delete(node);\n }\n }\n\n /** ONE property of a DTO — its type, its optionality, its prose and its numeric constraints. */\n private fieldOf(\n member: ts.TypeElement | ts.ClassElement,\n ownerName: string,\n ): DocumentedField | undefined {\n if (!ts.isPropertySignature(member) && !ts.isPropertyDeclaration(member)) {\n return undefined;\n }\n if (!ts.isIdentifier(member.name) && !ts.isStringLiteral(member.name)) {\n return undefined;\n }\n const name = member.name.text;\n if (member.type === undefined) {\n return undefined;\n }\n\n const optional =\n member.questionToken !== undefined || TypeResolver.declaresUndefined(member.type);\n const nullable = TypeResolver.declaresNull(member.type);\n\n let type = this.resolve(member.type, `${ownerName}.${name}`);\n if (TypeResolver.hasDecorator(member, INT_DECORATOR)) {\n type = TypeResolver.markInteger(type);\n }\n\n const doc = JsDoc.read(member);\n const min = this.numericArgument(member, MIN_DECORATOR);\n const max = this.numericArgument(member, MAX_DECORATOR);\n this.assertNumericConstraintsFit(member, name, type, min, max);\n\n return new DocumentedField(\n name,\n type,\n optional,\n nullable,\n doc.description,\n doc.mcp,\n doc.format,\n min,\n max,\n doc.mcpHeader,\n );\n }\n\n /**\n * `@WpMin` / `@WpMax` on a non-numeric field is a BUILD FAILURE, not a warning. A minimum on a\n * string is not something a renderer can emit sensibly, and a document that silently dropped it\n * would publish a contract weaker than the one its author wrote down.\n */\n private assertNumericConstraintsFit(\n member: ts.Node,\n name: string,\n type: TypeRef,\n min: number | undefined,\n max: number | undefined,\n ): void {\n if (min === undefined && max === undefined) {\n return;\n }\n const numeric = type.isNumeric() || (type.kind === 'array' && type.items!.isNumeric());\n if (numeric) {\n return;\n }\n throw new ApiDocExtractionError(\n `@${MIN_DECORATOR}/@${MAX_DECORATOR} on non-numeric field '${name}'`,\n SourceLocation.of(member),\n 'Put the constraint on a `number` / `Integer` field, or drop it.',\n );\n }\n\n /** `@WpInt()` decorates the FIELD, so the integer flag is pushed onto the right leaf. */\n // webpieces-disable no-function-outside-class -- private static helper of this class\n private static markInteger(type: TypeRef): TypeRef {\n if (type.kind === 'array') {\n return TypeRef.array(type.items!.asInteger());\n }\n if (type.kind === 'openMap') {\n return TypeRef.openMap(type.values!.asInteger());\n }\n return type.asInteger();\n }\n\n // webpieces-disable no-function-outside-class -- private static helper of this class\n private static declaresUndefined(node: ts.TypeNode): boolean {\n return (\n ts.isUnionTypeNode(node) &&\n node.types.some((t: ts.TypeNode) => t.kind === ts.SyntaxKind.UndefinedKeyword)\n );\n }\n\n // webpieces-disable no-function-outside-class -- private static helper of this class\n private static declaresNull(node: ts.TypeNode): boolean {\n return (\n ts.isUnionTypeNode(node) &&\n node.types.some(\n (t: ts.TypeNode) =>\n t.kind === ts.SyntaxKind.NullKeyword ||\n (ts.isLiteralTypeNode(t) && t.literal.kind === ts.SyntaxKind.NullKeyword),\n )\n );\n }\n\n // webpieces-disable no-function-outside-class -- private static helper of this class\n private static hasDecorator(node: ts.Node, decoratorName: string): boolean {\n return TypeResolver.decoratorCall(node, decoratorName) !== undefined;\n }\n\n // webpieces-disable no-function-outside-class -- private static helper of this class\n private static decoratorCall(\n node: ts.Node,\n decoratorName: string,\n ): ts.CallExpression | undefined {\n const decorators = ts.canHaveDecorators(node) ? (ts.getDecorators(node) ?? []) : [];\n for (const decorator of decorators) {\n const call = decorator.expression;\n if (\n ts.isCallExpression(call) &&\n ts.isIdentifier(call.expression) &&\n call.expression.text === decoratorName\n ) {\n return call;\n }\n }\n return undefined;\n }\n\n private numericArgument(node: ts.Node, decoratorName: string): number | undefined {\n const call = TypeResolver.decoratorCall(node, decoratorName);\n const argument = call?.arguments[0];\n if (argument === undefined) {\n return undefined;\n }\n if (ts.isNumericLiteral(argument)) {\n return Number(argument.text);\n }\n if (\n ts.isPrefixUnaryExpression(argument) &&\n argument.operator === ts.SyntaxKind.MinusToken &&\n ts.isNumericLiteral(argument.operand)\n ) {\n return -Number(argument.operand.text);\n }\n throw new ApiDocExtractionError(\n `@${decoratorName} argument is not a numeric literal: '${argument.getText()}'`,\n SourceLocation.of(argument),\n 'Write the bound as a numeric literal. A value only known at runtime cannot be published.',\n );\n }\n\n /** The declaration a type name points at, through imports and aliases. */\n private declarationOf(name: ts.EntityName): ts.Declaration | undefined {\n const symbol = this.checker.getSymbolAtLocation(name);\n const resolved =\n symbol !== undefined && (symbol.flags & ts.SymbolFlags.Alias) !== 0\n ? this.checker.getAliasedSymbol(symbol)\n : symbol;\n return resolved?.declarations?.[0];\n }\n\n private recordUnmapped(node: ts.Node, reason: string): TypeRef {\n const text = node.getText();\n this.unmapped.push(new UnmappedType(text, SourceLocation.of(node), reason));\n return TypeRef.unmapped(text);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"TypeResolver.js","sourceRoot":"","sources":["../../../../../../packages/docs/api-doc-model/src/extract/TypeResolver.ts"],"names":[],"mappings":"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","sourcesContent":["import * as ts from 'typescript';\nimport { WpInt, WpMax, WpMin } from '@webpieces/core-util';\nimport {\n DocumentedField,\n DocumentedType,\n UnionDiscriminator,\n UnmappedType,\n} from '../model/ApiDocModel';\nimport { PrimitiveKind, TypeRef } from '../model/TypeRef';\nimport { ApiDocExtractionError } from './ApiDocExtractionError';\nimport { JsDoc } from './JsDoc';\nimport { SourceLocation } from './SourceLocation';\n\n/**\n * The decorators this resolver reads off a DTO property, named from the REAL SYMBOLS — a rename in\n * `core-util` is a compile error here rather than a literal that quietly stops matching. See\n * {@link ApiDocExtractor}'s constants for the full argument (issue #1001).\n */\nconst INT_DECORATOR = WpInt.name;\nconst MIN_DECORATOR = WpMin.name;\nconst MAX_DECORATOR = WpMax.name;\n\n/**\n * The type-alias name that DECLARES integer-ness.\n *\n * This one is a LITERAL and cannot be anything else: `Integer` is a TYPE ALIAS, so there is no\n * runtime symbol whose `.name` could be read — `.name` is a property of a function, and a type has\n * erased by then. It is the one name in this package that a rename in `core-util` would not break at\n * compile time; the cure if that ever bites is to make integer-ness a decorator here too, not to\n * pretend a type has a runtime identity. See {@link ApiDocExtractor}'s constants for the argument\n * everywhere else (issue #1001).\n */\nconst INTEGER_ALIAS = 'Integer';\n\n/**\n * Resolve declared TypeScript types into {@link TypeRef}s, registering every NAMED type it meets as\n * a {@link DocumentedType} a renderer can `$ref`.\n *\n * ## It walks TYPE NODES, not checker types, and that is load-bearing\n *\n * `type Integer = number` resolves, in the checker, to `number` — the alias is gone. Integer-ness is\n * therefore invisible to a checker-driven walk, and the whole reason `Integer` is the PREFERRED\n * spelling is that it COMPOSES: `Integer[]` and `Record<string, Integer>` say exactly which thing is\n * an integer, where a decorator on `counts?: number[]` cannot (the same ambiguity the deleted\n * `arrayItems` argument had). Walking the written syntax is what keeps that composition readable.\n *\n * ## Cycles terminate BY CONSTRUCTION\n *\n * Every named type is ONE entry in the model, registered before its fields are walked, so a type\n * that refers back to itself resolves to a `$ref` at the second visit and stops. There is NO depth\n * counter anywhere — a deep-but-finite graph of 7, 20 or 200 named hops is fully expanded, because\n * truncating one would silently publish an incomplete document. The ONLY thing that is cut is a\n * self-referential ANONYMOUS type, and it is cut by NODE IDENTITY (it has no name to `$ref`), with an\n * {@link UnmappedType} recorded so #982's guard has something to name.\n */\nexport class TypeResolver {\n private readonly types = new Map<string, DocumentedType>();\n private readonly unmapped: UnmappedType[] = [];\n /** Named types already registered (or mid-registration) — the cycle stop for the NAMED case. */\n private readonly registered = new Set<string>();\n /** Anonymous type literals currently being expanded — the cycle stop for the ANONYMOUS case. */\n private readonly expandingAnonymous = new Set<ts.TypeNode>();\n\n constructor(private readonly checker: ts.TypeChecker) {}\n\n /** Every named type reached so far, by name. */\n collectedTypes(): ReadonlyMap<string, DocumentedType> {\n return this.types;\n }\n\n /** Everything that could not be represented — recorded, never dropped. */\n collectedUnmapped(): readonly UnmappedType[] {\n return this.unmapped;\n }\n\n /** Resolve one written type, registering whatever named types it reaches. */\n resolve(node: ts.TypeNode, ownerName: string): TypeRef {\n if (ts.isParenthesizedTypeNode(node)) {\n return this.resolve(node.type, ownerName);\n }\n if (ts.isArrayTypeNode(node)) {\n return TypeRef.array(this.resolve(node.elementType, ownerName));\n }\n if (ts.isUnionTypeNode(node)) {\n return this.resolveUnion(node, ownerName);\n }\n if (ts.isTypeLiteralNode(node)) {\n return this.resolveAnonymousObject(node, ownerName);\n }\n if (ts.isLiteralTypeNode(node)) {\n return this.resolveLiteral(node);\n }\n if (ts.isTypeReferenceNode(node)) {\n return this.resolveReference(node, ownerName);\n }\n const primitive = TypeResolver.keywordOf(node.kind);\n if (primitive !== undefined) {\n return TypeRef.primitiveOf(primitive);\n }\n return this.recordUnmapped(node, 'no model representation for this type form');\n }\n\n /** `string` / `number` / `boolean` / `null` / `unknown`, or undefined for anything else. */\n // webpieces-disable no-function-outside-class -- private static lookup table of this class\n private static keywordOf(kind: ts.SyntaxKind): PrimitiveKind | undefined {\n switch (kind) {\n case ts.SyntaxKind.StringKeyword:\n return 'string';\n case ts.SyntaxKind.NumberKeyword:\n return 'number';\n case ts.SyntaxKind.BooleanKeyword:\n return 'boolean';\n case ts.SyntaxKind.NullKeyword:\n return 'null';\n case ts.SyntaxKind.UnknownKeyword:\n case ts.SyntaxKind.AnyKeyword:\n case ts.SyntaxKind.VoidKeyword:\n return 'unknown';\n default:\n return undefined;\n }\n }\n\n private resolveLiteral(node: ts.LiteralTypeNode): TypeRef {\n if (ts.isStringLiteral(node.literal)) {\n return TypeRef.enumOf([node.literal.text]);\n }\n if (node.literal.kind === ts.SyntaxKind.NullKeyword) {\n return TypeRef.primitiveOf('null');\n }\n if (\n node.literal.kind === ts.SyntaxKind.TrueKeyword ||\n node.literal.kind === ts.SyntaxKind.FalseKeyword\n ) {\n return TypeRef.primitiveOf('boolean');\n }\n if (ts.isNumericLiteral(node.literal)) {\n return TypeRef.primitiveOf('number');\n }\n return this.recordUnmapped(\n node,\n 'literal type is neither a string, a number nor a boolean',\n );\n }\n\n /**\n * A union, after `null` / `undefined` have been dropped (the FIELD records those as nullable /\n * optional — see {@link fieldOf} — because `{}` and `{x: null}` are different wire documents).\n *\n * Three outcomes, in this order:\n * - every branch a string literal -> an ENUM\n * - one branch left -> that branch\n * - every branch a named object -> a UNION, with a DERIVED discriminator when every branch\n * carries the same property typed as ONE string literal\n * - anything else -> an {@link UnmappedType}. No invented discriminator, ever:\n * a union TypeScript itself cannot narrow is not one a\n * renderer may claim to.\n */\n private resolveUnion(node: ts.UnionTypeNode, ownerName: string): TypeRef {\n const branches = node.types.filter((t: ts.TypeNode) => !TypeResolver.isNullish(t));\n\n const literals = branches.filter(\n (t: ts.TypeNode) => ts.isLiteralTypeNode(t) && ts.isStringLiteral(t.literal),\n );\n if (literals.length === branches.length && branches.length > 0) {\n return TypeRef.enumOf(\n literals.map(\n (t: ts.TypeNode) =>\n ((t as ts.LiteralTypeNode).literal as ts.StringLiteral).text,\n ),\n );\n }\n\n if (branches.length === 1) {\n return this.resolve(branches[0], ownerName);\n }\n if (branches.length === 0) {\n return TypeRef.primitiveOf('null');\n }\n\n const refs: TypeRef[] = branches.map((t: ts.TypeNode) => this.resolve(t, ownerName));\n if (!refs.every((r: TypeRef) => r.kind === 'ref')) {\n return this.recordUnmapped(\n node,\n 'a union whose branches are not all NAMED object types has no discriminator a renderer could narrow on',\n );\n }\n\n const names = refs.map((r: TypeRef) => r.refName!);\n const discriminator = this.deriveDiscriminator(names);\n if (discriminator === undefined) {\n return this.recordUnmapped(\n node,\n 'no property is typed as a single string literal on EVERY branch, so this union has no derivable discriminator',\n );\n }\n this.registerUnionAlias(node, names, discriminator);\n return TypeRef.union(names);\n }\n\n /** `null` and `undefined` branches — recorded as nullable/optional on the FIELD, not in the union. */\n // webpieces-disable no-function-outside-class -- private static predicate of this class\n private static isNullish(node: ts.TypeNode): boolean {\n if (\n node.kind === ts.SyntaxKind.UndefinedKeyword ||\n node.kind === ts.SyntaxKind.NullKeyword\n ) {\n return true;\n }\n return ts.isLiteralTypeNode(node) && node.literal.kind === ts.SyntaxKind.NullKeyword;\n }\n\n /**\n * The DERIVED discriminator: the property every branch declares as exactly ONE string literal,\n * with a value no two branches share. Derived, never invented — if the source does not narrow,\n * neither does the document.\n */\n private deriveDiscriminator(branchNames: readonly string[]): UnionDiscriminator | undefined {\n const branches = branchNames.map((name: string) => this.types.get(name));\n if (branches.some((b: DocumentedType | undefined) => b === undefined)) {\n return undefined;\n }\n const first = branches[0]!;\n for (const field of first.fields) {\n const values = new Map<string, string>();\n for (let i = 0; i < branches.length; i++) {\n const candidate = branches[i]!.fields.find(\n (f: DocumentedField) => f.name === field.name,\n );\n const literal =\n candidate !== undefined &&\n candidate.type.kind === 'enum' &&\n candidate.type.enumValues.length === 1\n ? candidate.type.enumValues[0]\n : undefined;\n if (literal === undefined) {\n values.clear();\n break;\n }\n values.set(branchNames[i], literal);\n }\n if (values.size === branches.length && new Set(values.values()).size === values.size) {\n return new UnionDiscriminator(field.name, values);\n }\n }\n return undefined;\n }\n\n /** A union written as a named `type X = A | B` becomes its own model entry, so #982 can `$ref` it. */\n private registerUnionAlias(\n node: ts.UnionTypeNode,\n branchNames: readonly string[],\n discriminator: UnionDiscriminator,\n ): void {\n const alias = node.parent;\n if (!ts.isTypeAliasDeclaration(alias)) {\n return;\n }\n const name = alias.name.text;\n if (this.registered.has(name)) {\n return;\n }\n this.registered.add(name);\n this.types.set(\n name,\n new DocumentedType(\n name,\n JsDoc.read(alias).description,\n [],\n [],\n branchNames,\n discriminator,\n undefined,\n ),\n );\n }\n\n /**\n * `Integer`, `Array<T>`, `Record<string, V>`, `Promise<T>`, and everything named — an interface,\n * a class, or a type alias. Anything else (a `Map`, a `Date`, a generic parameter) is recorded\n * rather than guessed at.\n */\n private resolveReference(node: ts.TypeReferenceNode, ownerName: string): TypeRef {\n const name = ts.isIdentifier(node.typeName) ? node.typeName.text : node.typeName.right.text;\n const args = node.typeArguments ?? [];\n\n if (name === INTEGER_ALIAS) {\n return TypeRef.primitiveOf('number', /*integer*/ true);\n }\n if ((name === 'Array' || name === 'ReadonlyArray') && args.length === 1) {\n return TypeRef.array(this.resolve(args[0], ownerName));\n }\n if ((name === 'Record' || name === 'Partial') && args.length === 2) {\n return TypeRef.openMap(this.resolve(args[1], ownerName));\n }\n if (name === 'Promise' && args.length === 1) {\n return this.resolve(args[0], ownerName);\n }\n\n const declaration = this.declarationOf(node.typeName);\n if (declaration === undefined) {\n return this.recordUnmapped(node, `no declaration found for '${name}'`);\n }\n return this.resolveDeclaration(name, declaration, ownerName);\n }\n\n /**\n * Resolve a type by its DECLARATION rather than by a reference to it.\n *\n * The reference path above is the normal one — a field says `Customer` and the resolver follows\n * it. This entry point exists for a type that is named from OUTSIDE the source: a manifest naming\n * the document-wide error body, which no field in the contract points at. Same registration, same\n * cycle story, so the two cannot disagree about what a type IS.\n */\n resolveDeclaration(name: string, declaration: ts.Declaration, ownerName: string): TypeRef {\n if (ts.isInterfaceDeclaration(declaration) || ts.isClassDeclaration(declaration)) {\n return this.registerNamedObject(name, declaration);\n }\n if (ts.isTypeAliasDeclaration(declaration)) {\n return this.resolveAlias(name, declaration, ownerName);\n }\n if (ts.isEnumDeclaration(declaration)) {\n return this.registerStringEnum(name, declaration);\n }\n return this.recordUnmapped(\n declaration,\n `'${name}' is declared as something with no document shape`,\n );\n }\n\n /** `type X = ...` — registered under X when it has a shape of its own, else transparent. */\n private resolveAlias(name: string, alias: ts.TypeAliasDeclaration, ownerName: string): TypeRef {\n if (this.registered.has(name)) {\n return this.types.get(name)?.unionRefNames.length\n ? TypeRef.union(this.types.get(name)!.unionRefNames)\n : TypeRef.ref(name);\n }\n\n if (ts.isUnionTypeNode(alias.type)) {\n const resolved = this.resolve(alias.type, ownerName);\n if (resolved.kind === 'enum') {\n this.registered.add(name);\n this.types.set(\n name,\n new DocumentedType(\n name,\n JsDoc.read(alias).description,\n [],\n resolved.enumValues,\n [],\n undefined,\n undefined,\n ),\n );\n return TypeRef.ref(name);\n }\n return resolved;\n }\n\n if (ts.isTypeLiteralNode(alias.type)) {\n return this.registerNamedObject(name, alias.type, alias);\n }\n return this.resolve(alias.type, ownerName);\n }\n\n /** A TS `enum` of string members — the one non-union enum shape a document can carry. */\n private registerStringEnum(name: string, declaration: ts.EnumDeclaration): TypeRef {\n if (this.registered.has(name)) {\n return TypeRef.ref(name);\n }\n const values: string[] = [];\n for (const member of declaration.members) {\n if (member.initializer && ts.isStringLiteral(member.initializer)) {\n values.push(member.initializer.text);\n }\n }\n if (values.length !== declaration.members.length) {\n return this.recordUnmapped(\n declaration,\n `enum '${name}' has members that are not string literals`,\n );\n }\n this.registered.add(name);\n this.types.set(\n name,\n new DocumentedType(\n name,\n JsDoc.read(declaration).description,\n [],\n values,\n [],\n undefined,\n undefined,\n ),\n );\n return TypeRef.ref(name);\n }\n\n /**\n * Register a named object shape, RESERVING THE NAME BEFORE walking its fields. That order is the\n * whole cycle story: a type that refers back to itself meets `registered.has(name)` on the second\n * visit and resolves to a `$ref`, so the walk terminates with no counter and no truncation.\n */\n private registerNamedObject(\n name: string,\n shape: ts.InterfaceDeclaration | ts.ClassDeclaration | ts.TypeLiteralNode,\n docSource?: ts.Node,\n ): TypeRef {\n if (this.registered.has(name)) {\n return TypeRef.ref(name);\n }\n this.registered.add(name);\n\n const fields: DocumentedField[] = [];\n let indexSignature: TypeRef | undefined;\n for (const member of shape.members) {\n if (ts.isIndexSignatureDeclaration(member)) {\n indexSignature = this.resolve(member.type, name);\n continue;\n }\n const field = this.fieldOf(member, name);\n if (field !== undefined) {\n fields.push(field);\n }\n }\n\n this.types.set(\n name,\n new DocumentedType(\n name,\n JsDoc.read(docSource ?? shape).description,\n fields,\n [],\n [],\n undefined,\n indexSignature,\n ),\n );\n return TypeRef.ref(name);\n }\n\n /**\n * An inline `{ ... }`. It has no name to `$ref`, so it is registered under an OWNER-DERIVED one\n * (`Parent.field`) — a renderer needs a target, and a name derived from where the shape is\n * written is the only honest one available.\n *\n * A self-referential anonymous type is cut HERE, by NODE IDENTITY. It cannot be a `$ref` (there\n * is no declared name to point at) and it cannot be expanded (it would never end), so it is\n * recorded as unmapped and the walk returns.\n */\n private resolveAnonymousObject(node: ts.TypeLiteralNode, ownerName: string): TypeRef {\n if (this.expandingAnonymous.has(node)) {\n return this.recordUnmapped(\n node,\n 'a self-referential ANONYMOUS object type has no name a renderer could $ref; give it a name',\n );\n }\n const indexOnly =\n node.members.length === 1 && ts.isIndexSignatureDeclaration(node.members[0]);\n if (indexOnly) {\n const signature = node.members[0] as ts.IndexSignatureDeclaration;\n return TypeRef.openMap(this.resolve(signature.type, ownerName));\n }\n\n this.expandingAnonymous.add(node);\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- the stack entry must be dropped whatever the walk does\n try {\n return this.registerNamedObject(ownerName, node);\n } finally {\n this.expandingAnonymous.delete(node);\n }\n }\n\n /** ONE property of a DTO — its type, its optionality, its prose and its numeric constraints. */\n private fieldOf(\n member: ts.TypeElement | ts.ClassElement,\n ownerName: string,\n ): DocumentedField | undefined {\n if (!ts.isPropertySignature(member) && !ts.isPropertyDeclaration(member)) {\n return undefined;\n }\n if (!ts.isIdentifier(member.name) && !ts.isStringLiteral(member.name)) {\n return undefined;\n }\n const name = member.name.text;\n if (member.type === undefined) {\n return undefined;\n }\n\n const optional =\n member.questionToken !== undefined || TypeResolver.declaresUndefined(member.type);\n const nullable = TypeResolver.declaresNull(member.type);\n\n let type = this.resolve(member.type, `${ownerName}.${name}`);\n if (TypeResolver.hasDecorator(member, INT_DECORATOR)) {\n type = TypeResolver.markInteger(type);\n }\n\n const doc = JsDoc.read(member);\n const min = this.numericArgument(member, MIN_DECORATOR);\n const max = this.numericArgument(member, MAX_DECORATOR);\n this.assertNumericConstraintsFit(member, name, type, min, max);\n\n return new DocumentedField(\n name,\n type,\n optional,\n nullable,\n doc.description,\n doc.mcp,\n doc.format,\n min,\n max,\n doc.mcpHeader,\n SourceLocation.of(member),\n );\n }\n\n /**\n * `@WpMin` / `@WpMax` on a non-numeric field is a BUILD FAILURE, not a warning. A minimum on a\n * string is not something a renderer can emit sensibly, and a document that silently dropped it\n * would publish a contract weaker than the one its author wrote down.\n */\n private assertNumericConstraintsFit(\n member: ts.Node,\n name: string,\n type: TypeRef,\n min: number | undefined,\n max: number | undefined,\n ): void {\n if (min === undefined && max === undefined) {\n return;\n }\n const numeric = type.isNumeric() || (type.kind === 'array' && type.items!.isNumeric());\n if (numeric) {\n return;\n }\n throw new ApiDocExtractionError(\n `@${MIN_DECORATOR}/@${MAX_DECORATOR} on non-numeric field '${name}'`,\n SourceLocation.of(member),\n 'Put the constraint on a `number` / `Integer` field, or drop it.',\n );\n }\n\n /** `@WpInt()` decorates the FIELD, so the integer flag is pushed onto the right leaf. */\n // webpieces-disable no-function-outside-class -- private static helper of this class\n private static markInteger(type: TypeRef): TypeRef {\n if (type.kind === 'array') {\n return TypeRef.array(type.items!.asInteger());\n }\n if (type.kind === 'openMap') {\n return TypeRef.openMap(type.values!.asInteger());\n }\n return type.asInteger();\n }\n\n // webpieces-disable no-function-outside-class -- private static helper of this class\n private static declaresUndefined(node: ts.TypeNode): boolean {\n return (\n ts.isUnionTypeNode(node) &&\n node.types.some((t: ts.TypeNode) => t.kind === ts.SyntaxKind.UndefinedKeyword)\n );\n }\n\n // webpieces-disable no-function-outside-class -- private static helper of this class\n private static declaresNull(node: ts.TypeNode): boolean {\n return (\n ts.isUnionTypeNode(node) &&\n node.types.some(\n (t: ts.TypeNode) =>\n t.kind === ts.SyntaxKind.NullKeyword ||\n (ts.isLiteralTypeNode(t) && t.literal.kind === ts.SyntaxKind.NullKeyword),\n )\n );\n }\n\n // webpieces-disable no-function-outside-class -- private static helper of this class\n private static hasDecorator(node: ts.Node, decoratorName: string): boolean {\n return TypeResolver.decoratorCall(node, decoratorName) !== undefined;\n }\n\n // webpieces-disable no-function-outside-class -- private static helper of this class\n private static decoratorCall(\n node: ts.Node,\n decoratorName: string,\n ): ts.CallExpression | undefined {\n const decorators = ts.canHaveDecorators(node) ? (ts.getDecorators(node) ?? []) : [];\n for (const decorator of decorators) {\n const call = decorator.expression;\n if (\n ts.isCallExpression(call) &&\n ts.isIdentifier(call.expression) &&\n call.expression.text === decoratorName\n ) {\n return call;\n }\n }\n return undefined;\n }\n\n private numericArgument(node: ts.Node, decoratorName: string): number | undefined {\n const call = TypeResolver.decoratorCall(node, decoratorName);\n const argument = call?.arguments[0];\n if (argument === undefined) {\n return undefined;\n }\n if (ts.isNumericLiteral(argument)) {\n return Number(argument.text);\n }\n if (\n ts.isPrefixUnaryExpression(argument) &&\n argument.operator === ts.SyntaxKind.MinusToken &&\n ts.isNumericLiteral(argument.operand)\n ) {\n return -Number(argument.operand.text);\n }\n throw new ApiDocExtractionError(\n `@${decoratorName} argument is not a numeric literal: '${argument.getText()}'`,\n SourceLocation.of(argument),\n 'Write the bound as a numeric literal. A value only known at runtime cannot be published.',\n );\n }\n\n /** The declaration a type name points at, through imports and aliases. */\n private declarationOf(name: ts.EntityName): ts.Declaration | undefined {\n const symbol = this.checker.getSymbolAtLocation(name);\n const resolved =\n symbol !== undefined && (symbol.flags & ts.SymbolFlags.Alias) !== 0\n ? this.checker.getAliasedSymbol(symbol)\n : symbol;\n return resolved?.declarations?.[0];\n }\n\n private recordUnmapped(node: ts.Node, reason: string): TypeRef {\n const text = node.getText();\n this.unmapped.push(new UnmappedType(text, SourceLocation.of(node), reason));\n return TypeRef.unmapped(text);\n }\n}\n"]}
|
|
@@ -72,6 +72,16 @@ export declare class DocumentedField {
|
|
|
72
72
|
* fact at all.
|
|
73
73
|
*/
|
|
74
74
|
readonly mcpHeader: string | undefined;
|
|
75
|
+
/**
|
|
76
|
+
* Pointer-style `path/to/File.ts:12:5` for the property declaration itself.
|
|
77
|
+
*
|
|
78
|
+
* A renderer never needs it — it publishes a schema, not a file offset. The build RULES do:
|
|
79
|
+
* `api-rules-for-openapi` refuses a field whose value type is `unknown`, and a refusal that
|
|
80
|
+
* cannot say WHERE costs the author a grep over every DTO the contract reaches. It is
|
|
81
|
+
* carried on the FIELD rather than recomputed because only the extractor still has the
|
|
82
|
+
* syntax node, and a second reader deriving it would be a second answer to "where is this".
|
|
83
|
+
*/
|
|
84
|
+
readonly location: string;
|
|
75
85
|
constructor(name: string, type: TypeRef,
|
|
76
86
|
/**
|
|
77
87
|
* OPTIONAL (`name?: string`) — the property may be ABSENT. Distinguished from
|
|
@@ -104,7 +114,17 @@ export declare class DocumentedField {
|
|
|
104
114
|
* field, rather than in a decorator argument — and since #984 it is the only spelling of the
|
|
105
115
|
* fact at all.
|
|
106
116
|
*/
|
|
107
|
-
mcpHeader: string | undefined
|
|
117
|
+
mcpHeader: string | undefined,
|
|
118
|
+
/**
|
|
119
|
+
* Pointer-style `path/to/File.ts:12:5` for the property declaration itself.
|
|
120
|
+
*
|
|
121
|
+
* A renderer never needs it — it publishes a schema, not a file offset. The build RULES do:
|
|
122
|
+
* `api-rules-for-openapi` refuses a field whose value type is `unknown`, and a refusal that
|
|
123
|
+
* cannot say WHERE costs the author a grep over every DTO the contract reaches. It is
|
|
124
|
+
* carried on the FIELD rather than recomputed because only the extractor still has the
|
|
125
|
+
* syntax node, and a second reader deriving it would be a second answer to "where is this".
|
|
126
|
+
*/
|
|
127
|
+
location: string);
|
|
108
128
|
}
|
|
109
129
|
/** One named type reachable from a contract: an object DTO, a string-literal enum, or a union. */
|
|
110
130
|
export declare class DocumentedType {
|
|
@@ -266,6 +286,17 @@ export declare class DocumentedEndpoint {
|
|
|
266
286
|
readonly options: DocumentedEndpointOptions;
|
|
267
287
|
readonly auth: DocumentedAuth | undefined;
|
|
268
288
|
readonly mcpTool: DocumentedMcpTool | undefined;
|
|
289
|
+
/**
|
|
290
|
+
* `@InvalidEndpointForMcp('<reason>')`'s reason, when the method carries one — this endpoint
|
|
291
|
+
* is PERMANENTLY outside MCP and was never a tool candidate.
|
|
292
|
+
*
|
|
293
|
+
* Distinct from "has no `@WpMcpTool`", which only says "not a tool yet". A renderer must not
|
|
294
|
+
* report one of these as a SKIPPED tool, and `api-rules-for-mcp` stops asking a method with
|
|
295
|
+
* one whether it could be served — the declaration is the answer. Carrying the reason rather
|
|
296
|
+
* than a boolean is the point: the rule restates the list of exclusions with their arguments
|
|
297
|
+
* on every run.
|
|
298
|
+
*/
|
|
299
|
+
readonly invalidForMcp: string | undefined;
|
|
269
300
|
/** `@WpMcpAuthJwt(...)`'s argument text, when present. */
|
|
270
301
|
readonly mcpAuthText: string | undefined;
|
|
271
302
|
/** `@MaskLog({...})` — field name -> mask mode. */
|
|
@@ -299,6 +330,17 @@ export declare class DocumentedEndpoint {
|
|
|
299
330
|
hidden: boolean,
|
|
300
331
|
/** `{ openWorld: true }` — this operation may touch systems outside this service. */
|
|
301
332
|
openWorld: boolean, options: DocumentedEndpointOptions, auth: DocumentedAuth | undefined, mcpTool: DocumentedMcpTool | undefined,
|
|
333
|
+
/**
|
|
334
|
+
* `@InvalidEndpointForMcp('<reason>')`'s reason, when the method carries one — this endpoint
|
|
335
|
+
* is PERMANENTLY outside MCP and was never a tool candidate.
|
|
336
|
+
*
|
|
337
|
+
* Distinct from "has no `@WpMcpTool`", which only says "not a tool yet". A renderer must not
|
|
338
|
+
* report one of these as a SKIPPED tool, and `api-rules-for-mcp` stops asking a method with
|
|
339
|
+
* one whether it could be served — the declaration is the answer. Carrying the reason rather
|
|
340
|
+
* than a boolean is the point: the rule restates the list of exclusions with their arguments
|
|
341
|
+
* on every run.
|
|
342
|
+
*/
|
|
343
|
+
invalidForMcp: string | undefined,
|
|
302
344
|
/** `@WpMcpAuthJwt(...)`'s argument text, when present. */
|
|
303
345
|
mcpAuthText: string | undefined,
|
|
304
346
|
/** `@MaskLog({...})` — field name -> mask mode. */
|
package/src/model/ApiDocModel.js
CHANGED
|
@@ -54,6 +54,7 @@ class DocumentedField {
|
|
|
54
54
|
min;
|
|
55
55
|
max;
|
|
56
56
|
mcpHeader;
|
|
57
|
+
location;
|
|
57
58
|
constructor(name, type,
|
|
58
59
|
/**
|
|
59
60
|
* OPTIONAL (`name?: string`) — the property may be ABSENT. Distinguished from
|
|
@@ -86,7 +87,17 @@ class DocumentedField {
|
|
|
86
87
|
* field, rather than in a decorator argument — and since #984 it is the only spelling of the
|
|
87
88
|
* fact at all.
|
|
88
89
|
*/
|
|
89
|
-
mcpHeader
|
|
90
|
+
mcpHeader,
|
|
91
|
+
/**
|
|
92
|
+
* Pointer-style `path/to/File.ts:12:5` for the property declaration itself.
|
|
93
|
+
*
|
|
94
|
+
* A renderer never needs it — it publishes a schema, not a file offset. The build RULES do:
|
|
95
|
+
* `api-rules-for-openapi` refuses a field whose value type is `unknown`, and a refusal that
|
|
96
|
+
* cannot say WHERE costs the author a grep over every DTO the contract reaches. It is
|
|
97
|
+
* carried on the FIELD rather than recomputed because only the extractor still has the
|
|
98
|
+
* syntax node, and a second reader deriving it would be a second answer to "where is this".
|
|
99
|
+
*/
|
|
100
|
+
location) {
|
|
90
101
|
this.name = name;
|
|
91
102
|
this.type = type;
|
|
92
103
|
this.optional = optional;
|
|
@@ -97,6 +108,7 @@ class DocumentedField {
|
|
|
97
108
|
this.min = min;
|
|
98
109
|
this.max = max;
|
|
99
110
|
this.mcpHeader = mcpHeader;
|
|
111
|
+
this.location = location;
|
|
100
112
|
}
|
|
101
113
|
}
|
|
102
114
|
exports.DocumentedField = DocumentedField;
|
|
@@ -249,6 +261,7 @@ class DocumentedEndpoint {
|
|
|
249
261
|
options;
|
|
250
262
|
auth;
|
|
251
263
|
mcpTool;
|
|
264
|
+
invalidForMcp;
|
|
252
265
|
mcpAuthText;
|
|
253
266
|
maskLog;
|
|
254
267
|
description;
|
|
@@ -279,6 +292,17 @@ class DocumentedEndpoint {
|
|
|
279
292
|
hidden,
|
|
280
293
|
/** `{ openWorld: true }` — this operation may touch systems outside this service. */
|
|
281
294
|
openWorld, options, auth, mcpTool,
|
|
295
|
+
/**
|
|
296
|
+
* `@InvalidEndpointForMcp('<reason>')`'s reason, when the method carries one — this endpoint
|
|
297
|
+
* is PERMANENTLY outside MCP and was never a tool candidate.
|
|
298
|
+
*
|
|
299
|
+
* Distinct from "has no `@WpMcpTool`", which only says "not a tool yet". A renderer must not
|
|
300
|
+
* report one of these as a SKIPPED tool, and `api-rules-for-mcp` stops asking a method with
|
|
301
|
+
* one whether it could be served — the declaration is the answer. Carrying the reason rather
|
|
302
|
+
* than a boolean is the point: the rule restates the list of exclusions with their arguments
|
|
303
|
+
* on every run.
|
|
304
|
+
*/
|
|
305
|
+
invalidForMcp,
|
|
282
306
|
/** `@WpMcpAuthJwt(...)`'s argument text, when present. */
|
|
283
307
|
mcpAuthText,
|
|
284
308
|
/** `@MaskLog({...})` — field name -> mask mode. */
|
|
@@ -295,6 +319,7 @@ class DocumentedEndpoint {
|
|
|
295
319
|
this.options = options;
|
|
296
320
|
this.auth = auth;
|
|
297
321
|
this.mcpTool = mcpTool;
|
|
322
|
+
this.invalidForMcp = invalidForMcp;
|
|
298
323
|
this.mcpAuthText = mcpAuthText;
|
|
299
324
|
this.maskLog = maskLog;
|
|
300
325
|
this.description = description;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApiDocModel.js","sourceRoot":"","sources":["../../../../../../packages/docs/api-doc-model/src/model/ApiDocModel.ts"],"names":[],"mappings":"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","sourcesContent":["import { TypeRef } from './TypeRef';\n\n/**\n * The model classes. Every one of them is a CLASS with an explicit constructor per `CLAUDE.md` §1 —\n * these are data-only structures, and a renderer (#982) builds nothing, it only reads.\n *\n * Nothing in this file imports anything but {@link TypeRef}: the package depends on `typescript` and\n * NOTHING else, so it can be pointed at any upstream project's contract. One app-specific import\n * here would end that, which is why `responsibilities.md` states the constraint rather than leaving\n * it to be discovered.\n */\n\n/** A type the extractor could not represent. RECORDED, never dropped — #982's guard needs a name. */\nexport class UnmappedType {\n constructor(\n /** The verbatim TypeScript type text, e.g. `Map<string, Widget>`. */\n readonly typeText: string,\n /** Pointer-style location: `path/to/File.ts:12:5`. */\n readonly location: string,\n /** Why it could not be mapped, in one sentence a renderer can print. */\n readonly reason: string,\n ) {}\n}\n\n/** The DERIVED discriminator of a union — never invented, only observed. See {@link DocumentedType}. */\nexport class UnionDiscriminator {\n constructor(\n /** The property every branch carries. */\n readonly propertyName: string,\n /** branch type name -> the single string literal that branch's property holds. */\n readonly branchValues: ReadonlyMap<string, string>,\n ) {}\n}\n\n/** One field of one DTO. */\nexport class DocumentedField {\n constructor(\n readonly name: string,\n readonly type: TypeRef,\n /**\n * OPTIONAL (`name?: string`) — the property may be ABSENT. Distinguished from\n * {@link nullable} on purpose: `{}` and `{name: null}` are different wire documents, and a\n * renderer that conflates them emits a schema that rejects one of them.\n */\n readonly optional: boolean,\n /** NULLABLE (`name: string | null`) — the property is present and may hold `null`. */\n readonly nullable: boolean,\n /** The JSDoc body, links flattened. Empty string when undocumented. */\n readonly description: string,\n /**\n * The `@mcp` block tag — an OPTIONAL agent-facing override. Undefined means \"no override\",\n * and a renderer falls back to {@link description}; the fallback is NOT applied here so a\n * renderer can tell a deliberate agent-facing sentence from a reused human one.\n */\n readonly mcpDescription: string | undefined,\n /** The `@format` tag, lifted onto the SCALAR (on an array, onto the ITEM). */\n readonly format: string | undefined,\n /** `@WpMin(n)` — numeric fields only; anything else is a build failure. */\n readonly min: number | undefined,\n /** `@WpMax(n)` — numeric fields only; anything else is a build failure. */\n readonly max: number | undefined,\n /**\n * The `@mcpHeader <token>` JSDoc tag — the MCP 2026 SEP-2243 header this PRIMITIVE field is\n * mirrored into (`Mcp-Param-{token}`). Undefined for every field that is not mirrored, which\n * is nearly all of them.\n *\n * It is documentation and therefore lives in JSDoc, next to the sentence describing the\n * field, rather than in a decorator argument — and since #984 it is the only spelling of the\n * fact at all.\n */\n readonly mcpHeader: string | undefined,\n ) {}\n}\n\n/** One named type reachable from a contract: an object DTO, a string-literal enum, or a union. */\nexport class DocumentedType {\n constructor(\n readonly name: string,\n readonly description: string,\n /** Object shape. Empty for an enum or a union. */\n readonly fields: readonly DocumentedField[],\n /** Set for a string-literal union that has a name. */\n readonly enumValues: readonly string[],\n /** Set for a union of named object types. */\n readonly unionRefNames: readonly string[],\n /** Set only when EVERY branch carries the same property typed as one string literal. */\n readonly discriminator: UnionDiscriminator | undefined,\n /** An index signature (`[k: string]: X`) — the OPEN-MAP half of an object that also has fields. */\n readonly indexSignatureValue: TypeRef | undefined,\n ) {}\n}\n\n/** `@Endpoint(httpMethod, path, operation, kind, options?)`'s LAST argument, as a document sees it. */\nexport class DocumentedEndpointOptions {\n constructor(\n readonly formPost: boolean,\n /** `calledBy` — REQUIRED by the decorator for `external`, absent otherwise. */\n readonly calledBy: string | undefined,\n readonly callerKind: string | undefined,\n ) {}\n}\n\n/**\n * The `@WpMcpTool('search_stores')` declaration, when the method carries one — the ONE fact the\n * source cannot otherwise state, and nothing else.\n *\n * `description` used to sit on the decorator too. The method's JSDoc is the description, for the\n * agent and for the partner alike, byte-identical: two authored copies of one paragraph is the\n * two-spellings shim, and its failure mode is concrete — the partner reads the JSDoc in the OpenAPI\n * document while the agent reads the decorator string in `tools/list`, and they drift the first time\n * somebody edits one. #984 deleted it, which left the decorator holding one field, so it takes the\n * name as a plain string.\n *\n * The three side-effect hints are COMPUTED from the endpoint's `operation` by `mcpHintsForOperation`\n * in `@webpieces/core-util`, which is the one place that mapping lives — `READ | WRITE_IDEMPOTENT |\n * WRITE` already says whether repeating a call is safe, so a hand-declared hint would be a second\n * answer to a question the contract has answered. `openWorldHint` is `@Endpoint`'s `openWorld`.\n */\nexport class DocumentedMcpTool {\n constructor(\n /**\n * The STABLE protocol name. Deliberately independent of the method name, because renaming a\n * method must not break a saved agent workflow.\n */\n readonly name: string,\n ) {}\n}\n\n/**\n * ONE credential of an api-key regime, PARSED — `{ in: 'header', name: 'x-api-key' }` or\n * `{ in: 'bearer' }`.\n *\n * Parsed rather than left as source text because it is the one auth argument a renderer must turn\n * into a STRUCTURE: an OpenAPI `securityScheme` is `{type: apiKey, in, name}` or\n * `{type: http, scheme: bearer}`, and those are different documents. A renderer handed the string\n * `\"{ in: 'header', name: 'x-api-key' }\"` would have to parse TypeScript to emit either one, which\n * is this package's job and not a renderer's.\n */\nexport class DocumentedApiKeyCredential {\n constructor(\n /** `header` or `bearer`, verbatim from the declaration. */\n readonly location: string,\n /** The header name. Undefined for `bearer`, whose location IS `Authorization`. */\n readonly name: string | undefined,\n /** The prose a docs site renders on its authorization card. */\n readonly description: string | undefined,\n ) {}\n}\n\n/** `@WpAuthApiKey(regime, credentials)`, parsed. See {@link DocumentedApiKeyCredential}. */\nexport class DocumentedApiKey {\n constructor(\n readonly regime: string,\n /**\n * Every credential the regime requires, IN DECLARATION ORDER. They are an AND — all of them\n * are presented together — and the order is the order a published document lists them in.\n */\n readonly credentials: readonly DocumentedApiKeyCredential[],\n ) {}\n}\n\n/** WHICH credential an endpoint demands — `@WpAuthPublic`, `@WpAuthJwt`, … — verbatim from the source. */\nexport class DocumentedAuth {\n constructor(\n /** The decorator name as written, e.g. `WpAuthJwt`. */\n readonly decorator: string,\n /** Every argument's text, verbatim and in order. Empty for `@WpAuthPublic()`. */\n readonly argumentTexts: readonly string[],\n /**\n * The PARSED api-key declaration, set only for `@WpAuthApiKey`. Every other decorator's\n * argument is prose or a role list that a document quotes rather than restructures, so\n * {@link argumentTexts} is all they need — see {@link DocumentedApiKeyCredential} for why\n * this one is different.\n */\n readonly apiKey: DocumentedApiKey | undefined,\n ) {}\n}\n\n/** One `@Endpoint` method of one contract. */\nexport class DocumentedEndpoint {\n constructor(\n readonly methodName: string,\n /**\n * `GET` or `POST`, constant-folded from `@Endpoint`'s FIRST argument. A document cannot be\n * written without it — the verb is the key an operation hangs under in `paths`.\n */\n readonly httpMethod: string,\n /** The path, constant-folded. A const that cannot be folded is a HARD FAILURE, never a guess. */\n readonly path: string,\n /**\n * `read` | `write-idempotent` | `write`, verbatim. The SIDE-EFFECT contract, which is\n * independent of the verb: webpieces POSTs a read. A renderer publishes it rather than\n * inferring safety from the verb, which for this framework would be wrong.\n */\n readonly operation: string,\n /** `rpc` | `cloudtasks` | `cron` | `external`, verbatim — this package invents no taxonomy. */\n readonly kind: string,\n /**\n * `{ hidden: true }` — this method is absent from the CUSTOMER document. It stays in the\n * private one, and in the MCP one when it is a tool. WHICH documents the CONTRACT feeds at\n * all is a different, class-level decision; see {@link ApiDocModel.apiTypes}.\n */\n readonly hidden: boolean,\n /** `{ openWorld: true }` — this operation may touch systems outside this service. */\n readonly openWorld: boolean,\n readonly options: DocumentedEndpointOptions,\n readonly auth: DocumentedAuth | undefined,\n readonly mcpTool: DocumentedMcpTool | undefined,\n /** `@WpMcpAuthJwt(...)`'s argument text, when present. */\n readonly mcpAuthText: string | undefined,\n /** `@MaskLog({...})` — field name -> mask mode. */\n readonly maskLog: ReadonlyMap<string, string>,\n readonly description: string,\n /** The `@mcp` override. See {@link DocumentedField.mcpDescription}. */\n readonly mcpDescription: string | undefined,\n readonly request: TypeRef | undefined,\n readonly response: TypeRef | undefined,\n ) {}\n}\n\n/** ONE extraction pass over ONE contract file. Both #982's renderers read exactly this. */\nexport class ApiDocModel {\n constructor(\n /** The contract class name, e.g. `SaveApi`. */\n readonly contractName: string,\n /**\n * WHICH generated documents this contract feeds — `svc-to-svc`, `external-customer`, `mcp`,\n * verbatim from `@ApiType(...)`, defaulting to `svc-to-svc` alone when it declares nothing.\n *\n * A named list rather than a falsy default, because the grant has to be the TOKEN: a default\n * that reached customers would publish a contract whose author typed nothing about it.\n */\n readonly apiTypes: readonly string[],\n /** `@ApiPath(...)`, constant-folded. */\n readonly basePath: string,\n /** The JSDoc on the contract class, links flattened. */\n readonly description: string,\n readonly endpoints: readonly DocumentedEndpoint[],\n /** Every named type reachable from the endpoints, by name. A `$ref` target for a renderer. */\n readonly types: ReadonlyMap<string, DocumentedType>,\n /** Everything that could not be represented — recorded, not dropped. */\n readonly unmapped: readonly UnmappedType[],\n ) {}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ApiDocModel.js","sourceRoot":"","sources":["../../../../../../packages/docs/api-doc-model/src/model/ApiDocModel.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;GAQG;AAEH,qGAAqG;AACrG,MAAa,YAAY;IAGR;IAEA;IAEA;IANb;IACI,qEAAqE;IAC5D,QAAgB;IACzB,sDAAsD;IAC7C,QAAgB;IACzB,wEAAwE;IAC/D,MAAc;QAJd,aAAQ,GAAR,QAAQ,CAAQ;QAEhB,aAAQ,GAAR,QAAQ,CAAQ;QAEhB,WAAM,GAAN,MAAM,CAAQ;IACxB,CAAC;CACP;AATD,oCASC;AAED,wGAAwG;AACxG,MAAa,kBAAkB;IAGd;IAEA;IAJb;IACI,yCAAyC;IAChC,YAAoB;IAC7B,kFAAkF;IACzE,YAAyC;QAFzC,iBAAY,GAAZ,YAAY,CAAQ;QAEpB,iBAAY,GAAZ,YAAY,CAA6B;IACnD,CAAC;CACP;AAPD,gDAOC;AAED,4BAA4B;AAC5B,MAAa,eAAe;IAEX;IACA;IAMA;IAEA;IAEA;IAMA;IAEA;IAEA;IAEA;IAUA;IAUA;IA5Cb,YACa,IAAY,EACZ,IAAa;IACtB;;;;OAIG;IACM,QAAiB;IAC1B,sFAAsF;IAC7E,QAAiB;IAC1B,uEAAuE;IAC9D,WAAmB;IAC5B;;;;OAIG;IACM,cAAkC;IAC3C,8EAA8E;IACrE,MAA0B;IACnC,2EAA2E;IAClE,GAAuB;IAChC,2EAA2E;IAClE,GAAuB;IAChC;;;;;;;;OAQG;IACM,SAA6B;IACtC;;;;;;;;OAQG;IACM,QAAgB;QA3ChB,SAAI,GAAJ,IAAI,CAAQ;QACZ,SAAI,GAAJ,IAAI,CAAS;QAMb,aAAQ,GAAR,QAAQ,CAAS;QAEjB,aAAQ,GAAR,QAAQ,CAAS;QAEjB,gBAAW,GAAX,WAAW,CAAQ;QAMnB,mBAAc,GAAd,cAAc,CAAoB;QAElC,WAAM,GAAN,MAAM,CAAoB;QAE1B,QAAG,GAAH,GAAG,CAAoB;QAEvB,QAAG,GAAH,GAAG,CAAoB;QAUvB,cAAS,GAAT,SAAS,CAAoB;QAU7B,aAAQ,GAAR,QAAQ,CAAQ;IAC1B,CAAC;CACP;AA/CD,0CA+CC;AAED,kGAAkG;AAClG,MAAa,cAAc;IAEV;IACA;IAEA;IAEA;IAEA;IAEA;IAEA;IAZb,YACa,IAAY,EACZ,WAAmB;IAC5B,kDAAkD;IACzC,MAAkC;IAC3C,sDAAsD;IAC7C,UAA6B;IACtC,6CAA6C;IACpC,aAAgC;IACzC,wFAAwF;IAC/E,aAA6C;IACtD,mGAAmG;IAC1F,mBAAwC;QAXxC,SAAI,GAAJ,IAAI,CAAQ;QACZ,gBAAW,GAAX,WAAW,CAAQ;QAEnB,WAAM,GAAN,MAAM,CAA4B;QAElC,eAAU,GAAV,UAAU,CAAmB;QAE7B,kBAAa,GAAb,aAAa,CAAmB;QAEhC,kBAAa,GAAb,aAAa,CAAgC;QAE7C,wBAAmB,GAAnB,mBAAmB,CAAqB;IAClD,CAAC;CACP;AAfD,wCAeC;AAED,uGAAuG;AACvG,MAAa,yBAAyB;IAErB;IAEA;IACA;IAJb,YACa,QAAiB;IAC1B,+EAA+E;IACtE,QAA4B,EAC5B,UAA8B;QAH9B,aAAQ,GAAR,QAAQ,CAAS;QAEjB,aAAQ,GAAR,QAAQ,CAAoB;QAC5B,eAAU,GAAV,UAAU,CAAoB;IACxC,CAAC;CACP;AAPD,8DAOC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAa,iBAAiB;IAMb;IALb;IACI;;;OAGG;IACM,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;IACtB,CAAC;CACP;AARD,8CAQC;AAED;;;;;;;;;GASG;AACH,MAAa,0BAA0B;IAGtB;IAEA;IAEA;IANb;IACI,2DAA2D;IAClD,QAAgB;IACzB,kFAAkF;IACzE,IAAwB;IACjC,+DAA+D;IACtD,WAA+B;QAJ/B,aAAQ,GAAR,QAAQ,CAAQ;QAEhB,SAAI,GAAJ,IAAI,CAAoB;QAExB,gBAAW,GAAX,WAAW,CAAoB;IACzC,CAAC;CACP;AATD,gEASC;AAED,4FAA4F;AAC5F,MAAa,gBAAgB;IAEZ;IAKA;IANb,YACa,MAAc;IACvB;;;OAGG;IACM,WAAkD;QALlD,WAAM,GAAN,MAAM,CAAQ;QAKd,gBAAW,GAAX,WAAW,CAAuC;IAC5D,CAAC;CACP;AATD,4CASC;AAED,0GAA0G;AAC1G,MAAa,cAAc;IAGV;IAEA;IAOA;IAXb;IACI,uDAAuD;IAC9C,SAAiB;IAC1B,iFAAiF;IACxE,aAAgC;IACzC;;;;;OAKG;IACM,MAAoC;QATpC,cAAS,GAAT,SAAS,CAAQ;QAEjB,kBAAa,GAAb,aAAa,CAAmB;QAOhC,WAAM,GAAN,MAAM,CAA8B;IAC9C,CAAC;CACP;AAdD,wCAcC;AAED,8CAA8C;AAC9C,MAAa,kBAAkB;IAEd;IAKA;IAEA;IAMA;IAEA;IAMA;IAEA;IACA;IACA;IACA;IAWA;IAEA;IAEA;IACA;IAEA;IACA;IACA;IA/Cb,YACa,UAAkB;IAC3B;;;OAGG;IACM,UAAkB;IAC3B,iGAAiG;IACxF,IAAY;IACrB;;;;OAIG;IACM,SAAiB;IAC1B,+FAA+F;IACtF,IAAY;IACrB;;;;OAIG;IACM,MAAe;IACxB,qFAAqF;IAC5E,SAAkB,EAClB,OAAkC,EAClC,IAAgC,EAChC,OAAsC;IAC/C;;;;;;;;;OASG;IACM,aAAiC;IAC1C,0DAA0D;IACjD,WAA+B;IACxC,mDAAmD;IAC1C,OAAoC,EACpC,WAAmB;IAC5B,uEAAuE;IAC9D,cAAkC,EAClC,OAA4B,EAC5B,QAA6B;QA9C7B,eAAU,GAAV,UAAU,CAAQ;QAKlB,eAAU,GAAV,UAAU,CAAQ;QAElB,SAAI,GAAJ,IAAI,CAAQ;QAMZ,cAAS,GAAT,SAAS,CAAQ;QAEjB,SAAI,GAAJ,IAAI,CAAQ;QAMZ,WAAM,GAAN,MAAM,CAAS;QAEf,cAAS,GAAT,SAAS,CAAS;QAClB,YAAO,GAAP,OAAO,CAA2B;QAClC,SAAI,GAAJ,IAAI,CAA4B;QAChC,YAAO,GAAP,OAAO,CAA+B;QAWtC,kBAAa,GAAb,aAAa,CAAoB;QAEjC,gBAAW,GAAX,WAAW,CAAoB;QAE/B,YAAO,GAAP,OAAO,CAA6B;QACpC,gBAAW,GAAX,WAAW,CAAQ;QAEnB,mBAAc,GAAd,cAAc,CAAoB;QAClC,YAAO,GAAP,OAAO,CAAqB;QAC5B,aAAQ,GAAR,QAAQ,CAAqB;IACvC,CAAC;CACP;AAlDD,gDAkDC;AAED,2FAA2F;AAC3F,MAAa,WAAW;IAGP;IAQA;IAEA;IAEA;IACA;IAEA;IAEA;IAnBb;IACI,+CAA+C;IACtC,YAAoB;IAC7B;;;;;;OAMG;IACM,QAA2B;IACpC,wCAAwC;IAC/B,QAAgB;IACzB,wDAAwD;IAC/C,WAAmB,EACnB,SAAwC;IACjD,8FAA8F;IACrF,KAA0C;IACnD,wEAAwE;IAC/D,QAAiC;QAjBjC,iBAAY,GAAZ,YAAY,CAAQ;QAQpB,aAAQ,GAAR,QAAQ,CAAmB;QAE3B,aAAQ,GAAR,QAAQ,CAAQ;QAEhB,gBAAW,GAAX,WAAW,CAAQ;QACnB,cAAS,GAAT,SAAS,CAA+B;QAExC,UAAK,GAAL,KAAK,CAAqC;QAE1C,aAAQ,GAAR,QAAQ,CAAyB;IAC3C,CAAC;CACP;AAtBD,kCAsBC","sourcesContent":["import { TypeRef } from './TypeRef';\n\n/**\n * The model classes. Every one of them is a CLASS with an explicit constructor per `CLAUDE.md` §1 —\n * these are data-only structures, and a renderer (#982) builds nothing, it only reads.\n *\n * Nothing in this file imports anything but {@link TypeRef}: the package depends on `typescript` and\n * NOTHING else, so it can be pointed at any upstream project's contract. One app-specific import\n * here would end that, which is why `responsibilities.md` states the constraint rather than leaving\n * it to be discovered.\n */\n\n/** A type the extractor could not represent. RECORDED, never dropped — #982's guard needs a name. */\nexport class UnmappedType {\n constructor(\n /** The verbatim TypeScript type text, e.g. `Map<string, Widget>`. */\n readonly typeText: string,\n /** Pointer-style location: `path/to/File.ts:12:5`. */\n readonly location: string,\n /** Why it could not be mapped, in one sentence a renderer can print. */\n readonly reason: string,\n ) {}\n}\n\n/** The DERIVED discriminator of a union — never invented, only observed. See {@link DocumentedType}. */\nexport class UnionDiscriminator {\n constructor(\n /** The property every branch carries. */\n readonly propertyName: string,\n /** branch type name -> the single string literal that branch's property holds. */\n readonly branchValues: ReadonlyMap<string, string>,\n ) {}\n}\n\n/** One field of one DTO. */\nexport class DocumentedField {\n constructor(\n readonly name: string,\n readonly type: TypeRef,\n /**\n * OPTIONAL (`name?: string`) — the property may be ABSENT. Distinguished from\n * {@link nullable} on purpose: `{}` and `{name: null}` are different wire documents, and a\n * renderer that conflates them emits a schema that rejects one of them.\n */\n readonly optional: boolean,\n /** NULLABLE (`name: string | null`) — the property is present and may hold `null`. */\n readonly nullable: boolean,\n /** The JSDoc body, links flattened. Empty string when undocumented. */\n readonly description: string,\n /**\n * The `@mcp` block tag — an OPTIONAL agent-facing override. Undefined means \"no override\",\n * and a renderer falls back to {@link description}; the fallback is NOT applied here so a\n * renderer can tell a deliberate agent-facing sentence from a reused human one.\n */\n readonly mcpDescription: string | undefined,\n /** The `@format` tag, lifted onto the SCALAR (on an array, onto the ITEM). */\n readonly format: string | undefined,\n /** `@WpMin(n)` — numeric fields only; anything else is a build failure. */\n readonly min: number | undefined,\n /** `@WpMax(n)` — numeric fields only; anything else is a build failure. */\n readonly max: number | undefined,\n /**\n * The `@mcpHeader <token>` JSDoc tag — the MCP 2026 SEP-2243 header this PRIMITIVE field is\n * mirrored into (`Mcp-Param-{token}`). Undefined for every field that is not mirrored, which\n * is nearly all of them.\n *\n * It is documentation and therefore lives in JSDoc, next to the sentence describing the\n * field, rather than in a decorator argument — and since #984 it is the only spelling of the\n * fact at all.\n */\n readonly mcpHeader: string | undefined,\n /**\n * Pointer-style `path/to/File.ts:12:5` for the property declaration itself.\n *\n * A renderer never needs it — it publishes a schema, not a file offset. The build RULES do:\n * `api-rules-for-openapi` refuses a field whose value type is `unknown`, and a refusal that\n * cannot say WHERE costs the author a grep over every DTO the contract reaches. It is\n * carried on the FIELD rather than recomputed because only the extractor still has the\n * syntax node, and a second reader deriving it would be a second answer to \"where is this\".\n */\n readonly location: string,\n ) {}\n}\n\n/** One named type reachable from a contract: an object DTO, a string-literal enum, or a union. */\nexport class DocumentedType {\n constructor(\n readonly name: string,\n readonly description: string,\n /** Object shape. Empty for an enum or a union. */\n readonly fields: readonly DocumentedField[],\n /** Set for a string-literal union that has a name. */\n readonly enumValues: readonly string[],\n /** Set for a union of named object types. */\n readonly unionRefNames: readonly string[],\n /** Set only when EVERY branch carries the same property typed as one string literal. */\n readonly discriminator: UnionDiscriminator | undefined,\n /** An index signature (`[k: string]: X`) — the OPEN-MAP half of an object that also has fields. */\n readonly indexSignatureValue: TypeRef | undefined,\n ) {}\n}\n\n/** `@Endpoint(httpMethod, path, operation, kind, options?)`'s LAST argument, as a document sees it. */\nexport class DocumentedEndpointOptions {\n constructor(\n readonly formPost: boolean,\n /** `calledBy` — REQUIRED by the decorator for `external`, absent otherwise. */\n readonly calledBy: string | undefined,\n readonly callerKind: string | undefined,\n ) {}\n}\n\n/**\n * The `@WpMcpTool('search_stores')` declaration, when the method carries one — the ONE fact the\n * source cannot otherwise state, and nothing else.\n *\n * `description` used to sit on the decorator too. The method's JSDoc is the description, for the\n * agent and for the partner alike, byte-identical: two authored copies of one paragraph is the\n * two-spellings shim, and its failure mode is concrete — the partner reads the JSDoc in the OpenAPI\n * document while the agent reads the decorator string in `tools/list`, and they drift the first time\n * somebody edits one. #984 deleted it, which left the decorator holding one field, so it takes the\n * name as a plain string.\n *\n * The three side-effect hints are COMPUTED from the endpoint's `operation` by `mcpHintsForOperation`\n * in `@webpieces/core-util`, which is the one place that mapping lives — `READ | WRITE_IDEMPOTENT |\n * WRITE` already says whether repeating a call is safe, so a hand-declared hint would be a second\n * answer to a question the contract has answered. `openWorldHint` is `@Endpoint`'s `openWorld`.\n */\nexport class DocumentedMcpTool {\n constructor(\n /**\n * The STABLE protocol name. Deliberately independent of the method name, because renaming a\n * method must not break a saved agent workflow.\n */\n readonly name: string,\n ) {}\n}\n\n/**\n * ONE credential of an api-key regime, PARSED — `{ in: 'header', name: 'x-api-key' }` or\n * `{ in: 'bearer' }`.\n *\n * Parsed rather than left as source text because it is the one auth argument a renderer must turn\n * into a STRUCTURE: an OpenAPI `securityScheme` is `{type: apiKey, in, name}` or\n * `{type: http, scheme: bearer}`, and those are different documents. A renderer handed the string\n * `\"{ in: 'header', name: 'x-api-key' }\"` would have to parse TypeScript to emit either one, which\n * is this package's job and not a renderer's.\n */\nexport class DocumentedApiKeyCredential {\n constructor(\n /** `header` or `bearer`, verbatim from the declaration. */\n readonly location: string,\n /** The header name. Undefined for `bearer`, whose location IS `Authorization`. */\n readonly name: string | undefined,\n /** The prose a docs site renders on its authorization card. */\n readonly description: string | undefined,\n ) {}\n}\n\n/** `@WpAuthApiKey(regime, credentials)`, parsed. See {@link DocumentedApiKeyCredential}. */\nexport class DocumentedApiKey {\n constructor(\n readonly regime: string,\n /**\n * Every credential the regime requires, IN DECLARATION ORDER. They are an AND — all of them\n * are presented together — and the order is the order a published document lists them in.\n */\n readonly credentials: readonly DocumentedApiKeyCredential[],\n ) {}\n}\n\n/** WHICH credential an endpoint demands — `@WpAuthPublic`, `@WpAuthJwt`, … — verbatim from the source. */\nexport class DocumentedAuth {\n constructor(\n /** The decorator name as written, e.g. `WpAuthJwt`. */\n readonly decorator: string,\n /** Every argument's text, verbatim and in order. Empty for `@WpAuthPublic()`. */\n readonly argumentTexts: readonly string[],\n /**\n * The PARSED api-key declaration, set only for `@WpAuthApiKey`. Every other decorator's\n * argument is prose or a role list that a document quotes rather than restructures, so\n * {@link argumentTexts} is all they need — see {@link DocumentedApiKeyCredential} for why\n * this one is different.\n */\n readonly apiKey: DocumentedApiKey | undefined,\n ) {}\n}\n\n/** One `@Endpoint` method of one contract. */\nexport class DocumentedEndpoint {\n constructor(\n readonly methodName: string,\n /**\n * `GET` or `POST`, constant-folded from `@Endpoint`'s FIRST argument. A document cannot be\n * written without it — the verb is the key an operation hangs under in `paths`.\n */\n readonly httpMethod: string,\n /** The path, constant-folded. A const that cannot be folded is a HARD FAILURE, never a guess. */\n readonly path: string,\n /**\n * `read` | `write-idempotent` | `write`, verbatim. The SIDE-EFFECT contract, which is\n * independent of the verb: webpieces POSTs a read. A renderer publishes it rather than\n * inferring safety from the verb, which for this framework would be wrong.\n */\n readonly operation: string,\n /** `rpc` | `cloudtasks` | `cron` | `external`, verbatim — this package invents no taxonomy. */\n readonly kind: string,\n /**\n * `{ hidden: true }` — this method is absent from the CUSTOMER document. It stays in the\n * private one, and in the MCP one when it is a tool. WHICH documents the CONTRACT feeds at\n * all is a different, class-level decision; see {@link ApiDocModel.apiTypes}.\n */\n readonly hidden: boolean,\n /** `{ openWorld: true }` — this operation may touch systems outside this service. */\n readonly openWorld: boolean,\n readonly options: DocumentedEndpointOptions,\n readonly auth: DocumentedAuth | undefined,\n readonly mcpTool: DocumentedMcpTool | undefined,\n /**\n * `@InvalidEndpointForMcp('<reason>')`'s reason, when the method carries one — this endpoint\n * is PERMANENTLY outside MCP and was never a tool candidate.\n *\n * Distinct from \"has no `@WpMcpTool`\", which only says \"not a tool yet\". A renderer must not\n * report one of these as a SKIPPED tool, and `api-rules-for-mcp` stops asking a method with\n * one whether it could be served — the declaration is the answer. Carrying the reason rather\n * than a boolean is the point: the rule restates the list of exclusions with their arguments\n * on every run.\n */\n readonly invalidForMcp: string | undefined,\n /** `@WpMcpAuthJwt(...)`'s argument text, when present. */\n readonly mcpAuthText: string | undefined,\n /** `@MaskLog({...})` — field name -> mask mode. */\n readonly maskLog: ReadonlyMap<string, string>,\n readonly description: string,\n /** The `@mcp` override. See {@link DocumentedField.mcpDescription}. */\n readonly mcpDescription: string | undefined,\n readonly request: TypeRef | undefined,\n readonly response: TypeRef | undefined,\n ) {}\n}\n\n/** ONE extraction pass over ONE contract file. Both #982's renderers read exactly this. */\nexport class ApiDocModel {\n constructor(\n /** The contract class name, e.g. `SaveApi`. */\n readonly contractName: string,\n /**\n * WHICH generated documents this contract feeds — `svc-to-svc`, `external-customer`, `mcp`,\n * verbatim from `@ApiType(...)`, defaulting to `svc-to-svc` alone when it declares nothing.\n *\n * A named list rather than a falsy default, because the grant has to be the TOKEN: a default\n * that reached customers would publish a contract whose author typed nothing about it.\n */\n readonly apiTypes: readonly string[],\n /** `@ApiPath(...)`, constant-folded. */\n readonly basePath: string,\n /** The JSDoc on the contract class, links flattened. */\n readonly description: string,\n readonly endpoints: readonly DocumentedEndpoint[],\n /** Every named type reachable from the endpoints, by name. A `$ref` target for a renderer. */\n readonly types: ReadonlyMap<string, DocumentedType>,\n /** Everything that could not be represented — recorded, not dropped. */\n readonly unmapped: readonly UnmappedType[],\n ) {}\n}\n"]}
|