@wildo-ai/saas-technical-doc 1.1.4 → 1.1.6
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/dist/esm/build/csp-emit.d.ts.map +1 -1
- package/dist/esm/build/load-materialized-frontend-providers.d.ts.map +1 -1
- package/dist/esm/companion/application-documentation/application-administration-documentation.d.ts.map +1 -1
- package/dist/esm/companion/application-documentation/application-administration-documentation.js.map +1 -1
- package/dist/esm/companion/application-documentation/application-authentication-documentation.d.ts.map +1 -1
- package/dist/esm/companion/application-documentation/application-connection-documentation.d.ts +37 -0
- package/dist/esm/companion/application-documentation/application-connection-documentation.d.ts.map +1 -1
- package/dist/esm/companion/application-documentation/application-connection-documentation.js +46 -5
- package/dist/esm/companion/application-documentation/application-connection-documentation.js.map +1 -1
- package/dist/esm/companion/application-documentation/application-documentation-chapters.d.ts +101 -0
- package/dist/esm/companion/application-documentation/application-documentation-chapters.d.ts.map +1 -0
- package/dist/esm/companion/application-documentation/application-documentation-chapters.js +205 -0
- package/dist/esm/companion/application-documentation/application-documentation-chapters.js.map +1 -0
- package/dist/esm/companion/application-documentation/application-domain-documentation.d.ts.map +1 -1
- package/dist/esm/companion/application-documentation/application-domain-documentation.js.map +1 -1
- package/dist/esm/companion/application-documentation/application-integration-documentation.d.ts.map +1 -1
- package/dist/esm/companion/application-documentation/application-integration-documentation.js.map +1 -1
- package/dist/esm/companion/application-documentation/application-organization-role-documentation.d.ts.map +1 -1
- package/dist/esm/companion/application-documentation/application-organization-role-documentation.js.map +1 -1
- package/dist/esm/companion/application-documentation/application-organization-unit-resource-documentation.d.ts.map +1 -1
- package/dist/esm/companion/application-documentation/application-organization-unit-resource-documentation.js +3 -0
- package/dist/esm/companion/application-documentation/application-organization-unit-resource-documentation.js.map +1 -1
- package/dist/esm/companion/application-documentation/docs-api-origin-substitution.d.ts +34 -0
- package/dist/esm/companion/application-documentation/docs-api-origin-substitution.d.ts.map +1 -0
- package/dist/esm/companion/application-documentation/docs-api-origin-substitution.js +45 -0
- package/dist/esm/companion/application-documentation/docs-api-origin-substitution.js.map +1 -0
- package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.d.ts +24 -10
- package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.d.ts.map +1 -1
- package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.js +25 -15
- package/dist/esm/companion/application-documentation/technical-documentation-engine-content-bundle.js.map +1 -1
- package/dist/esm/companion/application-documentation/technical-documentation-operational-evidence.d.ts.map +1 -1
- package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.d.ts +11 -3
- package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.d.ts.map +1 -1
- package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.js +9 -2
- package/dist/esm/companion/application-documentation/technical-documentation-private-derivation.js.map +1 -1
- package/dist/esm/companion/application-documentation/technical-documentation-publication-policy.d.ts.map +1 -1
- package/dist/esm/companion/application-documentation/technical-documentation-publication-policy.js +10 -4
- package/dist/esm/companion/application-documentation/technical-documentation-publication-policy.js.map +1 -1
- package/dist/esm/companion/content/application-consumer-documentation-content-loader.d.ts.map +1 -1
- package/dist/esm/companion/index.d.ts +2 -0
- package/dist/esm/companion/index.d.ts.map +1 -1
- package/dist/esm/companion/index.js +2 -0
- package/dist/esm/companion/index.js.map +1 -1
- package/dist/esm/companion/manual-controller-route-projection.d.ts.map +1 -1
- package/dist/esm/companion/manual-controller-route-projection.js.map +1 -1
- package/dist/esm/companion/openapi-example-derivation.d.ts +53 -0
- package/dist/esm/companion/openapi-example-derivation.d.ts.map +1 -0
- package/dist/esm/companion/openapi-example-derivation.js +229 -0
- package/dist/esm/companion/openapi-example-derivation.js.map +1 -0
- package/dist/esm/companion/openapi-generator.d.ts +8 -4
- package/dist/esm/companion/openapi-generator.d.ts.map +1 -1
- package/dist/esm/companion/openapi-generator.js +323 -33
- package/dist/esm/companion/openapi-generator.js.map +1 -1
- package/dist/esm/companion/operation-projection.schemas.d.ts +57 -1
- package/dist/esm/companion/operation-projection.schemas.d.ts.map +1 -1
- package/dist/esm/companion/operation-projection.schemas.js +29 -0
- package/dist/esm/companion/operation-projection.schemas.js.map +1 -1
- package/dist/esm/companion/publish-result.types.d.ts.map +1 -1
- package/dist/esm/companion/publish-result.types.js.map +1 -1
- package/dist/esm/companion/rendering/technical-documentation-authorized-bundle-reader.d.ts.map +1 -1
- package/dist/esm/companion/rendering/technical-documentation-docusaurus-renderer.d.ts.map +1 -1
- package/dist/esm/companion/rendering/technical-documentation-docusaurus-renderer.js +8 -0
- package/dist/esm/companion/rendering/technical-documentation-docusaurus-renderer.js.map +1 -1
- package/dist/esm/companion/rendering/technical-documentation-managed-tree-validator.d.ts.map +1 -1
- package/dist/esm/companion/rendering/technical-documentation-managed-tree-validator.js +20 -0
- package/dist/esm/companion/rendering/technical-documentation-managed-tree-validator.js.map +1 -1
- package/dist/esm/companion/rendering/technical-documentation-openapi-renderer.d.ts +2 -0
- package/dist/esm/companion/rendering/technical-documentation-openapi-renderer.d.ts.map +1 -1
- package/dist/esm/companion/rendering/technical-documentation-openapi-renderer.js +48 -31
- package/dist/esm/companion/rendering/technical-documentation-openapi-renderer.js.map +1 -1
- package/dist/esm/companion/rendering/technical-documentation-render-model.d.ts.map +1 -1
- package/dist/esm/companion/rendering/technical-documentation-render-model.js +26 -10
- package/dist/esm/companion/rendering/technical-documentation-render-model.js.map +1 -1
- package/dist/esm/companion/rendering/technical-documentation-search-index-renderer.d.ts.map +1 -1
- package/dist/esm/companion/rendering/technical-documentation-search-index-renderer.js.map +1 -1
- package/dist/esm/companion/spec-to-operation-doc.d.ts +52 -10
- package/dist/esm/companion/spec-to-operation-doc.d.ts.map +1 -1
- package/dist/esm/companion/spec-to-operation-doc.js +125 -7
- package/dist/esm/companion/spec-to-operation-doc.js.map +1 -1
- package/dist/esm/companion/technical-documentation-asset-path.d.ts.map +1 -1
- package/dist/esm/companion/technical-documentation-capture-execution-port.d.ts.map +1 -1
- package/dist/esm/companion/technical-documentation-capture-execution-port.js.map +1 -1
- package/dist/esm/companion/technical-documentation-diagram-definitions.d.ts.map +1 -1
- package/dist/esm/companion/technical-documentation-diagram-definitions.js.map +1 -1
- package/dist/esm/companion/technical-documentation-diagram-materializer.d.ts.map +1 -1
- package/dist/esm/companion/technical-documentation-diagram-materializer.js.map +1 -1
- package/dist/esm/companion/technical-documentation-placeholder-materializer.d.ts.map +1 -1
- package/dist/esm/companion/zod-to-openapi.d.ts.map +1 -1
- package/dist/esm/companion-exports.d.ts.map +1 -1
- package/dist/esm/config/define-tech-doc-config.d.ts.map +1 -1
- package/dist/esm/config/index.d.ts.map +1 -1
- package/dist/esm/config/wildo-tech-doc-config.schemas.d.ts.map +1 -1
- package/dist/esm/config/wildo-tech-doc-config.schemas.js.map +1 -1
- package/dist/esm/content/application-consumer-documentation-content-manifest.schemas.d.ts.map +1 -1
- package/dist/esm/content/application-consumer-documentation-content.techdoc.d.ts +27 -24
- package/dist/esm/content/application-consumer-documentation-content.techdoc.d.ts.map +1 -1
- package/dist/esm/content/application-consumer-documentation-content.techdoc.js +205 -82
- package/dist/esm/content/application-consumer-documentation-content.techdoc.js.map +1 -1
- package/dist/esm/content.exports.d.ts.map +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/openapi/api-reference-link-index.d.ts +3 -0
- package/dist/esm/openapi/api-reference-link-index.d.ts.map +1 -1
- package/dist/esm/openapi/api-reference-link-index.js +26 -15
- package/dist/esm/openapi/api-reference-link-index.js.map +1 -1
- package/dist/esm/openapi/api-reference-pages.d.ts +55 -0
- package/dist/esm/openapi/api-reference-pages.d.ts.map +1 -0
- package/dist/esm/openapi/api-reference-pages.js +229 -0
- package/dist/esm/openapi/api-reference-pages.js.map +1 -0
- package/dist/esm/openapi/api-reference-search.d.ts +53 -0
- package/dist/esm/openapi/api-reference-search.d.ts.map +1 -0
- package/dist/esm/openapi/api-reference-search.js +100 -0
- package/dist/esm/openapi/api-reference-search.js.map +1 -0
- package/dist/esm/openapi/api-reference-targets.d.ts +11 -0
- package/dist/esm/openapi/api-reference-targets.d.ts.map +1 -1
- package/dist/esm/openapi/api-reference-targets.js +8 -0
- package/dist/esm/openapi/api-reference-targets.js.map +1 -1
- package/dist/esm/openapi/index.d.ts +2 -0
- package/dist/esm/openapi/index.d.ts.map +1 -1
- package/dist/esm/openapi/index.js +2 -0
- package/dist/esm/openapi/index.js.map +1 -1
- package/dist/esm/openapi/openapi-generation-output.schemas.d.ts.map +1 -1
- package/dist/esm/openapi-reference-model.exports.d.ts +2 -0
- package/dist/esm/openapi-reference-model.exports.d.ts.map +1 -1
- package/dist/esm/openapi-reference-model.exports.js +2 -0
- package/dist/esm/openapi-reference-model.exports.js.map +1 -1
- package/dist/esm/runtime/AuthExchangePage.d.ts +45 -4
- package/dist/esm/runtime/AuthExchangePage.d.ts.map +1 -1
- package/dist/esm/runtime/AuthExchangePage.js +45 -12
- package/dist/esm/runtime/AuthExchangePage.js.map +1 -1
- package/dist/esm/runtime/DocsAuthContext.d.ts +2 -2
- package/dist/esm/runtime/DocsAuthContext.d.ts.map +1 -1
- package/dist/esm/runtime/DocsAuthContext.js +8 -4
- package/dist/esm/runtime/DocsAuthContext.js.map +1 -1
- package/dist/esm/runtime/DocsFrontendProviders.d.ts +30 -0
- package/dist/esm/runtime/DocsFrontendProviders.d.ts.map +1 -0
- package/dist/esm/runtime/DocsFrontendProviders.js +39 -0
- package/dist/esm/runtime/DocsFrontendProviders.js.map +1 -0
- package/dist/esm/runtime/DocsProviderComponent.d.ts +41 -0
- package/dist/esm/runtime/DocsProviderComponent.d.ts.map +1 -0
- package/dist/esm/runtime/DocsProviderComponent.js +17 -0
- package/dist/esm/runtime/DocsProviderComponent.js.map +1 -0
- package/dist/esm/runtime/decode-jwt-claims.d.ts.map +1 -1
- package/dist/esm/runtime/docs-auth-client.d.ts.map +1 -1
- package/dist/esm/runtime/docs-auth-session.schemas.d.ts.map +1 -1
- package/dist/esm/runtime/documentation-site-translator.d.ts +53 -0
- package/dist/esm/runtime/documentation-site-translator.d.ts.map +1 -0
- package/dist/esm/runtime/documentation-site-translator.js +51 -0
- package/dist/esm/runtime/documentation-site-translator.js.map +1 -0
- package/dist/esm/runtime/frontend-provider-registry.techdoc.d.ts +1 -2
- package/dist/esm/runtime/frontend-provider-registry.techdoc.d.ts.map +1 -1
- package/dist/esm/runtime/frontend-provider-registry.techdoc.js.map +1 -1
- package/dist/esm/runtime/index.d.ts +8 -0
- package/dist/esm/runtime/index.d.ts.map +1 -1
- package/dist/esm/runtime/index.js +8 -0
- package/dist/esm/runtime/index.js.map +1 -1
- package/dist/esm/runtime/openapi-reference-conservation.d.ts.map +1 -1
- package/dist/esm/runtime/openapi-reference-model.d.ts +30 -0
- package/dist/esm/runtime/openapi-reference-model.d.ts.map +1 -1
- package/dist/esm/runtime/openapi-reference-model.js +85 -11
- package/dist/esm/runtime/openapi-reference-model.js.map +1 -1
- package/dist/esm/runtime/openapi-reference-navigation.d.ts +50 -0
- package/dist/esm/runtime/openapi-reference-navigation.d.ts.map +1 -0
- package/dist/esm/runtime/openapi-reference-navigation.js +46 -0
- package/dist/esm/runtime/openapi-reference-navigation.js.map +1 -0
- package/dist/esm/runtime/openapi-reference-samples.d.ts +40 -0
- package/dist/esm/runtime/openapi-reference-samples.d.ts.map +1 -0
- package/dist/esm/runtime/openapi-reference-samples.js +169 -0
- package/dist/esm/runtime/openapi-reference-samples.js.map +1 -0
- package/dist/esm/runtime/openapi-reference-styles.d.ts +28 -0
- package/dist/esm/runtime/openapi-reference-styles.d.ts.map +1 -0
- package/dist/esm/runtime/openapi-reference-styles.js +292 -0
- package/dist/esm/runtime/openapi-reference-styles.js.map +1 -0
- package/dist/esm/runtime/openapi-reference-view.d.ts +40 -5
- package/dist/esm/runtime/openapi-reference-view.d.ts.map +1 -1
- package/dist/esm/runtime/openapi-reference-view.js +828 -82
- package/dist/esm/runtime/openapi-reference-view.js.map +1 -1
- package/dist/esm/runtime/openapi-reference-words-context.d.ts +12 -0
- package/dist/esm/runtime/openapi-reference-words-context.d.ts.map +1 -0
- package/dist/esm/runtime/openapi-reference-words-context.js +30 -0
- package/dist/esm/runtime/openapi-reference-words-context.js.map +1 -0
- package/dist/esm/runtime/openapi-reference-words.d.ts +205 -0
- package/dist/esm/runtime/openapi-reference-words.d.ts.map +1 -0
- package/dist/esm/runtime/openapi-reference-words.js +162 -0
- package/dist/esm/runtime/openapi-reference-words.js.map +1 -0
- package/dist/esm/runtime/provider-component-registry.techdoc.d.ts +31 -0
- package/dist/esm/runtime/provider-component-registry.techdoc.d.ts.map +1 -0
- package/dist/esm/runtime/provider-component-registry.techdoc.js +35 -0
- package/dist/esm/runtime/provider-component-registry.techdoc.js.map +1 -0
- package/dist/esm/runtime/use-docs-auth-session.d.ts.map +1 -1
- package/dist/esm/runtime/use-docs-frontend-provider-registry.d.ts +1 -0
- package/dist/esm/runtime/use-docs-frontend-provider-registry.d.ts.map +1 -1
- package/dist/esm/runtime/use-docs-frontend-provider-registry.js +10 -2
- package/dist/esm/runtime/use-docs-frontend-provider-registry.js.map +1 -1
- package/dist/esm/runtime/use-docs-provider-component.d.ts +29 -0
- package/dist/esm/runtime/use-docs-provider-component.d.ts.map +1 -0
- package/dist/esm/runtime/use-docs-provider-component.js +42 -0
- package/dist/esm/runtime/use-docs-provider-component.js.map +1 -0
- package/dist/esm/runtime/use-docs-provider-scripts.d.ts +37 -0
- package/dist/esm/runtime/use-docs-provider-scripts.d.ts.map +1 -0
- package/dist/esm/runtime/use-docs-provider-scripts.js +47 -0
- package/dist/esm/runtime/use-docs-provider-scripts.js.map +1 -0
- package/dist/esm/runtime/use-docs-provider-sdks.d.ts.map +1 -1
- package/dist/esm/runtime/use-docs-provider-sdks.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +8 -24
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"technical-documentation-render-model.js","sourceRoot":"","sources":["../../../../src/companion/rendering/technical-documentation-render-model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,gDAAgD,EAAE,MAAM,4EAA4E,CAAC;AAE9I,OAAO,EACL,kDAAkD,EAGlD,kDAAkD,GASnD,MAAM,uDAAuD,CAAC;AAE/D;;;;;GAKG;AACH,MAAM,UAAU,iCAAiC,CAAC,KAAiB;IACjE,OAAO,UAAU,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;AACtE,CAAC;AAwBD,MAAM,UAAU,6CAA6C,CAAC,KAM7D;IACC;;;;;OAKG;IACH,OAAO;QACL,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,eAAe,EAAE,KAAK,CAAC,eAAe;QACtC,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;KACzC,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,IAAkC;IACrD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC;IAC9D,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACpF,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,IAAI,CAAC,OAAO,+BAA+B,CAAC,CAAC;IACpH,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,wBAAwB,GAAqC;IAC/D,yBAAyB,EAAE,aAAa;IACxC,+BAA+B,EAAE,+BAA+B;IAChE,cAAc,EAAE,8BAA8B;IAC9C,iBAAiB,EAAE,qCAAqC;IACxD,kBAAkB,EAAE,sCAAsC;IAC1D,6BAA6B,EAAE,iDAAiD;IAChF,sBAAsB,EAAE,0CAA0C;IAClE,gBAAgB,EAAE,oCAAoC;IACtD,eAAe,EAAE,mCAAmC;IACpD,0BAA0B,EAAE,8CAA8C;IAC1E,kBAAkB,EAAE,sCAAsC;IAC1D,UAAU,EAAE,8BAA8B;IAC1C,2BAA2B,EAAE,+CAA+C;IAC5E,oBAAoB,EAAE,wCAAwC;IAC9D,uBAAuB,EAAE,2CAA2C;IACpE,gBAAgB,EAAE,oCAAoC;IACtD,uBAAuB,EAAE,2CAA2C;IACpE,kCAAkC,EAAE,sDAAsD;IAC1F,0BAA0B,EAAE,8CAA8C;IAC1E,qBAAqB,EAAE,qBAAqB;IAC5C,uBAAuB,EAAE,2CAA2C;IACpE,yBAAyB,EAAE,6CAA6C;IACxE,oBAAoB,EAAE,2CAA2C;IACjE,oBAAoB,EAAE,wCAAwC;IAC9D,2BAA2B,EAAE,+CAA+C;IAC5E,oCAAoC,EAAE,wDAAwD;IAC9F,iCAAiC,EAAE,qDAAqD;IACxF,4BAA4B,EAAE,gDAAgD;IAC9E,wBAAwB,EAAE,4CAA4C;IACtE,yBAAyB,EAAE,6CAA6C;IACxE,0BAA0B,EAAE,8CAA8C;IAC1E,IAAI,EAAE,uCAAuC;IAC7C,4BAA4B,EAAE,gDAAgD;IAC9E,gBAAgB,EAAE,oCAAoC;IACtD,sBAAsB,EAAE,0CAA0C;IAClE,WAAW,EAAE,+BAA+B;IAC5C,gCAAgC,EAAE,oDAAoD;IACtF,4BAA4B,EAAE,gDAAgD;IAC9E,4BAA4B,EAAE,gDAAgD;IAC9E,+BAA+B,EAAE,mDAAmD;IACpF,gBAAgB,EAAE,oBAAoB;IACtC,yBAAyB,EAAE,sCAAsC;IACjE,sCAAsC,EAAE,0CAA0C;IAClF,sBAAsB,EAAE,yCAAyC;IACjE,uBAAuB,EAAE,mCAAmC;IAC5D,aAAa,EAAE,gCAAgC;IAC/C,yBAAyB,EAAE,4CAA4C;IACvE,cAAc,EAAE,iCAAiC;IACjD,wCAAwC,EAAE,iCAAiC;IAC3E,8BAA8B,EAAE,iDAAiD;IACjF,mCAAmC,EAAE,qCAAqC;IAC1E,YAAY,EAAE,cAAc;IAC5B,sBAAsB,EAAE,mCAAmC;IAC3D,aAAa,EAAE,6BAA6B;IAC5C,gBAAgB,EAAE,gCAAgC;IAClD,cAAc,EAAE,8BAA8B;IAC9C,iBAAiB,EAAE,8BAA8B;IACjD,gBAAgB,EAAE,8BAA8B;IAChD,eAAe,EAAE,6BAA6B;IAC9C,qBAAqB,EAAE,mCAAmC;IAC1D,wBAAwB,EAAE,qBAAqB;IAC/C,kBAAkB,EAAE,kBAAkB;IACtC,kBAAkB,EAAE,kBAAkB;IACtC,eAAe,EAAE,0CAA0C;IAC3D,iBAAiB,EAAE,uBAAuB;IAC1C,sBAAsB,EAAE,+BAA+B;IACvD,kBAAkB,EAAE,gCAAgC;IACpD,2BAA2B,EAAE,oCAAoC;IACjE,iCAAiC,EAAE,uCAAuC;IAC1E,0BAA0B,EAAE,gCAAgC;IAC5D,QAAQ,EAAE,uBAAuB;IACjC,qCAAqC,EAAE,0CAA0C;IACjF,yBAAyB,EAAE,uCAAuC;IAClE,4BAA4B,EAAE,0CAA0C;IACxE,iCAAiC,EAAE,oCAAoC;CAC1E,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAwB,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC,CAAC;AAExG;;;;;;;;;;;;;;GAcG;AACH,SAAS,WAAW,CAAC,IAAkC;IACrD,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAC/B;;;;;;;;;;;;OAYG;IACH,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,gDAAgD,CAAC,EAAE,CAAC;QAC9E,MAAM,kBAAkB,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,gDAAgD,CAAC,MAAM,CAAC,CAAC;QACvG,IAAI,kBAAkB,CAAC,MAAM,KAAK,CAAC,IAAI,kBAAkB,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACxE,MAAM,IAAI,KAAK,CAAC,mDAAmD,IAAI,CAAC,OAAO,4CAA4C,CAAC,CAAC;QAC/H,CAAC;QACD,OAAO,GAAG,wBAAwB,CAAC,+BAA+B,CAAC,IAAI,kBAAkB,EAAE,CAAC;IAC9F,CAAC;IACD,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,+BAA+B,CAAC,EAAE,CAAC;QAC7D,MAAM,IAAI,GAAG,wBAAwB,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,0CAA0C,IAAI,CAAC,OAAO,kCAAkC,CAAC,CAAC;IAC5G,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,gCAAgC,IAAI,CAAC,OAAO,sCAAsC,CAAC,CAAC;AACtG,CAAC;AAED,MAAM,UAAU,uCAAuC,CACrD,gBAAkE;IAElE,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;IAChD,MAAM,aAAa,GAAG,IAAI,GAAG,EAAU,CAAC;IACxC,KAAK,MAAM,IAAI,IAAI,gBAAgB,CAAC,KAAK,EAAE,CAAC;QAC1C,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,0DAA0D,IAAI,EAAE,CAAC,CAAC;QAC/G,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACxB,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,wBAAwB,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,gBAAgB,CAAC,SAAS,EAAE,OAAO,EAAE,gBAAgB,CAAC,aAAa,EAAE,CAAC;QACrH,OAAO,EAAE,gBAAgB,CAAC,OAAO;QACjC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACjD,aAAa;KACd,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,mDAAmD,CAAC,KAQnE;IACC,MAAM,kBAAkB,GAAG,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACnF,MAAM,OAAO,GAAG,KAAK,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACpF,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,cAAc,EAAE,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC;QACxC,sBAAsB,EAAE,kDAAkD,CAAC,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC;QAC7G,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU;QACjC,UAAU,EAAE,iCAAiC,CAAC,IAAI,CAAC,KAAK,CAAC;KAC1D,CAAC,CAAC,CAAC,CAAC;IACL,OAAO,kDAAkD,CAAC;QACxD,aAAa,EAAE,CAAC;QAChB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,aAAa,EAAE,KAAK,CAAC,aAAa;QAClC,wBAAwB,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,gBAAgB,CAAC,SAAS,EAAE,OAAO,EAAE,KAAK,CAAC,gBAAgB,CAAC,aAAa,EAAE;QAClH,2BAA2B,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,mBAAmB,CAAC,cAAc,EAAE,OAAO,EAAE,KAAK,CAAC,mBAAmB,CAAC,kBAAkB,EAAE;QACrI,mBAAmB,EAAE,KAAK,CAAC,mBAAmB;QAC9C,kBAAkB;QAClB,OAAO;KACR,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { createHash } from 'node:crypto';\n\nimport { APPLICATION_DOMAIN_RESOURCE_PAGE_UNIT_REF_PREFIX } from '../application-documentation/technical-documentation-engine-content-bundle';\n\nimport {\n createTechnicalDocumentationRenderOutputManifestV1,\n canonicalizeTechnicalDocumentationJson,\n TechnicalDocumentationOutputKind,\n TechnicalDocumentationNormalizedRelativePathSchema,\n TechnicalDocumentationRendererKind,\n type TechnicalDocumentationAuthorizedBundleManifestV1,\n type TechnicalDocumentationRenderOutputManifestV1,\n type TechnicalDocumentationRendererExecutionV1,\n type TechnicalDocumentationVersionedIdentityV1,\n type TechnicalDocumentationResolvedAssetBundleManifestV1,\n type TechnicalDocumentationSupportedApiVersion,\n type TechnicalDocumentationUnitV1,\n} from '@wildo-ai/saas-specifications/technical-documentation';\n\n/**\n * Names opaque emitted bytes, and detects their corruption when a reader compares this against the\n * bytes it actually loaded. That two-sided check is why it survived the 2026-08-27 digest\n * demolition; its string-hashing sibling did not, because every caller of that one was recording\n * agreement between two parts of the repository rather than naming content.\n */\nexport function technicalDocumentationSha256Bytes(bytes: Uint8Array): string {\n return `sha256:${createHash('sha256').update(bytes).digest('hex')}`;\n}\n\nexport interface TechnicalDocumentationRenderModel {\n readonly authorizedBundleIdentity: TechnicalDocumentationVersionedIdentityV1;\n readonly channel: TechnicalDocumentationAuthorizedBundleManifestV1['channel'];\n readonly units: readonly TechnicalDocumentationUnitV1[];\n readonly unitPathByRef: ReadonlyMap<string, string>;\n}\n\nexport interface TechnicalDocumentationRenderedFile {\n readonly outputRef: string;\n readonly rendererRef: string;\n readonly outputKind: TechnicalDocumentationOutputKind;\n readonly sourceUnitRefs: readonly string[];\n readonly normalizedRelativePath: string;\n readonly mediaType: string;\n readonly bytes: Uint8Array;\n}\n\nexport interface TechnicalDocumentationRendererResult {\n readonly execution: TechnicalDocumentationRendererExecutionV1;\n readonly files: readonly TechnicalDocumentationRenderedFile[];\n}\n\nexport function createTechnicalDocumentationRendererExecution(input: {\n readonly rendererKind: TechnicalDocumentationRendererKind;\n readonly rendererRef: string;\n readonly rendererVersion: number;\n /** Names the renderer's configuration. `rendererRef@rendererVersion` names the implementation. */\n readonly configurationRef: string;\n}): TechnicalDocumentationRendererExecutionV1 {\n /*\n * This built two sha256 fields until 2026-08-27: one over the renderer's own function bodies\n * (`Function.prototype.toString()`), one over its configuration object. Neither was ever compared\n * to anything — they rode into the manifest beside the `rendererRef` and `rendererVersion` that\n * already say which renderer ran, in a form a reader can act on.\n */\n return {\n rendererKind: input.rendererKind,\n rendererRef: input.rendererRef,\n rendererVersion: input.rendererVersion,\n configurationRef: input.configurationRef,\n };\n}\n\nfunction slugForUnit(unit: TechnicalDocumentationUnitV1): string {\n const source = unit.unitRef.split('/').at(-1) ?? unit.unitRef;\n const slug = source.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');\n if (slug.length === 0) throw new Error(`technical-documentation unit ${unit.unitRef} cannot produce a stable path`);\n return slug;\n}\n\n/**\n * Every route the engine content module owns, keyed by unit slug. Exported as a SET so the\n * renderers can tell a gated page this application does not publish (flatten the link) from a\n * misspelled route (leave it for the managed-tree validator).\n */\nconst ENGINE_UNIT_PATH_BY_SLUG: Readonly<Record<string, string>> = {\n 'application-orientation': 'get-started',\n 'what-this-application-manages': 'what-this-application-manages',\n authentication: 'access-and-identity/overview',\n 'sign-in-and-mfa': 'access-and-identity/sign-in-and-mfa',\n 'complete-sign-in': 'access-and-identity/complete-sign-in',\n 'mfa-enrollment-and-recovery': 'access-and-identity/mfa-enrollment-and-recovery',\n 'sign-in-troubleshoot': 'access-and-identity/sign-in-troubleshoot',\n 'single-sign-on': 'access-and-identity/single-sign-on',\n 'sso-configure': 'access-and-identity/sso-configure',\n 'sso-rollout-and-recovery': 'access-and-identity/sso-rollout-and-recovery',\n 'sso-troubleshoot': 'access-and-identity/sso-troubleshoot',\n 'api-keys': 'access-and-identity/api-keys',\n 'api-keys-create-and-store': 'access-and-identity/api-keys-create-and-store',\n 'api-keys-lifecycle': 'access-and-identity/api-keys-lifecycle',\n 'api-keys-troubleshoot': 'access-and-identity/api-keys-troubleshoot',\n 'oauth-provider': 'access-and-identity/oauth-provider',\n 'oauth-register-client': 'access-and-identity/oauth-register-client',\n 'oauth-authorize-delegated-access': 'access-and-identity/oauth-authorize-delegated-access',\n 'oauth-operate-and-revoke': 'access-and-identity/oauth-operate-and-revoke',\n 'user-administration': 'user-administration',\n 'manage-users-manually': 'user-administration/manage-users-manually',\n 'invite-and-onboard-user': 'user-administration/invite-and-onboard-user',\n 'organization-roles': 'user-administration/roles-and-permissions',\n 'change-user-access': 'user-administration/change-user-access',\n 'manage-organization-units': 'user-administration/manage-organization-units',\n 'design-organization-unit-hierarchy': 'user-administration/design-organization-unit-hierarchy',\n 'assign-organization-unit-access': 'user-administration/assign-organization-unit-access',\n 'operate-organization-units': 'user-administration/operate-organization-units',\n 'suspend-or-remove-user': 'user-administration/suspend-or-remove-user',\n 'review-users-and-access': 'user-administration/review-users-and-access',\n 'troubleshoot-user-access': 'user-administration/troubleshoot-user-access',\n scim: 'user-administration/scim-provisioning',\n 'scim-protocol-and-payloads': 'user-administration/scim-protocol-and-payloads',\n 'scim-configure': 'user-administration/scim-configure',\n 'scim-microsoft-entra': 'user-administration/scim-microsoft-entra',\n 'scim-okta': 'user-administration/scim-okta',\n 'scim-ldap-and-active-directory': 'user-administration/scim-ldap-and-active-directory',\n 'scim-map-profile-and-units': 'user-administration/scim-map-profile-and-units',\n 'scim-validate-and-roll-out': 'user-administration/scim-validate-and-roll-out',\n 'scim-operate-and-troubleshoot': 'user-administration/scim-operate-and-troubleshoot',\n 'audit-and-siem': 'security-and-audit',\n 'investigate-audit-event': 'security-and-audit/investigate-event',\n 'review-privileged-and-access-changes': 'security-and-audit/review-access-changes',\n 'export-audit-records': 'security-and-audit/export-audit-records',\n 'configure-siem-export': 'security-and-audit/configure-siem',\n 'siem-splunk': 'security-and-audit/siem-splunk',\n 'siem-microsoft-sentinel': 'security-and-audit/siem-microsoft-sentinel',\n 'siem-elastic': 'security-and-audit/siem-elastic',\n 'operate-and-troubleshoot-siem-delivery': 'security-and-audit/operate-siem',\n 'respond-to-leaked-credential': 'security-and-audit/respond-to-leaked-credential',\n 'protect-and-retain-audit-evidence': 'security-and-audit/protect-evidence',\n integrations: 'integrations',\n 'automation-platforms': 'integrations/automation-platforms',\n 'connect-n8n': 'integrations/automation/n8n',\n 'connect-zapier': 'integrations/automation/zapier',\n 'connect-make': 'integrations/automation/make',\n 'ai-coding-tools': 'integrations/ai-coding-tools',\n 'connect-cursor': 'integrations/ai-tools/cursor',\n 'connect-codex': 'integrations/ai-tools/codex',\n 'connect-claude-code': 'integrations/ai-tools/claude-code',\n 'agent-interoperability': 'integrations/agents',\n 'mcp-integrations': 'integrations/mcp',\n 'a2a-integrations': 'integrations/a2a',\n 'first-request': 'integrations/create-your-own-integration',\n 'common-rest-api': 'integrations/rest-api',\n 'rest-api-conventions': 'integrations/rest/conventions',\n 'send-api-request': 'integrations/rest/send-request',\n 'work-with-api-collections': 'integrations/rest/read-collections',\n 'write-and-reconcile-api-changes': 'integrations/rest/write-and-reconcile',\n 'troubleshoot-api-request': 'integrations/rest/troubleshoot',\n webhooks: 'integrations/webhooks',\n 'configure-and-test-webhook-endpoint': 'integrations/webhooks/configure-and-test',\n 'verify-webhook-delivery': 'integrations/webhooks/verify-delivery',\n 'operate-webhook-deliveries': 'integrations/webhooks/operate-deliveries',\n 'troubleshoot-webhook-deliveries': 'integrations/webhooks/troubleshoot',\n};\n\nexport const ENGINE_UNIT_ROUTES: ReadonlySet<string> = new Set(Object.values(ENGINE_UNIT_PATH_BY_SLUG));\n\n/**\n * Maps a published semantic unit to its consumer navigation home.\n *\n * This is deliberately renderer-owned rather than inferred from Markdown file\n * names: the semantic unit is the stable composition input, while a renderer\n * owns audience-facing URLs. The route table is deliberately organized by a\n * customer's product responsibility—not the internal framework that implements\n * it—so readers can find access, organization, security and integration\n * material without learning Wildo vocabulary.\n *\n * One namespace is DERIVED rather than listed — `unit/manages/<resource>`, the page per\n * application resource — because those units cannot be enumerated when this file is written. An\n * application-OWNED unit still fails closed instead of acquiring an implicit route; that refusal\n * is what this table is for, and it is untouched.\n */\nfunction pathForUnit(unit: TechnicalDocumentationUnitV1): string {\n const slug = slugForUnit(unit);\n /*\n * ONE derived branch, and it is deliberately narrow.\n *\n * Every other route in this table is a constant, because a renderer owns audience-facing URLs\n * and an authored page's URL is a decision somebody made. A page per application resource cannot\n * work that way — the resources are not known when this file is written — so its route is\n * DERIVED from the reserved `unit/manages/` namespace the projector emits.\n *\n * What has NOT changed is the refusal below. A unit an application named still fails closed; the\n * generated pages are engine units carrying an application subject, which is why they can be\n * routed at all. Anything outside both the fixed table and this one namespace is still a\n * missing decision rather than an implicit URL.\n */\n if (unit.unitRef.startsWith(APPLICATION_DOMAIN_RESOURCE_PAGE_UNIT_REF_PREFIX)) {\n const resourceIdentifier = unit.unitRef.slice(APPLICATION_DOMAIN_RESOURCE_PAGE_UNIT_REF_PREFIX.length);\n if (resourceIdentifier.length === 0 || resourceIdentifier.includes('/')) {\n throw new Error(`technical-documentation generated resource unit ${unit.unitRef} has no single-segment resource identifier`);\n }\n return `${ENGINE_UNIT_PATH_BY_SLUG['what-this-application-manages']}/${resourceIdentifier}`;\n }\n if (unit.unitRef.startsWith('technical-documentation:unit/')) {\n const path = ENGINE_UNIT_PATH_BY_SLUG[slug];\n if (path !== undefined) return path;\n throw new Error(`technical-documentation framework unit ${unit.unitRef} has no consumer navigation path`);\n }\n throw new Error(`technical-documentation unit ${unit.unitRef} has no consumer navigation category`);\n}\n\nexport function createTechnicalDocumentationRenderModel(\n authorizedBundle: TechnicalDocumentationAuthorizedBundleManifestV1,\n): TechnicalDocumentationRenderModel {\n const unitPathByRef = new Map<string, string>();\n const occupiedPaths = new Set<string>();\n for (const unit of authorizedBundle.units) {\n const path = pathForUnit(unit);\n if (occupiedPaths.has(path)) throw new Error(`technical-documentation units collide on renderer path ${path}`);\n occupiedPaths.add(path);\n unitPathByRef.set(unit.unitRef, path);\n }\n return Object.freeze({\n authorizedBundleIdentity: Object.freeze({ ref: authorizedBundle.bundleRef, version: authorizedBundle.bundleVersion }),\n channel: authorizedBundle.channel,\n units: Object.freeze([...authorizedBundle.units]),\n unitPathByRef,\n });\n}\n\nexport function createTechnicalDocumentationAggregateRenderManifest(input: {\n readonly authorizedBundle: TechnicalDocumentationAuthorizedBundleManifestV1;\n readonly resolvedAssetBundle: TechnicalDocumentationResolvedAssetBundleManifestV1;\n readonly supportedApiVersion: TechnicalDocumentationSupportedApiVersion;\n readonly rendererResults: readonly TechnicalDocumentationRendererResult[];\n /** This render's own identity; the publication pointer selects a render by it. */\n readonly renderRef: string;\n readonly renderVersion: number;\n}): TechnicalDocumentationRenderOutputManifestV1 {\n const rendererExecutions = input.rendererResults.map((result) => result.execution);\n const outputs = input.rendererResults.flatMap((result) => result.files.map((file) => ({\n outputRef: file.outputRef,\n rendererRef: file.rendererRef,\n outputKind: file.outputKind,\n sourceUnitRefs: [...file.sourceUnitRefs],\n normalizedRelativePath: TechnicalDocumentationNormalizedRelativePathSchema.parse(file.normalizedRelativePath),\n mediaType: file.mediaType,\n byteLength: file.bytes.byteLength,\n byteDigest: technicalDocumentationSha256Bytes(file.bytes),\n })));\n return createTechnicalDocumentationRenderOutputManifestV1({\n schemaVersion: 1,\n renderRef: input.renderRef,\n renderVersion: input.renderVersion,\n authorizedBundleIdentity: { ref: input.authorizedBundle.bundleRef, version: input.authorizedBundle.bundleVersion },\n resolvedAssetBundleIdentity: { ref: input.resolvedAssetBundle.assetBundleRef, version: input.resolvedAssetBundle.assetBundleVersion },\n supportedApiVersion: input.supportedApiVersion,\n rendererExecutions,\n outputs,\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"technical-documentation-render-model.js","sourceRoot":"","sources":["../../../../../src/companion/rendering/technical-documentation-render-model.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from 'node:crypto';\n\nimport { APPLICATION_DOMAIN_RESOURCE_PAGE_UNIT_REF_PREFIX } from '../application-documentation/technical-documentation-engine-content-bundle';\nimport {\n APPLICATION_DOCUMENTATION_CHAPTER_ROUTE_DIRECTORY,\n APPLICATION_DOCUMENTATION_CHAPTER_UNIT_REF_PREFIX,\n} from '../application-documentation/application-documentation-chapters';\n\nimport {\n createTechnicalDocumentationRenderOutputManifestV1,\n canonicalizeTechnicalDocumentationJson,\n TechnicalDocumentationOutputKind,\n TechnicalDocumentationNormalizedRelativePathSchema,\n TechnicalDocumentationRendererKind,\n type TechnicalDocumentationAuthorizedBundleManifestV1,\n type TechnicalDocumentationRenderOutputManifestV1,\n type TechnicalDocumentationRendererExecutionV1,\n type TechnicalDocumentationVersionedIdentityV1,\n type TechnicalDocumentationResolvedAssetBundleManifestV1,\n type TechnicalDocumentationSupportedApiVersion,\n type TechnicalDocumentationUnitV1,\n} from '@wildo-ai/saas-specifications/technical-documentation';\n\n/**\n * Names opaque emitted bytes, and detects their corruption when a reader compares this against the\n * bytes it actually loaded. That two-sided check is why it survived the 2026-08-27 digest\n * demolition; its string-hashing sibling did not, because every caller of that one was recording\n * agreement between two parts of the repository rather than naming content.\n */\nexport function technicalDocumentationSha256Bytes(bytes: Uint8Array): string {\n return `sha256:${createHash('sha256').update(bytes).digest('hex')}`;\n}\n\nexport interface TechnicalDocumentationRenderModel {\n readonly authorizedBundleIdentity: TechnicalDocumentationVersionedIdentityV1;\n readonly channel: TechnicalDocumentationAuthorizedBundleManifestV1['channel'];\n readonly units: readonly TechnicalDocumentationUnitV1[];\n readonly unitPathByRef: ReadonlyMap<string, string>;\n}\n\nexport interface TechnicalDocumentationRenderedFile {\n readonly outputRef: string;\n readonly rendererRef: string;\n readonly outputKind: TechnicalDocumentationOutputKind;\n readonly sourceUnitRefs: readonly string[];\n readonly normalizedRelativePath: string;\n readonly mediaType: string;\n readonly bytes: Uint8Array;\n}\n\nexport interface TechnicalDocumentationRendererResult {\n readonly execution: TechnicalDocumentationRendererExecutionV1;\n readonly files: readonly TechnicalDocumentationRenderedFile[];\n}\n\nexport function createTechnicalDocumentationRendererExecution(input: {\n readonly rendererKind: TechnicalDocumentationRendererKind;\n readonly rendererRef: string;\n readonly rendererVersion: number;\n /** Names the renderer's configuration. `rendererRef@rendererVersion` names the implementation. */\n readonly configurationRef: string;\n}): TechnicalDocumentationRendererExecutionV1 {\n /*\n * This built two sha256 fields until 2026-08-27: one over the renderer's own function bodies\n * (`Function.prototype.toString()`), one over its configuration object. Neither was ever compared\n * to anything — they rode into the manifest beside the `rendererRef` and `rendererVersion` that\n * already say which renderer ran, in a form a reader can act on.\n */\n return {\n rendererKind: input.rendererKind,\n rendererRef: input.rendererRef,\n rendererVersion: input.rendererVersion,\n configurationRef: input.configurationRef,\n };\n}\n\nfunction slugForUnit(unit: TechnicalDocumentationUnitV1): string {\n const source = unit.unitRef.split('/').at(-1) ?? unit.unitRef;\n const slug = source.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');\n if (slug.length === 0) throw new Error(`technical-documentation unit ${unit.unitRef} cannot produce a stable path`);\n return slug;\n}\n\n/**\n * Every route the engine content module owns, keyed by unit slug. Exported as a SET so the\n * renderers can tell a gated page this application does not publish (flatten the link) from a\n * misspelled route (leave it for the managed-tree validator).\n */\nconst ENGINE_UNIT_PATH_BY_SLUG: Readonly<Record<string, string>> = {\n 'application-orientation': 'get-started',\n 'what-this-application-manages': 'what-this-application-manages',\n authentication: 'access-and-identity/overview',\n 'sign-in-and-mfa': 'access-and-identity/sign-in-and-mfa',\n 'complete-sign-in': 'access-and-identity/complete-sign-in',\n 'mfa-enrollment-and-recovery': 'access-and-identity/mfa-enrollment-and-recovery',\n 'sign-in-troubleshoot': 'access-and-identity/sign-in-troubleshoot',\n 'single-sign-on': 'access-and-identity/single-sign-on',\n 'sso-configure': 'access-and-identity/sso-configure',\n 'sso-rollout-and-recovery': 'access-and-identity/sso-rollout-and-recovery',\n 'sso-troubleshoot': 'access-and-identity/sso-troubleshoot',\n 'api-keys': 'access-and-identity/api-keys',\n 'api-keys-create-and-store': 'access-and-identity/api-keys-create-and-store',\n 'api-keys-lifecycle': 'access-and-identity/api-keys-lifecycle',\n 'api-keys-troubleshoot': 'access-and-identity/api-keys-troubleshoot',\n 'oauth-provider': 'access-and-identity/oauth-provider',\n 'oauth-register-client': 'access-and-identity/oauth-register-client',\n 'oauth-authorize-delegated-access': 'access-and-identity/oauth-authorize-delegated-access',\n 'oauth-operate-and-revoke': 'access-and-identity/oauth-operate-and-revoke',\n 'user-administration': 'user-administration',\n 'manage-users-manually': 'user-administration/manage-users-manually',\n 'invite-and-onboard-user': 'user-administration/invite-and-onboard-user',\n 'organization-roles': 'user-administration/roles-and-permissions',\n 'change-user-access': 'user-administration/change-user-access',\n 'manage-organization-units': 'user-administration/manage-organization-units',\n 'design-organization-unit-hierarchy': 'user-administration/design-organization-unit-hierarchy',\n 'assign-organization-unit-access': 'user-administration/assign-organization-unit-access',\n 'operate-organization-units': 'user-administration/operate-organization-units',\n 'suspend-or-remove-user': 'user-administration/suspend-or-remove-user',\n 'review-users-and-access': 'user-administration/review-users-and-access',\n 'troubleshoot-user-access': 'user-administration/troubleshoot-user-access',\n scim: 'user-administration/scim-provisioning',\n 'scim-protocol-and-payloads': 'user-administration/scim-protocol-and-payloads',\n 'scim-configure': 'user-administration/scim-configure',\n 'scim-microsoft-entra': 'user-administration/scim-microsoft-entra',\n 'scim-okta': 'user-administration/scim-okta',\n 'scim-ldap-and-active-directory': 'user-administration/scim-ldap-and-active-directory',\n 'scim-map-profile-and-units': 'user-administration/scim-map-profile-and-units',\n 'scim-validate-and-roll-out': 'user-administration/scim-validate-and-roll-out',\n 'scim-operate-and-troubleshoot': 'user-administration/scim-operate-and-troubleshoot',\n 'audit-and-siem': 'security-and-audit',\n 'investigate-audit-event': 'security-and-audit/investigate-event',\n 'review-privileged-and-access-changes': 'security-and-audit/review-access-changes',\n 'export-audit-records': 'security-and-audit/export-audit-records',\n 'configure-siem-export': 'security-and-audit/configure-siem',\n 'siem-splunk': 'security-and-audit/siem-splunk',\n 'siem-microsoft-sentinel': 'security-and-audit/siem-microsoft-sentinel',\n 'siem-elastic': 'security-and-audit/siem-elastic',\n 'operate-and-troubleshoot-siem-delivery': 'security-and-audit/operate-siem',\n 'respond-to-leaked-credential': 'security-and-audit/respond-to-leaked-credential',\n 'protect-and-retain-audit-evidence': 'security-and-audit/protect-evidence',\n integrations: 'integrations',\n 'automation-platforms': 'integrations/automation-platforms',\n 'connect-n8n': 'integrations/automation/n8n',\n 'connect-zapier': 'integrations/automation/zapier',\n 'connect-make': 'integrations/automation/make',\n 'ai-coding-tools': 'integrations/ai-coding-tools',\n 'connect-cursor': 'integrations/ai-tools/cursor',\n 'connect-codex': 'integrations/ai-tools/codex',\n 'connect-claude-code': 'integrations/ai-tools/claude-code',\n 'agent-interoperability': 'integrations/agents',\n 'mcp-integrations': 'integrations/mcp',\n 'a2a-integrations': 'integrations/a2a',\n 'first-request': 'integrations/create-your-own-integration',\n 'common-rest-api': 'integrations/rest-api',\n 'rest-api-conventions': 'integrations/rest/conventions',\n 'send-api-request': 'integrations/rest/send-request',\n 'work-with-api-collections': 'integrations/rest/read-collections',\n 'write-and-reconcile-api-changes': 'integrations/rest/write-and-reconcile',\n 'troubleshoot-api-request': 'integrations/rest/troubleshoot',\n webhooks: 'integrations/webhooks',\n 'configure-and-test-webhook-endpoint': 'integrations/webhooks/configure-and-test',\n 'verify-webhook-delivery': 'integrations/webhooks/verify-delivery',\n 'operate-webhook-deliveries': 'integrations/webhooks/operate-deliveries',\n 'troubleshoot-webhook-deliveries': 'integrations/webhooks/troubleshoot',\n};\n\nexport const ENGINE_UNIT_ROUTES: ReadonlySet<string> = new Set(Object.values(ENGINE_UNIT_PATH_BY_SLUG));\n\n/**\n * Maps a published semantic unit to its consumer navigation home.\n *\n * This is deliberately renderer-owned rather than inferred from Markdown file\n * names: the semantic unit is the stable composition input, while a renderer\n * owns audience-facing URLs. The route table is deliberately organized by a\n * customer's product responsibility—not the internal framework that implements\n * it—so readers can find access, organization, security and integration\n * material without learning Wildo vocabulary.\n *\n * Two namespaces are DERIVED rather than listed, because their units cannot be enumerated when this\n * file is written: `unit/manages/<resource>`, the page per application resource, and\n * `unit/guides/<slug>`, the chapters an application authors (#874). Both are RESERVED engine\n * namespaces the projectors emit; the application supplies a subject or a slug and never a URL\n * scheme. Any other unit — including one whose ref an application chose freely — still fails closed\n * instead of acquiring an implicit route; that refusal is what this table is for.\n */\nfunction pathForUnit(unit: TechnicalDocumentationUnitV1): string {\n const slug = slugForUnit(unit);\n /*\n * The first of TWO derived branches, both deliberately narrow.\n *\n * Every other route in this table is a constant, because a renderer owns audience-facing URLs\n * and an authored page's URL is a decision somebody made. A page per application resource cannot\n * work that way — the resources are not known when this file is written — so its route is\n * DERIVED from the reserved `unit/manages/` namespace the projector emits. The second branch,\n * below, does the same for the reserved `unit/guides/` namespace of authored chapters (#874).\n *\n * What has NOT changed is the refusal at the end. A unit whose ref an application chose freely\n * still fails closed; both derived namespaces are reserved by an engine projector, which is why\n * their units can be routed at all. Anything outside the fixed table and these two namespaces is\n * still a missing decision rather than an implicit URL.\n */\n if (unit.unitRef.startsWith(APPLICATION_DOMAIN_RESOURCE_PAGE_UNIT_REF_PREFIX)) {\n const resourceIdentifier = unit.unitRef.slice(APPLICATION_DOMAIN_RESOURCE_PAGE_UNIT_REF_PREFIX.length);\n if (resourceIdentifier.length === 0 || resourceIdentifier.includes('/')) {\n throw new Error(`technical-documentation generated resource unit ${unit.unitRef} has no single-segment resource identifier`);\n }\n return `${ENGINE_UNIT_PATH_BY_SLUG['what-this-application-manages']}/${resourceIdentifier}`;\n }\n /*\n * The second derived branch, for authored chapters (#874). Checked BEFORE the fixed table on\n * purpose: a chapter slug may coincide with an engine slug (`webhooks`), and the reserved prefix —\n * not the slug — is what says whose page this is.\n */\n if (unit.unitRef.startsWith(APPLICATION_DOCUMENTATION_CHAPTER_UNIT_REF_PREFIX)) {\n const chapterSlug = unit.unitRef.slice(APPLICATION_DOCUMENTATION_CHAPTER_UNIT_REF_PREFIX.length);\n if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(chapterSlug)) {\n throw new Error(`technical-documentation chapter unit ${unit.unitRef} has no single-segment kebab-case slug`);\n }\n return `${APPLICATION_DOCUMENTATION_CHAPTER_ROUTE_DIRECTORY}/${chapterSlug}`;\n }\n if (unit.unitRef.startsWith('technical-documentation:unit/')) {\n const path = ENGINE_UNIT_PATH_BY_SLUG[slug];\n if (path !== undefined) return path;\n throw new Error(`technical-documentation framework unit ${unit.unitRef} has no consumer navigation path`);\n }\n throw new Error(`technical-documentation unit ${unit.unitRef} has no consumer navigation category`);\n}\n\nexport function createTechnicalDocumentationRenderModel(\n authorizedBundle: TechnicalDocumentationAuthorizedBundleManifestV1,\n): TechnicalDocumentationRenderModel {\n const unitPathByRef = new Map<string, string>();\n const occupiedPaths = new Set<string>();\n for (const unit of authorizedBundle.units) {\n const path = pathForUnit(unit);\n if (occupiedPaths.has(path)) throw new Error(`technical-documentation units collide on renderer path ${path}`);\n occupiedPaths.add(path);\n unitPathByRef.set(unit.unitRef, path);\n }\n return Object.freeze({\n authorizedBundleIdentity: Object.freeze({ ref: authorizedBundle.bundleRef, version: authorizedBundle.bundleVersion }),\n channel: authorizedBundle.channel,\n units: Object.freeze([...authorizedBundle.units]),\n unitPathByRef,\n });\n}\n\nexport function createTechnicalDocumentationAggregateRenderManifest(input: {\n readonly authorizedBundle: TechnicalDocumentationAuthorizedBundleManifestV1;\n readonly resolvedAssetBundle: TechnicalDocumentationResolvedAssetBundleManifestV1;\n readonly supportedApiVersion: TechnicalDocumentationSupportedApiVersion;\n readonly rendererResults: readonly TechnicalDocumentationRendererResult[];\n /** This render's own identity; the publication pointer selects a render by it. */\n readonly renderRef: string;\n readonly renderVersion: number;\n}): TechnicalDocumentationRenderOutputManifestV1 {\n const rendererExecutions = input.rendererResults.map((result) => result.execution);\n const outputs = input.rendererResults.flatMap((result) => result.files.map((file) => ({\n outputRef: file.outputRef,\n rendererRef: file.rendererRef,\n outputKind: file.outputKind,\n sourceUnitRefs: [...file.sourceUnitRefs],\n normalizedRelativePath: TechnicalDocumentationNormalizedRelativePathSchema.parse(file.normalizedRelativePath),\n mediaType: file.mediaType,\n byteLength: file.bytes.byteLength,\n byteDigest: technicalDocumentationSha256Bytes(file.bytes),\n })));\n return createTechnicalDocumentationRenderOutputManifestV1({\n schemaVersion: 1,\n renderRef: input.renderRef,\n renderVersion: input.renderVersion,\n authorizedBundleIdentity: { ref: input.authorizedBundle.bundleRef, version: input.authorizedBundle.bundleVersion },\n resolvedAssetBundleIdentity: { ref: input.resolvedAssetBundle.assetBundleRef, version: input.resolvedAssetBundle.assetBundleVersion },\n supportedApiVersion: input.supportedApiVersion,\n rendererExecutions,\n outputs,\n });\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"technical-documentation-search-index-renderer.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"technical-documentation-search-index-renderer.d.ts","sourceRoot":"","sources":["../../../../../src/companion/rendering/technical-documentation-search-index-renderer.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,iCAAiC,EACtC,KAAK,oCAAoC,EAC1C,MAAM,wCAAwC,CAAC;AAIhD;;;;;;;;;GASG;AACH,wBAAgB,yCAAyC,CAAC,KAAK,EAAE,iCAAiC,GAAG,oCAAoC,CA6BxI"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"technical-documentation-search-index-renderer.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"technical-documentation-search-index-renderer.js","sourceRoot":"","sources":["../../../../../src/companion/rendering/technical-documentation-search-index-renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gCAAgC,EAAE,kCAAkC,EAAE,MAAM,uDAAuD,CAAC;AAE7I,OAAO,EACL,6CAA6C,GAG9C,MAAM,wCAAwC,CAAC;AAEhD,MAAM,mBAAmB,GAAG,+CAA+C,CAAC;AAE5E;;;;;;;;;GASG;AACH,MAAM,UAAU,yCAAyC,CAAC,KAAwC;IAChG,MAAM,cAAc,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACxC,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;QACzD,eAAe,EAAE,IAAI,CAAC,eAAe;QACrC,IAAI,EAAE,IAAI,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;KAClD,CAAC,CAAC,CAAC;IACJ,OAAO;QACL,SAAS,EAAE,6CAA6C,CAAC;YACvD,YAAY,EAAE,kCAAkC,CAAC,QAAQ;YACzD,WAAW,EAAE,mBAAmB;YAChC,eAAe,EAAE,CAAC;YAClB,gBAAgB,EAAE,qEAAqE;SACxF,CAAC;QACF,KAAK,EAAE;YACL;gBACE,SAAS,EAAE,6CAA6C;gBACxD,WAAW,EAAE,mBAAmB;gBAChC,UAAU,EAAE,gCAAgC,CAAC,gBAAgB;gBAC7D,cAAc;gBACd,sBAAsB,EAAE,qBAAqB;gBAC7C,SAAS,EAAE,kBAAkB;gBAC7B,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC;aAChG;SACF;KACF,CAAC;AACJ,CAAC","sourcesContent":["import { TechnicalDocumentationOutputKind, TechnicalDocumentationRendererKind } from '@wildo-ai/saas-specifications/technical-documentation';\n\nimport {\n createTechnicalDocumentationRendererExecution,\n type TechnicalDocumentationRenderModel,\n type TechnicalDocumentationRendererResult,\n} from './technical-documentation-render-model';\n\nconst SEARCH_RENDERER_REF = 'technical-documentation:renderer/search-index';\n\n/**\n * The ONE index the site reads: `indexes/search.json`, imported by the application's own\n * `src/pages/search.tsx`.\n *\n * A second `indexes/navigation.json` was emitted here and read by nothing — measured with a positive\n * control, so the empty result is a real absence rather than a bad probe. The site's navigation is\n * the Docusaurus sidebar, which the Docusaurus renderer emits; a second navigation index was a\n * record with no reader (#274, and `application-creation-directive.md`: if we write a record,\n * something reads it).\n */\nexport function renderTechnicalDocumentationSearchIndexes(model: TechnicalDocumentationRenderModel): TechnicalDocumentationRendererResult {\n const sourceUnitRefs = model.units.map((unit) => unit.unitRef);\n const search = model.units.map((unit) => ({\n unitRef: unit.unitRef,\n title: unit.title,\n summary: unit.summary,\n headings: unit.sections.map((section) => section.heading),\n readerAudiences: unit.readerAudiences,\n path: `/${model.unitPathByRef.get(unit.unitRef)}`,\n }));\n return {\n execution: createTechnicalDocumentationRendererExecution({\n rendererKind: TechnicalDocumentationRendererKind.MARKDOWN,\n rendererRef: SEARCH_RENDERER_REF,\n rendererVersion: 1,\n configurationRef: 'technical-documentation:renderer-configuration/search-index-json-v1',\n }),\n files: [\n {\n outputRef: 'technical-documentation:output/search-index',\n rendererRef: SEARCH_RENDERER_REF,\n outputKind: TechnicalDocumentationOutputKind.NAVIGATION_INDEX,\n sourceUnitRefs,\n normalizedRelativePath: 'indexes/search.json',\n mediaType: 'application/json',\n bytes: Buffer.from(`${JSON.stringify({ schemaVersion: 1, units: search }, null, 2)}\\n`, 'utf8'),\n },\n ],\n };\n}\n"]}
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
* - **Tier 2** `injectFieldDocsIntoJsonSchema` — per-field `meaning` /
|
|
11
11
|
* `whyItMatters` / `relationshipContext` / enum-value meanings → property
|
|
12
12
|
* `description` + `x-enum-descriptions` on a request/response JSON-Schema
|
|
13
|
-
* fragment
|
|
13
|
+
* fragment; `injectFieldDocsIntoCollectionContract` applies the same to a
|
|
14
|
+
* paginated collection's `filters` bag and `data[]` items.
|
|
14
15
|
*
|
|
15
16
|
* See `.claude/plans/technical-doc-openapi-spec-integration.md`. Without authored
|
|
16
17
|
* spec prose the description is empty and the operation falls back to the
|
|
@@ -130,23 +131,64 @@ export interface FieldDoc {
|
|
|
130
131
|
* Joins by EXACT property-name match — DTO property names that diverge from
|
|
131
132
|
* the resource's field names (renamed / computed / backend-stripped fields)
|
|
132
133
|
* are simply left undocumented rather than mis-documented.
|
|
134
|
+
*
|
|
135
|
+
* "Top level" includes each branch of a top-level `oneOf` / `anyOf` / `allOf`.
|
|
136
|
+
* A polymorphic resource's representation is a union whose branches carry the
|
|
137
|
+
* properties themselves — the fragment has no `properties` of its own — and
|
|
138
|
+
* every branch's properties are still the resource's own top-level fields. Only
|
|
139
|
+
* composition keywords are entered, never an object property, so the rule above
|
|
140
|
+
* still holds. Without this, 42 of the 58 properties of Wonder Todos' `todos`
|
|
141
|
+
* read and list representations (`title`, `status`, `priority`, …) carried no
|
|
142
|
+
* description.
|
|
143
|
+
*
|
|
144
|
+
* A paginated collection re-wraps those fields one level down; see
|
|
145
|
+
* `injectFieldDocsIntoCollectionContract` for the two containers it adds.
|
|
133
146
|
*/
|
|
134
147
|
export declare const injectFieldDocsIntoJsonSchema: (fragment: unknown, fieldDocsByName: Record<string, FieldDoc>) => void;
|
|
148
|
+
/**
|
|
149
|
+
* Enrich the two places a paginated collection contract carries the resource's OWN fields one
|
|
150
|
+
* level down, where `injectFieldDocsIntoJsonSchema` (top level only) cannot reach them:
|
|
151
|
+
*
|
|
152
|
+
* - the request's `filters` object — one property per filterable field, which the generator
|
|
153
|
+
* flattens into query parameters (`?status=…`), copying each property's `description`;
|
|
154
|
+
* - the response envelope's `data[]` items — the resource rows a LIST / SEARCH returns.
|
|
155
|
+
*
|
|
156
|
+
* This is not the general nested walk `injectFieldDocsIntoJsonSchema` declines: a nested object's
|
|
157
|
+
* properties have no field specification, while these two containers hold the resource's own
|
|
158
|
+
* top-level fields, re-wrapped by the framework's collection contract. Before this, 59% of the
|
|
159
|
+
* list-item properties and 219 query filters in the Wonder Todos document carried no description,
|
|
160
|
+
* although the same fields were fully described in the read and create responses.
|
|
161
|
+
*
|
|
162
|
+
* Call it only for a paginated collection operation (LIST, or SEARCH-like). Anything else passes
|
|
163
|
+
* through unchanged, because neither container exists.
|
|
164
|
+
*/
|
|
165
|
+
export declare const injectFieldDocsIntoCollectionContract: (requestBodySchema: unknown, responseBodySchema: unknown, fieldDocsByName: Record<string, FieldDoc>) => void;
|
|
135
166
|
/**
|
|
136
167
|
* Projection-shaped HTTP documentation for one operation (Tier 3). Mirrors the
|
|
137
168
|
* authored `ResourceOperationSpecification` HTTP fields, normalized to plain
|
|
138
169
|
* JSON the OpenAPI generator emits as `responses` / `examples` / extensions.
|
|
139
170
|
*/
|
|
171
|
+
/**
|
|
172
|
+
* One documented failure mode, with the error-body field each identifier appears in.
|
|
173
|
+
*
|
|
174
|
+
* `errorType` is `error.type`, `customMessageReference` is `error.customMessageReference`, and
|
|
175
|
+
* `errorCode` is `error.code` — three different fields a client branches on, carried separately
|
|
176
|
+
* because the authored specification names them separately (see
|
|
177
|
+
* `ResourceOperationErrorScenarioSpecification`). Values are the wire strings.
|
|
178
|
+
*/
|
|
179
|
+
export interface OperationErrorScenarioDoc {
|
|
180
|
+
code: string;
|
|
181
|
+
when: string;
|
|
182
|
+
errorType?: string;
|
|
183
|
+
customMessageReference?: string;
|
|
184
|
+
errorCode?: string;
|
|
185
|
+
}
|
|
140
186
|
export interface OperationHttpDoc {
|
|
141
187
|
responseStatuses?: Array<{
|
|
142
188
|
code: string;
|
|
143
189
|
meaning: string;
|
|
144
190
|
}>;
|
|
145
|
-
errorScenarios?:
|
|
146
|
-
code: string;
|
|
147
|
-
when: string;
|
|
148
|
-
errorCode?: string;
|
|
149
|
-
}>;
|
|
191
|
+
errorScenarios?: OperationErrorScenarioDoc[];
|
|
150
192
|
idempotent?: boolean;
|
|
151
193
|
rateLimitNote?: string;
|
|
152
194
|
examples?: Array<{
|
|
@@ -167,10 +209,10 @@ export interface OperationHttpDoc {
|
|
|
167
209
|
*
|
|
168
210
|
* Prose fields (`meaning` / `when` / `title` / `rateLimitNote`) are cleaned of
|
|
169
211
|
* implementation-only noise via `asCleanProse`, consistent with the Tier-1
|
|
170
|
-
* `description` and Tier-2 field descriptions. `code` / `forStatus`
|
|
171
|
-
* `
|
|
172
|
-
*
|
|
173
|
-
*
|
|
212
|
+
* `description` and Tier-2 field descriptions. `code` / `forStatus` are
|
|
213
|
+
* `HttpResponseStatusCode` values whose runtime string (`'200'`, …) is the OpenAPI
|
|
214
|
+
* `responses` key; `errorType` / `customMessageReference` / `errorCode` are the
|
|
215
|
+
* error-body wire values a client branches on. All pass through untouched.
|
|
174
216
|
*/
|
|
175
217
|
export declare const buildOperationHttpDocFromSpec: (operationSpec: unknown, variantKey?: string) => OperationHttpDoc;
|
|
176
218
|
//# sourceMappingURL=spec-to-operation-doc.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec-to-operation-doc.d.ts","sourceRoot":"","sources":["../../../../src/companion/spec-to-operation-doc.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"spec-to-operation-doc.d.ts","sourceRoot":"","sources":["../../../../src/companion/spec-to-operation-doc.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
* - **Tier 2** `injectFieldDocsIntoJsonSchema` — per-field `meaning` /
|
|
11
11
|
* `whyItMatters` / `relationshipContext` / enum-value meanings → property
|
|
12
12
|
* `description` + `x-enum-descriptions` on a request/response JSON-Schema
|
|
13
|
-
* fragment
|
|
13
|
+
* fragment; `injectFieldDocsIntoCollectionContract` applies the same to a
|
|
14
|
+
* paginated collection's `filters` bag and `data[]` items.
|
|
14
15
|
*
|
|
15
16
|
* See `.claude/plans/technical-doc-openapi-spec-integration.md`. Without authored
|
|
16
17
|
* spec prose the description is empty and the operation falls back to the
|
|
@@ -180,11 +181,36 @@ const composeFieldDescription = (doc) => {
|
|
|
180
181
|
* Joins by EXACT property-name match — DTO property names that diverge from
|
|
181
182
|
* the resource's field names (renamed / computed / backend-stripped fields)
|
|
182
183
|
* are simply left undocumented rather than mis-documented.
|
|
184
|
+
*
|
|
185
|
+
* "Top level" includes each branch of a top-level `oneOf` / `anyOf` / `allOf`.
|
|
186
|
+
* A polymorphic resource's representation is a union whose branches carry the
|
|
187
|
+
* properties themselves — the fragment has no `properties` of its own — and
|
|
188
|
+
* every branch's properties are still the resource's own top-level fields. Only
|
|
189
|
+
* composition keywords are entered, never an object property, so the rule above
|
|
190
|
+
* still holds. Without this, 42 of the 58 properties of Wonder Todos' `todos`
|
|
191
|
+
* read and list representations (`title`, `status`, `priority`, …) carried no
|
|
192
|
+
* description.
|
|
193
|
+
*
|
|
194
|
+
* A paginated collection re-wraps those fields one level down; see
|
|
195
|
+
* `injectFieldDocsIntoCollectionContract` for the two containers it adds.
|
|
183
196
|
*/
|
|
184
197
|
export const injectFieldDocsIntoJsonSchema = (fragment, fieldDocsByName) => {
|
|
185
198
|
if (!isPlainObject(fragment)) {
|
|
186
199
|
return;
|
|
187
200
|
}
|
|
201
|
+
// A body that is a LIST of rows (a bulk create or update answers one row per item, #1872) documents its rows.
|
|
202
|
+
if (fragment['type'] === 'array' && isPlainObject(fragment['items'])) {
|
|
203
|
+
injectFieldDocsIntoJsonSchema(fragment['items'], fieldDocsByName);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
for (const compositionKeyword of ['oneOf', 'anyOf', 'allOf']) {
|
|
207
|
+
const branches = fragment[compositionKeyword];
|
|
208
|
+
if (Array.isArray(branches)) {
|
|
209
|
+
for (const branch of branches) {
|
|
210
|
+
injectFieldDocsIntoJsonSchema(branch, fieldDocsByName);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
188
214
|
const properties = fragment['properties'];
|
|
189
215
|
if (!isPlainObject(properties)) {
|
|
190
216
|
return;
|
|
@@ -211,14 +237,100 @@ export const injectFieldDocsIntoJsonSchema = (fragment, fieldDocsByName) => {
|
|
|
211
237
|
}
|
|
212
238
|
}
|
|
213
239
|
};
|
|
240
|
+
/**
|
|
241
|
+
* Enrich the two places a paginated collection contract carries the resource's OWN fields one
|
|
242
|
+
* level down, where `injectFieldDocsIntoJsonSchema` (top level only) cannot reach them:
|
|
243
|
+
*
|
|
244
|
+
* - the request's `filters` object — one property per filterable field, which the generator
|
|
245
|
+
* flattens into query parameters (`?status=…`), copying each property's `description`;
|
|
246
|
+
* - the response envelope's `data[]` items — the resource rows a LIST / SEARCH returns.
|
|
247
|
+
*
|
|
248
|
+
* This is not the general nested walk `injectFieldDocsIntoJsonSchema` declines: a nested object's
|
|
249
|
+
* properties have no field specification, while these two containers hold the resource's own
|
|
250
|
+
* top-level fields, re-wrapped by the framework's collection contract. Before this, 59% of the
|
|
251
|
+
* list-item properties and 219 query filters in the Wonder Todos document carried no description,
|
|
252
|
+
* although the same fields were fully described in the read and create responses.
|
|
253
|
+
*
|
|
254
|
+
* Call it only for a paginated collection operation (LIST, or SEARCH-like). Anything else passes
|
|
255
|
+
* through unchanged, because neither container exists.
|
|
256
|
+
*/
|
|
257
|
+
export const injectFieldDocsIntoCollectionContract = (requestBodySchema, responseBodySchema, fieldDocsByName) => {
|
|
258
|
+
const filters = isPlainObject(requestBodySchema) && isPlainObject(requestBodySchema['properties'])
|
|
259
|
+
? requestBodySchema['properties']['filters']
|
|
260
|
+
: undefined;
|
|
261
|
+
injectFieldDocsIntoJsonSchema(filters, fieldDocsByName);
|
|
262
|
+
const data = isPlainObject(responseBodySchema) && isPlainObject(responseBodySchema['properties'])
|
|
263
|
+
? responseBodySchema['properties']['data']
|
|
264
|
+
: undefined;
|
|
265
|
+
const items = isPlainObject(data) ? data['items'] : undefined;
|
|
266
|
+
injectFieldDocsIntoJsonSchema(items, fieldDocsByName);
|
|
267
|
+
injectNestedFilterDescriptionsFromRows(filters, items);
|
|
268
|
+
};
|
|
269
|
+
/**
|
|
270
|
+
* A filter on a nested field is keyed by its dotted path (`linkedResource.resourceType`, #1630), so it
|
|
271
|
+
* matches no field specification by name and was published with no description. The field it filters
|
|
272
|
+
* is described where it is declared — in the row schema the same collection returns — so the filter
|
|
273
|
+
* takes that description, found by walking the row along the path. Only a filter that has none of its
|
|
274
|
+
* own is filled in, and a path the rows do not carry (or reach only through a `$ref`) is left as is.
|
|
275
|
+
*/
|
|
276
|
+
const injectNestedFilterDescriptionsFromRows = (filters, rowSchema) => {
|
|
277
|
+
if (!isPlainObject(filters) || !isPlainObject(filters['properties'])) {
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
for (const [filterName, filterSchema] of Object.entries(filters['properties'])) {
|
|
281
|
+
if (!filterName.includes('.') || !isPlainObject(filterSchema) || filterSchema['description'] !== undefined) {
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
const description = describedPropertyAtPath(rowSchema, filterName.split('.'));
|
|
285
|
+
if (description !== undefined) {
|
|
286
|
+
filterSchema['description'] = description;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
/**
|
|
291
|
+
* The description of the property `path` names inside `schema`, entering `oneOf` / `anyOf` / `allOf`
|
|
292
|
+
* branches at each step — a nullable object is `anyOf [object, null]` — and taking the first branch
|
|
293
|
+
* that has the property.
|
|
294
|
+
*/
|
|
295
|
+
const describedPropertyAtPath = (schema, path) => {
|
|
296
|
+
if (!isPlainObject(schema) || path.length === 0) {
|
|
297
|
+
return undefined;
|
|
298
|
+
}
|
|
299
|
+
const [head, ...rest] = path;
|
|
300
|
+
const properties = schema['properties'];
|
|
301
|
+
if (isPlainObject(properties) && isPlainObject(properties[head])) {
|
|
302
|
+
const property = properties[head];
|
|
303
|
+
if (rest.length === 0) {
|
|
304
|
+
return typeof property['description'] === 'string' ? property['description'] : undefined;
|
|
305
|
+
}
|
|
306
|
+
const found = describedPropertyAtPath(property, rest);
|
|
307
|
+
if (found !== undefined) {
|
|
308
|
+
return found;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
for (const compositionKeyword of ['oneOf', 'anyOf', 'allOf']) {
|
|
312
|
+
const branches = schema[compositionKeyword];
|
|
313
|
+
if (!Array.isArray(branches)) {
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
for (const branch of branches) {
|
|
317
|
+
const found = describedPropertyAtPath(branch, path);
|
|
318
|
+
if (found !== undefined) {
|
|
319
|
+
return found;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return undefined;
|
|
324
|
+
};
|
|
214
325
|
const asNonEmptyString = (value) => typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;
|
|
215
326
|
/**
|
|
216
327
|
* Like `asNonEmptyString`, but for PROSE fields surfaced verbatim to API
|
|
217
328
|
* consumers (response-status `meaning`, error-scenario `when`, example `title`,
|
|
218
329
|
* `rateLimitNote`): additionally strips implementation-only noise (see
|
|
219
330
|
* `stripImplementationNoise`) and returns `undefined` if the value is empty
|
|
220
|
-
* before OR after cleaning. Do NOT use for code-like fields (`code`,
|
|
221
|
-
* `errorCode`, `forStatus`) — those pass through untouched via
|
|
331
|
+
* before OR after cleaning. Do NOT use for code-like fields (`code`, `errorType`,
|
|
332
|
+
* `customMessageReference`, `errorCode`, `forStatus`) — those pass through untouched via
|
|
333
|
+
* `asNonEmptyString`.
|
|
222
334
|
*/
|
|
223
335
|
const asCleanProse = (value) => {
|
|
224
336
|
const raw = asNonEmptyString(value);
|
|
@@ -239,10 +351,10 @@ const asCleanProse = (value) => {
|
|
|
239
351
|
*
|
|
240
352
|
* Prose fields (`meaning` / `when` / `title` / `rateLimitNote`) are cleaned of
|
|
241
353
|
* implementation-only noise via `asCleanProse`, consistent with the Tier-1
|
|
242
|
-
* `description` and Tier-2 field descriptions. `code` / `forStatus`
|
|
243
|
-
* `
|
|
244
|
-
*
|
|
245
|
-
*
|
|
354
|
+
* `description` and Tier-2 field descriptions. `code` / `forStatus` are
|
|
355
|
+
* `HttpResponseStatusCode` values whose runtime string (`'200'`, …) is the OpenAPI
|
|
356
|
+
* `responses` key; `errorType` / `customMessageReference` / `errorCode` are the
|
|
357
|
+
* error-body wire values a client branches on. All pass through untouched.
|
|
246
358
|
*/
|
|
247
359
|
export const buildOperationHttpDocFromSpec = (operationSpec, variantKey) => {
|
|
248
360
|
if (!isPlainObject(operationSpec)) {
|
|
@@ -274,6 +386,12 @@ export const buildOperationHttpDocFromSpec = (operationSpec, variantKey) => {
|
|
|
274
386
|
if (code === undefined || when === undefined)
|
|
275
387
|
return undefined;
|
|
276
388
|
const scenario = { code, when };
|
|
389
|
+
const errorType = asNonEmptyString(entry['errorType']);
|
|
390
|
+
if (errorType !== undefined)
|
|
391
|
+
scenario.errorType = errorType;
|
|
392
|
+
const customMessageReference = asNonEmptyString(entry['customMessageReference']);
|
|
393
|
+
if (customMessageReference !== undefined)
|
|
394
|
+
scenario.customMessageReference = customMessageReference;
|
|
277
395
|
const errorCode = asNonEmptyString(entry['errorCode']);
|
|
278
396
|
if (errorCode !== undefined)
|
|
279
397
|
scenario.errorCode = errorCode;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec-to-operation-doc.js","sourceRoot":"","sources":["../../../../src/companion/spec-to-operation-doc.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @wildo-package @wildo-ai/saas-technical-doc/companion (spec → OpenAPI enrichment)\n *\n * Pure mappers from a resource SPECIFICATION's authored prose into OpenAPI:\n * - **Tier 1** `buildOperationDocFromSpec` — operation `purpose` / `outcome` /\n * `whenToUse` (with per-variant overrides) → operation `description` on an\n * `OperationProjection`. The `summary` (operation TITLE) is intentionally NOT\n * produced here: it is a short verb-first label the generator derives\n * (`buildDefaultSummary`), kept separate from the authored prose.\n * - **Tier 2** `injectFieldDocsIntoJsonSchema` — per-field `meaning` /\n * `whyItMatters` / `relationshipContext` / enum-value meanings → property\n * `description` + `x-enum-descriptions` on a request/response JSON-Schema\n * fragment.\n *\n * See `.claude/plans/technical-doc-openapi-spec-integration.md`. Without authored\n * spec prose the description is empty and the operation falls back to the\n * generator's humanized verb-first title alone (e.g. `\"List users\"`) with no\n * field documentation — the \"quality will be very poor\" failure mode this\n * integration removes.\n *\n * @wildo-boundary\n * Imports NOTHING — pure string composition. It deliberately declares its\n * own NARROW structural input types instead of importing\n * `ResourceOperationSpecification` / `ResourceOperationVariantSpecification`\n * from `@wildo-ai/saas-specifications`. Same K-3 boundary reasoning the rest\n * of `companion/` follows (see `operation-projection.schemas.ts`): pulling\n * the spec package would drag a heavy type graph into the decorator-free\n * technical-doc companion bundle. The types below MUST remain a structural\n * SUBSET of the authored spec types — only the prose fields this mapper\n * reads. If the spec layer renames a prose field, update these in lockstep.\n */\n\n/**\n * Narrow structural view of a per-variant operation spec — the prose fields\n * a variant may override. Subset of `ResourceOperationVariantSpecification`.\n */\nexport interface OperationSpecVariantProse {\n purpose?: string;\n outcome?: string;\n whenToUse?: string;\n /** Complete OpenAPI example replacement for this response-shape variant. */\n examples?: Array<{ title: string; request?: unknown; response?: unknown; forStatus?: string }>;\n}\n\n/**\n * Narrow structural view of an operation spec — the base prose plus the\n * per-variant overrides map. Subset of `ResourceOperationSpecification`.\n * `variants` is keyed by the named variant key, with the reserved `'default'`\n * key for the no-`variantKey` (default-variant) path.\n */\nexport interface OperationSpecProse {\n purpose?: string;\n outcome?: string;\n whenToUse?: string;\n variants?: Record<string, OperationSpecVariantProse | undefined>;\n}\n\n/** The OpenAPI prose this mapper produces. Both fields optional. */\nexport interface OperationDoc {\n summary?: string;\n description?: string;\n}\n\n/** OperationProjection description cap: ≤2000 (Zod-enforced downstream). The\n * summary (title) is derived by the generator, not built here. */\nconst DESCRIPTION_MAX_LENGTH = 2000;\n\n/** Collapse all whitespace runs to single spaces and trim (single-line summary). */\nconst toSingleLine = (value: string): string => value.replace(/\\s+/gu, ' ').trim();\n\n/** Clamp to `max` chars, appending an ellipsis when truncated. */\nconst clampLength = (value: string, max: number): string =>\n value.length <= max ? value : `${value.slice(0, max - 1).trimEnd()}…`;\n\n/**\n * Strip implementation-only noise that authored spec prose carries for the\n * FRAMEWORK-KNOWLEDGE audience but that means nothing to an API consumer\n * reading the generated docs:\n * - Parentheticals naming a runtime variant — `(API_CALL in factory)`,\n * `(REPOSITORY_ONLY create in factory — …)`.\n * - Dangling `in factory` / `in the factory` phrases.\n * Then normalise the leftover spacing/punctuation. Conservative by design — it\n * only removes parentheticals that actually contain a variant marker, so\n * ordinary parenthetical prose survives.\n *\n * This is the single canonical \"spec prose → consumer prose\" cleaner, applied\n * to EVERY prose surface that reaches the OpenAPI output: the Tier-1 operation\n * `description` (here), Tier-2 field descriptions + `x-enum-descriptions`\n * (`composeFieldDescription` / `cleanEnumMeanings`), Tier-3 response/error/\n * example/rate-limit prose (`asCleanProse`), and the resource `tags[].description`\n * (applied by the generator — `openapi-generator.ts` imports this). Exported so\n * those out-of-module surfaces clean prose identically rather than diverging.\n */\nexport const stripImplementationNoise = (value: string): string =>\n value\n .replace(\n /\\s*\\([^()]*\\b(?:API_CALL_WITH_CALLBACK|API_CALL|REPOSITORY_ONLY|INTERNAL_CALL|CRON_JOB|BATCH_JOB)\\b[^()]*\\)/gu,\n '',\n )\n .replace(/\\s+in\\s+(?:the\\s+)?factory\\b/giu, '')\n .replace(/\\(\\s*\\)/gu, '')\n .replace(/\\s+([.,;:])/gu, '$1')\n .replace(/\\s{2,}/gu, ' ')\n .trim();\n\n/**\n * Resolve the EFFECTIVE prose for an operation, applying variant overlay\n * semantics: a present variant field REPLACES the base field; an absent\n * variant field falls back to the base. `variantKey === undefined` resolves\n * the reserved `'default'` variant.\n *\n * Returns `{}` when the spec is absent or carries no prose at all — callers\n * leave `OperationProjection.summary` / `.description` unset so the\n * generator's humanized fallback applies (graceful degradation for\n * operations / resources with no authored spec).\n */\nexport const buildOperationDocFromSpec = (\n operationSpec: OperationSpecProse | undefined,\n variantKey: string | undefined,\n): OperationDoc => {\n if (operationSpec === undefined) {\n return {};\n }\n\n const variant = operationSpec.variants?.[variantKey ?? 'default'];\n const effectivePurpose = variant?.purpose ?? operationSpec.purpose;\n const effectiveOutcome = variant?.outcome ?? operationSpec.outcome;\n const effectiveWhenToUse = variant?.whenToUse ?? operationSpec.whenToUse;\n\n const doc: OperationDoc = {};\n\n // The OpenAPI `summary` (operation TITLE / nav label / breadcrumb) is\n // intentionally NOT taken from `purpose`. `purpose` is impl-aware intent prose\n // authored for the framework-knowledge layer — a full sentence, often with\n // runtime detail like \"(API_CALL in factory)\" — which is far too long and too\n // internal to be a title. The generator derives a short verb-first title\n // (`buildDefaultSummary`); here we only build the DESCRIPTION from the authored\n // prose. The description LEADS with `purpose` (the intent), then the observable\n // `outcome`, then a \"When to use\" clause — each cleaned of implementation noise.\n const descriptionParts: string[] = [];\n if (effectivePurpose !== undefined) {\n const purpose = stripImplementationNoise(toSingleLine(effectivePurpose));\n if (purpose.length > 0) descriptionParts.push(purpose);\n }\n if (effectiveOutcome !== undefined) {\n const outcome = stripImplementationNoise(effectiveOutcome.trim());\n if (outcome.length > 0) descriptionParts.push(outcome);\n }\n if (effectiveWhenToUse !== undefined) {\n const whenToUse = stripImplementationNoise(effectiveWhenToUse.trim());\n if (whenToUse.length > 0) descriptionParts.push(`**When to use:** ${whenToUse}`);\n }\n if (descriptionParts.length > 0) {\n doc.description = clampLength(descriptionParts.join('\\n\\n'), DESCRIPTION_MAX_LENGTH);\n }\n\n return doc;\n};\n\n// ---------------------------------------------------------------------------\n// Tier 2 — field / enum documentation\n// ---------------------------------------------------------------------------\n\n/**\n * Narrow structural view of one field's authored documentation. Built by the\n * companion projector from the extracted resource field specs and consumed by\n * `injectFieldDocsIntoJsonSchema`. Boundary-clean (no `@wildo-ai/saas-specifications`\n * import): the projector maps `ExtractedFieldSpec.params.{meaning,whyItMatters,\n * relationshipContext,values}` into this shape before calling the injector.\n */\nexport interface FieldDoc {\n /** Business meaning of the field (becomes the lead of the property description). */\n meaning?: string;\n /** Why the field is included (appended to the description). */\n whyItMatters?: string;\n /** For foreign keys: the relationship this field expresses. */\n relationshipContext?: string;\n /** For enum fields: enum value string → authored meaning. */\n enumValueMeanings?: Record<string, string>;\n}\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\n/**\n * Clean an enum value→meaning record for consumer-facing output: strip\n * implementation-only noise from each meaning (see `stripImplementationNoise`)\n * and drop any entry that is non-string or empty after cleaning. Used for both\n * the human-readable \"Values:\" legend and the machine `x-enum-descriptions`\n * extension so the two never diverge.\n */\nconst cleanEnumMeanings = (enumValueMeanings: Record<string, string>): Record<string, string> => {\n const cleaned: Record<string, string> = {};\n for (const [value, meaning] of Object.entries(enumValueMeanings)) {\n if (typeof meaning !== 'string') {\n continue;\n }\n const cleanedMeaning = stripImplementationNoise(meaning.trim());\n if (cleanedMeaning.length > 0) {\n cleaned[value] = cleanedMeaning;\n }\n }\n return cleaned;\n};\n\n/**\n * Compose a single property `description` from a field's authored docs:\n * meaning + whyItMatters + relationshipContext as space-joined sentences,\n * then an optional markdown \"Values:\" legend from enum meanings. Each authored\n * sentence is run through `stripImplementationNoise` — the field-spec prose is\n * authored for the framework-knowledge audience and may carry runtime markers\n * (`(API_CALL in factory)`) that mean nothing to an API consumer. Returns\n * `undefined` when the field carries no usable prose.\n */\nconst composeFieldDescription = (doc: FieldDoc): string | undefined => {\n const sentences: string[] = [];\n for (const candidate of [doc.meaning, doc.whyItMatters, doc.relationshipContext]) {\n if (typeof candidate === 'string' && candidate.trim().length > 0) {\n const cleaned = stripImplementationNoise(candidate.trim());\n if (cleaned.length > 0) {\n sentences.push(cleaned);\n }\n }\n }\n let description = sentences.join(' ');\n\n if (doc.enumValueMeanings !== undefined) {\n const legend = Object.entries(cleanEnumMeanings(doc.enumValueMeanings)).map(\n ([value, meaning]) => `- \\`${value}\\`: ${meaning}`,\n );\n if (legend.length > 0) {\n const block = `Values:\\n${legend.join('\\n')}`;\n description = description.length > 0 ? `${description}\\n\\n${block}` : block;\n }\n }\n\n return description.length > 0 ? description : undefined;\n};\n\n/**\n * Enrich the TOP-LEVEL properties of an OpenAPI/JSON-Schema object fragment\n * (a `requestBodySchema` / `responseBodySchema` produced by\n * `convertZodSchemaToOpenApiSchema`) with authored field documentation.\n * Mutates `fragment` in place.\n *\n * Rules:\n * - Property `description` is composed from the field's docs ONLY when the\n * property has no existing `description` — a Zod `.describe()` authored on\n * the DTO field wins (it is closer to the wire contract).\n * - `x-enum-descriptions` (value → meaning) is set whenever enum meanings\n * exist, independent of the description-clobber rule, for machine consumers.\n *\n * Only top-level properties are walked: the field-spec extractor produces\n * specs for top-level schema fields only, so nested-object properties have no\n * authored docs to apply. No-op for non-object fragments (`null`, scalars).\n * Joins by EXACT property-name match — DTO property names that diverge from\n * the resource's field names (renamed / computed / backend-stripped fields)\n * are simply left undocumented rather than mis-documented.\n */\nexport const injectFieldDocsIntoJsonSchema = (\n fragment: unknown,\n fieldDocsByName: Record<string, FieldDoc>,\n): void => {\n if (!isPlainObject(fragment)) {\n return;\n }\n const properties = fragment['properties'];\n if (!isPlainObject(properties)) {\n return;\n }\n for (const [propertyName, rawPropertySchema] of Object.entries(properties)) {\n if (!isPlainObject(rawPropertySchema)) {\n continue;\n }\n const doc = fieldDocsByName[propertyName];\n if (doc === undefined) {\n continue;\n }\n if (rawPropertySchema['description'] === undefined) {\n const description = composeFieldDescription(doc);\n if (description !== undefined) {\n rawPropertySchema['description'] = description;\n }\n }\n if (doc.enumValueMeanings !== undefined) {\n const cleanedEnumMeanings = cleanEnumMeanings(doc.enumValueMeanings);\n if (Object.keys(cleanedEnumMeanings).length > 0) {\n rawPropertySchema['x-enum-descriptions'] = cleanedEnumMeanings;\n }\n }\n }\n};\n\n// ---------------------------------------------------------------------------\n// Tier 3 — operation HTTP documentation (response statuses / errors / examples)\n// ---------------------------------------------------------------------------\n\n/**\n * Projection-shaped HTTP documentation for one operation (Tier 3). Mirrors the\n * authored `ResourceOperationSpecification` HTTP fields, normalized to plain\n * JSON the OpenAPI generator emits as `responses` / `examples` / extensions.\n */\nexport interface OperationHttpDoc {\n responseStatuses?: Array<{ code: string; meaning: string }>;\n errorScenarios?: Array<{ code: string; when: string; errorCode?: string }>;\n idempotent?: boolean;\n rateLimitNote?: string;\n examples?: Array<{ title: string; request?: unknown; response?: unknown; forStatus?: string }>;\n}\n\nconst asNonEmptyString = (value: unknown): string | undefined =>\n typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;\n\n/**\n * Like `asNonEmptyString`, but for PROSE fields surfaced verbatim to API\n * consumers (response-status `meaning`, error-scenario `when`, example `title`,\n * `rateLimitNote`): additionally strips implementation-only noise (see\n * `stripImplementationNoise`) and returns `undefined` if the value is empty\n * before OR after cleaning. Do NOT use for code-like fields (`code`,\n * `errorCode`, `forStatus`) — those pass through untouched via `asNonEmptyString`.\n */\nconst asCleanProse = (value: unknown): string | undefined => {\n const raw = asNonEmptyString(value);\n if (raw === undefined) {\n return undefined;\n }\n const cleaned = stripImplementationNoise(raw);\n return cleaned.length > 0 ? cleaned : undefined;\n};\n\n/**\n * Extract + normalize the Tier-3 HTTP-documentation fields from a raw authored\n * operation spec into the projection shape. Variant examples are a complete\n * overlay: when `variants.<key>.examples` is present it replaces the base\n * operation examples, rather than merging a payload that may target a different\n * response schema. Defensive: a malformed entry is dropped rather than\n * poisoning the whole projection (the generator re-validates via Zod). Returns\n * `{}` when the operation authored no HTTP docs.\n *\n * Prose fields (`meaning` / `when` / `title` / `rateLimitNote`) are cleaned of\n * implementation-only noise via `asCleanProse`, consistent with the Tier-1\n * `description` and Tier-2 field descriptions. `code` / `forStatus` /\n * `errorCode` are `HttpResponseStatusCode` / error-code enum values whose\n * runtime string value (`'200'`, …) is the OpenAPI `responses` key / a machine\n * code, so they pass through untouched as strings.\n */\nexport const buildOperationHttpDocFromSpec = (operationSpec: unknown, variantKey?: string): OperationHttpDoc => {\n if (!isPlainObject(operationSpec)) {\n return {};\n }\n const doc: OperationHttpDoc = {};\n\n const responseStatuses = operationSpec['responseStatuses'];\n if (Array.isArray(responseStatuses)) {\n const normalized = responseStatuses\n .map((entry) => {\n if (!isPlainObject(entry)) return undefined;\n const code = asNonEmptyString(entry['code']);\n const meaning = asCleanProse(entry['meaning']);\n return code !== undefined && meaning !== undefined ? { code, meaning } : undefined;\n })\n .filter((entry): entry is { code: string; meaning: string } => entry !== undefined);\n if (normalized.length > 0) doc.responseStatuses = normalized;\n }\n\n const errorScenarios = operationSpec['errorScenarios'];\n if (Array.isArray(errorScenarios)) {\n const normalized = errorScenarios\n .map((entry) => {\n if (!isPlainObject(entry)) return undefined;\n const code = asNonEmptyString(entry['code']);\n const when = asCleanProse(entry['when']);\n if (code === undefined || when === undefined) return undefined;\n const scenario: { code: string; when: string; errorCode?: string } = { code, when };\n const errorCode = asNonEmptyString(entry['errorCode']);\n if (errorCode !== undefined) scenario.errorCode = errorCode;\n return scenario;\n })\n .filter((entry): entry is { code: string; when: string; errorCode?: string } => entry !== undefined);\n if (normalized.length > 0) doc.errorScenarios = normalized;\n }\n\n if (typeof operationSpec['idempotent'] === 'boolean') {\n doc.idempotent = operationSpec['idempotent'];\n }\n\n const rateLimitNote = asCleanProse(operationSpec['rateLimitNote']);\n if (rateLimitNote !== undefined) {\n doc.rateLimitNote = rateLimitNote;\n }\n\n const variants = operationSpec['variants'];\n const variant = isPlainObject(variants) ? variants[variantKey ?? 'default'] : undefined;\n // A present variant `examples` member deliberately suppresses the base even\n // when it is malformed or empty: falling back would publish a payload under a\n // schema the variant does not own. The normalizer below emits no example for\n // that invalid/empty override, which is safer than a misleading one.\n const examples =\n isPlainObject(variant) && Object.prototype.hasOwnProperty.call(variant, 'examples')\n ? variant['examples']\n : operationSpec['examples'];\n if (Array.isArray(examples)) {\n const normalized = examples\n .map((entry) => {\n if (!isPlainObject(entry)) return undefined;\n const title = asCleanProse(entry['title']);\n if (title === undefined) return undefined;\n const example: { title: string; request?: unknown; response?: unknown; forStatus?: string } = { title };\n if (entry['request'] !== undefined) example.request = entry['request'];\n if (entry['response'] !== undefined) example.response = entry['response'];\n const forStatus = asNonEmptyString(entry['forStatus']);\n if (forStatus !== undefined) example.forStatus = forStatus;\n return example;\n })\n .filter(\n (entry): entry is { title: string; request?: unknown; response?: unknown; forStatus?: string } =>\n entry !== undefined,\n );\n if (normalized.length > 0) doc.examples = normalized;\n }\n\n return doc;\n};\n"]}
|
|
1
|
+
{"version":3,"file":"spec-to-operation-doc.js","sourceRoot":"","sources":["../../../../src/companion/spec-to-operation-doc.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @wildo-package @wildo-ai/saas-technical-doc/companion (spec → OpenAPI enrichment)\n *\n * Pure mappers from a resource SPECIFICATION's authored prose into OpenAPI:\n * - **Tier 1** `buildOperationDocFromSpec` — operation `purpose` / `outcome` /\n * `whenToUse` (with per-variant overrides) → operation `description` on an\n * `OperationProjection`. The `summary` (operation TITLE) is intentionally NOT\n * produced here: it is a short verb-first label the generator derives\n * (`buildDefaultSummary`), kept separate from the authored prose.\n * - **Tier 2** `injectFieldDocsIntoJsonSchema` — per-field `meaning` /\n * `whyItMatters` / `relationshipContext` / enum-value meanings → property\n * `description` + `x-enum-descriptions` on a request/response JSON-Schema\n * fragment; `injectFieldDocsIntoCollectionContract` applies the same to a\n * paginated collection's `filters` bag and `data[]` items.\n *\n * See `.claude/plans/technical-doc-openapi-spec-integration.md`. Without authored\n * spec prose the description is empty and the operation falls back to the\n * generator's humanized verb-first title alone (e.g. `\"List users\"`) with no\n * field documentation — the \"quality will be very poor\" failure mode this\n * integration removes.\n *\n * @wildo-boundary\n * Imports NOTHING — pure string composition. It deliberately declares its\n * own NARROW structural input types instead of importing\n * `ResourceOperationSpecification` / `ResourceOperationVariantSpecification`\n * from `@wildo-ai/saas-specifications`. Same K-3 boundary reasoning the rest\n * of `companion/` follows (see `operation-projection.schemas.ts`): pulling\n * the spec package would drag a heavy type graph into the decorator-free\n * technical-doc companion bundle. The types below MUST remain a structural\n * SUBSET of the authored spec types — only the prose fields this mapper\n * reads. If the spec layer renames a prose field, update these in lockstep.\n */\n\n/**\n * Narrow structural view of a per-variant operation spec — the prose fields\n * a variant may override. Subset of `ResourceOperationVariantSpecification`.\n */\nexport interface OperationSpecVariantProse {\n purpose?: string;\n outcome?: string;\n whenToUse?: string;\n /** Complete OpenAPI example replacement for this response-shape variant. */\n examples?: Array<{ title: string; request?: unknown; response?: unknown; forStatus?: string }>;\n}\n\n/**\n * Narrow structural view of an operation spec — the base prose plus the\n * per-variant overrides map. Subset of `ResourceOperationSpecification`.\n * `variants` is keyed by the named variant key, with the reserved `'default'`\n * key for the no-`variantKey` (default-variant) path.\n */\nexport interface OperationSpecProse {\n purpose?: string;\n outcome?: string;\n whenToUse?: string;\n variants?: Record<string, OperationSpecVariantProse | undefined>;\n}\n\n/** The OpenAPI prose this mapper produces. Both fields optional. */\nexport interface OperationDoc {\n summary?: string;\n description?: string;\n}\n\n/** OperationProjection description cap: ≤2000 (Zod-enforced downstream). The\n * summary (title) is derived by the generator, not built here. */\nconst DESCRIPTION_MAX_LENGTH = 2000;\n\n/** Collapse all whitespace runs to single spaces and trim (single-line summary). */\nconst toSingleLine = (value: string): string => value.replace(/\\s+/gu, ' ').trim();\n\n/** Clamp to `max` chars, appending an ellipsis when truncated. */\nconst clampLength = (value: string, max: number): string =>\n value.length <= max ? value : `${value.slice(0, max - 1).trimEnd()}…`;\n\n/**\n * Strip implementation-only noise that authored spec prose carries for the\n * FRAMEWORK-KNOWLEDGE audience but that means nothing to an API consumer\n * reading the generated docs:\n * - Parentheticals naming a runtime variant — `(API_CALL in factory)`,\n * `(REPOSITORY_ONLY create in factory — …)`.\n * - Dangling `in factory` / `in the factory` phrases.\n * Then normalise the leftover spacing/punctuation. Conservative by design — it\n * only removes parentheticals that actually contain a variant marker, so\n * ordinary parenthetical prose survives.\n *\n * This is the single canonical \"spec prose → consumer prose\" cleaner, applied\n * to EVERY prose surface that reaches the OpenAPI output: the Tier-1 operation\n * `description` (here), Tier-2 field descriptions + `x-enum-descriptions`\n * (`composeFieldDescription` / `cleanEnumMeanings`), Tier-3 response/error/\n * example/rate-limit prose (`asCleanProse`), and the resource `tags[].description`\n * (applied by the generator — `openapi-generator.ts` imports this). Exported so\n * those out-of-module surfaces clean prose identically rather than diverging.\n */\nexport const stripImplementationNoise = (value: string): string =>\n value\n .replace(\n /\\s*\\([^()]*\\b(?:API_CALL_WITH_CALLBACK|API_CALL|REPOSITORY_ONLY|INTERNAL_CALL|CRON_JOB|BATCH_JOB)\\b[^()]*\\)/gu,\n '',\n )\n .replace(/\\s+in\\s+(?:the\\s+)?factory\\b/giu, '')\n .replace(/\\(\\s*\\)/gu, '')\n .replace(/\\s+([.,;:])/gu, '$1')\n .replace(/\\s{2,}/gu, ' ')\n .trim();\n\n/**\n * Resolve the EFFECTIVE prose for an operation, applying variant overlay\n * semantics: a present variant field REPLACES the base field; an absent\n * variant field falls back to the base. `variantKey === undefined` resolves\n * the reserved `'default'` variant.\n *\n * Returns `{}` when the spec is absent or carries no prose at all — callers\n * leave `OperationProjection.summary` / `.description` unset so the\n * generator's humanized fallback applies (graceful degradation for\n * operations / resources with no authored spec).\n */\nexport const buildOperationDocFromSpec = (\n operationSpec: OperationSpecProse | undefined,\n variantKey: string | undefined,\n): OperationDoc => {\n if (operationSpec === undefined) {\n return {};\n }\n\n const variant = operationSpec.variants?.[variantKey ?? 'default'];\n const effectivePurpose = variant?.purpose ?? operationSpec.purpose;\n const effectiveOutcome = variant?.outcome ?? operationSpec.outcome;\n const effectiveWhenToUse = variant?.whenToUse ?? operationSpec.whenToUse;\n\n const doc: OperationDoc = {};\n\n // The OpenAPI `summary` (operation TITLE / nav label / breadcrumb) is\n // intentionally NOT taken from `purpose`. `purpose` is impl-aware intent prose\n // authored for the framework-knowledge layer — a full sentence, often with\n // runtime detail like \"(API_CALL in factory)\" — which is far too long and too\n // internal to be a title. The generator derives a short verb-first title\n // (`buildDefaultSummary`); here we only build the DESCRIPTION from the authored\n // prose. The description LEADS with `purpose` (the intent), then the observable\n // `outcome`, then a \"When to use\" clause — each cleaned of implementation noise.\n const descriptionParts: string[] = [];\n if (effectivePurpose !== undefined) {\n const purpose = stripImplementationNoise(toSingleLine(effectivePurpose));\n if (purpose.length > 0) descriptionParts.push(purpose);\n }\n if (effectiveOutcome !== undefined) {\n const outcome = stripImplementationNoise(effectiveOutcome.trim());\n if (outcome.length > 0) descriptionParts.push(outcome);\n }\n if (effectiveWhenToUse !== undefined) {\n const whenToUse = stripImplementationNoise(effectiveWhenToUse.trim());\n if (whenToUse.length > 0) descriptionParts.push(`**When to use:** ${whenToUse}`);\n }\n if (descriptionParts.length > 0) {\n doc.description = clampLength(descriptionParts.join('\\n\\n'), DESCRIPTION_MAX_LENGTH);\n }\n\n return doc;\n};\n\n// ---------------------------------------------------------------------------\n// Tier 2 — field / enum documentation\n// ---------------------------------------------------------------------------\n\n/**\n * Narrow structural view of one field's authored documentation. Built by the\n * companion projector from the extracted resource field specs and consumed by\n * `injectFieldDocsIntoJsonSchema`. Boundary-clean (no `@wildo-ai/saas-specifications`\n * import): the projector maps `ExtractedFieldSpec.params.{meaning,whyItMatters,\n * relationshipContext,values}` into this shape before calling the injector.\n */\nexport interface FieldDoc {\n /** Business meaning of the field (becomes the lead of the property description). */\n meaning?: string;\n /** Why the field is included (appended to the description). */\n whyItMatters?: string;\n /** For foreign keys: the relationship this field expresses. */\n relationshipContext?: string;\n /** For enum fields: enum value string → authored meaning. */\n enumValueMeanings?: Record<string, string>;\n}\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\n/**\n * Clean an enum value→meaning record for consumer-facing output: strip\n * implementation-only noise from each meaning (see `stripImplementationNoise`)\n * and drop any entry that is non-string or empty after cleaning. Used for both\n * the human-readable \"Values:\" legend and the machine `x-enum-descriptions`\n * extension so the two never diverge.\n */\nconst cleanEnumMeanings = (enumValueMeanings: Record<string, string>): Record<string, string> => {\n const cleaned: Record<string, string> = {};\n for (const [value, meaning] of Object.entries(enumValueMeanings)) {\n if (typeof meaning !== 'string') {\n continue;\n }\n const cleanedMeaning = stripImplementationNoise(meaning.trim());\n if (cleanedMeaning.length > 0) {\n cleaned[value] = cleanedMeaning;\n }\n }\n return cleaned;\n};\n\n/**\n * Compose a single property `description` from a field's authored docs:\n * meaning + whyItMatters + relationshipContext as space-joined sentences,\n * then an optional markdown \"Values:\" legend from enum meanings. Each authored\n * sentence is run through `stripImplementationNoise` — the field-spec prose is\n * authored for the framework-knowledge audience and may carry runtime markers\n * (`(API_CALL in factory)`) that mean nothing to an API consumer. Returns\n * `undefined` when the field carries no usable prose.\n */\nconst composeFieldDescription = (doc: FieldDoc): string | undefined => {\n const sentences: string[] = [];\n for (const candidate of [doc.meaning, doc.whyItMatters, doc.relationshipContext]) {\n if (typeof candidate === 'string' && candidate.trim().length > 0) {\n const cleaned = stripImplementationNoise(candidate.trim());\n if (cleaned.length > 0) {\n sentences.push(cleaned);\n }\n }\n }\n let description = sentences.join(' ');\n\n if (doc.enumValueMeanings !== undefined) {\n const legend = Object.entries(cleanEnumMeanings(doc.enumValueMeanings)).map(\n ([value, meaning]) => `- \\`${value}\\`: ${meaning}`,\n );\n if (legend.length > 0) {\n const block = `Values:\\n${legend.join('\\n')}`;\n description = description.length > 0 ? `${description}\\n\\n${block}` : block;\n }\n }\n\n return description.length > 0 ? description : undefined;\n};\n\n/**\n * Enrich the TOP-LEVEL properties of an OpenAPI/JSON-Schema object fragment\n * (a `requestBodySchema` / `responseBodySchema` produced by\n * `convertZodSchemaToOpenApiSchema`) with authored field documentation.\n * Mutates `fragment` in place.\n *\n * Rules:\n * - Property `description` is composed from the field's docs ONLY when the\n * property has no existing `description` — a Zod `.describe()` authored on\n * the DTO field wins (it is closer to the wire contract).\n * - `x-enum-descriptions` (value → meaning) is set whenever enum meanings\n * exist, independent of the description-clobber rule, for machine consumers.\n *\n * Only top-level properties are walked: the field-spec extractor produces\n * specs for top-level schema fields only, so nested-object properties have no\n * authored docs to apply. No-op for non-object fragments (`null`, scalars).\n * Joins by EXACT property-name match — DTO property names that diverge from\n * the resource's field names (renamed / computed / backend-stripped fields)\n * are simply left undocumented rather than mis-documented.\n *\n * \"Top level\" includes each branch of a top-level `oneOf` / `anyOf` / `allOf`.\n * A polymorphic resource's representation is a union whose branches carry the\n * properties themselves — the fragment has no `properties` of its own — and\n * every branch's properties are still the resource's own top-level fields. Only\n * composition keywords are entered, never an object property, so the rule above\n * still holds. Without this, 42 of the 58 properties of Wonder Todos' `todos`\n * read and list representations (`title`, `status`, `priority`, …) carried no\n * description.\n *\n * A paginated collection re-wraps those fields one level down; see\n * `injectFieldDocsIntoCollectionContract` for the two containers it adds.\n */\nexport const injectFieldDocsIntoJsonSchema = (\n fragment: unknown,\n fieldDocsByName: Record<string, FieldDoc>,\n): void => {\n if (!isPlainObject(fragment)) {\n return;\n }\n // A body that is a LIST of rows (a bulk create or update answers one row per item, #1872) documents its rows.\n if (fragment['type'] === 'array' && isPlainObject(fragment['items'])) {\n injectFieldDocsIntoJsonSchema(fragment['items'], fieldDocsByName);\n return;\n }\n for (const compositionKeyword of ['oneOf', 'anyOf', 'allOf'] as const) {\n const branches = fragment[compositionKeyword];\n if (Array.isArray(branches)) {\n for (const branch of branches) {\n injectFieldDocsIntoJsonSchema(branch, fieldDocsByName);\n }\n }\n }\n const properties = fragment['properties'];\n if (!isPlainObject(properties)) {\n return;\n }\n for (const [propertyName, rawPropertySchema] of Object.entries(properties)) {\n if (!isPlainObject(rawPropertySchema)) {\n continue;\n }\n const doc = fieldDocsByName[propertyName];\n if (doc === undefined) {\n continue;\n }\n if (rawPropertySchema['description'] === undefined) {\n const description = composeFieldDescription(doc);\n if (description !== undefined) {\n rawPropertySchema['description'] = description;\n }\n }\n if (doc.enumValueMeanings !== undefined) {\n const cleanedEnumMeanings = cleanEnumMeanings(doc.enumValueMeanings);\n if (Object.keys(cleanedEnumMeanings).length > 0) {\n rawPropertySchema['x-enum-descriptions'] = cleanedEnumMeanings;\n }\n }\n }\n};\n\n/**\n * Enrich the two places a paginated collection contract carries the resource's OWN fields one\n * level down, where `injectFieldDocsIntoJsonSchema` (top level only) cannot reach them:\n *\n * - the request's `filters` object — one property per filterable field, which the generator\n * flattens into query parameters (`?status=…`), copying each property's `description`;\n * - the response envelope's `data[]` items — the resource rows a LIST / SEARCH returns.\n *\n * This is not the general nested walk `injectFieldDocsIntoJsonSchema` declines: a nested object's\n * properties have no field specification, while these two containers hold the resource's own\n * top-level fields, re-wrapped by the framework's collection contract. Before this, 59% of the\n * list-item properties and 219 query filters in the Wonder Todos document carried no description,\n * although the same fields were fully described in the read and create responses.\n *\n * Call it only for a paginated collection operation (LIST, or SEARCH-like). Anything else passes\n * through unchanged, because neither container exists.\n */\nexport const injectFieldDocsIntoCollectionContract = (\n requestBodySchema: unknown,\n responseBodySchema: unknown,\n fieldDocsByName: Record<string, FieldDoc>,\n): void => {\n const filters = isPlainObject(requestBodySchema) && isPlainObject(requestBodySchema['properties'])\n ? requestBodySchema['properties']['filters']\n : undefined;\n injectFieldDocsIntoJsonSchema(filters, fieldDocsByName);\n const data = isPlainObject(responseBodySchema) && isPlainObject(responseBodySchema['properties'])\n ? responseBodySchema['properties']['data']\n : undefined;\n const items = isPlainObject(data) ? data['items'] : undefined;\n injectFieldDocsIntoJsonSchema(items, fieldDocsByName);\n injectNestedFilterDescriptionsFromRows(filters, items);\n};\n\n/**\n * A filter on a nested field is keyed by its dotted path (`linkedResource.resourceType`, #1630), so it\n * matches no field specification by name and was published with no description. The field it filters\n * is described where it is declared — in the row schema the same collection returns — so the filter\n * takes that description, found by walking the row along the path. Only a filter that has none of its\n * own is filled in, and a path the rows do not carry (or reach only through a `$ref`) is left as is.\n */\nconst injectNestedFilterDescriptionsFromRows = (filters: unknown, rowSchema: unknown): void => {\n if (!isPlainObject(filters) || !isPlainObject(filters['properties'])) {\n return;\n }\n for (const [filterName, filterSchema] of Object.entries(filters['properties'])) {\n if (!filterName.includes('.') || !isPlainObject(filterSchema) || filterSchema['description'] !== undefined) {\n continue;\n }\n const description = describedPropertyAtPath(rowSchema, filterName.split('.'));\n if (description !== undefined) {\n filterSchema['description'] = description;\n }\n }\n};\n\n/**\n * The description of the property `path` names inside `schema`, entering `oneOf` / `anyOf` / `allOf`\n * branches at each step — a nullable object is `anyOf [object, null]` — and taking the first branch\n * that has the property.\n */\nconst describedPropertyAtPath = (schema: unknown, path: readonly string[]): string | undefined => {\n if (!isPlainObject(schema) || path.length === 0) {\n return undefined;\n }\n const [head, ...rest] = path;\n const properties = schema['properties'];\n if (isPlainObject(properties) && isPlainObject(properties[head!])) {\n const property = properties[head!] as Record<string, unknown>;\n if (rest.length === 0) {\n return typeof property['description'] === 'string' ? property['description'] : undefined;\n }\n const found = describedPropertyAtPath(property, rest);\n if (found !== undefined) {\n return found;\n }\n }\n for (const compositionKeyword of ['oneOf', 'anyOf', 'allOf'] as const) {\n const branches = schema[compositionKeyword];\n if (!Array.isArray(branches)) {\n continue;\n }\n for (const branch of branches) {\n const found = describedPropertyAtPath(branch, path);\n if (found !== undefined) {\n return found;\n }\n }\n }\n return undefined;\n};\n\n// ---------------------------------------------------------------------------\n// Tier 3 — operation HTTP documentation (response statuses / errors / examples)\n// ---------------------------------------------------------------------------\n\n/**\n * Projection-shaped HTTP documentation for one operation (Tier 3). Mirrors the\n * authored `ResourceOperationSpecification` HTTP fields, normalized to plain\n * JSON the OpenAPI generator emits as `responses` / `examples` / extensions.\n */\n/**\n * One documented failure mode, with the error-body field each identifier appears in.\n *\n * `errorType` is `error.type`, `customMessageReference` is `error.customMessageReference`, and\n * `errorCode` is `error.code` — three different fields a client branches on, carried separately\n * because the authored specification names them separately (see\n * `ResourceOperationErrorScenarioSpecification`). Values are the wire strings.\n */\nexport interface OperationErrorScenarioDoc {\n code: string;\n when: string;\n errorType?: string;\n customMessageReference?: string;\n errorCode?: string;\n}\n\nexport interface OperationHttpDoc {\n responseStatuses?: Array<{ code: string; meaning: string }>;\n errorScenarios?: OperationErrorScenarioDoc[];\n idempotent?: boolean;\n rateLimitNote?: string;\n examples?: Array<{ title: string; request?: unknown; response?: unknown; forStatus?: string }>;\n}\n\nconst asNonEmptyString = (value: unknown): string | undefined =>\n typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;\n\n/**\n * Like `asNonEmptyString`, but for PROSE fields surfaced verbatim to API\n * consumers (response-status `meaning`, error-scenario `when`, example `title`,\n * `rateLimitNote`): additionally strips implementation-only noise (see\n * `stripImplementationNoise`) and returns `undefined` if the value is empty\n * before OR after cleaning. Do NOT use for code-like fields (`code`, `errorType`,\n * `customMessageReference`, `errorCode`, `forStatus`) — those pass through untouched via\n * `asNonEmptyString`.\n */\nconst asCleanProse = (value: unknown): string | undefined => {\n const raw = asNonEmptyString(value);\n if (raw === undefined) {\n return undefined;\n }\n const cleaned = stripImplementationNoise(raw);\n return cleaned.length > 0 ? cleaned : undefined;\n};\n\n/**\n * Extract + normalize the Tier-3 HTTP-documentation fields from a raw authored\n * operation spec into the projection shape. Variant examples are a complete\n * overlay: when `variants.<key>.examples` is present it replaces the base\n * operation examples, rather than merging a payload that may target a different\n * response schema. Defensive: a malformed entry is dropped rather than\n * poisoning the whole projection (the generator re-validates via Zod). Returns\n * `{}` when the operation authored no HTTP docs.\n *\n * Prose fields (`meaning` / `when` / `title` / `rateLimitNote`) are cleaned of\n * implementation-only noise via `asCleanProse`, consistent with the Tier-1\n * `description` and Tier-2 field descriptions. `code` / `forStatus` are\n * `HttpResponseStatusCode` values whose runtime string (`'200'`, …) is the OpenAPI\n * `responses` key; `errorType` / `customMessageReference` / `errorCode` are the\n * error-body wire values a client branches on. All pass through untouched.\n */\nexport const buildOperationHttpDocFromSpec = (operationSpec: unknown, variantKey?: string): OperationHttpDoc => {\n if (!isPlainObject(operationSpec)) {\n return {};\n }\n const doc: OperationHttpDoc = {};\n\n const responseStatuses = operationSpec['responseStatuses'];\n if (Array.isArray(responseStatuses)) {\n const normalized = responseStatuses\n .map((entry) => {\n if (!isPlainObject(entry)) return undefined;\n const code = asNonEmptyString(entry['code']);\n const meaning = asCleanProse(entry['meaning']);\n return code !== undefined && meaning !== undefined ? { code, meaning } : undefined;\n })\n .filter((entry): entry is { code: string; meaning: string } => entry !== undefined);\n if (normalized.length > 0) doc.responseStatuses = normalized;\n }\n\n const errorScenarios = operationSpec['errorScenarios'];\n if (Array.isArray(errorScenarios)) {\n const normalized = errorScenarios\n .map((entry) => {\n if (!isPlainObject(entry)) return undefined;\n const code = asNonEmptyString(entry['code']);\n const when = asCleanProse(entry['when']);\n if (code === undefined || when === undefined) return undefined;\n const scenario: OperationErrorScenarioDoc = { code, when };\n const errorType = asNonEmptyString(entry['errorType']);\n if (errorType !== undefined) scenario.errorType = errorType;\n const customMessageReference = asNonEmptyString(entry['customMessageReference']);\n if (customMessageReference !== undefined) scenario.customMessageReference = customMessageReference;\n const errorCode = asNonEmptyString(entry['errorCode']);\n if (errorCode !== undefined) scenario.errorCode = errorCode;\n return scenario;\n })\n .filter((entry): entry is OperationErrorScenarioDoc => entry !== undefined);\n if (normalized.length > 0) doc.errorScenarios = normalized;\n }\n\n if (typeof operationSpec['idempotent'] === 'boolean') {\n doc.idempotent = operationSpec['idempotent'];\n }\n\n const rateLimitNote = asCleanProse(operationSpec['rateLimitNote']);\n if (rateLimitNote !== undefined) {\n doc.rateLimitNote = rateLimitNote;\n }\n\n const variants = operationSpec['variants'];\n const variant = isPlainObject(variants) ? variants[variantKey ?? 'default'] : undefined;\n // A present variant `examples` member deliberately suppresses the base even\n // when it is malformed or empty: falling back would publish a payload under a\n // schema the variant does not own. The normalizer below emits no example for\n // that invalid/empty override, which is safer than a misleading one.\n const examples =\n isPlainObject(variant) && Object.prototype.hasOwnProperty.call(variant, 'examples')\n ? variant['examples']\n : operationSpec['examples'];\n if (Array.isArray(examples)) {\n const normalized = examples\n .map((entry) => {\n if (!isPlainObject(entry)) return undefined;\n const title = asCleanProse(entry['title']);\n if (title === undefined) return undefined;\n const example: { title: string; request?: unknown; response?: unknown; forStatus?: string } = { title };\n if (entry['request'] !== undefined) example.request = entry['request'];\n if (entry['response'] !== undefined) example.response = entry['response'];\n const forStatus = asNonEmptyString(entry['forStatus']);\n if (forStatus !== undefined) example.forStatus = forStatus;\n return example;\n })\n .filter(\n (entry): entry is { title: string; request?: unknown; response?: unknown; forStatus?: string } =>\n entry !== undefined,\n );\n if (normalized.length > 0) doc.examples = normalized;\n }\n\n return doc;\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"technical-documentation-asset-path.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"technical-documentation-asset-path.d.ts","sourceRoot":"","sources":["../../../../src/companion/technical-documentation-asset-path.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,+BAA+B,EAChC,MAAM,uDAAuD,CAAC;AAE/D;;;;;;GAMG;AACH,wBAAgB,mCAAmC,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAEjF;AAED,gGAAgG;AAChG,wBAAgB,gDAAgD,CAAC,KAAK,EAAE;IACtE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,+BAA+B,CAAC;IAC/C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B,GAAG,MAAM,CAIT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"technical-documentation-capture-execution-port.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"technical-documentation-capture-execution-port.d.ts","sourceRoot":"","sources":["../../../../src/companion/technical-documentation-capture-execution-port.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,+CAA+C,EAC/C,sCAAsC,EACvC,MAAM,uDAAuD,CAAC;AAE/D;;;GAGG;AACH,MAAM,WAAW,4CAA4C;IAC3D,QAAQ,CAAC,OAAO,EAAE,sCAAsC,CAAC;IACzD,QAAQ,CAAC,WAAW,EAAE,UAAU,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,WAAW,0CAA0C;IACzD,OAAO,CAAC,OAAO,EAAE,+CAA+C,GAAG,OAAO,CAAC,4CAA4C,CAAC,CAAC;CAC1H"}
|