fumadocs-openapi 10.6.7 → 10.7.0
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/css/generated/shared.css +2 -5
- package/dist/_virtual/_rolldown/runtime.js +2 -1
- package/dist/i18n.js +3 -2
- package/dist/node_modules/.pnpm/@fastify_deepmerge@3.2.1/node_modules/@fastify/deepmerge/index.js +108 -0
- package/dist/node_modules/.pnpm/@scalar_helpers@0.4.3/node_modules/@scalar/helpers/dist/general/create-limiter.js +43 -0
- package/dist/node_modules/.pnpm/@scalar_helpers@0.4.3/node_modules/@scalar/helpers/dist/object/is-object.js +26 -0
- package/dist/node_modules/.pnpm/@scalar_helpers@0.4.3/node_modules/@scalar/helpers/dist/object/prevent-pollution.js +33 -0
- package/dist/node_modules/.pnpm/@scalar_helpers@0.4.3/node_modules/@scalar/helpers/dist/queue/queue.js +106 -0
- package/dist/node_modules/.pnpm/@scalar_helpers@0.4.3/node_modules/@scalar/helpers/dist/string/generate-hash.js +120 -0
- package/dist/node_modules/.pnpm/@scalar_json-magic@0.12.5/node_modules/@scalar/json-magic/dist/bundle/bundle.js +346 -0
- package/dist/node_modules/.pnpm/@scalar_json-magic@0.12.5/node_modules/@scalar/json-magic/dist/bundle/plugins/fetch-urls/index.js +73 -0
- package/dist/node_modules/.pnpm/@scalar_json-magic@0.12.5/node_modules/@scalar/json-magic/dist/bundle/plugins/node.js +3 -0
- package/dist/node_modules/.pnpm/@scalar_json-magic@0.12.5/node_modules/@scalar/json-magic/dist/bundle/plugins/parse-yaml/index.js +1 -0
- package/dist/node_modules/.pnpm/@scalar_json-magic@0.12.5/node_modules/@scalar/json-magic/dist/bundle/plugins/read-files/index.js +51 -0
- package/dist/node_modules/.pnpm/@scalar_json-magic@0.12.5/node_modules/@scalar/json-magic/dist/bundle/value-generator.js +88 -0
- package/dist/node_modules/.pnpm/@scalar_json-magic@0.12.5/node_modules/@scalar/json-magic/dist/helpers/convert-to-local-ref.js +24 -0
- package/dist/node_modules/.pnpm/@scalar_json-magic@0.12.5/node_modules/@scalar/json-magic/dist/helpers/escape-json-pointer.js +11 -0
- package/dist/node_modules/.pnpm/@scalar_json-magic@0.12.5/node_modules/@scalar/json-magic/dist/helpers/get-schemas.js +44 -0
- package/dist/node_modules/.pnpm/@scalar_json-magic@0.12.5/node_modules/@scalar/json-magic/dist/helpers/get-segments-from-path.js +10 -0
- package/dist/node_modules/.pnpm/@scalar_json-magic@0.12.5/node_modules/@scalar/json-magic/dist/helpers/get-value-by-path.js +42 -0
- package/dist/node_modules/.pnpm/@scalar_json-magic@0.12.5/node_modules/@scalar/json-magic/dist/helpers/is-file-path.js +23 -0
- package/dist/node_modules/.pnpm/@scalar_json-magic@0.12.5/node_modules/@scalar/json-magic/dist/helpers/is-http-url.js +23 -0
- package/dist/node_modules/.pnpm/@scalar_json-magic@0.12.5/node_modules/@scalar/json-magic/dist/helpers/is-json-object.js +28 -0
- package/dist/node_modules/.pnpm/@scalar_json-magic@0.12.5/node_modules/@scalar/json-magic/dist/helpers/is-yaml.js +21 -0
- package/dist/node_modules/.pnpm/@scalar_json-magic@0.12.5/node_modules/@scalar/json-magic/dist/helpers/normalize.js +26 -0
- package/dist/node_modules/.pnpm/@scalar_json-magic@0.12.5/node_modules/@scalar/json-magic/dist/helpers/resolve-reference-path.js +30 -0
- package/dist/node_modules/.pnpm/@scalar_json-magic@0.12.5/node_modules/@scalar/json-magic/dist/helpers/set-value-at-path.js +70 -0
- package/dist/node_modules/.pnpm/@scalar_json-magic@0.12.5/node_modules/@scalar/json-magic/dist/helpers/to-relative-path.js +33 -0
- package/dist/node_modules/.pnpm/@scalar_json-magic@0.12.5/node_modules/@scalar/json-magic/dist/helpers/unescape-json-pointer.js +12 -0
- package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.4/node_modules/@scalar/openapi-upgrader/dist/2.0-to-3.0/upgrade-from-two-to-three.js +487 -0
- package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.4/node_modules/@scalar/openapi-upgrader/dist/3.0-to-3.1/upgrade-from-three-to-three-one.js +95 -0
- package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.4/node_modules/@scalar/openapi-upgrader/dist/3.1-to-3.2/upgrade-from-three-one-to-three-two.js +59 -0
- package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.4/node_modules/@scalar/openapi-upgrader/dist/helpers/traverse.js +25 -0
- package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.4/node_modules/@scalar/openapi-upgrader/dist/upgrade.js +15 -0
- package/dist/node_modules/.pnpm/fast-content-type-parse@3.0.0/node_modules/fast-content-type-parse/index.js +115 -0
- package/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/index.js +19 -0
- package/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/shared/pathe.M-eThtNZ.js +430 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/compose/compose-collection.js +50 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/compose/compose-doc.js +39 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/compose/compose-node.js +85 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/compose/compose-scalar.js +57 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/compose/composer.js +193 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/compose/resolve-block-map.js +82 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/compose/resolve-block-scalar.js +173 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/compose/resolve-block-seq.js +40 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/compose/resolve-end.js +36 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/compose/resolve-flow-collection.js +153 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/compose/resolve-flow-scalar.js +204 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/compose/resolve-props.js +105 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/compose/util-contains-newline.js +27 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/compose/util-empty-scalar-position.js +25 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/compose/util-flow-indent-check.js +10 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/compose/util-map-includes.js +10 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/doc/Document.js +277 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/doc/anchors.js +57 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/doc/applyReviver.js +38 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/doc/createNode.js +61 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/doc/directives.js +163 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/errors.js +48 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/index.js +16 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/log.js +6 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/nodes/Alias.js +91 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/nodes/Collection.js +117 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/nodes/Node.js +32 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/nodes/Pair.js +29 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/nodes/Scalar.js +24 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/nodes/YAMLMap.js +106 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/nodes/YAMLSeq.js +104 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/nodes/addPairToJSMap.js +49 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/nodes/identity.js +33 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/nodes/toJS.js +35 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/parse/cst-scalar.js +3 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/parse/cst-visit.js +89 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/parse/cst.js +40 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/parse/lexer.js +517 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/parse/line-counter.js +45 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/parse/parser.js +852 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/public-api.js +44 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/schema/Schema.js +27 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/schema/common/map.js +16 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/schema/common/null.js +13 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/schema/common/seq.js +16 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/schema/common/string.js +14 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/schema/core/bool.js +17 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/schema/core/float.js +38 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/schema/core/int.js +37 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/schema/core/schema.js +23 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/schema/json/schema.js +61 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/schema/tags.js +81 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/schema/yaml-1.1/binary.js +44 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/schema/yaml-1.1/bool.js +24 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/schema/yaml-1.1/float.js +41 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/schema/yaml-1.1/int.js +70 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/schema/yaml-1.1/merge.js +36 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/schema/yaml-1.1/omap.js +60 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/schema/yaml-1.1/pairs.js +56 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/schema/yaml-1.1/schema.js +39 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/schema/yaml-1.1/set.js +65 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/schema/yaml-1.1/timestamp.js +79 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/stringify/foldFlowLines.js +111 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/stringify/stringify.js +105 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/stringify/stringifyCollection.js +116 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/stringify/stringifyComment.js +16 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/stringify/stringifyDocument.js +59 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/stringify/stringifyNumber.js +19 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/stringify/stringifyPair.js +95 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/stringify/stringifyString.js +222 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/dist/visit.js +187 -0
- package/dist/node_modules/.pnpm/yaml@2.8.3/node_modules/yaml/browser/index.js +16 -0
- package/dist/playground/components/oauth-dialog.js +17 -11
- package/dist/playground/components/result-display.js +3 -2
- package/dist/playground/schema.js +1 -1
- package/dist/scalar/client.js +15 -24
- package/dist/ui/operation/get-example-requests.js +1 -1
- package/dist/ui/operation/response-tabs.js +1 -1
- package/dist/utils/document/process.js +5 -3
- package/dist/utils/schema/sample.js +442 -0
- package/package.json +26 -25
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { isObject } from "../../../../../../@scalar_helpers@0.4.3/node_modules/@scalar/helpers/dist/object/is-object.js";
|
|
2
|
+
import { convertToLocalRef } from "../helpers/convert-to-local-ref.js";
|
|
3
|
+
import { getId, getSchemas } from "../helpers/get-schemas.js";
|
|
4
|
+
import { getValueByPath } from "../helpers/get-value-by-path.js";
|
|
5
|
+
import { isHttpUrl } from "../helpers/is-http-url.js";
|
|
6
|
+
import { isFilePath } from "../helpers/is-file-path.js";
|
|
7
|
+
import { resolveReferencePath } from "../helpers/resolve-reference-path.js";
|
|
8
|
+
import { getSegmentsFromPath } from "../helpers/get-segments-from-path.js";
|
|
9
|
+
import { setValueAtPath } from "../helpers/set-value-at-path.js";
|
|
10
|
+
import { toRelativePath } from "../helpers/to-relative-path.js";
|
|
11
|
+
import { escapeJsonPointer } from "../helpers/escape-json-pointer.js";
|
|
12
|
+
import { getHash, uniqueValueGeneratorFactory } from "./value-generator.js";
|
|
13
|
+
//#region ../../node_modules/.pnpm/@scalar+json-magic@0.12.5/node_modules/@scalar/json-magic/dist/bundle/bundle.js
|
|
14
|
+
/** Type guard to check if a value is an object with a $ref property */
|
|
15
|
+
const hasRef = (value) => isObject(value) && "$ref" in value && typeof value["$ref"] === "string";
|
|
16
|
+
/**
|
|
17
|
+
* Checks if a string is a local reference (starts with #)
|
|
18
|
+
* @param value - The reference string to check
|
|
19
|
+
* @returns true if the string is a local reference, false otherwise
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* isLocalRef('#/components/schemas/User') // true
|
|
23
|
+
* isLocalRef('https://example.com/schema.json') // false
|
|
24
|
+
* isLocalRef('./local-schema.json') // false
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
function isLocalRef(value) {
|
|
28
|
+
return value.startsWith("#");
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Resolves a string by finding and executing the appropriate plugin.
|
|
32
|
+
* @param value - The string to resolve (URL, file path, etc)
|
|
33
|
+
* @param plugins - Array of plugins that can handle different types of strings
|
|
34
|
+
* @returns A promise that resolves to either the content or an error result
|
|
35
|
+
* @example
|
|
36
|
+
* // Using a URL plugin
|
|
37
|
+
* await resolveContents('https://example.com/schema.json', [urlPlugin])
|
|
38
|
+
* // Using a file plugin
|
|
39
|
+
* await resolveContents('./schemas/user.json', [filePlugin])
|
|
40
|
+
* // No matching plugin returns { ok: false }
|
|
41
|
+
* await resolveContents('#/components/schemas/User', [urlPlugin, filePlugin])
|
|
42
|
+
*/
|
|
43
|
+
function resolveContents(value, plugins) {
|
|
44
|
+
const plugin = plugins.find((p) => p.validate(value));
|
|
45
|
+
if (plugin) return plugin.exec(value);
|
|
46
|
+
return Promise.resolve({ ok: false });
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Prefixes an internal JSON reference with a given path prefix.
|
|
50
|
+
* Takes a local reference (starting with #) and prepends the provided prefix segments.
|
|
51
|
+
*
|
|
52
|
+
* @param input - The internal reference string to prefix (must start with #)
|
|
53
|
+
* @param prefix - Array of path segments to prepend to the reference
|
|
54
|
+
* @returns The prefixed reference string
|
|
55
|
+
* @throws Error if input is not a local reference
|
|
56
|
+
* @example
|
|
57
|
+
* prefixInternalRef('#/components/schemas/User', ['definitions'])
|
|
58
|
+
* // Returns: '#/definitions/components/schemas/User'
|
|
59
|
+
*/
|
|
60
|
+
function prefixInternalRef(input, prefix) {
|
|
61
|
+
if (!isLocalRef(input)) throw "Please provide an internal ref";
|
|
62
|
+
return `#/${prefix.map(escapeJsonPointer).join("/")}${input.substring(1)}`;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Updates internal references in an object by adding a prefix to their paths.
|
|
66
|
+
* Recursively traverses the input object and modifies any local $ref references
|
|
67
|
+
* by prepending the given prefix to their paths. This is used when embedding external
|
|
68
|
+
* documents to maintain correct reference paths relative to the main document.
|
|
69
|
+
*
|
|
70
|
+
* @param input - The object to update references in
|
|
71
|
+
* @param prefix - Array of path segments to prepend to internal reference paths
|
|
72
|
+
* @returns void
|
|
73
|
+
* @example
|
|
74
|
+
* ```ts
|
|
75
|
+
* const input = {
|
|
76
|
+
* foo: {
|
|
77
|
+
* $ref: '#/components/schemas/User'
|
|
78
|
+
* }
|
|
79
|
+
* }
|
|
80
|
+
* prefixInternalRefRecursive(input, ['definitions'])
|
|
81
|
+
* // Result:
|
|
82
|
+
* // {
|
|
83
|
+
* // foo: {
|
|
84
|
+
* // $ref: '#/definitions/components/schemas/User'
|
|
85
|
+
* // }
|
|
86
|
+
* // }
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
function prefixInternalRefRecursive(input, prefix) {
|
|
90
|
+
if (Array.isArray(input)) {
|
|
91
|
+
input.forEach((el) => prefixInternalRefRecursive(el, prefix));
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (!isObject(input)) return;
|
|
95
|
+
Object.values(input).forEach((el) => prefixInternalRefRecursive(el, prefix));
|
|
96
|
+
if (typeof input === "object" && "$ref" in input && typeof input["$ref"] === "string") {
|
|
97
|
+
const ref = input["$ref"];
|
|
98
|
+
if (!isLocalRef(ref)) return;
|
|
99
|
+
input["$ref"] = prefixInternalRef(ref, prefix);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Resolves and copies referenced values from a source document to a target document.
|
|
104
|
+
* This function traverses the document and copies referenced values to the target document,
|
|
105
|
+
* while tracking processed references to avoid duplicates. It only processes references
|
|
106
|
+
* that belong to the same external document.
|
|
107
|
+
*
|
|
108
|
+
* @param targetDocument - The document to copy referenced values to
|
|
109
|
+
* @param sourceDocument - The source document containing the references
|
|
110
|
+
* @param referencePath - The JSON pointer path to the reference
|
|
111
|
+
* @param externalRefsKey - The key used for external references (e.g. 'x-ext')
|
|
112
|
+
* @param documentKey - The key identifying the external document
|
|
113
|
+
* @param bundleLocalRefs - Also bundles the local refs
|
|
114
|
+
* @param processedNodes - Set of already processed nodes to prevent duplicates
|
|
115
|
+
* @example
|
|
116
|
+
* ```ts
|
|
117
|
+
* const source = {
|
|
118
|
+
* components: {
|
|
119
|
+
* schemas: {
|
|
120
|
+
* User: {
|
|
121
|
+
* $ref: '#/x-ext/users~1schema/definitions/Person'
|
|
122
|
+
* }
|
|
123
|
+
* }
|
|
124
|
+
* }
|
|
125
|
+
* }
|
|
126
|
+
*
|
|
127
|
+
* const target = {}
|
|
128
|
+
* resolveAndCopyReferences(
|
|
129
|
+
* target,
|
|
130
|
+
* source,
|
|
131
|
+
* '/components/schemas/User',
|
|
132
|
+
* 'x-ext',
|
|
133
|
+
* 'users/schema'
|
|
134
|
+
* )
|
|
135
|
+
* // Result: target will contain the User schema with resolved references
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
const resolveAndCopyReferences = (targetDocument, sourceDocument, referencePath, externalRefsKey, documentKey, bundleLocalRefs = false, processedNodes = /* @__PURE__ */ new Set()) => {
|
|
139
|
+
const referencedValue = getValueByPath(sourceDocument, getSegmentsFromPath(referencePath)).value;
|
|
140
|
+
if (processedNodes.has(referencedValue)) return;
|
|
141
|
+
processedNodes.add(referencedValue);
|
|
142
|
+
setValueAtPath(targetDocument, referencePath, referencedValue);
|
|
143
|
+
const traverse = (node) => {
|
|
144
|
+
if (!node || typeof node !== "object") return;
|
|
145
|
+
if ("$ref" in node && typeof node["$ref"] === "string") {
|
|
146
|
+
if (node["$ref"].startsWith(`#/${externalRefsKey}/${escapeJsonPointer(documentKey)}`)) resolveAndCopyReferences(targetDocument, sourceDocument, node["$ref"].substring(1), externalRefsKey, documentKey, bundleLocalRefs, processedNodes);
|
|
147
|
+
else if (bundleLocalRefs) resolveAndCopyReferences(targetDocument, sourceDocument, node["$ref"].substring(1), externalRefsKey, documentKey, bundleLocalRefs, processedNodes);
|
|
148
|
+
}
|
|
149
|
+
for (const value of Object.values(node)) traverse(value);
|
|
150
|
+
};
|
|
151
|
+
traverse(referencedValue);
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* Extension keys used for bundling external references in OpenAPI documents.
|
|
155
|
+
* These custom extensions help maintain the structure and traceability of bundled documents.
|
|
156
|
+
*/
|
|
157
|
+
const extensions = {
|
|
158
|
+
externalDocuments: "x-ext",
|
|
159
|
+
externalDocumentsMappings: "x-ext-urls"
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* Bundles an OpenAPI specification by resolving all external references.
|
|
163
|
+
* This function traverses the input object recursively and embeds external $ref
|
|
164
|
+
* references into an x-ext section. External references can be URLs or local files.
|
|
165
|
+
* The original $refs are updated to point to their embedded content in the x-ext section.
|
|
166
|
+
* If the input is an object, it will be modified in place by adding an x-ext
|
|
167
|
+
* property to store resolved external references.
|
|
168
|
+
*
|
|
169
|
+
* @param input - The OpenAPI specification to bundle. Can be either an object or string.
|
|
170
|
+
* If a string is provided, it will be resolved using the provided plugins.
|
|
171
|
+
* If no plugin can process the input, the onReferenceError hook will be invoked
|
|
172
|
+
* and an error will be emitted to the console.
|
|
173
|
+
* @param config - Configuration object containing plugins and options for bundling OpenAPI specifications
|
|
174
|
+
* @returns A promise that resolves to the bundled specification with all references embedded
|
|
175
|
+
* @example
|
|
176
|
+
* // Example with object input
|
|
177
|
+
* const spec = {
|
|
178
|
+
* paths: {
|
|
179
|
+
* '/users': {
|
|
180
|
+
* $ref: 'https://example.com/schemas/users.yaml'
|
|
181
|
+
* }
|
|
182
|
+
* }
|
|
183
|
+
* }
|
|
184
|
+
*
|
|
185
|
+
* const bundled = await bundle(spec, {
|
|
186
|
+
* plugins: [fetchUrls()],
|
|
187
|
+
* treeShake: true,
|
|
188
|
+
* urlMap: true,
|
|
189
|
+
* hooks: {
|
|
190
|
+
* onResolveStart: (ref) => console.log('Resolving:', ref.$ref),
|
|
191
|
+
* onResolveSuccess: (ref) => console.log('Resolved:', ref.$ref),
|
|
192
|
+
* onResolveError: (ref) => console.log('Failed to resolve:', ref.$ref)
|
|
193
|
+
* }
|
|
194
|
+
* })
|
|
195
|
+
* // Result:
|
|
196
|
+
* // {
|
|
197
|
+
* // paths: {
|
|
198
|
+
* // '/users': {
|
|
199
|
+
* // $ref: '#/x-ext/abc123'
|
|
200
|
+
* // }
|
|
201
|
+
* // },
|
|
202
|
+
* // 'x-ext': {
|
|
203
|
+
* // 'abc123': {
|
|
204
|
+
* // // Resolved content from users.yaml
|
|
205
|
+
* // }
|
|
206
|
+
* // },
|
|
207
|
+
* // 'x-ext-urls': {
|
|
208
|
+
* // 'https://example.com/schemas/users.yaml': 'abc123'
|
|
209
|
+
* // }
|
|
210
|
+
* // }
|
|
211
|
+
*
|
|
212
|
+
* // Example with URL input
|
|
213
|
+
* const bundledFromUrl = await bundle('https://example.com/openapi.yaml', {
|
|
214
|
+
* plugins: [fetchUrls()],
|
|
215
|
+
* treeShake: true,
|
|
216
|
+
* urlMap: true,
|
|
217
|
+
* hooks: {
|
|
218
|
+
* onResolveStart: (ref) => console.log('Resolving:', ref.$ref),
|
|
219
|
+
* onResolveSuccess: (ref) => console.log('Resolved:', ref.$ref),
|
|
220
|
+
* onResolveError: (ref) => console.log('Failed to resolve:', ref.$ref)
|
|
221
|
+
* }
|
|
222
|
+
* })
|
|
223
|
+
* // The function will first fetch the OpenAPI spec from the URL,
|
|
224
|
+
* // then bundle all its external references into the x-ext section
|
|
225
|
+
*/
|
|
226
|
+
async function bundle(input, config) {
|
|
227
|
+
config.externalDocumentsKey = config.externalDocumentsKey ?? extensions.externalDocuments;
|
|
228
|
+
config.externalDocumentsMappingsKey = config.externalDocumentsMappingsKey ?? extensions.externalDocumentsMappings;
|
|
229
|
+
const cache = config.cache ?? /* @__PURE__ */ new Map();
|
|
230
|
+
const loaderPlugins = config.plugins.filter((it) => it.type === "loader");
|
|
231
|
+
const lifecyclePlugin = config.plugins.filter((it) => it.type === "lifecycle");
|
|
232
|
+
/**
|
|
233
|
+
* Resolves the input value by either returning it directly if it's not a string,
|
|
234
|
+
* or attempting to resolve it using the provided plugins if it is a string.
|
|
235
|
+
* @returns The resolved input data or throws an error if resolution fails
|
|
236
|
+
*/
|
|
237
|
+
const resolveInput = async () => {
|
|
238
|
+
if (typeof input !== "string") return input;
|
|
239
|
+
const result = await resolveContents(input, loaderPlugins);
|
|
240
|
+
if (result.ok && typeof result.data === "object") return result.data;
|
|
241
|
+
throw new Error("Failed to resolve input: Please provide a valid string value or pass a loader to process the input");
|
|
242
|
+
};
|
|
243
|
+
const rawSpecification = await resolveInput();
|
|
244
|
+
const documentRoot = config.root ?? rawSpecification;
|
|
245
|
+
const schemas = getSchemas(documentRoot);
|
|
246
|
+
const isPartialBundling = config.root !== void 0 && config.root !== rawSpecification || config.depth !== void 0;
|
|
247
|
+
const processedNodes = config.visitedNodes ?? /* @__PURE__ */ new Set();
|
|
248
|
+
const getDefaultOrigin = () => {
|
|
249
|
+
const id = getId(documentRoot);
|
|
250
|
+
if (id) return id;
|
|
251
|
+
if (config.origin) return config.origin;
|
|
252
|
+
if (typeof input !== "string") return "/";
|
|
253
|
+
if (isHttpUrl(input) || isFilePath(input)) return input;
|
|
254
|
+
return "/";
|
|
255
|
+
};
|
|
256
|
+
const defaultOrigin = getDefaultOrigin();
|
|
257
|
+
if (documentRoot[config.externalDocumentsMappingsKey] === void 0) documentRoot[config.externalDocumentsMappingsKey] = {};
|
|
258
|
+
const { generate } = uniqueValueGeneratorFactory(config.compress ?? getHash, documentRoot[config.externalDocumentsMappingsKey]);
|
|
259
|
+
/**
|
|
260
|
+
* Executes lifecycle hooks defined both in the bundler configuration and any extended lifecycle plugins.
|
|
261
|
+
* This utility function ensures that all relevant hooks for a given event type are called in order:
|
|
262
|
+
* - First, the hook directly provided via the config (if present)
|
|
263
|
+
* - Then, all matching hooks from registered lifecycle plugins (if present)
|
|
264
|
+
*
|
|
265
|
+
* Hooks are awaited in sequence for the given event type and argument list.
|
|
266
|
+
*
|
|
267
|
+
* @param type The hook event type, corresponding to a key of Config['hooks'].
|
|
268
|
+
* @param args Arguments to pass to the hook function, matching HookFn<T>.
|
|
269
|
+
*/
|
|
270
|
+
const executeHooks = async (type, ...args) => {
|
|
271
|
+
const hook = config.hooks?.[type];
|
|
272
|
+
if (hook) await hook(...args);
|
|
273
|
+
for (const plugin of lifecyclePlugin) {
|
|
274
|
+
const pluginHook = plugin[type];
|
|
275
|
+
if (pluginHook) await pluginHook(...args);
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
const bundler = async (root, origin = defaultOrigin, isChunkParent = false, depth = 0, currentPath = [], parent = null) => {
|
|
279
|
+
if (config.depth !== void 0 && depth > config.depth) return;
|
|
280
|
+
if (!isObject(root) && !Array.isArray(root)) return;
|
|
281
|
+
if (processedNodes.has(root)) return;
|
|
282
|
+
processedNodes.add(root);
|
|
283
|
+
const context = {
|
|
284
|
+
path: currentPath,
|
|
285
|
+
resolutionCache: cache,
|
|
286
|
+
parentNode: parent,
|
|
287
|
+
rootNode: documentRoot,
|
|
288
|
+
loaders: loaderPlugins
|
|
289
|
+
};
|
|
290
|
+
await executeHooks("onBeforeNodeProcess", root, context);
|
|
291
|
+
const id = getId(root);
|
|
292
|
+
if (hasRef(root)) {
|
|
293
|
+
const ref = root["$ref"];
|
|
294
|
+
const isChunk = "$global" in root && typeof root["$global"] === "boolean" && root["$global"];
|
|
295
|
+
const localRef = convertToLocalRef(ref, id ?? origin, schemas);
|
|
296
|
+
if (localRef !== void 0) {
|
|
297
|
+
if (isPartialBundling) {
|
|
298
|
+
const segments = getSegmentsFromPath(`/${localRef}`);
|
|
299
|
+
const parent = segments.length > 0 ? getValueByPath(documentRoot, segments.slice(0, -1)).value : void 0;
|
|
300
|
+
const targetValue = getValueByPath(documentRoot, segments);
|
|
301
|
+
await bundler(targetValue.value, targetValue.context, isChunkParent, depth + 1, segments, parent);
|
|
302
|
+
}
|
|
303
|
+
await executeHooks("onAfterNodeProcess", root, context);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
const [prefix, path = ""] = ref.split("#", 2);
|
|
307
|
+
const resolvedPath = resolveReferencePath(id ?? origin, prefix);
|
|
308
|
+
const relativePath = toRelativePath(resolvedPath, defaultOrigin);
|
|
309
|
+
const compressedPath = await generate(relativePath);
|
|
310
|
+
const seen = cache.has(relativePath);
|
|
311
|
+
if (!seen) cache.set(relativePath, resolveContents(resolvedPath, loaderPlugins));
|
|
312
|
+
await executeHooks("onResolveStart", root);
|
|
313
|
+
const result = await cache.get(relativePath);
|
|
314
|
+
if (result.ok) {
|
|
315
|
+
if (!seen) {
|
|
316
|
+
if (!isChunk) prefixInternalRefRecursive(result.data, [extensions.externalDocuments, compressedPath]);
|
|
317
|
+
await bundler(result.data, isChunk ? origin : resolvedPath, isChunk, depth + 1, [
|
|
318
|
+
config.externalDocumentsKey,
|
|
319
|
+
compressedPath,
|
|
320
|
+
documentRoot[config.externalDocumentsMappingsKey]
|
|
321
|
+
]);
|
|
322
|
+
setValueAtPath(documentRoot, `/${config.externalDocumentsMappingsKey}/${escapeJsonPointer(compressedPath)}`, relativePath);
|
|
323
|
+
}
|
|
324
|
+
if (config.treeShake === true) resolveAndCopyReferences(documentRoot, { [config.externalDocumentsKey]: { [compressedPath]: result.data } }, prefixInternalRef(`#${path}`, [config.externalDocumentsKey, compressedPath]).substring(1), config.externalDocumentsKey, compressedPath);
|
|
325
|
+
else if (!seen) setValueAtPath(documentRoot, `/${config.externalDocumentsKey}/${compressedPath}`, result.data);
|
|
326
|
+
root.$ref = prefixInternalRef(`#${path}`, [config.externalDocumentsKey, compressedPath]);
|
|
327
|
+
await executeHooks("onResolveSuccess", root);
|
|
328
|
+
await executeHooks("onAfterNodeProcess", root, context);
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
await executeHooks("onResolveError", root);
|
|
332
|
+
await executeHooks("onAfterNodeProcess", root, context);
|
|
333
|
+
return console.warn(`Failed to resolve external reference "${resolvedPath}". The reference may be invalid, inaccessible, or missing a loader for this type of reference.`);
|
|
334
|
+
}
|
|
335
|
+
for (const key in root) {
|
|
336
|
+
if (key === config.externalDocumentsKey || key === config.externalDocumentsMappingsKey) continue;
|
|
337
|
+
await bundler(root[key], id ?? origin, isChunkParent, depth + 1, [...currentPath, key], root);
|
|
338
|
+
}
|
|
339
|
+
await executeHooks("onAfterNodeProcess", root, context);
|
|
340
|
+
};
|
|
341
|
+
await bundler(rawSpecification);
|
|
342
|
+
if (!config.urlMap && !isPartialBundling) delete documentRoot[config.externalDocumentsMappingsKey];
|
|
343
|
+
return rawSpecification;
|
|
344
|
+
}
|
|
345
|
+
//#endregion
|
|
346
|
+
export { bundle };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { isHttpUrl } from "../../../helpers/is-http-url.js";
|
|
2
|
+
import { createLimiter } from "../../../../../../../../@scalar_helpers@0.4.3/node_modules/@scalar/helpers/dist/general/create-limiter.js";
|
|
3
|
+
import { normalize } from "../../../helpers/normalize.js";
|
|
4
|
+
//#region ../../node_modules/.pnpm/@scalar+json-magic@0.12.5/node_modules/@scalar/json-magic/dist/bundle/plugins/fetch-urls/index.js
|
|
5
|
+
/**
|
|
6
|
+
* Safely checks for host from a URL
|
|
7
|
+
* Needed because we cannot create a URL from a relative remote URL ex: examples/openapi.json
|
|
8
|
+
*/
|
|
9
|
+
const getHost = (url) => {
|
|
10
|
+
try {
|
|
11
|
+
return new URL(url).host;
|
|
12
|
+
} catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Fetches and normalizes data from a remote URL
|
|
18
|
+
* @param url - The URL to fetch data from
|
|
19
|
+
* @returns A promise that resolves to either the normalized data or an error result
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* const result = await fetchUrl('https://api.example.com/data.json')
|
|
23
|
+
* if (result.ok) {
|
|
24
|
+
* console.log(result.data) // The normalized data
|
|
25
|
+
* } else {
|
|
26
|
+
* console.log('Failed to fetch data')
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
async function fetchUrl(url, limiter, config) {
|
|
31
|
+
try {
|
|
32
|
+
const host = getHost(url);
|
|
33
|
+
const headers = config?.headers?.find((a) => a.domains.find((d) => d === host) !== void 0)?.headers;
|
|
34
|
+
const exec = config?.fetch ?? fetch;
|
|
35
|
+
const result = await limiter(() => exec(url, { headers }));
|
|
36
|
+
if (result.ok) {
|
|
37
|
+
const body = await result.text();
|
|
38
|
+
return {
|
|
39
|
+
ok: true,
|
|
40
|
+
data: normalize(body),
|
|
41
|
+
raw: body
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const contentType = result.headers.get("Content-Type") ?? "";
|
|
45
|
+
if (["text/html", "application/xml"].includes(contentType)) console.warn(`[WARN] We only support JSON/YAML formats, received ${contentType}`);
|
|
46
|
+
console.warn(`[WARN] Fetch failed with status ${result.status} ${result.statusText} for URL: ${url}`);
|
|
47
|
+
return { ok: false };
|
|
48
|
+
} catch {
|
|
49
|
+
console.warn(`[WARN] Failed to parse JSON/YAML from URL: ${url}`);
|
|
50
|
+
return { ok: false };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Creates a plugin for handling remote URL references.
|
|
55
|
+
* This plugin validates and fetches data from HTTP/HTTPS URLs.
|
|
56
|
+
*
|
|
57
|
+
* @returns A plugin object with validate and exec functions
|
|
58
|
+
* @example
|
|
59
|
+
* const urlPlugin = fetchUrls()
|
|
60
|
+
* if (urlPlugin.validate('https://example.com/schema.json')) {
|
|
61
|
+
* const result = await urlPlugin.exec('https://example.com/schema.json')
|
|
62
|
+
* }
|
|
63
|
+
*/
|
|
64
|
+
function fetchUrls(config) {
|
|
65
|
+
const limiter = config?.limit ? createLimiter(config.limit) : (fn) => fn();
|
|
66
|
+
return {
|
|
67
|
+
type: "loader",
|
|
68
|
+
validate: isHttpUrl,
|
|
69
|
+
exec: (value) => fetchUrl(value, limiter, config)
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
//#endregion
|
|
73
|
+
export { fetchUrls };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "../../../../../../../../yaml@2.8.3/node_modules/yaml/browser/index.js";
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { isFilePath } from "../../../helpers/is-file-path.js";
|
|
2
|
+
import { normalize } from "../../../helpers/normalize.js";
|
|
3
|
+
//#region ../../node_modules/.pnpm/@scalar+json-magic@0.12.5/node_modules/@scalar/json-magic/dist/bundle/plugins/read-files/index.js
|
|
4
|
+
/**
|
|
5
|
+
* Reads and normalizes data from a local file
|
|
6
|
+
* @param path - The file path to read from
|
|
7
|
+
* @returns A promise that resolves to either the normalized data or an error result
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const result = await readFile('./schemas/user.json')
|
|
11
|
+
* if (result.ok) {
|
|
12
|
+
* console.log(result.data) // The normalized data
|
|
13
|
+
* } else {
|
|
14
|
+
* console.log('Failed to read file')
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
async function readFile(path) {
|
|
19
|
+
const fs = typeof window === "undefined" ? await import("node:fs/promises") : void 0;
|
|
20
|
+
if (fs === void 0) throw "Can not use readFiles plugin outside of a node environment";
|
|
21
|
+
try {
|
|
22
|
+
const fileContents = await fs.readFile(path, { encoding: "utf-8" });
|
|
23
|
+
return {
|
|
24
|
+
ok: true,
|
|
25
|
+
data: normalize(fileContents),
|
|
26
|
+
raw: fileContents
|
|
27
|
+
};
|
|
28
|
+
} catch {
|
|
29
|
+
return { ok: false };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Creates a plugin for handling local file references.
|
|
34
|
+
* This plugin validates and reads data from local filesystem paths.
|
|
35
|
+
*
|
|
36
|
+
* @returns A plugin object with validate and exec functions
|
|
37
|
+
* @example
|
|
38
|
+
* const filePlugin = readFiles()
|
|
39
|
+
* if (filePlugin.validate('./local-schema.json')) {
|
|
40
|
+
* const result = await filePlugin.exec('./local-schema.json')
|
|
41
|
+
* }
|
|
42
|
+
*/
|
|
43
|
+
function readFiles() {
|
|
44
|
+
return {
|
|
45
|
+
type: "loader",
|
|
46
|
+
validate: isFilePath,
|
|
47
|
+
exec: readFile
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { readFiles };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { generateHash } from "../../../../../../@scalar_helpers@0.4.3/node_modules/@scalar/helpers/dist/string/generate-hash.js";
|
|
2
|
+
//#region ../../node_modules/.pnpm/@scalar+json-magic@0.12.5/node_modules/@scalar/json-magic/dist/bundle/value-generator.js
|
|
3
|
+
/**
|
|
4
|
+
* Generates a short hash from a string value using xxhash.
|
|
5
|
+
*
|
|
6
|
+
* This function is used to create unique identifiers for external references
|
|
7
|
+
* while keeping the hash length manageable. It uses xxhash-wasm instead of
|
|
8
|
+
* crypto.subtle because crypto.subtle is only available in secure contexts (HTTPS) or on localhost.
|
|
9
|
+
* Returns the first 7 characters of the hash string.
|
|
10
|
+
* If the hash would be all numbers, it ensures at least one letter is included.
|
|
11
|
+
*
|
|
12
|
+
* @param value - The string to hash
|
|
13
|
+
* @returns A Promise that resolves to a 7-character hexadecimal hash with at least one letter
|
|
14
|
+
* @example
|
|
15
|
+
* // Returns "2ae91d7"
|
|
16
|
+
* getHash("https://example.com/schema.json")
|
|
17
|
+
*/
|
|
18
|
+
function getHash(value) {
|
|
19
|
+
const hash = generateHash(value).substring(0, 7);
|
|
20
|
+
return hash.match(/^\d+$/) ? "a" + hash.substring(1) : hash;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Generates a unique compressed value for a string, handling collisions by recursively compressing
|
|
24
|
+
* until a unique value is found. This is used to create unique identifiers for external
|
|
25
|
+
* references in the bundled OpenAPI document.
|
|
26
|
+
*
|
|
27
|
+
* @param compress - Function that generates a compressed value from a string
|
|
28
|
+
* @param value - The original string value to compress
|
|
29
|
+
* @param compressedToValue - Object mapping compressed values to their original values
|
|
30
|
+
* @param prevCompressedValue - Optional previous compressed value to use as input for generating a new value
|
|
31
|
+
* @param depth - Current recursion depth to prevent infinite loops
|
|
32
|
+
* @returns A unique compressed value that doesn't conflict with existing values
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* const valueMap = {}
|
|
36
|
+
* // First call generates compressed value for "example.com/schema.json"
|
|
37
|
+
* const value1 = await generateUniqueValue(compress, "example.com/schema.json", valueMap)
|
|
38
|
+
* // Returns something like "2ae91d7"
|
|
39
|
+
*
|
|
40
|
+
* // Second call with same value returns same compressed value
|
|
41
|
+
* const value2 = await generateUniqueValue(compress, "example.com/schema.json", valueMap)
|
|
42
|
+
* // Returns same value as value1
|
|
43
|
+
*
|
|
44
|
+
* // Call with different value generates new unique compressed value
|
|
45
|
+
* const value3 = await generateUniqueValue(compress, "example.com/other.json", valueMap)
|
|
46
|
+
* // Returns different value like "3bf82e9"
|
|
47
|
+
*/
|
|
48
|
+
async function generateUniqueValue(compress, value, compressedToValue, prevCompressedValue, depth = 0) {
|
|
49
|
+
if (depth >= 100) throw "Can not generate unique compressed values";
|
|
50
|
+
const compressedValue = await compress(prevCompressedValue ?? value);
|
|
51
|
+
if (compressedToValue[compressedValue] !== void 0 && compressedToValue[compressedValue] !== value) return generateUniqueValue(compress, value, compressedToValue, compressedValue, depth + 1);
|
|
52
|
+
compressedToValue[compressedValue] = value;
|
|
53
|
+
return compressedValue;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Factory function that creates a value generator with caching capabilities.
|
|
57
|
+
* The generator maintains a bidirectional mapping between original values and their compressed forms.
|
|
58
|
+
*
|
|
59
|
+
* @param compress - Function that generates a compressed value from a string
|
|
60
|
+
* @param compressedToValue - Initial mapping of compressed values to their original values
|
|
61
|
+
* @returns An object with a generate method that produces unique compressed values
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* const compress = (value) => value.substring(0, 6) // Simple compression example
|
|
65
|
+
* const initialMap = { 'abc123': 'example.com/schema.json' }
|
|
66
|
+
* const generator = uniqueValueGeneratorFactory(compress, initialMap)
|
|
67
|
+
*
|
|
68
|
+
* // Generate compressed value for new string
|
|
69
|
+
* const compressed = await generator.generate('example.com/other.json')
|
|
70
|
+
* // Returns something like 'example'
|
|
71
|
+
*
|
|
72
|
+
* // Generate compressed value for existing string
|
|
73
|
+
* const cached = await generator.generate('example.com/schema.json')
|
|
74
|
+
* // Returns 'abc123' from cache
|
|
75
|
+
*/
|
|
76
|
+
const uniqueValueGeneratorFactory = (compress, compressedToValue) => {
|
|
77
|
+
const valueToCompressed = Object.fromEntries(Object.entries(compressedToValue).map(([key, value]) => [value, key]));
|
|
78
|
+
return { generate: async (value) => {
|
|
79
|
+
const cache = valueToCompressed[value];
|
|
80
|
+
if (cache) return cache;
|
|
81
|
+
const generatedValue = await generateUniqueValue(compress, value, compressedToValue);
|
|
82
|
+
const compressedValue = generatedValue.match(/^\d+$/) ? `a${generatedValue}` : generatedValue;
|
|
83
|
+
valueToCompressed[value] = compressedValue;
|
|
84
|
+
return compressedValue;
|
|
85
|
+
} };
|
|
86
|
+
};
|
|
87
|
+
//#endregion
|
|
88
|
+
export { getHash, uniqueValueGeneratorFactory };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//#region ../../node_modules/.pnpm/@scalar+json-magic@0.12.5/node_modules/@scalar/json-magic/dist/helpers/convert-to-local-ref.js
|
|
2
|
+
/**
|
|
3
|
+
* Translates a JSON Reference ($ref) to a local object path within the root schema.
|
|
4
|
+
*
|
|
5
|
+
* @param ref - The JSON Reference string (e.g., "#/foo/bar", "other.json#/baz", "other.json#anchor")
|
|
6
|
+
* @param currentContext - The current base context (usually the $id of the current schema or parent)
|
|
7
|
+
* @param schemas - A map of schema identifiers ($id, $anchor) to their local object paths
|
|
8
|
+
* @returns The local object path as a string, or undefined if the reference cannot be resolved
|
|
9
|
+
*/
|
|
10
|
+
const convertToLocalRef = (ref, currentContext, schemas) => {
|
|
11
|
+
const [baseUrl, pathOrAnchor] = ref.split("#", 2);
|
|
12
|
+
if (baseUrl) {
|
|
13
|
+
if (!schemas.has(baseUrl)) return;
|
|
14
|
+
if (!pathOrAnchor) return schemas.get(baseUrl);
|
|
15
|
+
if (pathOrAnchor.startsWith("/")) return `${schemas.get(baseUrl)}${pathOrAnchor}`;
|
|
16
|
+
return schemas.get(`${baseUrl}#${pathOrAnchor}`);
|
|
17
|
+
}
|
|
18
|
+
if (pathOrAnchor) {
|
|
19
|
+
if (pathOrAnchor.startsWith("/")) return pathOrAnchor.slice(1);
|
|
20
|
+
return schemas.get(`${currentContext}#${pathOrAnchor}`);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
//#endregion
|
|
24
|
+
export { convertToLocalRef };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region ../../node_modules/.pnpm/@scalar+json-magic@0.12.5/node_modules/@scalar/json-magic/dist/helpers/escape-json-pointer.js
|
|
2
|
+
/**
|
|
3
|
+
* Escapes a JSON pointer string.
|
|
4
|
+
*
|
|
5
|
+
* Example: `/foo/bar~baz` -> `'~1foo~1bar~0baz'`
|
|
6
|
+
*/
|
|
7
|
+
function escapeJsonPointer(str) {
|
|
8
|
+
return str.replace(/~/g, "~0").replace(/\//g, "~1");
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
export { escapeJsonPointer };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//#region ../../node_modules/.pnpm/@scalar+json-magic@0.12.5/node_modules/@scalar/json-magic/dist/helpers/get-schemas.js
|
|
2
|
+
/**
|
|
3
|
+
* Retrieves the $id property from the input object if it exists and is a string.
|
|
4
|
+
*
|
|
5
|
+
* @param input - The object to extract the $id from.
|
|
6
|
+
* @returns The $id string if present, otherwise undefined.
|
|
7
|
+
*/
|
|
8
|
+
const getId = (input) => {
|
|
9
|
+
if (input && typeof input === "object" && input["$id"] && typeof input["$id"] === "string") return input["$id"];
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Joins an array of path segments into a single string separated by '/'.
|
|
13
|
+
*
|
|
14
|
+
* @param segments - The array of path segments.
|
|
15
|
+
* @returns The joined path string.
|
|
16
|
+
*/
|
|
17
|
+
const getPath = (segments) => {
|
|
18
|
+
return segments.join("/");
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Recursively traverses the input object to collect all schemas identified by $id and $anchor properties.
|
|
22
|
+
*
|
|
23
|
+
* - If an object has a $id property, it is added to the map with its $id as the key.
|
|
24
|
+
* - If an object has a $anchor property, it is added to the map with a key composed of the current base and the anchor.
|
|
25
|
+
* - The function performs a depth-first search (DFS) through all nested objects.
|
|
26
|
+
*
|
|
27
|
+
* @param input - The input object to traverse.
|
|
28
|
+
* @param base - The current base URI, used for resolving anchors.
|
|
29
|
+
* @param map - The map collecting found schemas.
|
|
30
|
+
* @returns A map of schema identifiers to their corresponding objects.
|
|
31
|
+
*/
|
|
32
|
+
const getSchemas = (input, base = "", segments = [], map = /* @__PURE__ */ new Map(), visited = /* @__PURE__ */ new WeakSet()) => {
|
|
33
|
+
if (typeof input !== "object" || input === null) return map;
|
|
34
|
+
if (visited.has(input)) return map;
|
|
35
|
+
visited.add(input);
|
|
36
|
+
const id = getId(input);
|
|
37
|
+
if (id) map.set(id, getPath(segments));
|
|
38
|
+
const newBase = id ?? base;
|
|
39
|
+
if (input["$anchor"] && typeof input["$anchor"] === "string") map.set(`${newBase}#${input["$anchor"]}`, getPath(segments));
|
|
40
|
+
for (const key in input) if (typeof input[key] === "object" && input[key] !== null) getSchemas(input[key], newBase, [...segments, key], map, visited);
|
|
41
|
+
return map;
|
|
42
|
+
};
|
|
43
|
+
//#endregion
|
|
44
|
+
export { getId, getSchemas };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { unescapeJsonPointer } from "./unescape-json-pointer.js";
|
|
2
|
+
//#region ../../node_modules/.pnpm/@scalar+json-magic@0.12.5/node_modules/@scalar/json-magic/dist/helpers/get-segments-from-path.js
|
|
3
|
+
/**
|
|
4
|
+
* Translate `/paths/~1test` to `['paths', '/test']`
|
|
5
|
+
*/
|
|
6
|
+
function getSegmentsFromPath(path) {
|
|
7
|
+
return path.split("/").slice(1).map(unescapeJsonPointer);
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
export { getSegmentsFromPath };
|