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
package/src/cli/cli-arguments.ts
CHANGED
|
@@ -83,23 +83,95 @@ const REMOVED_FLAGS: readonly (readonly [string, string])[] = [
|
|
|
83
83
|
];
|
|
84
84
|
|
|
85
85
|
/** Flags that only work together with `--root-types`. */
|
|
86
|
-
const ROOT_TYPES_FLAGS = ["
|
|
86
|
+
const ROOT_TYPES_FLAGS = ["rootTypesNoSchemaPrefix", "rootTypesKeepCasing"] as const;
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
const OPTIONS_END = "--";
|
|
89
|
+
const LONG_PREFIX = "--";
|
|
90
|
+
const NEGATION_PREFIX = "--no-";
|
|
91
|
+
const VALUE_SEPARATOR = "=";
|
|
92
|
+
const BOOLEAN_VALUES: ReadonlySet<string> = new Set(["true", "false"]);
|
|
93
|
+
|
|
94
|
+
/** A flag as written before `--`: its name (`--redoc`, `-o`) and the text after `=`, if any. */
|
|
95
|
+
interface WrittenFlag {
|
|
96
|
+
readonly name: string;
|
|
97
|
+
readonly value: string | undefined;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function writtenFlags(argv: readonly string[]): WrittenFlag[] {
|
|
101
|
+
const end = argv.indexOf(OPTIONS_END);
|
|
102
|
+
return (end === -1 ? argv : argv.slice(0, end))
|
|
103
|
+
.filter((arg) => arg.startsWith("-") && arg !== "-")
|
|
104
|
+
.map((arg) => {
|
|
105
|
+
const at = arg.indexOf(VALUE_SEPARATOR);
|
|
106
|
+
return at === -1
|
|
107
|
+
? { name: arg, value: undefined }
|
|
108
|
+
: { name: arg.slice(0, at), value: arg.slice(at + 1) };
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* A long flag as yargs-parser reads it: in kebab-case and without `--no-`, so `--immutableTypes`
|
|
114
|
+
* and `--no-immutable-types` are `--immutable-types`. A short flag stays as written.
|
|
115
|
+
*/
|
|
116
|
+
function canonicalFlagName(name: string): string {
|
|
117
|
+
if (!name.startsWith(LONG_PREFIX)) {
|
|
118
|
+
return name;
|
|
119
|
+
}
|
|
120
|
+
const bare = name.startsWith(NEGATION_PREFIX)
|
|
121
|
+
? name.slice(NEGATION_PREFIX.length)
|
|
122
|
+
: name.slice(LONG_PREFIX.length);
|
|
123
|
+
return `${LONG_PREFIX}${kebabCase(bare)}`;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** An old flag fails by its name in any spelling, also with a value (`--redoc=redocly.yaml`). */
|
|
127
|
+
function rejectRemovedFlags(flags: readonly WrittenFlag[]): void {
|
|
128
|
+
const names = new Set(flags.map(({ name }) => canonicalFlagName(name)));
|
|
89
129
|
for (const [flag, message] of REMOVED_FLAGS) {
|
|
90
|
-
if (
|
|
130
|
+
if (names.has(flag)) {
|
|
91
131
|
throw cliError("CLI_FLAG_REMOVED", message);
|
|
92
132
|
}
|
|
93
133
|
}
|
|
94
134
|
}
|
|
95
135
|
|
|
136
|
+
const ALIASES = { redocly: ["c"], exportType: ["t"], output: ["o"] };
|
|
137
|
+
|
|
138
|
+
/** The short aliases of boolean flags (`-t`), which take a value the same way (`-t=true`). */
|
|
139
|
+
const BOOLEAN_ALIASES = Object.entries(ALIASES)
|
|
140
|
+
.filter(([flag]) => CAMEL_CASE_BOOLEAN_FLAGS.includes(flag))
|
|
141
|
+
.flatMap(([, aliases]) => aliases.map((alias) => `-${alias}`));
|
|
142
|
+
|
|
143
|
+
const BOOLEAN_FLAG_NAMES: ReadonlySet<string> = new Set([
|
|
144
|
+
...BOOLEAN_FLAGS.map((flag) => `${LONG_PREFIX}${flag}`),
|
|
145
|
+
...BOOLEAN_ALIASES,
|
|
146
|
+
]);
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* A boolean flag takes `=true` or `=false`, and its `--no-` form takes no value. yargs-parser read
|
|
150
|
+
* any other value as false (`--enum=1`, `--alphabetize=yes`), which turned the option off.
|
|
151
|
+
*/
|
|
152
|
+
function rejectInvalidBooleans(flags: readonly WrittenFlag[]): void {
|
|
153
|
+
for (const { name, value } of flags) {
|
|
154
|
+
const negated = name.startsWith(NEGATION_PREFIX)
|
|
155
|
+
? `${LONG_PREFIX}${name.slice(NEGATION_PREFIX.length)}`
|
|
156
|
+
: undefined;
|
|
157
|
+
const isNegatedWithValue = negated !== undefined && BOOLEAN_FLAG_NAMES.has(negated);
|
|
158
|
+
const isInvalid = BOOLEAN_FLAG_NAMES.has(name) && !BOOLEAN_VALUES.has(value ?? "true");
|
|
159
|
+
if (value !== undefined && (isNegatedWithValue || isInvalid)) {
|
|
160
|
+
throw cliError(
|
|
161
|
+
"CLI_FLAG_INVALID",
|
|
162
|
+
`${name}=${value}: a boolean flag takes no value, or =true or =false.`,
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
96
168
|
/** Notices for flags that have no effect in this combination, printed before the run. */
|
|
97
|
-
export function ineffectiveFlagNotices(
|
|
98
|
-
if (
|
|
169
|
+
export function ineffectiveFlagNotices(flags: GeneratorFlags): string[] {
|
|
170
|
+
if (flags.rootTypes === true) {
|
|
99
171
|
return [];
|
|
100
172
|
}
|
|
101
|
-
return ROOT_TYPES_FLAGS.filter((flag) =>
|
|
102
|
-
(flag) =>
|
|
173
|
+
return ROOT_TYPES_FLAGS.filter((flag) => flags[flag] === true).map(
|
|
174
|
+
(flag) => `--${kebabCase(flag)} has no effect without --root-types flag`,
|
|
103
175
|
);
|
|
104
176
|
}
|
|
105
177
|
|
|
@@ -117,7 +189,10 @@ function optionalString(value: unknown): string | undefined {
|
|
|
117
189
|
return value === undefined ? undefined : String(value);
|
|
118
190
|
}
|
|
119
191
|
|
|
120
|
-
/**
|
|
192
|
+
/**
|
|
193
|
+
* The last value of a flag that takes one value: given twice, the last one wins, as for the
|
|
194
|
+
* boolean flags (yargs-parser gives a list of every value).
|
|
195
|
+
*/
|
|
121
196
|
function lastString(value: unknown): string | undefined {
|
|
122
197
|
return optionalString(Array.isArray(value) ? value.at(-1) : value);
|
|
123
198
|
}
|
|
@@ -154,8 +229,6 @@ const STRING_FLAGS = [
|
|
|
154
229
|
...["localRefRoot", "remoteRefHosts"].flatMap((flag) => [flag, kebabCase(flag)]),
|
|
155
230
|
];
|
|
156
231
|
|
|
157
|
-
const ALIASES = { redocly: ["c"], exportType: ["t"], output: ["o"] };
|
|
158
|
-
|
|
159
232
|
/** Every name yargs-parser can return for a flag this CLI reads. */
|
|
160
233
|
const KNOWN_FLAGS = new Set<string>([
|
|
161
234
|
...BOOLEAN_FLAGS,
|
|
@@ -186,11 +259,14 @@ function writtenFlagName(key: string, argv: readonly string[]): string {
|
|
|
186
259
|
}
|
|
187
260
|
|
|
188
261
|
/**
|
|
189
|
-
* Parse the arguments after `node cli.js`. Fails with `CLI_FLAG_REMOVED` for an old flag
|
|
262
|
+
* Parse the arguments after `node cli.js`. Fails with `CLI_FLAG_REMOVED` for an old flag, with
|
|
263
|
+
* `CLI_FLAG_INVALID` for a boolean flag with another value than true or false, and with
|
|
190
264
|
* `OPTION_FIX_UNKNOWN` for an unknown `--fix` name.
|
|
191
265
|
*/
|
|
192
266
|
export function parseCliArguments(argv: readonly string[]): CliArguments {
|
|
193
|
-
|
|
267
|
+
const flags = writtenFlags(argv);
|
|
268
|
+
rejectRemovedFlags(flags);
|
|
269
|
+
rejectInvalidBooleans(flags);
|
|
194
270
|
const parsed = parser([...argv], {
|
|
195
271
|
boolean: BOOLEAN_FLAGS,
|
|
196
272
|
string: STRING_FLAGS,
|
|
@@ -198,8 +274,8 @@ export function parseCliArguments(argv: readonly string[]): CliArguments {
|
|
|
198
274
|
});
|
|
199
275
|
return {
|
|
200
276
|
input: optionalString(parsed._[0]),
|
|
201
|
-
output:
|
|
202
|
-
redocly:
|
|
277
|
+
output: lastString(parsed.output),
|
|
278
|
+
redocly: lastString(parsed.redocly),
|
|
203
279
|
isCheck: parsed.check === true,
|
|
204
280
|
isHelp: "help" in parsed,
|
|
205
281
|
isVersion: "version" in parsed,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Readable } from "node:stream";
|
|
2
2
|
import type {
|
|
3
3
|
DirectoryCheck,
|
|
4
|
+
FileCheck,
|
|
4
5
|
FileClaims,
|
|
5
6
|
FileIdentity,
|
|
6
7
|
FileReader,
|
|
@@ -33,10 +34,14 @@ export interface GeneratedTypes {
|
|
|
33
34
|
readonly localFiles: readonly URL[];
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
/**
|
|
37
|
+
/**
|
|
38
|
+
* Generate the types of one schema. With `apiName`, an API of `redocly.yaml`, every line the
|
|
39
|
+
* generation logs names that API.
|
|
40
|
+
*/
|
|
37
41
|
export type GenerateTypes = (
|
|
38
42
|
source: SchemaSource,
|
|
39
43
|
options: GeneratorOptions,
|
|
44
|
+
apiName?: string,
|
|
40
45
|
) => Promise<GeneratedTypes>;
|
|
41
46
|
|
|
42
47
|
export interface CliDependencies {
|
|
@@ -55,7 +60,7 @@ export interface CliDependencies {
|
|
|
55
60
|
* input with no prompt, which looks like a hang (upstream #1905).
|
|
56
61
|
*/
|
|
57
62
|
readonly isStdinTerminal: () => boolean;
|
|
58
|
-
readonly files: FileReader & FileWriter & FileIdentity & DirectoryCheck & FileClaims;
|
|
63
|
+
readonly files: FileReader & FileWriter & FileIdentity & DirectoryCheck & FileCheck & FileClaims;
|
|
59
64
|
readonly redoclyConfigs: RedoclyConfigSource;
|
|
60
65
|
readonly generate: GenerateTypes;
|
|
61
66
|
/** A monotonic time in milliseconds, for the time printed after each output. */
|
package/src/cli/cli-errors.ts
CHANGED
|
@@ -99,8 +99,10 @@ const CLI_ERROR_REPORTS: Readonly<Record<ErrorCode, CliErrorReport>> = {
|
|
|
99
99
|
ENUM_NAME_EMPTY: { exitCode: EXIT_CODES.SCHEMA },
|
|
100
100
|
CALLBACK_RESULT_UNREADABLE: { exitCode: EXIT_CODES.USAGE },
|
|
101
101
|
OPTION_FIX_UNKNOWN: { exitCode: EXIT_CODES.USAGE },
|
|
102
|
+
OPTION_INVALID: { exitCode: EXIT_CODES.USAGE },
|
|
102
103
|
TYPESCRIPT_NOT_FOUND: { exitCode: EXIT_CODES.USAGE },
|
|
103
104
|
CLI_FLAG_REMOVED: { exitCode: EXIT_CODES.USAGE },
|
|
105
|
+
CLI_FLAG_INVALID: { exitCode: EXIT_CODES.USAGE },
|
|
104
106
|
CLI_GLOB_UNSUPPORTED: { exitCode: EXIT_CODES.USAGE },
|
|
105
107
|
CLI_CONFIG_NOT_FOUND: { exitCode: EXIT_CODES.USAGE },
|
|
106
108
|
CLI_CONFIG_INVALID: { exitCode: EXIT_CODES.USAGE },
|
|
@@ -127,6 +129,10 @@ export interface CliFailure {
|
|
|
127
129
|
* else is a bug and prints its stack, so it can be reported.
|
|
128
130
|
*/
|
|
129
131
|
export function describeCliFailure(error: unknown): CliFailure {
|
|
132
|
+
if (error instanceof ApiFailure) {
|
|
133
|
+
const failure = describeCliFailure(error.cause);
|
|
134
|
+
return { ...failure, message: `API ${error.apiName}: ${failure.message}` };
|
|
135
|
+
}
|
|
130
136
|
if (!isOpenAPITypesafeError(error)) {
|
|
131
137
|
const text = error instanceof Error ? (error.stack ?? error.message) : String(error);
|
|
132
138
|
return { exitCode: EXIT_CODES.INTERNAL, message: `Unexpected error: ${text}` };
|
|
@@ -136,6 +142,22 @@ export function describeCliFailure(error: unknown): CliFailure {
|
|
|
136
142
|
return { exitCode: report.exitCode, message: `${message} (${error.code})` };
|
|
137
143
|
}
|
|
138
144
|
|
|
145
|
+
/**
|
|
146
|
+
* A failure of one API of a Redocly config. The CLI reports its cause with the API named first,
|
|
147
|
+
* as the config errors of an API are; the cause keeps its code and so its exit code.
|
|
148
|
+
*/
|
|
149
|
+
export class ApiFailure extends Error {
|
|
150
|
+
override readonly name = "ApiFailure";
|
|
151
|
+
override readonly cause: unknown;
|
|
152
|
+
readonly apiName: string;
|
|
153
|
+
|
|
154
|
+
constructor(apiName: string, cause: unknown) {
|
|
155
|
+
super(`API ${apiName} failed`, { cause });
|
|
156
|
+
this.apiName = apiName;
|
|
157
|
+
this.cause = cause;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
139
161
|
/** Errors of the CLI itself; its messages are the original CLI's messages. */
|
|
140
162
|
export function cliError(
|
|
141
163
|
code: Extract<ErrorCode, `CLI_${string}` | `OUTPUT_${string}`>,
|
package/src/cli/cli-output.ts
CHANGED
|
@@ -2,7 +2,9 @@ import path from "node:path";
|
|
|
2
2
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
3
3
|
import { formatDuration } from "../adapters/terminal-logger/terminal-logger.js";
|
|
4
4
|
import type { RedoclyConfig } from "../application/ports/redocly-config-source.js";
|
|
5
|
-
import {
|
|
5
|
+
import { hasUrlScheme } from "../domain/location-text.js";
|
|
6
|
+
import { terminalSafeText } from "../domain/terminal-text.js";
|
|
7
|
+
import { redactUnparsedUrl, redactUrlSecrets } from "../domain/url-secrets.js";
|
|
6
8
|
import type { CliArguments } from "./cli-arguments.js";
|
|
7
9
|
import type { CliDependencies, GeneratedTypes } from "./cli-dependencies.js";
|
|
8
10
|
import { cliError } from "./cli-errors.js";
|
|
@@ -27,12 +29,6 @@ export interface OutputFile extends NamedOutput {
|
|
|
27
29
|
readonly file: URL;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
|
-
/**
|
|
31
|
-
* A scheme of two or more characters (`https:`, `file:`). One letter is a Windows drive (`C:`), so
|
|
32
|
-
* `C:\\specs\\api.yaml` stays a path.
|
|
33
|
-
*/
|
|
34
|
-
const URL_SCHEME = /^[a-z][a-z\d+.-]+:/i;
|
|
35
|
-
|
|
36
32
|
/**
|
|
37
33
|
* The URL of a location the user wrote: a URL, else a file path, absolute or relative to the
|
|
38
34
|
* directory of `base` (a directory or file URL). A relative `file:` URL (`file:api.yaml`) resolves
|
|
@@ -41,7 +37,7 @@ const URL_SCHEME = /^[a-z][a-z\d+.-]+:/i;
|
|
|
41
37
|
* (`http://[::1/x`) fails with `CLI_LOCATION_INVALID`.
|
|
42
38
|
*/
|
|
43
39
|
export function resolveLocationUrl(location: string, base: URL): URL {
|
|
44
|
-
if (
|
|
40
|
+
if (hasUrlScheme(location)) {
|
|
45
41
|
const url = URL.parse(location, base.href);
|
|
46
42
|
if (url === null) {
|
|
47
43
|
const shown = redactUnparsedUrl(location);
|
|
@@ -202,15 +198,20 @@ export function duplicateOutputError(output: NamedOutput, others: readonly strin
|
|
|
202
198
|
|
|
203
199
|
/** As `resolveLocationUrl`, but undefined for a URL that does not parse instead of a throw. */
|
|
204
200
|
export function parseLocationUrl(location: string, base: URL): URL | undefined {
|
|
205
|
-
if (
|
|
201
|
+
if (hasUrlScheme(location)) {
|
|
206
202
|
return URL.parse(location, base.href) ?? undefined;
|
|
207
203
|
}
|
|
208
204
|
return resolveLocationUrl(location, base);
|
|
209
205
|
}
|
|
210
206
|
|
|
207
|
+
/**
|
|
208
|
+
* The line for a written file. It goes to the job log, so a source URL shows no secrets, and a
|
|
209
|
+
* line break or escape sequence in a name cannot start a forged line.
|
|
210
|
+
*/
|
|
211
211
|
function printDone(run: CliRun, output: OutputFile): void {
|
|
212
212
|
const { style, now } = run.deps;
|
|
213
|
-
const
|
|
213
|
+
const source = terminalSafeText(redactUrlSecrets(output.source));
|
|
214
|
+
const target = style.green(`${source} → ${style.bold(terminalSafeText(output.output))}`);
|
|
214
215
|
const duration = style.dim(`[${formatDuration(now() - run.startedAt)}]`);
|
|
215
216
|
run.deps.console.info(`🚀 ${target} ${duration}`);
|
|
216
217
|
}
|
package/src/cli/main.ts
CHANGED
|
@@ -3,11 +3,14 @@ import { isatty } from "node:tty";
|
|
|
3
3
|
import { pathToFileURL } from "node:url";
|
|
4
4
|
import colors from "ansi-colors";
|
|
5
5
|
import { createNodeFileSystem } from "../adapters/node-file-system/node-file-system.js";
|
|
6
|
+
import { createPipeSafeWriter } from "../adapters/pipe-safe-writer/pipe-safe-writer.js";
|
|
6
7
|
import { createRedoclyConfigSource } from "../adapters/redocly-loader/redocly-config-source.js";
|
|
7
8
|
import { astToString } from "../api/ast-to-string.js";
|
|
8
9
|
import { COMMENT_HEADER } from "../api/comment-header.js";
|
|
9
10
|
import { defaultLogger, monotonicNow, terminalSupportsColor } from "../api/default-ports.js";
|
|
10
11
|
import { defaultGeneratorPorts, generateDocument } from "../api/openapi-ts.js";
|
|
12
|
+
import { terminalSafeText } from "../domain/terminal-text.js";
|
|
13
|
+
import { apiLogger } from "./api-logger.js";
|
|
11
14
|
import type { CliConsole, CliDependencies, GenerateTypes, TextStyle } from "./cli-dependencies.js";
|
|
12
15
|
import { runCli } from "./run-cli.js";
|
|
13
16
|
|
|
@@ -36,8 +39,10 @@ function terminalStyle(): TextStyle {
|
|
|
36
39
|
|
|
37
40
|
const STDIN_DESCRIPTOR = 0;
|
|
38
41
|
|
|
39
|
-
const generateTypes: GenerateTypes = async (source, options) => {
|
|
40
|
-
const
|
|
42
|
+
const generateTypes: GenerateTypes = async (source, options, apiName) => {
|
|
43
|
+
const terminalLogger = defaultLogger(options.silent ?? false);
|
|
44
|
+
const logger = apiName === undefined ? terminalLogger : apiLogger(terminalLogger, apiName);
|
|
45
|
+
const ports = await defaultGeneratorPorts(options, logger);
|
|
41
46
|
const { declarations, localFiles } = await generateDocument(source, options, ports);
|
|
42
47
|
return { contents: `${COMMENT_HEADER}${astToString(declarations)}`, localFiles };
|
|
43
48
|
};
|
|
@@ -46,8 +51,9 @@ function terminalConsole(): CliConsole {
|
|
|
46
51
|
return {
|
|
47
52
|
// biome-ignore lint/suspicious/noConsole: the CLI's own output lines
|
|
48
53
|
info: (text) => console.info(text),
|
|
54
|
+
// A notice names flags and API names as written, so it is shown as one plain line.
|
|
49
55
|
// biome-ignore lint/suspicious/noConsole: the CLI's own notices
|
|
50
|
-
notice: (text) => console.warn(text),
|
|
56
|
+
notice: (text) => console.warn(terminalSafeText(text)),
|
|
51
57
|
};
|
|
52
58
|
}
|
|
53
59
|
|
|
@@ -58,7 +64,7 @@ function processDependencies(): CliDependencies {
|
|
|
58
64
|
version: readVersion(),
|
|
59
65
|
logger: defaultLogger(false),
|
|
60
66
|
console: terminalConsole(),
|
|
61
|
-
writeStdout: (
|
|
67
|
+
writeStdout: createPipeSafeWriter(process.stdout),
|
|
62
68
|
stdin: () => process.stdin,
|
|
63
69
|
// `isatty` reads the descriptor without opening `process.stdin`, which would keep the
|
|
64
70
|
// process alive.
|
package/src/cli/redocly-apis.ts
CHANGED
|
@@ -10,7 +10,8 @@ import {
|
|
|
10
10
|
unknownSettingWarnings,
|
|
11
11
|
} from "./api-settings.js";
|
|
12
12
|
import { type GeneratedApi, writeGeneratedApis } from "./api-writes.js";
|
|
13
|
-
import {
|
|
13
|
+
import { ineffectiveFlagNotices } from "./cli-arguments.js";
|
|
14
|
+
import { ApiFailure, cliError } from "./cli-errors.js";
|
|
14
15
|
import {
|
|
15
16
|
type CliRun,
|
|
16
17
|
ensureOutputIsNotSchema,
|
|
@@ -24,7 +25,7 @@ import {
|
|
|
24
25
|
} from "./cli-output.js";
|
|
25
26
|
import { MULTIPLE_SCHEMAS_DOCS_URL } from "./docs-links.js";
|
|
26
27
|
import { fixOption } from "./fix-option.js";
|
|
27
|
-
import { refLimitOptions } from "./ref-limits.js";
|
|
28
|
+
import { type RefLimitOptions, refLimitOptions } from "./ref-limits.js";
|
|
28
29
|
|
|
29
30
|
/** The `apis` of a Redocly config: each API is generated into its `x-openapi-ts.output`. */
|
|
30
31
|
|
|
@@ -92,16 +93,33 @@ function apiTarget(api: RedoclyApi, configRoot: URL): ApiTarget {
|
|
|
92
93
|
return { name, root, settings, configRoot };
|
|
93
94
|
}
|
|
94
95
|
|
|
95
|
-
/**
|
|
96
|
-
|
|
96
|
+
/**
|
|
97
|
+
* What every API of a run shares: the config, the files of all APIs, and the reference limits of
|
|
98
|
+
* the command line, which are checked once before any API, so an invalid flag fails the run once.
|
|
99
|
+
*/
|
|
100
|
+
interface ApiRun {
|
|
101
|
+
readonly redocly: RedoclyConfig;
|
|
102
|
+
readonly files: ConfigFiles;
|
|
103
|
+
readonly refLimits: RefLimitOptions;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* The generator options of one API: its own settings win over the CLI's flags. A flag that has
|
|
108
|
+
* no effect with the merged flags is named for this API, since its settings may turn on the flag
|
|
109
|
+
* that the command line lacks, or set one that has no effect themselves.
|
|
110
|
+
*/
|
|
111
|
+
function apiOptions(run: CliRun, apiRun: ApiRun, target: ApiTarget): GeneratorOptions {
|
|
97
112
|
const { name, settings, configRoot } = target;
|
|
113
|
+
const flags = { ...run.args.generatorFlags, ...apiFlags(name, settings) };
|
|
114
|
+
for (const notice of ineffectiveFlagNotices(flags)) {
|
|
115
|
+
run.deps.console.notice(`API ${name}: ${notice}`);
|
|
116
|
+
}
|
|
98
117
|
return {
|
|
99
|
-
...
|
|
100
|
-
...
|
|
101
|
-
...refLimitOptions(run.args, run.deps.cwd),
|
|
118
|
+
...flags,
|
|
119
|
+
...apiRun.refLimits,
|
|
102
120
|
...apiRefLimitOptions(name, settings, configRoot),
|
|
103
121
|
...fixOption(apiFixNames(name, settings) ?? run.args.fix),
|
|
104
|
-
redocly,
|
|
122
|
+
redocly: apiRun.redocly,
|
|
105
123
|
};
|
|
106
124
|
}
|
|
107
125
|
|
|
@@ -122,12 +140,8 @@ function otherOutputs(files: ConfigFiles, apiName: string): NamedFile[] {
|
|
|
122
140
|
* Generate the types of one API. Its output must not be a file the run reads before any API is
|
|
123
141
|
* loaded (the root of any API, the Redocly config) nor another API's output.
|
|
124
142
|
*/
|
|
125
|
-
async function generateApi(
|
|
126
|
-
|
|
127
|
-
redocly: RedoclyConfig,
|
|
128
|
-
target: ApiTarget,
|
|
129
|
-
files: ConfigFiles,
|
|
130
|
-
): Promise<GeneratedApi> {
|
|
143
|
+
async function generateApi(run: CliRun, apiRun: ApiRun, target: ApiTarget): Promise<GeneratedApi> {
|
|
144
|
+
const { files } = apiRun;
|
|
131
145
|
for (const warning of unknownSettingWarnings(target.name, target.settings)) {
|
|
132
146
|
run.deps.logger.warn(warning);
|
|
133
147
|
}
|
|
@@ -136,8 +150,13 @@ async function generateApi(
|
|
|
136
150
|
ensureOutputIsNotSchema(run, outputFile, files.schemas);
|
|
137
151
|
ensureOutputIsOwn(run, outputFile, otherOutputs(files, target.name));
|
|
138
152
|
const source = resolveLocationUrl(target.root, target.configRoot);
|
|
139
|
-
const
|
|
140
|
-
|
|
153
|
+
const options = apiOptions(run, apiRun, target);
|
|
154
|
+
try {
|
|
155
|
+
const types = await run.deps.generate(source, options, target.name);
|
|
156
|
+
return { name: target.name, outputFile, types };
|
|
157
|
+
} catch (error) {
|
|
158
|
+
throw new ApiFailure(target.name, error);
|
|
159
|
+
}
|
|
141
160
|
}
|
|
142
161
|
|
|
143
162
|
/**
|
|
@@ -192,8 +211,9 @@ async function settledInTurn<T, R>(
|
|
|
192
211
|
export async function generateRedoclyApis(run: CliRun, redocly: RedoclyConfig): Promise<unknown[]> {
|
|
193
212
|
const apis = redoclyApisOf(redocly);
|
|
194
213
|
const { configRoot, files } = configFilesOf(run, redocly, apis);
|
|
214
|
+
const apiRun = { redocly, files, refLimits: refLimitOptions(run.args, run.deps.cwd) };
|
|
195
215
|
const results = await settledInTurn(apis, (api) =>
|
|
196
|
-
generateApi(run,
|
|
216
|
+
generateApi(run, apiRun, apiTarget(api, configRoot)),
|
|
197
217
|
);
|
|
198
218
|
const generated = results.flatMap((result) =>
|
|
199
219
|
result.status === "fulfilled" ? [result.value] : [],
|
package/src/cli/ref-limits.ts
CHANGED
|
@@ -1,16 +1,35 @@
|
|
|
1
1
|
import type { GeneratorOptions } from "../types.js";
|
|
2
2
|
import type { CliArguments } from "./cli-arguments.js";
|
|
3
|
+
import { cliError } from "./cli-errors.js";
|
|
3
4
|
import { resolveLocationUrl } from "./cli-output.js";
|
|
4
5
|
|
|
5
6
|
/** The `$ref` limits of the CLI flags as generator options (threat model R1, R2, ADR-017). */
|
|
6
7
|
|
|
7
8
|
export type RefLimitOptions = Pick<GeneratorOptions, "localRefRoot" | "remoteRefHosts">;
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
const FILE_PROTOCOL = "file:";
|
|
11
|
+
|
|
12
|
+
/** A local `$ref` root as a URL; undefined for a URL of another protocol, which names no folder. */
|
|
13
|
+
export function localRootUrl(location: string, base: URL): URL | undefined {
|
|
14
|
+
const url = resolveLocationUrl(location, base);
|
|
15
|
+
return url.protocol === FILE_PROTOCOL ? url : undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* `--local-ref-root` resolves against the working directory, like every other CLI path. A URL of
|
|
20
|
+
* another protocol (`https://…`) fails with `CLI_FLAG_INVALID`.
|
|
21
|
+
*/
|
|
10
22
|
export function refLimitOptions(args: CliArguments, cwd: URL): RefLimitOptions {
|
|
11
23
|
const { localRefRoot, remoteRefHosts } = args.refLimits;
|
|
24
|
+
const localRoot = localRefRoot === undefined ? undefined : localRootUrl(localRefRoot, cwd);
|
|
25
|
+
if (localRefRoot !== undefined && localRoot === undefined) {
|
|
26
|
+
throw cliError(
|
|
27
|
+
"CLI_FLAG_INVALID",
|
|
28
|
+
`--local-ref-root ${localRefRoot}: a directory path or a file: URL.`,
|
|
29
|
+
);
|
|
30
|
+
}
|
|
12
31
|
return {
|
|
13
|
-
...(
|
|
32
|
+
...(localRoot === undefined ? {} : { localRefRoot: localRoot }),
|
|
14
33
|
...(remoteRefHosts === undefined ? {} : { remoteRefHosts }),
|
|
15
34
|
};
|
|
16
35
|
}
|
package/src/cli/run-cli.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Logger } from "../application/ports/logger.js";
|
|
2
2
|
import type { RedoclyConfig } from "../application/ports/redocly-config-source.js";
|
|
3
|
+
import { hasUrlScheme } from "../domain/location-text.js";
|
|
3
4
|
import { WARNING_CODES, warningText } from "../domain/warnings.js";
|
|
4
5
|
import type { SchemaSource } from "../types.js";
|
|
5
6
|
import { ineffectiveFlagNotices, parseCliArguments } from "./cli-arguments.js";
|
|
@@ -52,13 +53,29 @@ function schemaSource(run: CliRun): SchemaSource {
|
|
|
52
53
|
return run.deps.stdin();
|
|
53
54
|
}
|
|
54
55
|
|
|
56
|
+
/** The character that made the original CLI read a schema argument as a glob pattern. */
|
|
57
|
+
const GLOB_WILDCARD = "*";
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Whether the schema argument is a glob pattern, which the CLI no longer expands: a path with a
|
|
61
|
+
* `*` that names no file. A URL is no pattern (`?fields=*` is its query), nor a file whose name
|
|
62
|
+
* has a `*`, which the CLI reads as any other file.
|
|
63
|
+
*/
|
|
64
|
+
function isGlobPattern(run: CliRun, input: string): boolean {
|
|
65
|
+
return (
|
|
66
|
+
input.includes(GLOB_WILDCARD) &&
|
|
67
|
+
!hasUrlScheme(input) &&
|
|
68
|
+
!run.deps.files.isFile(resolveLocationUrl(input, run.deps.cwd))
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
55
72
|
/**
|
|
56
73
|
* One schema from a path, a URL or stdin; without `--output`, the types go to stdout. Warnings and
|
|
57
74
|
* errors go to stderr either way, so they never mix with the types (upstream dropped warnings).
|
|
58
75
|
*/
|
|
59
76
|
async function generateSingleSchema(run: CliRun, redocly: RedoclyConfig): Promise<void> {
|
|
60
77
|
const { input, output } = run.args;
|
|
61
|
-
if (input
|
|
78
|
+
if (input !== undefined && isGlobPattern(run, input)) {
|
|
62
79
|
throw cliError(
|
|
63
80
|
"CLI_GLOB_UNSUPPORTED",
|
|
64
81
|
"Globbing has been deprecated in favor of redocly.yaml’s `apis` keys. " +
|
|
@@ -72,6 +89,9 @@ async function generateSingleSchema(run: CliRun, redocly: RedoclyConfig): Promis
|
|
|
72
89
|
"--check needs the generated file to compare with: add --output <file>.",
|
|
73
90
|
);
|
|
74
91
|
}
|
|
92
|
+
for (const notice of ineffectiveFlagNotices(run.args.generatorFlags)) {
|
|
93
|
+
run.deps.console.notice(notice);
|
|
94
|
+
}
|
|
75
95
|
const source = schemaSource(run);
|
|
76
96
|
const outputFile = output ? singleOutputFile(run, output, source, redocly) : undefined;
|
|
77
97
|
const options = {
|
|
@@ -112,23 +132,35 @@ async function generate(run: CliRun): Promise<unknown[]> {
|
|
|
112
132
|
await generateSingleSchema(run, redocly);
|
|
113
133
|
return [];
|
|
114
134
|
}
|
|
115
|
-
|
|
116
|
-
|
|
135
|
+
warnAboutIgnoredArguments(run);
|
|
136
|
+
return generateRedoclyApis(run, redocly);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** With the APIs of a Redocly config, the input and the output of the command line are unused. */
|
|
140
|
+
function warnAboutIgnoredArguments(run: CliRun): void {
|
|
141
|
+
const { args, deps } = run;
|
|
142
|
+
if (args.input) {
|
|
143
|
+
deps.logger.warn(
|
|
117
144
|
warningText(
|
|
118
145
|
"APIs are specified both in Redocly Config and CLI argument. Only using Redocly config.",
|
|
119
146
|
WARNING_CODES.CLI_INPUT_IGNORED,
|
|
120
147
|
),
|
|
121
148
|
);
|
|
122
149
|
}
|
|
123
|
-
|
|
150
|
+
if (args.output) {
|
|
151
|
+
deps.logger.warn(
|
|
152
|
+
warningText(
|
|
153
|
+
`APIs are specified in Redocly Config, so --output ${args.output} is ignored: ` +
|
|
154
|
+
"each API is written to its x-openapi-ts.output.",
|
|
155
|
+
WARNING_CODES.CLI_OUTPUT_IGNORED,
|
|
156
|
+
),
|
|
157
|
+
);
|
|
158
|
+
}
|
|
124
159
|
}
|
|
125
160
|
|
|
126
161
|
/** Run the command; the failures it returns did not stop the other outputs. */
|
|
127
162
|
async function runCommand(argv: readonly string[], deps: CliDependencies): Promise<unknown[]> {
|
|
128
163
|
const startedAt = deps.now();
|
|
129
|
-
for (const notice of ineffectiveFlagNotices(argv)) {
|
|
130
|
-
deps.console.notice(notice);
|
|
131
|
-
}
|
|
132
164
|
const args = parseCliArguments(argv);
|
|
133
165
|
for (const flag of args.unknownFlags) {
|
|
134
166
|
deps.console.notice(`Unknown flag ${flag} is ignored (see --help)`);
|