openapi-typesafe 1.0.0-rc.4 → 1.0.0-rc.5
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/CHANGELOG.md +141 -0
- package/dist/adapters/node-file-system/node-file-system.cjs +7 -0
- package/dist/adapters/node-file-system/node-file-system.cjs.map +1 -1
- package/dist/adapters/node-file-system/node-file-system.mjs +7 -0
- package/dist/adapters/node-file-system/node-file-system.mjs.map +1 -1
- package/dist/adapters/pipe-safe-writer/pipe-safe-writer.cjs +19 -0
- package/dist/adapters/pipe-safe-writer/pipe-safe-writer.cjs.map +1 -0
- package/dist/adapters/pipe-safe-writer/pipe-safe-writer.mjs +17 -0
- package/dist/adapters/pipe-safe-writer/pipe-safe-writer.mjs.map +1 -0
- package/dist/adapters/redocly-loader/bundled-mapping-copies.cjs +5 -32
- package/dist/adapters/redocly-loader/bundled-mapping-copies.cjs.map +1 -1
- package/dist/adapters/redocly-loader/bundled-mapping-copies.mjs +6 -33
- package/dist/adapters/redocly-loader/bundled-mapping-copies.mjs.map +1 -1
- package/dist/adapters/redocly-loader/component-schemas.cjs +17 -0
- package/dist/adapters/redocly-loader/component-schemas.cjs.map +1 -0
- package/dist/adapters/redocly-loader/component-schemas.mjs +14 -0
- package/dist/adapters/redocly-loader/component-schemas.mjs.map +1 -0
- package/dist/adapters/redocly-loader/mapping-schema-names.cjs +22 -0
- package/dist/adapters/redocly-loader/mapping-schema-names.cjs.map +1 -0
- package/dist/adapters/redocly-loader/mapping-schema-names.mjs +20 -0
- package/dist/adapters/redocly-loader/mapping-schema-names.mjs.map +1 -0
- package/dist/adapters/redocly-loader/query-named-components.cjs +137 -0
- package/dist/adapters/redocly-loader/query-named-components.cjs.map +1 -0
- package/dist/adapters/redocly-loader/query-named-components.mjs +134 -0
- package/dist/adapters/redocly-loader/query-named-components.mjs.map +1 -0
- package/dist/adapters/redocly-loader/redocly-schema-loader.cjs +26 -14
- package/dist/adapters/redocly-loader/redocly-schema-loader.cjs.map +1 -1
- package/dist/adapters/redocly-loader/redocly-schema-loader.mjs +26 -14
- package/dist/adapters/redocly-loader/redocly-schema-loader.mjs.map +1 -1
- package/dist/adapters/redocly-loader/ref-access.cjs +16 -3
- package/dist/adapters/redocly-loader/ref-access.cjs.map +1 -1
- package/dist/adapters/redocly-loader/ref-access.mjs +16 -3
- package/dist/adapters/redocly-loader/ref-access.mjs.map +1 -1
- package/dist/adapters/redocly-loader/ref-holders.cjs +52 -10
- package/dist/adapters/redocly-loader/ref-holders.cjs.map +1 -1
- package/dist/adapters/redocly-loader/ref-holders.mjs +52 -11
- package/dist/adapters/redocly-loader/ref-holders.mjs.map +1 -1
- package/dist/adapters/redocly-loader/remote-fetch.cjs +5 -3
- package/dist/adapters/redocly-loader/remote-fetch.cjs.map +1 -1
- package/dist/adapters/redocly-loader/remote-fetch.mjs +5 -3
- package/dist/adapters/redocly-loader/remote-fetch.mjs.map +1 -1
- package/dist/adapters/redocly-loader/remote-node-limit.cjs +17 -3
- package/dist/adapters/redocly-loader/remote-node-limit.cjs.map +1 -1
- package/dist/adapters/redocly-loader/remote-node-limit.mjs +17 -3
- package/dist/adapters/redocly-loader/remote-node-limit.mjs.map +1 -1
- package/dist/adapters/redocly-loader/schema-source.cjs +7 -2
- package/dist/adapters/redocly-loader/schema-source.cjs.map +1 -1
- package/dist/adapters/redocly-loader/schema-source.mjs +8 -3
- package/dist/adapters/redocly-loader/schema-source.mjs.map +1 -1
- package/dist/adapters/terminal-logger/terminal-logger.cjs +7 -3
- package/dist/adapters/terminal-logger/terminal-logger.cjs.map +1 -1
- package/dist/adapters/terminal-logger/terminal-logger.mjs +7 -3
- package/dist/adapters/terminal-logger/terminal-logger.mjs.map +1 -1
- package/dist/api/document-refs.cjs +16 -1
- package/dist/api/document-refs.cjs.map +1 -1
- package/dist/api/document-refs.mjs +16 -1
- package/dist/api/document-refs.mjs.map +1 -1
- package/dist/api/document-run.cjs +4 -10
- package/dist/api/document-run.cjs.map +1 -1
- package/dist/api/document-run.mjs +4 -10
- package/dist/api/document-run.mjs.map +1 -1
- package/dist/api/openapi-ts.cjs +1 -2
- package/dist/api/openapi-ts.cjs.map +1 -1
- package/dist/api/openapi-ts.mjs +2 -3
- package/dist/api/openapi-ts.mjs.map +1 -1
- package/dist/api/ref-limit-options.cjs +63 -0
- package/dist/api/ref-limit-options.cjs.map +1 -0
- package/dist/api/ref-limit-options.mjs +57 -0
- package/dist/api/ref-limit-options.mjs.map +1 -0
- package/dist/api/transform-schema.cjs +12 -5
- package/dist/api/transform-schema.cjs.map +1 -1
- package/dist/api/transform-schema.mjs +12 -5
- package/dist/api/transform-schema.mjs.map +1 -1
- package/dist/application/transform/declared-value-types.cjs +36 -0
- package/dist/application/transform/declared-value-types.cjs.map +1 -0
- package/dist/application/transform/declared-value-types.mjs +34 -0
- package/dist/application/transform/declared-value-types.mjs.map +1 -0
- package/dist/application/transform/document/document.cjs +3 -1
- package/dist/application/transform/document/document.cjs.map +1 -1
- package/dist/application/transform/document/document.mjs +3 -1
- package/dist/application/transform/document/document.mjs.map +1 -1
- package/dist/application/transform/document/exploded-query-values.cjs +63 -0
- package/dist/application/transform/document/exploded-query-values.cjs.map +1 -0
- package/dist/application/transform/document/exploded-query-values.mjs +59 -0
- package/dist/application/transform/document/exploded-query-values.mjs.map +1 -0
- package/dist/application/transform/document/header.cjs +11 -3
- package/dist/application/transform/document/header.cjs.map +1 -1
- package/dist/application/transform/document/header.mjs +10 -2
- package/dist/application/transform/document/header.mjs.map +1 -1
- package/dist/application/transform/document/parameter.cjs +1 -1
- package/dist/application/transform/document/parameter.cjs.map +1 -1
- package/dist/application/transform/document/parameter.mjs +1 -1
- package/dist/application/transform/document/parameter.mjs.map +1 -1
- package/dist/application/transform/document/parameters.cjs +23 -5
- package/dist/application/transform/document/parameters.cjs.map +1 -1
- package/dist/application/transform/document/parameters.mjs +23 -5
- package/dist/application/transform/document/parameters.mjs.map +1 -1
- package/dist/application/transform/document/path-item.cjs +4 -3
- package/dist/application/transform/document/path-item.cjs.map +1 -1
- package/dist/application/transform/document/path-item.mjs +4 -4
- package/dist/application/transform/document/path-item.mjs.map +1 -1
- package/dist/application/transform/document/path-template-key.cjs +84 -0
- package/dist/application/transform/document/path-template-key.cjs.map +1 -0
- package/dist/application/transform/document/path-template-key.mjs +79 -0
- package/dist/application/transform/document/path-template-key.mjs.map +1 -0
- package/dist/application/transform/document/path-template-refs.cjs +70 -0
- package/dist/application/transform/document/path-template-refs.cjs.map +1 -0
- package/dist/application/transform/document/path-template-refs.mjs +67 -0
- package/dist/application/transform/document/path-template-refs.mjs.map +1 -0
- package/dist/application/transform/document/paths-enum.cjs +7 -6
- package/dist/application/transform/document/paths-enum.cjs.map +1 -1
- package/dist/application/transform/document/paths-enum.mjs +7 -6
- package/dist/application/transform/document/paths-enum.mjs.map +1 -1
- package/dist/application/transform/document/paths.cjs +38 -66
- package/dist/application/transform/document/paths.cjs.map +1 -1
- package/dist/application/transform/document/paths.mjs +36 -66
- package/dist/application/transform/document/paths.mjs.map +1 -1
- package/dist/application/transform/document/webhooks.cjs +10 -3
- package/dist/application/transform/document/webhooks.cjs.map +1 -1
- package/dist/application/transform/document/webhooks.mjs +9 -2
- package/dist/application/transform/document/webhooks.mjs.map +1 -1
- package/dist/application/transform/footer/document-footer.cjs +6 -3
- package/dist/application/transform/footer/document-footer.cjs.map +1 -1
- package/dist/application/transform/footer/document-footer.mjs +6 -3
- package/dist/application/transform/footer/document-footer.mjs.map +1 -1
- package/dist/application/transform/helper-types.cjs +3 -3
- package/dist/application/transform/helper-types.cjs.map +1 -1
- package/dist/application/transform/helper-types.mjs +3 -3
- package/dist/application/transform/helper-types.mjs.map +1 -1
- package/dist/application/transform/ref-pointer/generated-location.cjs +4 -4
- package/dist/application/transform/ref-pointer/generated-location.cjs.map +1 -1
- package/dist/application/transform/ref-pointer/generated-location.mjs +1 -1
- package/dist/application/transform/ref-pointer/generated-location.mjs.map +1 -1
- package/dist/application/transform/ref-pointer/generated-shape.cjs +47 -66
- package/dist/application/transform/ref-pointer/generated-shape.cjs.map +1 -1
- package/dist/application/transform/ref-pointer/generated-shape.mjs +36 -50
- package/dist/application/transform/ref-pointer/generated-shape.mjs.map +1 -1
- package/dist/application/transform/ref-pointer/inline-cycles.cjs +2 -2
- package/dist/application/transform/ref-pointer/inline-cycles.cjs.map +1 -1
- package/dist/application/transform/ref-pointer/inline-cycles.mjs +1 -1
- package/dist/application/transform/ref-pointer/inline-cycles.mjs.map +1 -1
- package/dist/application/transform/ref-pointer/located-node.cjs +23 -0
- package/dist/application/transform/ref-pointer/located-node.cjs.map +1 -0
- package/dist/application/transform/ref-pointer/located-node.mjs +18 -0
- package/dist/application/transform/ref-pointer/located-node.mjs.map +1 -0
- package/dist/application/transform/ref-pointer/original-index.cjs +68 -13
- package/dist/application/transform/ref-pointer/original-index.cjs.map +1 -1
- package/dist/application/transform/ref-pointer/original-index.mjs +70 -15
- package/dist/application/transform/ref-pointer/original-index.mjs.map +1 -1
- package/dist/application/transform/ref-pointer/pointer-type.cjs +2 -2
- package/dist/application/transform/ref-pointer/pointer-type.cjs.map +1 -1
- package/dist/application/transform/ref-pointer/pointer-type.mjs +1 -1
- package/dist/application/transform/ref-pointer/pointer-type.mjs.map +1 -1
- package/dist/application/transform/ref-pointer/pointer-walk.cjs +54 -13
- package/dist/application/transform/ref-pointer/pointer-walk.cjs.map +1 -1
- package/dist/application/transform/ref-pointer/pointer-walk.mjs +46 -7
- package/dist/application/transform/ref-pointer/pointer-walk.mjs.map +1 -1
- package/dist/application/transform/ref-pointer/property-shape.cjs +52 -0
- package/dist/application/transform/ref-pointer/property-shape.cjs.map +1 -0
- package/dist/application/transform/ref-pointer/property-shape.mjs +45 -0
- package/dist/application/transform/ref-pointer/property-shape.mjs.map +1 -0
- package/dist/application/transform/ref-pointer/typed-walk.cjs +79 -21
- package/dist/application/transform/ref-pointer/typed-walk.cjs.map +1 -1
- package/dist/application/transform/ref-pointer/typed-walk.mjs +76 -18
- package/dist/application/transform/ref-pointer/typed-walk.mjs.map +1 -1
- package/dist/application/transform/schema/access-flags.cjs.map +1 -1
- package/dist/application/transform/schema/access-flags.mjs.map +1 -1
- package/dist/application/transform/schema/index-signature-type.cjs +21 -0
- package/dist/application/transform/schema/index-signature-type.cjs.map +1 -0
- package/dist/application/transform/schema/index-signature-type.mjs +19 -0
- package/dist/application/transform/schema/index-signature-type.mjs.map +1 -0
- package/dist/application/transform/schema/input-location.cjs +23 -0
- package/dist/application/transform/schema/input-location.cjs.map +1 -0
- package/dist/application/transform/schema/input-location.mjs +21 -0
- package/dist/application/transform/schema/input-location.mjs.map +1 -0
- package/dist/application/transform/schema/object-type.cjs +15 -5
- package/dist/application/transform/schema/object-type.cjs.map +1 -1
- package/dist/application/transform/schema/object-type.mjs +15 -5
- package/dist/application/transform/schema/object-type.mjs.map +1 -1
- package/dist/application/transform/schema/schema-transform.cjs +2 -1
- package/dist/application/transform/schema/schema-transform.cjs.map +1 -1
- package/dist/application/transform/schema/schema-transform.mjs +2 -1
- package/dist/application/transform/schema/schema-transform.mjs.map +1 -1
- package/dist/application/transform/schema/unevaluated-properties.cjs +2 -30
- package/dist/application/transform/schema/unevaluated-properties.cjs.map +1 -1
- package/dist/application/transform/schema/unevaluated-properties.mjs +3 -31
- package/dist/application/transform/schema/unevaluated-properties.mjs.map +1 -1
- package/dist/cli/api-logger.cjs +13 -0
- package/dist/cli/api-logger.cjs.map +1 -0
- package/dist/cli/api-logger.mjs +11 -0
- package/dist/cli/api-logger.mjs.map +1 -0
- package/dist/cli/api-settings.cjs +7 -15
- package/dist/cli/api-settings.cjs.map +1 -1
- package/dist/cli/api-settings.mjs +8 -16
- package/dist/cli/api-settings.mjs.map +1 -1
- package/dist/cli/cli-arguments.cjs +51 -11
- package/dist/cli/cli-arguments.cjs.map +1 -1
- package/dist/cli/cli-arguments.mjs +51 -11
- package/dist/cli/cli-arguments.mjs.map +1 -1
- package/dist/cli/cli-errors.cjs +17 -0
- package/dist/cli/cli-errors.cjs.map +1 -1
- package/dist/cli/cli-errors.mjs +17 -1
- package/dist/cli/cli-errors.mjs.map +1 -1
- package/dist/cli/cli-output.cjs +6 -4
- package/dist/cli/cli-output.cjs.map +1 -1
- package/dist/cli/cli-output.mjs +7 -5
- package/dist/cli/cli-output.mjs.map +1 -1
- package/dist/cli/main.cjs +10 -4
- package/dist/cli/main.cjs.map +1 -1
- package/dist/cli/main.mjs +10 -4
- package/dist/cli/main.mjs.map +1 -1
- package/dist/cli/redocly-apis.cjs +20 -9
- package/dist/cli/redocly-apis.cjs.map +1 -1
- package/dist/cli/redocly-apis.mjs +22 -11
- package/dist/cli/redocly-apis.mjs.map +1 -1
- package/dist/cli/ref-limits.cjs +15 -1
- package/dist/cli/ref-limits.cjs.map +1 -1
- package/dist/cli/ref-limits.mjs +15 -2
- package/dist/cli/ref-limits.mjs.map +1 -1
- package/dist/cli/run-cli.cjs +24 -7
- package/dist/cli/run-cli.cjs.map +1 -1
- package/dist/cli/run-cli.mjs +25 -8
- package/dist/cli/run-cli.mjs.map +1 -1
- package/dist/domain/cause-secrets.cjs +31 -16
- package/dist/domain/cause-secrets.cjs.map +1 -1
- package/dist/domain/cause-secrets.mjs +31 -16
- package/dist/domain/cause-secrets.mjs.map +1 -1
- package/dist/domain/errors.cjs +2 -0
- package/dist/domain/errors.cjs.map +1 -1
- package/dist/domain/errors.mjs +2 -0
- package/dist/domain/errors.mjs.map +1 -1
- package/dist/domain/location-text.cjs +9 -0
- package/dist/domain/location-text.cjs.map +1 -0
- package/dist/domain/location-text.mjs +7 -0
- package/dist/domain/location-text.mjs.map +1 -0
- package/dist/domain/openapi/document-places.cjs +55 -0
- package/dist/domain/openapi/document-places.cjs.map +1 -0
- package/dist/domain/openapi/document-places.mjs +53 -0
- package/dist/domain/openapi/document-places.mjs.map +1 -0
- package/dist/domain/output-fixes.cjs +8 -2
- package/dist/domain/output-fixes.cjs.map +1 -1
- package/dist/domain/output-fixes.mjs +8 -2
- package/dist/domain/output-fixes.mjs.map +1 -1
- package/dist/domain/terminal-text.cjs +31 -0
- package/dist/domain/terminal-text.cjs.map +1 -0
- package/dist/domain/terminal-text.mjs +29 -0
- package/dist/domain/terminal-text.mjs.map +1 -0
- package/dist/domain/warnings.cjs +1 -0
- package/dist/domain/warnings.cjs.map +1 -1
- package/dist/domain/warnings.mjs +1 -0
- package/dist/domain/warnings.mjs.map +1 -1
- package/dist/index.d.cts +26 -18
- package/dist/index.d.mts +26 -18
- package/dist/index.d.ts +26 -18
- package/package.json +1 -1
- package/src/adapters/node-file-system/node-file-system.ts +14 -1
- package/src/adapters/pipe-safe-writer/pipe-safe-writer.ts +29 -0
- package/src/adapters/redocly-loader/bundled-mapping-copies.ts +7 -42
- package/src/adapters/redocly-loader/component-schemas.ts +19 -0
- package/src/adapters/redocly-loader/mapping-schema-names.ts +25 -0
- package/src/adapters/redocly-loader/query-named-components.ts +201 -0
- package/src/adapters/redocly-loader/redocly-schema-loader.ts +46 -14
- package/src/adapters/redocly-loader/ref-access.ts +16 -3
- package/src/adapters/redocly-loader/ref-holders.ts +75 -14
- package/src/adapters/redocly-loader/remote-fetch.ts +11 -2
- package/src/adapters/redocly-loader/remote-node-limit.ts +44 -4
- package/src/adapters/redocly-loader/schema-source.ts +15 -3
- package/src/adapters/terminal-logger/terminal-logger.ts +10 -4
- package/src/api/document-refs.ts +29 -1
- package/src/api/document-run.ts +6 -16
- package/src/api/openapi-ts.ts +6 -3
- package/src/api/ref-limit-options.ts +76 -0
- package/src/api/transform-schema.ts +20 -5
- package/src/application/ports/file-system.ts +8 -0
- package/src/application/transform/declared-value-types.ts +42 -0
- package/src/application/transform/document/document.ts +4 -2
- package/src/application/transform/document/exploded-query-values.ts +88 -0
- package/src/application/transform/document/header.ts +25 -5
- package/src/application/transform/document/parameter.ts +4 -4
- package/src/application/transform/document/parameters.ts +45 -10
- package/src/application/transform/document/path-item.ts +3 -3
- package/src/application/transform/document/path-template-key.ts +152 -0
- package/src/application/transform/document/path-template-refs.ts +106 -0
- package/src/application/transform/document/paths-enum.ts +23 -9
- package/src/application/transform/document/paths.ts +53 -123
- package/src/application/transform/document/webhooks.ts +18 -5
- package/src/application/transform/footer/document-footer.ts +18 -8
- package/src/application/transform/helper-types.ts +4 -4
- package/src/application/transform/ref-pointer/generated-location.ts +1 -1
- package/src/application/transform/ref-pointer/generated-shape.ts +67 -78
- package/src/application/transform/ref-pointer/inline-cycles.ts +1 -1
- package/src/application/transform/ref-pointer/located-node.ts +38 -0
- package/src/application/transform/ref-pointer/original-index.ts +100 -17
- package/src/application/transform/ref-pointer/pointer-type.ts +1 -1
- package/src/application/transform/ref-pointer/pointer-walk.ts +82 -8
- package/src/application/transform/ref-pointer/property-shape.ts +97 -0
- package/src/application/transform/ref-pointer/typed-walk.ts +117 -25
- package/src/application/transform/schema/access-flags.ts +5 -2
- package/src/application/transform/schema/index-signature-type.ts +31 -0
- package/src/application/transform/schema/input-location.ts +35 -0
- package/src/application/transform/schema/object-type.ts +18 -8
- package/src/application/transform/schema/schema-transform.ts +2 -1
- package/src/application/transform/schema/unevaluated-properties.ts +4 -44
- package/src/cli/api-logger.ts +17 -0
- package/src/cli/api-settings.ts +12 -20
- package/src/cli/cli-arguments.ts +90 -14
- package/src/cli/cli-dependencies.ts +7 -2
- package/src/cli/cli-errors.ts +22 -0
- package/src/cli/cli-output.ts +11 -10
- package/src/cli/main.ts +10 -4
- package/src/cli/redocly-apis.ts +37 -17
- package/src/cli/ref-limits.ts +21 -2
- package/src/cli/run-cli.ts +39 -7
- package/src/domain/cause-secrets.ts +59 -25
- package/src/domain/errors.ts +2 -0
- package/src/domain/location-text.ts +12 -0
- package/src/domain/openapi/document-places.ts +78 -0
- package/src/domain/output-fixes.ts +9 -2
- package/src/domain/terminal-text.ts +44 -0
- package/src/domain/warnings.ts +1 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { appendPointer, ROOT_POINTER } from "../../../domain/openapi/json-pointer.js";
|
|
2
2
|
import type { RefResolver } from "../schema/schema-context.js";
|
|
3
|
-
import { isJsonObject } from "./
|
|
3
|
+
import { isJsonObject } from "./located-node.js";
|
|
4
4
|
import {
|
|
5
5
|
leadingSegmentsOf,
|
|
6
6
|
type RefPointer,
|
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
import { isRawBinarySchema } from "../../../domain/openapi/binary-content.js";
|
|
2
2
|
import type { RefResolver, SchemaOptions } from "../schema/schema-context.js";
|
|
3
|
+
import {
|
|
4
|
+
childLocation,
|
|
5
|
+
followLocated,
|
|
6
|
+
isJsonObject,
|
|
7
|
+
type JsonObject,
|
|
8
|
+
type LocatedNode,
|
|
9
|
+
} from "./located-node.js";
|
|
10
|
+
import {
|
|
11
|
+
isExcludedProperty,
|
|
12
|
+
isMarkedProperty,
|
|
13
|
+
isNullableSchema,
|
|
14
|
+
isOptionalProperty,
|
|
15
|
+
} from "./property-shape.js";
|
|
3
16
|
|
|
4
17
|
/**
|
|
5
18
|
* What the generated type of a schema has under a key, read from the schema itself. It answers the
|
|
@@ -8,14 +21,19 @@ import type { RefResolver, SchemaOptions } from "../schema/schema-context.js";
|
|
|
8
21
|
*/
|
|
9
22
|
|
|
10
23
|
export type GeneratedMember =
|
|
11
|
-
| {
|
|
24
|
+
| {
|
|
25
|
+
readonly kind: "property";
|
|
26
|
+
readonly node: unknown;
|
|
27
|
+
readonly location: string | undefined;
|
|
28
|
+
readonly isOptional: boolean;
|
|
29
|
+
/** `$Read<T>` or `$Write<T>` (`isMarkedProperty`): no member but the marker's own. */
|
|
30
|
+
readonly isMarked: boolean;
|
|
31
|
+
}
|
|
12
32
|
/** An index signature; `node` is undefined when its value type is `unknown`. */
|
|
13
|
-
| { readonly kind: "index"; readonly node: unknown }
|
|
33
|
+
| { readonly kind: "index"; readonly node: unknown; readonly location: string | undefined }
|
|
14
34
|
| { readonly kind: "missing" }
|
|
15
35
|
| { readonly kind: "opaque" };
|
|
16
36
|
|
|
17
|
-
type JsonObject = Readonly<Record<string, unknown>>;
|
|
18
|
-
|
|
19
37
|
const OPAQUE_KEYS = ["not", "enum", "const", "$ref"] as const;
|
|
20
38
|
/** How deep `allOf`/`anyOf`/`oneOf` members are read; deeper shapes count as opaque. */
|
|
21
39
|
const MAX_DEPTH = 8;
|
|
@@ -23,23 +41,6 @@ const INDEX_RE = /^\d+$/;
|
|
|
23
41
|
const MISSING: GeneratedMember = { kind: "missing" };
|
|
24
42
|
const OPAQUE: GeneratedMember = { kind: "opaque" };
|
|
25
43
|
|
|
26
|
-
export function isJsonObject(value: unknown): value is JsonObject {
|
|
27
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** The schema a node stands for: a `$ref` is followed to its target. */
|
|
31
|
-
export function followRefs(node: unknown, refs: RefResolver): unknown {
|
|
32
|
-
return isJsonObject(node) && typeof node.$ref === "string" ? refs.resolve(node.$ref) : node;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** `nullable: true` or a `type` list with `null`: the generated type includes `null`. */
|
|
36
|
-
export function isNullableSchema(node: unknown): boolean {
|
|
37
|
-
if (!isJsonObject(node)) {
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
return node.nullable === true || (Array.isArray(node.type) && node.type.includes("null"));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
44
|
function typeNames(node: JsonObject): readonly unknown[] {
|
|
44
45
|
return Array.isArray(node.type) ? node.type : [node.type];
|
|
45
46
|
}
|
|
@@ -90,39 +91,37 @@ function isBuiltInMember(key: string, prototype: object): boolean {
|
|
|
90
91
|
return key in prototype;
|
|
91
92
|
}
|
|
92
93
|
|
|
93
|
-
function indexMember(node: JsonObject, options: SchemaOptions)
|
|
94
|
-
const { additionalProperties: values, patternProperties: patterns } = node;
|
|
94
|
+
function indexMember(owner: LocatedNode & { node: JsonObject }, options: SchemaOptions) {
|
|
95
|
+
const { additionalProperties: values, patternProperties: patterns } = owner.node;
|
|
95
96
|
if (isJsonObject(patterns) && Object.keys(patterns).length > 0) {
|
|
96
97
|
return OPAQUE;
|
|
97
98
|
}
|
|
98
99
|
if (isJsonObject(values) && Object.keys(values).length > 0) {
|
|
99
|
-
|
|
100
|
+
const location = childLocation(owner.location, "additionalProperties");
|
|
101
|
+
return { kind: "index", node: values, location } satisfies GeneratedMember;
|
|
100
102
|
}
|
|
101
103
|
const isImplicit = values === true || (isJsonObject(values) && Object.keys(values).length === 0);
|
|
102
104
|
return isImplicit || (!values && options.additionalProperties)
|
|
103
|
-
? { kind: "index", node: undefined }
|
|
105
|
+
? ({ kind: "index", node: undefined, location: undefined } satisfies GeneratedMember)
|
|
104
106
|
: null;
|
|
105
107
|
}
|
|
106
108
|
|
|
107
|
-
function
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
(hasDefault && options.defaultNonNullable);
|
|
115
|
-
return !isRequired;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function objectMember(node: JsonObject, key: string, options: SchemaOptions): GeneratedMember {
|
|
109
|
+
function objectMember(
|
|
110
|
+
owner: LocatedNode & { node: JsonObject },
|
|
111
|
+
key: string,
|
|
112
|
+
input: MemberInput,
|
|
113
|
+
): GeneratedMember {
|
|
114
|
+
const { options } = input;
|
|
115
|
+
const { node } = owner;
|
|
119
116
|
const properties = isJsonObject(node.properties) ? node.properties : {};
|
|
120
|
-
if (Object.hasOwn(properties, key)) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
117
|
+
if (Object.hasOwn(properties, key) && !isExcludedProperty(properties[key], options, input.refs)) {
|
|
118
|
+
if (isJsonObject(node.discriminator)) {
|
|
119
|
+
return OPAQUE;
|
|
120
|
+
}
|
|
121
|
+
const location = childLocation(owner.location, "properties", key);
|
|
122
|
+
const isOptional = isOptionalProperty(owner, key, options);
|
|
123
|
+
const isMarked = isMarkedProperty(properties[key], options, input.refs);
|
|
124
|
+
return { kind: "property", node: properties[key], location, isOptional, isMarked };
|
|
126
125
|
}
|
|
127
126
|
// `unevaluatedProperties` adds an index signature with its fix, so it counts as opaque too.
|
|
128
127
|
const isUnknownShape =
|
|
@@ -131,38 +130,23 @@ function objectMember(node: JsonObject, key: string, options: SchemaOptions): Ge
|
|
|
131
130
|
return OPAQUE;
|
|
132
131
|
}
|
|
133
132
|
return hasObjectKeywords(node)
|
|
134
|
-
? (indexMember(
|
|
133
|
+
? (indexMember(owner, options) ?? MISSING)
|
|
135
134
|
: emptyObjectMember(node, options);
|
|
136
135
|
}
|
|
137
136
|
|
|
138
|
-
/** Whether a value is there: `present`, `absent` (may be `undefined` or `null`) or `unknown`. */
|
|
139
|
-
export type Presence = "present" | "absent" | "unknown";
|
|
140
|
-
|
|
141
|
-
/** The presence of a value of `schema` itself: `absent` when its type includes `null`. */
|
|
142
|
-
export function schemaPresence(schema: unknown, refs: RefResolver): Presence {
|
|
143
|
-
return isNullableSchema(followRefs(schema, refs)) ? "absent" : "present";
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/** The presence of property `key` of `schema`: optional or nullable is `absent`. */
|
|
147
|
-
export function propertyPresence(
|
|
148
|
-
schema: unknown,
|
|
149
|
-
key: string,
|
|
150
|
-
options: SchemaOptions,
|
|
151
|
-
refs: RefResolver,
|
|
152
|
-
): Presence {
|
|
153
|
-
const node = followRefs(schema, refs);
|
|
154
|
-
const properties = isJsonObject(node) && isJsonObject(node.properties) ? node.properties : {};
|
|
155
|
-
if (!isJsonObject(node) || !Object.hasOwn(properties, key)) {
|
|
156
|
-
return "unknown";
|
|
157
|
-
}
|
|
158
|
-
return isOptionalProperty(node, key, options) ? "absent" : schemaPresence(properties[key], refs);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
137
|
function membersOf(node: JsonObject, keyword: string): readonly unknown[] {
|
|
162
138
|
const members = node[keyword];
|
|
163
139
|
return Array.isArray(members) ? members : [];
|
|
164
140
|
}
|
|
165
141
|
|
|
142
|
+
/** The members of a composition keyword with their locations. */
|
|
143
|
+
function locatedMembers(owner: LocatedNode & { node: JsonObject }, keyword: string): LocatedNode[] {
|
|
144
|
+
return membersOf(owner.node, keyword).map((node, index) => ({
|
|
145
|
+
node,
|
|
146
|
+
location: childLocation(owner.location, keyword, String(index)),
|
|
147
|
+
}));
|
|
148
|
+
}
|
|
149
|
+
|
|
166
150
|
function withoutComposition(node: JsonObject): JsonObject {
|
|
167
151
|
const { allOf: _allOf, anyOf: _anyOf, oneOf: _oneOf, ...own } = node;
|
|
168
152
|
return own;
|
|
@@ -178,8 +162,13 @@ function hasOwnObjectType(own: JsonObject): boolean {
|
|
|
178
162
|
* `anyOf` or `oneOf` alone is a union: a key is missing if one member misses it. A mix of both
|
|
179
163
|
* is written in more than one way (`anyof-properties`), so it counts as opaque.
|
|
180
164
|
*/
|
|
181
|
-
function composedMember(
|
|
182
|
-
|
|
165
|
+
function composedMember(
|
|
166
|
+
owner: LocatedNode & { node: JsonObject },
|
|
167
|
+
key: string,
|
|
168
|
+
input: MemberInput,
|
|
169
|
+
): GeneratedMember {
|
|
170
|
+
const { node } = owner;
|
|
171
|
+
const variants = [...locatedMembers(owner, "anyOf"), ...locatedMembers(owner, "oneOf")];
|
|
183
172
|
const own = withoutComposition(node);
|
|
184
173
|
const hasOwn = hasOwnObjectType(own);
|
|
185
174
|
if (variants.length > 0) {
|
|
@@ -187,7 +176,8 @@ function composedMember(node: JsonObject, key: string, input: MemberInput): Gene
|
|
|
187
176
|
const members = variants.map((variant) => memberAt(variant, key, input));
|
|
188
177
|
return isAlone && members.some((member) => member.kind === "missing") ? MISSING : OPAQUE;
|
|
189
178
|
}
|
|
190
|
-
const
|
|
179
|
+
const ownPart = { node: own, location: owner.location };
|
|
180
|
+
const parts = [...locatedMembers(owner, "allOf"), ...(hasOwn ? [ownPart] : [])];
|
|
191
181
|
return intersectionMember(parts.map((part) => memberAt(part, key, input)));
|
|
192
182
|
}
|
|
193
183
|
|
|
@@ -216,23 +206,22 @@ interface MemberInput {
|
|
|
216
206
|
readonly depth: number;
|
|
217
207
|
}
|
|
218
208
|
|
|
219
|
-
function memberAt(schema:
|
|
220
|
-
const
|
|
209
|
+
function memberAt(schema: LocatedNode, key: string, input: MemberInput): GeneratedMember {
|
|
210
|
+
const followed = followLocated(schema, input.refs);
|
|
211
|
+
const { node } = followed;
|
|
221
212
|
if (!isJsonObject(node) || OPAQUE_KEYS.some((name) => name in node) || input.depth > MAX_DEPTH) {
|
|
222
213
|
return OPAQUE;
|
|
223
214
|
}
|
|
215
|
+
const owner = { ...followed, node };
|
|
224
216
|
if (isNullableSchema(node)) {
|
|
225
217
|
// Every key of `T | null` is an error, unless `T` is unknown (then the type is `unknown`).
|
|
226
218
|
return isObjectShape(node) || isArrayShape(node) ? MISSING : OPAQUE;
|
|
227
219
|
}
|
|
228
|
-
if (input.options.readWriteMarkers) {
|
|
229
|
-
return OPAQUE;
|
|
230
|
-
}
|
|
231
220
|
if ("allOf" in node || "anyOf" in node || "oneOf" in node) {
|
|
232
|
-
return composedMember(
|
|
221
|
+
return composedMember(owner, key, { ...input, depth: input.depth + 1 });
|
|
233
222
|
}
|
|
234
223
|
if (isObjectShape(node)) {
|
|
235
|
-
return objectMember(
|
|
224
|
+
return objectMember(owner, key, input);
|
|
236
225
|
}
|
|
237
226
|
if (isArrayShape(node)) {
|
|
238
227
|
return INDEX_RE.test(key) || isBuiltInMember(key, []) ? OPAQUE : MISSING;
|
|
@@ -266,7 +255,7 @@ function primitiveMember(node: JsonObject, key: string): GeneratedMember {
|
|
|
266
255
|
|
|
267
256
|
/** The member `key` of the type generated for `schema` (a `$ref` is followed first). */
|
|
268
257
|
export function generatedMember(
|
|
269
|
-
schema:
|
|
258
|
+
schema: LocatedNode,
|
|
270
259
|
key: string,
|
|
271
260
|
options: SchemaOptions,
|
|
272
261
|
refs: RefResolver,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RefResolver, SchemaOptions } from "../schema/schema-context.js";
|
|
2
|
-
import { isJsonObject } from "./
|
|
2
|
+
import { isJsonObject } from "./located-node.js";
|
|
3
3
|
import { pointerNode, refPointerOf } from "./pointer-walk.js";
|
|
4
4
|
import { typedWalk } from "./typed-walk.js";
|
|
5
5
|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { appendPointer } from "../../../domain/openapi/json-pointer.js";
|
|
2
|
+
import type { RefResolver } from "../schema/schema-context.js";
|
|
3
|
+
|
|
4
|
+
/** Document nodes as the `$ref` pointer walks read them: with their place in the document. */
|
|
5
|
+
|
|
6
|
+
export type JsonObject = Readonly<Record<string, unknown>>;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A schema node and its JSON Pointer in the document. The generator writes the type of a schema
|
|
10
|
+
* reached by a `$ref` at the target, and the location decides whether a property with a `default`
|
|
11
|
+
* is required (`isInputLocation`). Undefined for a node that is not in the document.
|
|
12
|
+
*/
|
|
13
|
+
export interface LocatedNode {
|
|
14
|
+
readonly node: unknown;
|
|
15
|
+
readonly location: string | undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function isJsonObject(value: unknown): value is JsonObject {
|
|
19
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** The schema a node stands for: a `$ref` is followed to its target. */
|
|
23
|
+
export function followRefs(node: unknown, refs: RefResolver): unknown {
|
|
24
|
+
return isJsonObject(node) && typeof node.$ref === "string" ? refs.resolve(node.$ref) : node;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** `followRefs` with the location: a `$ref` is followed to its target and the target's pointer. */
|
|
28
|
+
export function followLocated(located: LocatedNode, refs: RefResolver): LocatedNode {
|
|
29
|
+
const { node } = located;
|
|
30
|
+
return isJsonObject(node) && typeof node.$ref === "string"
|
|
31
|
+
? { node: refs.resolve(node.$ref), location: node.$ref }
|
|
32
|
+
: located;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** The location of a child of a node at `location`, or undefined outside the document. */
|
|
36
|
+
export function childLocation(location: string | undefined, ...segments: string[]) {
|
|
37
|
+
return location === undefined ? undefined : appendPointer(location, segments);
|
|
38
|
+
}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import type { RefResolver, SchemaOptions } from "../schema/schema-context.js";
|
|
2
|
-
import {
|
|
2
|
+
import { generatedMember } from "./generated-shape.js";
|
|
3
|
+
import { childLocation, followLocated, isJsonObject } from "./located-node.js";
|
|
3
4
|
import {
|
|
5
|
+
type ContentForm,
|
|
6
|
+
headerParameterContentForm,
|
|
7
|
+
isExcludedOperation,
|
|
4
8
|
isOptionalHeader,
|
|
5
9
|
isOptionalRequestBody,
|
|
6
10
|
isParameterList,
|
|
7
11
|
isTypedAsSchema,
|
|
8
|
-
|
|
12
|
+
leadingLocated,
|
|
9
13
|
leadingSegmentsOf,
|
|
10
14
|
type RefPointer,
|
|
11
15
|
startsInSchema,
|
|
@@ -22,6 +26,8 @@ type Step = "fails" | "compiles" | "continue";
|
|
|
22
26
|
|
|
23
27
|
interface OriginalWalk {
|
|
24
28
|
readonly node: unknown;
|
|
29
|
+
/** The node's JSON Pointer (`LocatedNode`). */
|
|
30
|
+
readonly location: string | undefined;
|
|
25
31
|
readonly isSchema: boolean;
|
|
26
32
|
}
|
|
27
33
|
|
|
@@ -35,7 +41,7 @@ function schemaStep(walk: OriginalWalk, segment: string, isLast: boolean, input:
|
|
|
35
41
|
if (segment === "properties") {
|
|
36
42
|
return { step: "continue" as Step, walk };
|
|
37
43
|
}
|
|
38
|
-
const member = generatedMember(walk
|
|
44
|
+
const member = generatedMember(walk, segment, input.options, input.refs);
|
|
39
45
|
if (member.kind === "missing") {
|
|
40
46
|
return { step: "fails" as Step, walk };
|
|
41
47
|
}
|
|
@@ -43,49 +49,126 @@ function schemaStep(walk: OriginalWalk, segment: string, isLast: boolean, input:
|
|
|
43
49
|
return { step: "compiles" as Step, walk };
|
|
44
50
|
}
|
|
45
51
|
const isAbsentValue = member.kind === "index" && member.node === undefined;
|
|
46
|
-
const isUnsafe =
|
|
52
|
+
const isUnsafe =
|
|
53
|
+
member.kind === "property" ? member.isOptional || member.isMarked : isAbsentValue;
|
|
47
54
|
return {
|
|
48
55
|
step: (isUnsafe && !isLast ? "fails" : "continue") as Step,
|
|
49
|
-
walk: { ...walk, node: member.node },
|
|
56
|
+
walk: { ...walk, node: member.node, location: member.location },
|
|
50
57
|
};
|
|
51
58
|
}
|
|
52
59
|
|
|
53
60
|
function containerStep(walk: OriginalWalk, index: number, input: WalkInput) {
|
|
54
61
|
const segment = input.pointer.segments[index] as string;
|
|
55
62
|
const isLast = index === input.pointer.segments.length - 1;
|
|
63
|
+
if (isExcludedOperation(input.pointer, index, walk.node, input)) {
|
|
64
|
+
return { step: "fails" as Step, walk };
|
|
65
|
+
}
|
|
56
66
|
const isOptional =
|
|
57
67
|
(segment === "requestBody" && isOptionalRequestBody(walk.node, input.refs)) ||
|
|
58
68
|
isOptionalHeader(input.pointer, index, walk.node);
|
|
59
69
|
if (isOptional && !isLast) {
|
|
60
70
|
return { step: "fails" as Step, walk };
|
|
61
71
|
}
|
|
62
|
-
const child =
|
|
72
|
+
const child = followLocated(
|
|
73
|
+
{
|
|
74
|
+
node: isJsonObject(walk.node) ? walk.node[segment] : undefined,
|
|
75
|
+
location: childLocation(walk.location, segment),
|
|
76
|
+
},
|
|
77
|
+
input.refs,
|
|
78
|
+
);
|
|
63
79
|
return {
|
|
64
|
-
step: (child === undefined ? "compiles" : "continue") as Step,
|
|
65
|
-
walk: { ...walk,
|
|
80
|
+
step: (child.node === undefined ? "compiles" : "continue") as Step,
|
|
81
|
+
walk: { ...walk, ...child },
|
|
66
82
|
};
|
|
67
83
|
}
|
|
68
84
|
|
|
85
|
+
/** The schema of the first media type of a `content` map, `$ref`s followed. */
|
|
86
|
+
function firstMediaTypeSchema(walk: OriginalWalk, refs: RefResolver): OriginalWalk | null {
|
|
87
|
+
const content = isJsonObject(walk.node) ? walk.node.content : undefined;
|
|
88
|
+
if (!isJsonObject(content)) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
const [mediaType] = Object.keys(content);
|
|
92
|
+
if (mediaType === undefined) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
const location = childLocation(childLocation(walk.location, "content"), mediaType);
|
|
96
|
+
const entry = followLocated({ node: content[mediaType], location }, refs);
|
|
97
|
+
return ownSchema({ ...entry, isSchema: false }, refs);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** The schema a header or parameter is typed by, `$ref`s followed. */
|
|
101
|
+
function ownSchema(walk: OriginalWalk, refs: RefResolver): OriginalWalk {
|
|
102
|
+
const schema = isJsonObject(walk.node) ? walk.node.schema : undefined;
|
|
103
|
+
const location = childLocation(walk.location, "schema");
|
|
104
|
+
return { ...followLocated({ node: schema, location }, refs), isSchema: true };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** The schema whose type a header or parameter is, when not its media type members. */
|
|
108
|
+
function contentSchema(
|
|
109
|
+
walk: OriginalWalk,
|
|
110
|
+
form: Exclude<ContentForm, "media-type-members">,
|
|
111
|
+
refs: RefResolver,
|
|
112
|
+
): OriginalWalk | null {
|
|
113
|
+
switch (form) {
|
|
114
|
+
case "first-media-type":
|
|
115
|
+
return firstMediaTypeSchema(walk, refs);
|
|
116
|
+
case "schema":
|
|
117
|
+
return ownSchema(walk, refs);
|
|
118
|
+
case "string":
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* The original indexes the `content` of a header or parameter by name. The media type members
|
|
125
|
+
* have no `content` unless a media type is named so, and `string` and `unknown` (no media type)
|
|
126
|
+
* have none; the schema of the first media type, or the `schema` next to `content`, is walked on.
|
|
127
|
+
*/
|
|
128
|
+
function contentStep(walk: OriginalWalk, form: ContentForm, isLast: boolean, input: WalkInput) {
|
|
129
|
+
const content = isJsonObject(walk.node) ? walk.node.content : undefined;
|
|
130
|
+
if (form === "media-type-members") {
|
|
131
|
+
const hasMember = isJsonObject(content) && Object.hasOwn(content, "content");
|
|
132
|
+
return { step: (hasMember ? "compiles" : "fails") as Step, walk };
|
|
133
|
+
}
|
|
134
|
+
const schema = contentSchema(walk, form, input.refs);
|
|
135
|
+
return schema === null
|
|
136
|
+
? { step: "fails" as Step, walk }
|
|
137
|
+
: schemaStep(schema, "content", isLast, input);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* A step outside a schema: a header's or parameter's `content`, a schema's container, or another.
|
|
142
|
+
*/
|
|
143
|
+
function documentStep(walk: OriginalWalk, index: number, input: WalkInput) {
|
|
144
|
+
const segment = input.pointer.segments[index] as string;
|
|
145
|
+
const isLast = index === input.pointer.segments.length - 1;
|
|
146
|
+
const form = headerParameterContentForm(input.pointer, index, walk.node, input.options);
|
|
147
|
+
if (form !== null) {
|
|
148
|
+
return contentStep(walk, form, isLast, input);
|
|
149
|
+
}
|
|
150
|
+
if (isTypedAsSchema(input.pointer, index) && isJsonObject(walk.node)) {
|
|
151
|
+
// The container's type is its schema's type: the segment indexes that type.
|
|
152
|
+
return schemaStep(ownSchema(walk, input.refs), segment, isLast, input);
|
|
153
|
+
}
|
|
154
|
+
return containerStep(walk, index, input);
|
|
155
|
+
}
|
|
156
|
+
|
|
69
157
|
/** True when the original type of the `$ref` does not compile for sure. */
|
|
70
158
|
export function originalIndexFails(input: WalkInput): boolean {
|
|
71
159
|
const { segments } = input.pointer;
|
|
72
160
|
let walk: OriginalWalk = {
|
|
73
|
-
|
|
161
|
+
...leadingLocated(input.pointer, input.refs),
|
|
74
162
|
isSchema: startsInSchema(input.pointer),
|
|
75
163
|
};
|
|
76
164
|
for (let index = leadingSegmentsOf(input.pointer); index < segments.length; index++) {
|
|
77
|
-
const segment = segments[index] as string;
|
|
78
|
-
const isLast = index === segments.length - 1;
|
|
79
165
|
if (!walk.isSchema && isParameterList(input.pointer, index)) {
|
|
80
166
|
return true;
|
|
81
167
|
}
|
|
82
|
-
|
|
83
|
-
// The container's type is its schema's type: the segment indexes that type.
|
|
84
|
-
walk = { node: followRefs(walk.node.schema, input.refs), isSchema: true };
|
|
85
|
-
}
|
|
168
|
+
const isLast = index === segments.length - 1;
|
|
86
169
|
const result = walk.isSchema
|
|
87
|
-
? schemaStep(walk,
|
|
88
|
-
:
|
|
170
|
+
? schemaStep(walk, segments[index] as string, isLast, input)
|
|
171
|
+
: documentStep(walk, index, input);
|
|
89
172
|
if (result.step !== "continue") {
|
|
90
173
|
return result.step === "fails";
|
|
91
174
|
}
|
|
@@ -4,8 +4,8 @@ import { FIX } from "../../../domain/output-fixes.js";
|
|
|
4
4
|
import { InvalidRefError, refType } from "../ref-type.js";
|
|
5
5
|
import type { SchemaRequest } from "../schema/schema-rule.js";
|
|
6
6
|
import { generatedLocationOf } from "./generated-location.js";
|
|
7
|
-
import { isJsonObject } from "./generated-shape.js";
|
|
8
7
|
import { hasInlineCycle } from "./inline-cycles.js";
|
|
8
|
+
import { isJsonObject } from "./located-node.js";
|
|
9
9
|
import { originalIndexFails } from "./original-index.js";
|
|
10
10
|
import { leadingSegmentsOf, pointerNode, type RefPointer, refPointerOf } from "./pointer-walk.js";
|
|
11
11
|
import { typedWalk } from "./typed-walk.js";
|
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
1
|
+
import { placeOf } from "../../../domain/openapi/document-places.js";
|
|
2
|
+
import { parseRefPointer, ROOT_POINTER } from "../../../domain/openapi/json-pointer.js";
|
|
3
|
+
import { QUERYSTRING_LOCATION } from "../../../domain/openapi/parameter-object.js";
|
|
4
|
+
import { FIX } from "../../../domain/output-fixes.js";
|
|
5
|
+
import type { RefResolver, SchemaOptions } from "../schema/schema-context.js";
|
|
6
|
+
import {
|
|
7
|
+
childLocation,
|
|
8
|
+
followLocated,
|
|
9
|
+
followRefs,
|
|
10
|
+
isJsonObject,
|
|
11
|
+
type LocatedNode,
|
|
12
|
+
} from "./located-node.js";
|
|
4
13
|
|
|
5
14
|
/** The parts of a `$ref` pointer that both the original and the new types walk. */
|
|
6
15
|
|
|
@@ -27,13 +36,18 @@ export function refPointerOf(ref: string): RefPointer | null {
|
|
|
27
36
|
return rootSegment === undefined ? null : { rootSegment, segments };
|
|
28
37
|
}
|
|
29
38
|
|
|
30
|
-
/** The document node at the end of the leading segments, `$ref`s followed. */
|
|
31
|
-
export function
|
|
32
|
-
let
|
|
39
|
+
/** The document node at the end of the leading segments, `$ref`s followed, with its location. */
|
|
40
|
+
export function leadingLocated(pointer: RefPointer, refs: RefResolver): LocatedNode {
|
|
41
|
+
let located: LocatedNode = {
|
|
42
|
+
node: refs.resolve(`#/${pointer.rootSegment}`),
|
|
43
|
+
location: childLocation(ROOT_POINTER, pointer.rootSegment),
|
|
44
|
+
};
|
|
33
45
|
for (const segment of pointer.segments.slice(0, leadingSegmentsOf(pointer))) {
|
|
34
|
-
|
|
46
|
+
const { node, location } = located;
|
|
47
|
+
const child = isJsonObject(node) ? node[segment] : undefined;
|
|
48
|
+
located = followLocated({ node: child, location: childLocation(location, segment) }, refs);
|
|
35
49
|
}
|
|
36
|
-
return
|
|
50
|
+
return located;
|
|
37
51
|
}
|
|
38
52
|
|
|
39
53
|
/** The node at the whole pointer, without following a `$ref` at its end. */
|
|
@@ -62,6 +76,47 @@ export function isTypedAsSchema(pointer: RefPointer, index: number): boolean {
|
|
|
62
76
|
return owner === "content" || owner === "headers" || isComponentParameter;
|
|
63
77
|
}
|
|
64
78
|
|
|
79
|
+
/**
|
|
80
|
+
* How the generated type of a header or component parameter holds its `content` (header.ts,
|
|
81
|
+
* parameter.ts): one member per media type, the type of the first media type, `string` (a
|
|
82
|
+
* parameter without the `parameter-header-content` fix), or not at all (a `schema` wins).
|
|
83
|
+
*/
|
|
84
|
+
export type ContentForm = "media-type-members" | "first-media-type" | "string" | "schema";
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The form of the `content` at `index` when it belongs to a header or a component parameter; null
|
|
88
|
+
* for any other segment. An `in: querystring` parameter is typed by its `content` even next to a
|
|
89
|
+
* `schema`.
|
|
90
|
+
*/
|
|
91
|
+
export function headerParameterContentForm(
|
|
92
|
+
pointer: RefPointer,
|
|
93
|
+
index: number,
|
|
94
|
+
owner: unknown,
|
|
95
|
+
options: SchemaOptions,
|
|
96
|
+
): ContentForm | null {
|
|
97
|
+
const isHeader = pointer.segments[index - 2] === "headers";
|
|
98
|
+
const isComponentParameter =
|
|
99
|
+
pointer.rootSegment === "components" && index === 2 && pointer.segments[0] === "parameters";
|
|
100
|
+
const isOwnContent = pointer.segments[index] === "content" && (isHeader || isComponentParameter);
|
|
101
|
+
if (!isOwnContent || !isJsonObject(owner)) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
const isFixed = options.fixes.has(FIX.PARAMETER_HEADER_CONTENT);
|
|
105
|
+
if (isHeader) {
|
|
106
|
+
if (owner.schema) {
|
|
107
|
+
return "schema";
|
|
108
|
+
}
|
|
109
|
+
return isFixed ? "first-media-type" : "media-type-members";
|
|
110
|
+
}
|
|
111
|
+
if (owner.in === QUERYSTRING_LOCATION) {
|
|
112
|
+
return "first-media-type";
|
|
113
|
+
}
|
|
114
|
+
if (owner.schema !== undefined) {
|
|
115
|
+
return "schema";
|
|
116
|
+
}
|
|
117
|
+
return isFixed ? "first-media-type" : "string";
|
|
118
|
+
}
|
|
119
|
+
|
|
65
120
|
/**
|
|
66
121
|
* Whether the segment at `index` is an operation's or path item's `parameters` list, indexed by
|
|
67
122
|
* position next. The generated type groups parameters by `in` (`query`, `path`), so it has no
|
|
@@ -86,6 +141,25 @@ export function isOptionalHeader(pointer: RefPointer, index: number, headers: un
|
|
|
86
141
|
return isJsonObject(header) && header.$ref === undefined && header.required !== true;
|
|
87
142
|
}
|
|
88
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Whether the segment at `index` names an operation that `--exclude-deprecated` leaves out: the
|
|
146
|
+
* path item types it `never`, which has no member to index (`isIncludedOperation`).
|
|
147
|
+
*/
|
|
148
|
+
export function isExcludedOperation(
|
|
149
|
+
pointer: RefPointer,
|
|
150
|
+
index: number,
|
|
151
|
+
pathItem: unknown,
|
|
152
|
+
input: { readonly options: SchemaOptions; readonly refs: RefResolver },
|
|
153
|
+
): boolean {
|
|
154
|
+
const segments = [pointer.rootSegment, ...pointer.segments.slice(0, index + 1)];
|
|
155
|
+
if (!input.options.excludeDeprecated || placeOf(segments) !== "operation") {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
const segment = pointer.segments[index] as string;
|
|
159
|
+
const operation = isJsonObject(pathItem) ? followRefs(pathItem[segment], input.refs) : undefined;
|
|
160
|
+
return isJsonObject(operation) && Boolean(operation.deprecated);
|
|
161
|
+
}
|
|
162
|
+
|
|
89
163
|
/** A `requestBody` the operation does not mark `required` is an optional member. */
|
|
90
164
|
export function isOptionalRequestBody(container: unknown, refs: RefResolver): boolean {
|
|
91
165
|
if (!isJsonObject(container) || container.requestBody === undefined) {
|