@kubb/ast 5.0.0-beta.61 → 5.0.0-beta.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{defineMacro-BLIR6k-j.d.ts → defineMacro-BATi7xoC.d.ts} +11 -20
- package/dist/{defineMacro-Bv9R_9a2.cjs → defineMacro-CEZHaCXE.cjs} +13 -21
- package/dist/defineMacro-CEZHaCXE.cjs.map +1 -0
- package/dist/{defineMacro-BTXvS8nI.js → defineMacro-Shz8f6SG.js} +12 -19
- package/dist/defineMacro-Shz8f6SG.js.map +1 -0
- package/dist/factory.cjs +88 -28
- package/dist/factory.cjs.map +1 -0
- package/dist/factory.d.ts +6 -41
- package/dist/factory.js +58 -3
- package/dist/factory.js.map +1 -0
- package/dist/{index-BzjwdK2M.d.ts → index-B9cc8MBS.d.ts} +164 -194
- package/dist/index.cjs +144 -274
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +43 -37
- package/dist/index.js +109 -235
- package/dist/index.js.map +1 -1
- package/dist/macros.cjs +41 -28
- package/dist/macros.cjs.map +1 -1
- package/dist/macros.d.ts +14 -12
- package/dist/macros.js +34 -21
- package/dist/macros.js.map +1 -1
- package/dist/{operationParams-BZ07xDm0.d.ts → operationParams-k5CKwSWZ.d.ts} +9 -2
- package/dist/{visitor-DJ6ZEJvq.js → refs-BjNDuCBD.js} +116 -159
- package/dist/refs-BjNDuCBD.js.map +1 -0
- package/dist/{visitor-DpKZ9Tk0.cjs → refs-u5SDdyV7.cjs} +140 -195
- package/dist/refs-u5SDdyV7.cjs.map +1 -0
- package/dist/{response-hnSw2NKE.cjs → schema-BkvrrOAr.cjs} +496 -231
- package/dist/schema-BkvrrOAr.cjs.map +1 -0
- package/dist/{response-KUdWiDWw.js → schema-Cbnxmz4b.js} +472 -220
- package/dist/schema-Cbnxmz4b.js.map +1 -0
- package/dist/{types-DyDzizSf.d.ts → types-BB_xgRJ3.d.ts} +49 -123
- package/dist/types.d.ts +5 -6
- package/dist/{utils-BLJwyza-.cjs → utils-CEepwqmb.cjs} +76 -69
- package/dist/utils-CEepwqmb.cjs.map +1 -0
- package/dist/{utils-CF_-Pn_c.js → utils-DaXkewb1.js} +58 -51
- package/dist/utils-DaXkewb1.js.map +1 -0
- package/dist/utils.cjs +11 -11
- package/dist/utils.d.ts +53 -30
- package/dist/utils.js +3 -3
- package/package.json +1 -1
- package/src/constants.ts +3 -36
- package/src/defineMacro.ts +20 -13
- package/src/{node.ts → defineNode.ts} +12 -38
- package/src/{printer.ts → definePrinter.ts} +5 -3
- package/src/dialect.ts +52 -19
- package/src/factory.ts +7 -94
- package/src/index.ts +7 -9
- package/src/infer.ts +1 -1
- package/src/macros/macroDiscriminatorEnum.ts +7 -1
- package/src/macros/macroEnumName.ts +10 -2
- package/src/macros/macroSimplifyUnion.ts +29 -19
- package/src/nodes/code.ts +40 -80
- package/src/nodes/content.ts +2 -7
- package/src/nodes/file.ts +107 -18
- package/src/nodes/function.ts +46 -46
- package/src/nodes/index.ts +2 -3
- package/src/nodes/input.ts +13 -9
- package/src/nodes/operation.ts +8 -5
- package/src/nodes/output.ts +1 -1
- package/src/nodes/parameter.ts +5 -5
- package/src/nodes/property.ts +5 -5
- package/src/nodes/requestBody.ts +6 -13
- package/src/nodes/response.ts +93 -8
- package/src/nodes/schema.ts +5 -5
- package/src/optionality.ts +15 -0
- package/src/registry.ts +1 -1
- package/src/types.ts +4 -6
- package/src/utils/codegen.ts +6 -7
- package/src/utils/extractStringsFromNodes.ts +1 -0
- package/src/utils/fileMerge.ts +7 -8
- package/src/utils/operationParams.ts +9 -9
- package/src/utils/refs.ts +14 -18
- package/src/utils/schemaGraph.ts +41 -33
- package/src/utils/schemaMerge.ts +2 -2
- package/src/visitor.ts +3 -14
- package/dist/defineMacro-BTXvS8nI.js.map +0 -1
- package/dist/defineMacro-Bv9R_9a2.cjs.map +0 -1
- package/dist/extractStringsFromNodes-Cja-xxx5.js +0 -29
- package/dist/extractStringsFromNodes-Cja-xxx5.js.map +0 -1
- package/dist/extractStringsFromNodes-DKgDjFO0.cjs +0 -34
- package/dist/extractStringsFromNodes-DKgDjFO0.cjs.map +0 -1
- package/dist/extractStringsFromNodes-p4mX1TQD.d.ts +0 -14
- package/dist/factory-CZNOGI-N.js +0 -283
- package/dist/factory-CZNOGI-N.js.map +0 -1
- package/dist/factory-DG1CVkEb.cjs +0 -300
- package/dist/factory-DG1CVkEb.cjs.map +0 -1
- package/dist/response-KUdWiDWw.js.map +0 -1
- package/dist/response-hnSw2NKE.cjs.map +0 -1
- package/dist/utils-BLJwyza-.cjs.map +0 -1
- package/dist/utils-CF_-Pn_c.js.map +0 -1
- package/dist/visitor-DJ6ZEJvq.js.map +0 -1
- package/dist/visitor-DpKZ9Tk0.cjs.map +0 -1
- package/src/dedupe.ts +0 -239
- package/src/mocks.ts +0 -56
- package/src/nodes/http.ts +0 -85
|
@@ -33,58 +33,52 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
33
33
|
enumerable: true
|
|
34
34
|
}) : target, mod));
|
|
35
35
|
//#endregion
|
|
36
|
-
|
|
36
|
+
let node_crypto = require("node:crypto");
|
|
37
|
+
let node_path = require("node:path");
|
|
38
|
+
node_path = __toESM(node_path, 1);
|
|
39
|
+
//#region src/defineNode.ts
|
|
37
40
|
/**
|
|
38
|
-
*
|
|
41
|
+
* Visitor callback names, one per traversable node kind, in traversal order.
|
|
42
|
+
* Kept in sync with the keys of `Visitor` in `visitor.ts`.
|
|
39
43
|
*/
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
const visitorKeys = [
|
|
45
|
+
"input",
|
|
46
|
+
"output",
|
|
47
|
+
"operation",
|
|
48
|
+
"schema",
|
|
49
|
+
"property",
|
|
50
|
+
"parameter",
|
|
51
|
+
"response"
|
|
52
|
+
];
|
|
43
53
|
/**
|
|
44
|
-
*
|
|
45
|
-
* value and the schema's own `nullable`. Mirrors how OpenAPI parameters and
|
|
46
|
-
* object properties combine "required" and "nullable" into a single AST.
|
|
47
|
-
*
|
|
48
|
-
* - Non-required + non-nullable → `optional: true`.
|
|
49
|
-
* - Non-required + nullable → `nullish: true`.
|
|
50
|
-
* - Required → both flags cleared.
|
|
54
|
+
* Builds a type guard that matches nodes of the given `kind`.
|
|
51
55
|
*/
|
|
52
|
-
function
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
...schema,
|
|
56
|
-
optional: !required && !nullable ? true : void 0,
|
|
57
|
-
nullish: !required && nullable ? true : void 0
|
|
58
|
-
};
|
|
56
|
+
function isKind(kind) {
|
|
57
|
+
return (node) => node?.kind === kind;
|
|
59
58
|
}
|
|
60
59
|
/**
|
|
61
60
|
* Defines a node once and derives its `create` builder, `is` guard, and traversal
|
|
62
61
|
* metadata. `create` merges `defaults`, the `build` hook (or the raw input), and the
|
|
63
62
|
* `kind`, so node construction lives in one place without scattered `as` casts.
|
|
64
63
|
*
|
|
65
|
-
* Set `rebuild: true` when the `build` hook derives fields from children. After a
|
|
66
|
-
* transform rewrites those children, the registry reruns `create` so the derived
|
|
67
|
-
* fields stay correct.
|
|
68
|
-
*
|
|
69
64
|
* @example Simple node
|
|
70
65
|
* ```ts
|
|
71
66
|
* const importDef = defineNode<ImportNode>({ kind: 'Import' })
|
|
72
67
|
* const createImport = importDef.create
|
|
73
68
|
* ```
|
|
74
69
|
*
|
|
75
|
-
* @example Node with a build hook
|
|
70
|
+
* @example Node with a build hook
|
|
76
71
|
* ```ts
|
|
77
72
|
* const propertyDef = defineNode<PropertyNode, UserPropertyNode>({
|
|
78
73
|
* kind: 'Property',
|
|
79
74
|
* build: (props) => ({ ...props, required: props.required ?? false }),
|
|
80
75
|
* children: ['schema'],
|
|
81
76
|
* visitorKey: 'property',
|
|
82
|
-
* rebuild: true,
|
|
83
77
|
* })
|
|
84
78
|
* ```
|
|
85
79
|
*/
|
|
86
80
|
function defineNode(config) {
|
|
87
|
-
const { kind, defaults, build, children, visitorKey
|
|
81
|
+
const { kind, defaults, build, children, visitorKey } = config;
|
|
88
82
|
function create(input) {
|
|
89
83
|
const base = build ? build(input) : input;
|
|
90
84
|
return {
|
|
@@ -98,110 +92,48 @@ function defineNode(config) {
|
|
|
98
92
|
create,
|
|
99
93
|
is: isKind(kind),
|
|
100
94
|
children,
|
|
101
|
-
visitorKey
|
|
102
|
-
rebuild
|
|
95
|
+
visitorKey
|
|
103
96
|
};
|
|
104
97
|
}
|
|
105
98
|
//#endregion
|
|
106
|
-
//#region src/nodes/
|
|
99
|
+
//#region src/nodes/code.ts
|
|
107
100
|
/**
|
|
108
|
-
*
|
|
109
|
-
* Primitive types map to themselves. Special string formats map to `'string'`.
|
|
110
|
-
* Complex types (`ref`, `enum`, `union`, `intersection`, `tuple`, `blob`) are left unset.
|
|
101
|
+
* Definition for the {@link ConstNode}.
|
|
111
102
|
*/
|
|
112
|
-
const
|
|
113
|
-
string: "string",
|
|
114
|
-
number: "number",
|
|
115
|
-
integer: "integer",
|
|
116
|
-
bigint: "bigint",
|
|
117
|
-
boolean: "boolean",
|
|
118
|
-
null: "null",
|
|
119
|
-
any: "any",
|
|
120
|
-
unknown: "unknown",
|
|
121
|
-
void: "void",
|
|
122
|
-
never: "never",
|
|
123
|
-
object: "object",
|
|
124
|
-
array: "array",
|
|
125
|
-
date: "date",
|
|
126
|
-
uuid: "string",
|
|
127
|
-
email: "string",
|
|
128
|
-
url: "string",
|
|
129
|
-
datetime: "string",
|
|
130
|
-
time: "string"
|
|
131
|
-
};
|
|
103
|
+
const constDef = defineNode({ kind: "Const" });
|
|
132
104
|
/**
|
|
133
|
-
* Definition for the {@link
|
|
134
|
-
* empty array, and `primitive` is inferred from `type` when not explicitly provided.
|
|
105
|
+
* Definition for the {@link TypeNode}.
|
|
135
106
|
*/
|
|
136
|
-
const
|
|
137
|
-
kind: "Schema",
|
|
138
|
-
build: (props) => {
|
|
139
|
-
if (props.type === "object") return {
|
|
140
|
-
properties: [],
|
|
141
|
-
primitive: "object",
|
|
142
|
-
...props
|
|
143
|
-
};
|
|
144
|
-
return {
|
|
145
|
-
primitive: TYPE_TO_PRIMITIVE[props.type],
|
|
146
|
-
...props
|
|
147
|
-
};
|
|
148
|
-
},
|
|
149
|
-
children: [
|
|
150
|
-
"properties",
|
|
151
|
-
"items",
|
|
152
|
-
"members",
|
|
153
|
-
"additionalProperties"
|
|
154
|
-
],
|
|
155
|
-
visitorKey: "schema"
|
|
156
|
-
});
|
|
157
|
-
function createSchema(props) {
|
|
158
|
-
return schemaDef.create(props);
|
|
159
|
-
}
|
|
160
|
-
//#endregion
|
|
161
|
-
//#region ../../internals/utils/src/casing.ts
|
|
107
|
+
const typeDef = defineNode({ kind: "Type" });
|
|
162
108
|
/**
|
|
163
|
-
*
|
|
164
|
-
* Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
|
|
165
|
-
* and capitalizes each word according to `pascal`.
|
|
166
|
-
*
|
|
167
|
-
* When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
|
|
109
|
+
* Definition for the {@link FunctionNode}.
|
|
168
110
|
*/
|
|
169
|
-
|
|
170
|
-
return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => {
|
|
171
|
-
if (word.length > 1 && word === word.toUpperCase()) return word;
|
|
172
|
-
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
|
|
173
|
-
}).join("").replace(/[^a-zA-Z0-9]/g, "");
|
|
174
|
-
}
|
|
111
|
+
const functionDef = defineNode({ kind: "Function" });
|
|
175
112
|
/**
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
* @example Word boundaries
|
|
179
|
-
* `camelCase('hello-world') // 'helloWorld'`
|
|
180
|
-
*
|
|
181
|
-
* @example With a prefix
|
|
182
|
-
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
|
|
113
|
+
* Definition for the {@link ArrowFunctionNode}.
|
|
183
114
|
*/
|
|
184
|
-
|
|
185
|
-
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
|
|
186
|
-
}
|
|
115
|
+
const arrowFunctionDef = defineNode({ kind: "ArrowFunction" });
|
|
187
116
|
/**
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
* @example Word boundaries
|
|
191
|
-
* `pascalCase('hello-world') // 'HelloWorld'`
|
|
192
|
-
*
|
|
193
|
-
* @example With a suffix
|
|
194
|
-
* `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`
|
|
117
|
+
* Definition for the {@link TextNode}.
|
|
195
118
|
*/
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
//#region src/nodes/code.ts
|
|
119
|
+
const textDef = defineNode({
|
|
120
|
+
kind: "Text",
|
|
121
|
+
build: (value) => ({ value })
|
|
122
|
+
});
|
|
201
123
|
/**
|
|
202
|
-
* Definition for the {@link
|
|
124
|
+
* Definition for the {@link BreakNode}.
|
|
203
125
|
*/
|
|
204
|
-
const
|
|
126
|
+
const breakDef = defineNode({
|
|
127
|
+
kind: "Break",
|
|
128
|
+
build: () => ({})
|
|
129
|
+
});
|
|
130
|
+
/**
|
|
131
|
+
* Definition for the {@link JsxNode}.
|
|
132
|
+
*/
|
|
133
|
+
const jsxDef = defineNode({
|
|
134
|
+
kind: "Jsx",
|
|
135
|
+
build: (value) => ({ value })
|
|
136
|
+
});
|
|
205
137
|
/**
|
|
206
138
|
* Creates a `ConstNode` representing a TypeScript `const` declaration.
|
|
207
139
|
*
|
|
@@ -213,10 +145,6 @@ const constDef = defineNode({ kind: "Const" });
|
|
|
213
145
|
*/
|
|
214
146
|
const createConst = constDef.create;
|
|
215
147
|
/**
|
|
216
|
-
* Definition for the {@link TypeNode}.
|
|
217
|
-
*/
|
|
218
|
-
const typeDef = defineNode({ kind: "Type" });
|
|
219
|
-
/**
|
|
220
148
|
* Creates a `TypeNode` representing a TypeScript `type` alias declaration.
|
|
221
149
|
*
|
|
222
150
|
* @example
|
|
@@ -227,10 +155,6 @@ const typeDef = defineNode({ kind: "Type" });
|
|
|
227
155
|
*/
|
|
228
156
|
const createType = typeDef.create;
|
|
229
157
|
/**
|
|
230
|
-
* Definition for the {@link FunctionNode}.
|
|
231
|
-
*/
|
|
232
|
-
const functionDef = defineNode({ kind: "Function" });
|
|
233
|
-
/**
|
|
234
158
|
* Creates a `FunctionNode` representing a TypeScript `function` declaration.
|
|
235
159
|
*
|
|
236
160
|
* @example
|
|
@@ -241,10 +165,6 @@ const functionDef = defineNode({ kind: "Function" });
|
|
|
241
165
|
*/
|
|
242
166
|
const createFunction = functionDef.create;
|
|
243
167
|
/**
|
|
244
|
-
* Definition for the {@link ArrowFunctionNode}.
|
|
245
|
-
*/
|
|
246
|
-
const arrowFunctionDef = defineNode({ kind: "ArrowFunction" });
|
|
247
|
-
/**
|
|
248
168
|
* Creates an `ArrowFunctionNode` representing a TypeScript arrow function.
|
|
249
169
|
*
|
|
250
170
|
* @example
|
|
@@ -255,13 +175,6 @@ const arrowFunctionDef = defineNode({ kind: "ArrowFunction" });
|
|
|
255
175
|
*/
|
|
256
176
|
const createArrowFunction = arrowFunctionDef.create;
|
|
257
177
|
/**
|
|
258
|
-
* Definition for the {@link TextNode}.
|
|
259
|
-
*/
|
|
260
|
-
const textDef = defineNode({
|
|
261
|
-
kind: "Text",
|
|
262
|
-
build: (value) => ({ value })
|
|
263
|
-
});
|
|
264
|
-
/**
|
|
265
178
|
* Creates a {@link TextNode} representing a raw string fragment in the source output.
|
|
266
179
|
*
|
|
267
180
|
* @example
|
|
@@ -272,13 +185,6 @@ const textDef = defineNode({
|
|
|
272
185
|
*/
|
|
273
186
|
const createText = textDef.create;
|
|
274
187
|
/**
|
|
275
|
-
* Definition for the {@link BreakNode}.
|
|
276
|
-
*/
|
|
277
|
-
const breakDef = defineNode({
|
|
278
|
-
kind: "Break",
|
|
279
|
-
build: () => ({})
|
|
280
|
-
});
|
|
281
|
-
/**
|
|
282
188
|
* Creates a {@link BreakNode} representing a line break in the source output.
|
|
283
189
|
*
|
|
284
190
|
* @example
|
|
@@ -291,13 +197,6 @@ function createBreak() {
|
|
|
291
197
|
return breakDef.create();
|
|
292
198
|
}
|
|
293
199
|
/**
|
|
294
|
-
* Definition for the {@link JsxNode}.
|
|
295
|
-
*/
|
|
296
|
-
const jsxDef = defineNode({
|
|
297
|
-
kind: "Jsx",
|
|
298
|
-
build: (value) => ({ value })
|
|
299
|
-
});
|
|
300
|
-
/**
|
|
301
200
|
* Creates a {@link JsxNode} representing a raw JSX fragment in the source output.
|
|
302
201
|
*
|
|
303
202
|
* @example
|
|
@@ -321,12 +220,252 @@ const contentDef = defineNode({
|
|
|
321
220
|
*/
|
|
322
221
|
const createContent = contentDef.create;
|
|
323
222
|
//#endregion
|
|
223
|
+
//#region ../../internals/utils/src/casing.ts
|
|
224
|
+
/**
|
|
225
|
+
* Shared implementation for camelCase and PascalCase conversion.
|
|
226
|
+
* Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)
|
|
227
|
+
* and capitalizes each word according to `pascal`.
|
|
228
|
+
*
|
|
229
|
+
* When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.
|
|
230
|
+
*/
|
|
231
|
+
function toCamelOrPascal(text, pascal) {
|
|
232
|
+
return text.trim().replace(/([a-z\d])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/(\d)([a-z])/g, "$1 $2").split(/[\s\-_./\\:]+/).filter(Boolean).map((word, i) => {
|
|
233
|
+
if (word.length > 1 && word === word.toUpperCase()) return word;
|
|
234
|
+
return (i === 0 && !pascal ? word.charAt(0).toLowerCase() : word.charAt(0).toUpperCase()) + word.slice(1);
|
|
235
|
+
}).join("").replace(/[^a-zA-Z0-9]/g, "");
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Converts `text` to camelCase.
|
|
239
|
+
*
|
|
240
|
+
* @example Word boundaries
|
|
241
|
+
* `camelCase('hello-world') // 'helloWorld'`
|
|
242
|
+
*
|
|
243
|
+
* @example With a prefix
|
|
244
|
+
* `camelCase('tag', { prefix: 'create' }) // 'createTag'`
|
|
245
|
+
*/
|
|
246
|
+
function camelCase(text, { prefix = "", suffix = "" } = {}) {
|
|
247
|
+
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Converts `text` to PascalCase.
|
|
251
|
+
*
|
|
252
|
+
* @example Word boundaries
|
|
253
|
+
* `pascalCase('hello-world') // 'HelloWorld'`
|
|
254
|
+
*
|
|
255
|
+
* @example With a suffix
|
|
256
|
+
* `pascalCase('tag', { suffix: 'schema' }) // 'TagSchema'`
|
|
257
|
+
*/
|
|
258
|
+
function pascalCase(text, { prefix = "", suffix = "" } = {}) {
|
|
259
|
+
return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true);
|
|
260
|
+
}
|
|
261
|
+
//#endregion
|
|
262
|
+
//#region ../../internals/utils/src/fs.ts
|
|
263
|
+
/**
|
|
264
|
+
* Strips the file extension from a path or file name.
|
|
265
|
+
* Only removes the last `.ext` segment when the dot is not part of a directory name.
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* trimExtName('petStore.ts') // 'petStore'
|
|
269
|
+
* trimExtName('/src/models/pet.ts') // '/src/models/pet'
|
|
270
|
+
* trimExtName('/project.v2/gen/pet.ts') // '/project.v2/gen/pet'
|
|
271
|
+
* trimExtName('noExtension') // 'noExtension'
|
|
272
|
+
*/
|
|
273
|
+
function trimExtName(text) {
|
|
274
|
+
const dotIndex = text.lastIndexOf(".");
|
|
275
|
+
if (dotIndex > 0 && !text.includes("/", dotIndex)) return text.slice(0, dotIndex);
|
|
276
|
+
return text;
|
|
277
|
+
}
|
|
278
|
+
//#endregion
|
|
279
|
+
//#region src/utils/extractStringsFromNodes.ts
|
|
280
|
+
/**
|
|
281
|
+
* Extracts all string content from a `CodeNode` tree recursively.
|
|
282
|
+
*
|
|
283
|
+
* Collects text node values, identifier references in string fields (`params`, `generics`, `returnType`, `type`),
|
|
284
|
+
* and nested node content. Used to build the full source string for import filtering.
|
|
285
|
+
*/
|
|
286
|
+
function extractStringsFromNodes(nodes) {
|
|
287
|
+
if (!nodes?.length) return "";
|
|
288
|
+
return nodes.map((node) => {
|
|
289
|
+
if (typeof node === "string") return node;
|
|
290
|
+
if (node.kind === "Text") return node.value;
|
|
291
|
+
if (node.kind === "Break") return "";
|
|
292
|
+
if (node.kind === "Jsx") return node.value;
|
|
293
|
+
const parts = [];
|
|
294
|
+
if ("params" in node && node.params) parts.push(node.params);
|
|
295
|
+
if ("generics" in node && node.generics) parts.push(Array.isArray(node.generics) ? node.generics.join(", ") : node.generics);
|
|
296
|
+
if ("returnType" in node && node.returnType) parts.push(node.returnType);
|
|
297
|
+
if ("type" in node && typeof node.type === "string") parts.push(node.type);
|
|
298
|
+
const nested = extractStringsFromNodes(node.nodes);
|
|
299
|
+
if (nested) parts.push(nested);
|
|
300
|
+
return parts.join("\n");
|
|
301
|
+
}).filter(Boolean).join("\n");
|
|
302
|
+
}
|
|
303
|
+
//#endregion
|
|
304
|
+
//#region src/utils/fileMerge.ts
|
|
305
|
+
function sourceKey(source) {
|
|
306
|
+
return `${source.name ?? extractStringsFromNodes(source.nodes)}:${source.isExportable ?? false}:${source.isTypeOnly ?? false}`;
|
|
307
|
+
}
|
|
308
|
+
function pathTypeKey(path, isTypeOnly) {
|
|
309
|
+
return `${path}:${isTypeOnly ?? false}`;
|
|
310
|
+
}
|
|
311
|
+
function exportKey(path, name, isTypeOnly, asAlias) {
|
|
312
|
+
return `${path}:${name ?? ""}:${isTypeOnly ?? false}:${asAlias ?? ""}`;
|
|
313
|
+
}
|
|
314
|
+
function importKey(path, name, isTypeOnly) {
|
|
315
|
+
return `${path}:${name ?? ""}:${isTypeOnly ?? false}`;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Computes a multi-level sort key for exports and imports:
|
|
319
|
+
* non-array names first (wildcards/namespace aliases). Type-only before value. Alphabetical path. Unnamed before named.
|
|
320
|
+
*/
|
|
321
|
+
function sortKey(node) {
|
|
322
|
+
const isArray = Array.isArray(node.name) ? "1" : "0";
|
|
323
|
+
const typeOnly = node.isTypeOnly ? "0" : "1";
|
|
324
|
+
const hasName = node.name != null ? "1" : "0";
|
|
325
|
+
const name = Array.isArray(node.name) ? node.name.toSorted().join("\0") : node.name ?? "";
|
|
326
|
+
return `${isArray}:${typeOnly}:${node.path}:${hasName}:${name}`;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Deduplicates `SourceNode` objects by `name + isExportable + isTypeOnly`, keeping the first of each
|
|
330
|
+
* key. Unnamed sources fall back to their extracted node strings as the name part of the key. Returns
|
|
331
|
+
* the deduplicated array in original order.
|
|
332
|
+
*/
|
|
333
|
+
function combineSources(sources) {
|
|
334
|
+
const seen = /* @__PURE__ */ new Map();
|
|
335
|
+
for (const source of sources) {
|
|
336
|
+
const key = sourceKey(source);
|
|
337
|
+
if (!seen.has(key)) seen.set(key, source);
|
|
338
|
+
}
|
|
339
|
+
return [...seen.values()];
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Merges `incoming` names into `existing`, preserving order and dropping duplicates.
|
|
343
|
+
*
|
|
344
|
+
* Shared by `combineExports` and `combineImports` for the same-path name-merge case.
|
|
345
|
+
*/
|
|
346
|
+
function mergeNameArrays(existing, incoming) {
|
|
347
|
+
const merged = new Set(existing);
|
|
348
|
+
for (const name of incoming) merged.add(name);
|
|
349
|
+
return [...merged];
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Deduplicates and merges `ExportNode` objects by path and type.
|
|
353
|
+
*
|
|
354
|
+
* Named exports with the same path and `isTypeOnly` flag have their names merged into a single export.
|
|
355
|
+
* Non-array exports are deduplicated by exact identity. Returns a sorted, deduplicated array.
|
|
356
|
+
*/
|
|
357
|
+
function combineExports(exports) {
|
|
358
|
+
const result = [];
|
|
359
|
+
const namedByPath = /* @__PURE__ */ new Map();
|
|
360
|
+
const seen = /* @__PURE__ */ new Set();
|
|
361
|
+
const keyed = exports.map((node) => ({
|
|
362
|
+
node,
|
|
363
|
+
key: sortKey(node)
|
|
364
|
+
}));
|
|
365
|
+
keyed.sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
|
|
366
|
+
for (const { node: curr } of keyed) {
|
|
367
|
+
const { name, path, isTypeOnly, asAlias } = curr;
|
|
368
|
+
if (Array.isArray(name)) {
|
|
369
|
+
if (!name.length) continue;
|
|
370
|
+
const key = pathTypeKey(path, isTypeOnly);
|
|
371
|
+
const existing = namedByPath.get(key);
|
|
372
|
+
if (existing && Array.isArray(existing.name)) existing.name = mergeNameArrays(existing.name, name);
|
|
373
|
+
else {
|
|
374
|
+
const newItem = {
|
|
375
|
+
...curr,
|
|
376
|
+
name: [...new Set(name)]
|
|
377
|
+
};
|
|
378
|
+
result.push(newItem);
|
|
379
|
+
namedByPath.set(key, newItem);
|
|
380
|
+
}
|
|
381
|
+
} else {
|
|
382
|
+
const key = exportKey(path, name, isTypeOnly, asAlias);
|
|
383
|
+
if (!seen.has(key)) {
|
|
384
|
+
result.push(curr);
|
|
385
|
+
seen.add(key);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
return result;
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Deduplicates and merges `ImportNode` objects, filtering out unused imports.
|
|
393
|
+
*
|
|
394
|
+
* Retains imports that are referenced in `source` or re-exported. Imports with the same path and
|
|
395
|
+
* `isTypeOnly` flag have their names merged. Returns a sorted, deduplicated, filtered array.
|
|
396
|
+
*/
|
|
397
|
+
function combineImports(imports, exports, source) {
|
|
398
|
+
const exportedNames = new Set(exports.flatMap((e) => Array.isArray(e.name) ? e.name : e.name ? [e.name] : []));
|
|
399
|
+
const isUsed = (importName) => !source || source.includes(importName) || exportedNames.has(importName);
|
|
400
|
+
const importNameMemo = /* @__PURE__ */ new Map();
|
|
401
|
+
const canonicalizeName = (n) => {
|
|
402
|
+
if (typeof n === "string") return n;
|
|
403
|
+
const key = `${n.propertyName}:${n.name ?? ""}`;
|
|
404
|
+
if (!importNameMemo.has(key)) importNameMemo.set(key, n);
|
|
405
|
+
return importNameMemo.get(key);
|
|
406
|
+
};
|
|
407
|
+
const pathsWithUsedNamedImport = /* @__PURE__ */ new Set();
|
|
408
|
+
for (const node of imports) {
|
|
409
|
+
if (!Array.isArray(node.name)) continue;
|
|
410
|
+
if (node.name.some((item) => typeof item === "string" ? isUsed(item) : isUsed(item.name ?? item.propertyName))) pathsWithUsedNamedImport.add(node.path);
|
|
411
|
+
}
|
|
412
|
+
const result = [];
|
|
413
|
+
const namedByPath = /* @__PURE__ */ new Map();
|
|
414
|
+
const seen = /* @__PURE__ */ new Set();
|
|
415
|
+
const keyed = imports.map((node) => ({
|
|
416
|
+
node,
|
|
417
|
+
key: sortKey(node)
|
|
418
|
+
}));
|
|
419
|
+
keyed.sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
|
|
420
|
+
for (const { node: curr } of keyed) {
|
|
421
|
+
if (curr.path === curr.root) continue;
|
|
422
|
+
const { path, isTypeOnly } = curr;
|
|
423
|
+
let { name } = curr;
|
|
424
|
+
if (Array.isArray(name)) {
|
|
425
|
+
name = [...new Set(name.map(canonicalizeName))].filter((item) => typeof item === "string" ? isUsed(item) : isUsed(item.name ?? item.propertyName));
|
|
426
|
+
if (!name.length) continue;
|
|
427
|
+
const key = pathTypeKey(path, isTypeOnly);
|
|
428
|
+
const existing = namedByPath.get(key);
|
|
429
|
+
if (existing && Array.isArray(existing.name)) existing.name = mergeNameArrays(existing.name, name);
|
|
430
|
+
else {
|
|
431
|
+
const newItem = {
|
|
432
|
+
...curr,
|
|
433
|
+
name
|
|
434
|
+
};
|
|
435
|
+
result.push(newItem);
|
|
436
|
+
namedByPath.set(key, newItem);
|
|
437
|
+
}
|
|
438
|
+
} else {
|
|
439
|
+
if (name && !isUsed(name) && !pathsWithUsedNamedImport.has(path)) continue;
|
|
440
|
+
const key = importKey(path, name, isTypeOnly);
|
|
441
|
+
if (!seen.has(key)) {
|
|
442
|
+
result.push(curr);
|
|
443
|
+
seen.add(key);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
return result;
|
|
448
|
+
}
|
|
449
|
+
//#endregion
|
|
324
450
|
//#region src/nodes/file.ts
|
|
325
451
|
/**
|
|
326
452
|
* Definition for the {@link ImportNode}.
|
|
327
453
|
*/
|
|
328
454
|
const importDef = defineNode({ kind: "Import" });
|
|
329
455
|
/**
|
|
456
|
+
* Definition for the {@link ExportNode}.
|
|
457
|
+
*/
|
|
458
|
+
const exportDef = defineNode({ kind: "Export" });
|
|
459
|
+
/**
|
|
460
|
+
* Definition for the {@link SourceNode}.
|
|
461
|
+
*/
|
|
462
|
+
const sourceDef = defineNode({ kind: "Source" });
|
|
463
|
+
/**
|
|
464
|
+
* Definition for the {@link FileNode}. The fully resolved builder lives in
|
|
465
|
+
* `createFile`, so this definition only supplies the guard.
|
|
466
|
+
*/
|
|
467
|
+
const fileDef = defineNode({ kind: "File" });
|
|
468
|
+
/**
|
|
330
469
|
* Creates an `ImportNode` representing a language-agnostic import/dependency declaration.
|
|
331
470
|
*
|
|
332
471
|
* @example Named import
|
|
@@ -337,10 +476,6 @@ const importDef = defineNode({ kind: "Import" });
|
|
|
337
476
|
*/
|
|
338
477
|
const createImport = importDef.create;
|
|
339
478
|
/**
|
|
340
|
-
* Definition for the {@link ExportNode}.
|
|
341
|
-
*/
|
|
342
|
-
const exportDef = defineNode({ kind: "Export" });
|
|
343
|
-
/**
|
|
344
479
|
* Creates an `ExportNode` representing a language-agnostic export/public API declaration.
|
|
345
480
|
*
|
|
346
481
|
* @example Named export
|
|
@@ -351,10 +486,6 @@ const exportDef = defineNode({ kind: "Export" });
|
|
|
351
486
|
*/
|
|
352
487
|
const createExport = exportDef.create;
|
|
353
488
|
/**
|
|
354
|
-
* Definition for the {@link SourceNode}.
|
|
355
|
-
*/
|
|
356
|
-
const sourceDef = defineNode({ kind: "Source" });
|
|
357
|
-
/**
|
|
358
489
|
* Creates a `SourceNode` representing a fragment of source code within a file.
|
|
359
490
|
*
|
|
360
491
|
* @example
|
|
@@ -364,10 +495,64 @@ const sourceDef = defineNode({ kind: "Source" });
|
|
|
364
495
|
*/
|
|
365
496
|
const createSource = sourceDef.create;
|
|
366
497
|
/**
|
|
367
|
-
*
|
|
368
|
-
*
|
|
498
|
+
* Creates a fully resolved `FileNode` from a file input descriptor.
|
|
499
|
+
*
|
|
500
|
+
* Computes:
|
|
501
|
+
* - `id` SHA256 hash of the file path
|
|
502
|
+
* - `name` `baseName` without extension
|
|
503
|
+
* - `extname` extension extracted from `baseName`
|
|
504
|
+
*
|
|
505
|
+
* Deduplicates:
|
|
506
|
+
* - `sources` via `combineSources`
|
|
507
|
+
* - `exports` via `combineExports`
|
|
508
|
+
* - `imports` via `combineImports` (also filters unused imports)
|
|
509
|
+
*
|
|
510
|
+
* @throws {Error} when `baseName` has no extension.
|
|
511
|
+
*
|
|
512
|
+
* @example
|
|
513
|
+
* ```ts
|
|
514
|
+
* const file = createFile({
|
|
515
|
+
* baseName: 'petStore.ts',
|
|
516
|
+
* path: 'src/models/petStore.ts',
|
|
517
|
+
* sources: [createSource({ name: 'Pet', nodes: [createText('export type Pet = { id: number }')] })],
|
|
518
|
+
* imports: [createImport({ name: ['z'], path: 'zod' })],
|
|
519
|
+
* exports: [createExport({ name: ['Pet'], path: './petStore' })],
|
|
520
|
+
* })
|
|
521
|
+
* // file.id = SHA256 hash of 'src/models/petStore.ts'
|
|
522
|
+
* // file.name = 'petStore'
|
|
523
|
+
* // file.extname = '.ts'
|
|
524
|
+
* ```
|
|
369
525
|
*/
|
|
370
|
-
|
|
526
|
+
function createFile(input) {
|
|
527
|
+
const extname = node_path.default.extname(input.baseName) || (input.baseName.startsWith(".") ? input.baseName : "");
|
|
528
|
+
if (!extname) throw new Error(`No extname found for ${input.baseName}`);
|
|
529
|
+
const source = (input.sources ?? []).flatMap((item) => item.nodes ?? []).map((node) => extractStringsFromNodes([node])).filter(Boolean).join("\n\n");
|
|
530
|
+
const resolvedExports = input.exports?.length ? combineExports(input.exports) : [];
|
|
531
|
+
const combinedImports = input.imports?.length ? combineImports(input.imports, resolvedExports, source || void 0) : [];
|
|
532
|
+
const localNames = new Set((input.sources ?? []).map((item) => item.name).filter((name) => Boolean(name)));
|
|
533
|
+
const nameOf = (item) => typeof item === "string" ? item : item.name ?? item.propertyName;
|
|
534
|
+
const resolvedImports = combinedImports.filter((imp) => imp.path !== input.path).flatMap((imp) => {
|
|
535
|
+
if (!Array.isArray(imp.name)) return typeof imp.name === "string" && localNames.has(imp.name) ? [] : [imp];
|
|
536
|
+
const kept = imp.name.filter((item) => !localNames.has(nameOf(item)));
|
|
537
|
+
if (!kept.length) return [];
|
|
538
|
+
return [kept.length === imp.name.length ? imp : {
|
|
539
|
+
...imp,
|
|
540
|
+
name: kept
|
|
541
|
+
}];
|
|
542
|
+
});
|
|
543
|
+
const resolvedSources = input.sources?.length ? combineSources(input.sources) : [];
|
|
544
|
+
return {
|
|
545
|
+
kind: "File",
|
|
546
|
+
...input,
|
|
547
|
+
id: (0, node_crypto.hash)("sha256", input.path, "hex"),
|
|
548
|
+
name: trimExtName(input.baseName),
|
|
549
|
+
extname,
|
|
550
|
+
imports: resolvedImports,
|
|
551
|
+
exports: resolvedExports,
|
|
552
|
+
sources: resolvedSources,
|
|
553
|
+
meta: input.meta ?? {}
|
|
554
|
+
};
|
|
555
|
+
}
|
|
371
556
|
//#endregion
|
|
372
557
|
//#region src/nodes/function.ts
|
|
373
558
|
/**
|
|
@@ -375,44 +560,14 @@ const fileDef = defineNode({ kind: "File" });
|
|
|
375
560
|
*/
|
|
376
561
|
const typeLiteralDef = defineNode({ kind: "TypeLiteral" });
|
|
377
562
|
/**
|
|
378
|
-
* Creates a {@link TypeLiteralNode} representing an inline anonymous object type.
|
|
379
|
-
*
|
|
380
|
-
* @example
|
|
381
|
-
* ```ts
|
|
382
|
-
* createTypeLiteral({ members: [{ name: 'petId', type: 'string', optional: false }] })
|
|
383
|
-
* // { petId: string }
|
|
384
|
-
* ```
|
|
385
|
-
*/
|
|
386
|
-
const createTypeLiteral = typeLiteralDef.create;
|
|
387
|
-
/**
|
|
388
563
|
* Definition for the {@link IndexedAccessTypeNode}.
|
|
389
564
|
*/
|
|
390
565
|
const indexedAccessTypeDef = defineNode({ kind: "IndexedAccessType" });
|
|
391
566
|
/**
|
|
392
|
-
* Creates an {@link IndexedAccessTypeNode} representing a single field accessed from a named type.
|
|
393
|
-
*
|
|
394
|
-
* @example
|
|
395
|
-
* ```ts
|
|
396
|
-
* createIndexedAccessType({ objectType: 'DeletePetPathParams', indexType: 'petId' })
|
|
397
|
-
* // DeletePetPathParams['petId']
|
|
398
|
-
* ```
|
|
399
|
-
*/
|
|
400
|
-
const createIndexedAccessType = indexedAccessTypeDef.create;
|
|
401
|
-
/**
|
|
402
567
|
* Definition for the {@link ObjectBindingPatternNode}.
|
|
403
568
|
*/
|
|
404
569
|
const objectBindingPatternDef = defineNode({ kind: "ObjectBindingPattern" });
|
|
405
570
|
/**
|
|
406
|
-
* Creates an {@link ObjectBindingPatternNode} for a destructured parameter binding.
|
|
407
|
-
*
|
|
408
|
-
* @example
|
|
409
|
-
* ```ts
|
|
410
|
-
* createObjectBindingPattern({ elements: [{ name: 'id' }, { name: 'name' }] })
|
|
411
|
-
* // { id, name }
|
|
412
|
-
* ```
|
|
413
|
-
*/
|
|
414
|
-
const createObjectBindingPattern = objectBindingPatternDef.create;
|
|
415
|
-
/**
|
|
416
571
|
* Definition for the {@link FunctionParameterNode}. `optional` defaults to `false`.
|
|
417
572
|
* Passing `properties` builds a destructured group: an {@link ObjectBindingPatternNode} name
|
|
418
573
|
* paired with a {@link TypeLiteralNode} type.
|
|
@@ -437,6 +592,43 @@ const functionParameterDef = defineNode({
|
|
|
437
592
|
}
|
|
438
593
|
});
|
|
439
594
|
/**
|
|
595
|
+
* Definition for the {@link FunctionParametersNode}.
|
|
596
|
+
*/
|
|
597
|
+
const functionParametersDef = defineNode({
|
|
598
|
+
kind: "FunctionParameters",
|
|
599
|
+
defaults: { params: [] }
|
|
600
|
+
});
|
|
601
|
+
/**
|
|
602
|
+
* Creates a {@link TypeLiteralNode} representing an inline anonymous object type.
|
|
603
|
+
*
|
|
604
|
+
* @example
|
|
605
|
+
* ```ts
|
|
606
|
+
* createTypeLiteral({ members: [{ name: 'petId', type: 'string', optional: false }] })
|
|
607
|
+
* // { petId: string }
|
|
608
|
+
* ```
|
|
609
|
+
*/
|
|
610
|
+
const createTypeLiteral = typeLiteralDef.create;
|
|
611
|
+
/**
|
|
612
|
+
* Creates an {@link IndexedAccessTypeNode} representing a single field accessed from a named type.
|
|
613
|
+
*
|
|
614
|
+
* @example
|
|
615
|
+
* ```ts
|
|
616
|
+
* createIndexedAccessType({ target: 'DeletePetPathParams', key: 'petId' })
|
|
617
|
+
* // DeletePetPathParams['petId']
|
|
618
|
+
* ```
|
|
619
|
+
*/
|
|
620
|
+
const createIndexedAccessType = indexedAccessTypeDef.create;
|
|
621
|
+
/**
|
|
622
|
+
* Creates an {@link ObjectBindingPatternNode} for a destructured parameter binding.
|
|
623
|
+
*
|
|
624
|
+
* @example
|
|
625
|
+
* ```ts
|
|
626
|
+
* createObjectBindingPattern({ elements: [{ name: 'id' }, { name: 'name' }] })
|
|
627
|
+
* // { id, name }
|
|
628
|
+
* ```
|
|
629
|
+
*/
|
|
630
|
+
const createObjectBindingPattern = objectBindingPatternDef.create;
|
|
631
|
+
/**
|
|
440
632
|
* Creates a `FunctionParameterNode`. `optional` defaults to `false`.
|
|
441
633
|
*
|
|
442
634
|
* @example Optional param
|
|
@@ -453,13 +645,6 @@ const functionParameterDef = defineNode({
|
|
|
453
645
|
*/
|
|
454
646
|
const createFunctionParameter = functionParameterDef.create;
|
|
455
647
|
/**
|
|
456
|
-
* Definition for the {@link FunctionParametersNode}.
|
|
457
|
-
*/
|
|
458
|
-
const functionParametersDef = defineNode({
|
|
459
|
-
kind: "FunctionParameters",
|
|
460
|
-
defaults: { params: [] }
|
|
461
|
-
});
|
|
462
|
-
/**
|
|
463
648
|
* Creates a `FunctionParametersNode` from an ordered list of parameters.
|
|
464
649
|
*
|
|
465
650
|
* @example
|
|
@@ -491,8 +676,8 @@ const inputDef = defineNode({
|
|
|
491
676
|
});
|
|
492
677
|
/**
|
|
493
678
|
* Creates an `InputNode`. Pass `stream: true` for the streaming variant whose `schemas` and
|
|
494
|
-
* `operations` are `AsyncIterable` sources
|
|
495
|
-
*
|
|
679
|
+
* `operations` are `AsyncIterable` sources. Otherwise it builds the eager variant with array
|
|
680
|
+
* `schemas`/`operations`. Both variants get the defaulted `meta`.
|
|
496
681
|
*
|
|
497
682
|
* @example Eager
|
|
498
683
|
* ```ts
|
|
@@ -509,6 +694,10 @@ function createInput(options = {}) {
|
|
|
509
694
|
const { stream, ...overrides } = options;
|
|
510
695
|
if (stream) return {
|
|
511
696
|
kind: "Input",
|
|
697
|
+
meta: {
|
|
698
|
+
circularNames: [],
|
|
699
|
+
enumNames: []
|
|
700
|
+
},
|
|
512
701
|
...overrides
|
|
513
702
|
};
|
|
514
703
|
return inputDef.create(overrides);
|
|
@@ -516,18 +705,15 @@ function createInput(options = {}) {
|
|
|
516
705
|
//#endregion
|
|
517
706
|
//#region src/nodes/requestBody.ts
|
|
518
707
|
/**
|
|
519
|
-
* Definition for the {@link RequestBodyNode}
|
|
708
|
+
* Definition for the {@link RequestBodyNode}. Content entries are built upfront with
|
|
709
|
+
* {@link createContent}, mirroring how `parameters` and `responses` take prebuilt nodes.
|
|
520
710
|
*/
|
|
521
711
|
const requestBodyDef = defineNode({
|
|
522
712
|
kind: "RequestBody",
|
|
523
|
-
build: (props) => ({
|
|
524
|
-
...props,
|
|
525
|
-
content: props.content?.map(createContent)
|
|
526
|
-
}),
|
|
527
713
|
children: ["content"]
|
|
528
714
|
});
|
|
529
715
|
/**
|
|
530
|
-
* Creates a `RequestBodyNode
|
|
716
|
+
* Creates a `RequestBodyNode`.
|
|
531
717
|
*/
|
|
532
718
|
const createRequestBody = requestBodyDef.create;
|
|
533
719
|
//#endregion
|
|
@@ -584,10 +770,24 @@ function createOutput(overrides = {}) {
|
|
|
584
770
|
return outputDef.create(overrides);
|
|
585
771
|
}
|
|
586
772
|
//#endregion
|
|
773
|
+
//#region src/optionality.ts
|
|
774
|
+
/**
|
|
775
|
+
* Generic JSON Schema optionality: a non-required field is optional, and a
|
|
776
|
+
* non-required nullable field is nullish.
|
|
777
|
+
*/
|
|
778
|
+
function optionality(schema, required) {
|
|
779
|
+
const nullable = schema.nullable ?? false;
|
|
780
|
+
return {
|
|
781
|
+
...schema,
|
|
782
|
+
optional: !required && !nullable ? true : void 0,
|
|
783
|
+
nullish: !required && nullable ? true : void 0
|
|
784
|
+
};
|
|
785
|
+
}
|
|
786
|
+
//#endregion
|
|
587
787
|
//#region src/nodes/parameter.ts
|
|
588
788
|
/**
|
|
589
|
-
* Definition for the {@link ParameterNode}. `required` defaults to `false
|
|
590
|
-
*
|
|
789
|
+
* Definition for the {@link ParameterNode}. `required` defaults to `false`, and the schema's
|
|
790
|
+
* `optional`/`nullish` flags are derived from it through {@link optionality}.
|
|
591
791
|
*/
|
|
592
792
|
const parameterDef = defineNode({
|
|
593
793
|
kind: "Parameter",
|
|
@@ -596,12 +796,11 @@ const parameterDef = defineNode({
|
|
|
596
796
|
return {
|
|
597
797
|
...props,
|
|
598
798
|
required,
|
|
599
|
-
schema:
|
|
799
|
+
schema: optionality(props.schema, required)
|
|
600
800
|
};
|
|
601
801
|
},
|
|
602
802
|
children: ["schema"],
|
|
603
|
-
visitorKey: "parameter"
|
|
604
|
-
rebuild: true
|
|
803
|
+
visitorKey: "parameter"
|
|
605
804
|
});
|
|
606
805
|
/**
|
|
607
806
|
* Creates a `ParameterNode`.
|
|
@@ -620,8 +819,8 @@ const createParameter = parameterDef.create;
|
|
|
620
819
|
//#endregion
|
|
621
820
|
//#region src/nodes/property.ts
|
|
622
821
|
/**
|
|
623
|
-
* Definition for the {@link PropertyNode}. `required` defaults to `false
|
|
624
|
-
*
|
|
822
|
+
* Definition for the {@link PropertyNode}. `required` defaults to `false`, and the schema's
|
|
823
|
+
* `optional`/`nullish` flags are derived from it through {@link optionality}.
|
|
625
824
|
*/
|
|
626
825
|
const propertyDef = defineNode({
|
|
627
826
|
kind: "Property",
|
|
@@ -630,12 +829,11 @@ const propertyDef = defineNode({
|
|
|
630
829
|
return {
|
|
631
830
|
...props,
|
|
632
831
|
required,
|
|
633
|
-
schema:
|
|
832
|
+
schema: optionality(props.schema, required)
|
|
634
833
|
};
|
|
635
834
|
},
|
|
636
835
|
children: ["schema"],
|
|
637
|
-
visitorKey: "property"
|
|
638
|
-
rebuild: true
|
|
836
|
+
visitorKey: "property"
|
|
639
837
|
});
|
|
640
838
|
/**
|
|
641
839
|
* Creates a `PropertyNode`.
|
|
@@ -661,14 +859,14 @@ const responseDef = defineNode({
|
|
|
661
859
|
kind: "Response",
|
|
662
860
|
build: (props) => {
|
|
663
861
|
const { schema, mediaType, keysToOmit, content, ...rest } = props;
|
|
664
|
-
const entries = content ?? (schema ? [{
|
|
862
|
+
const entries = content ?? (schema ? [createContent({
|
|
665
863
|
contentType: mediaType ?? "application/json",
|
|
666
864
|
schema,
|
|
667
865
|
keysToOmit: keysToOmit ?? null
|
|
668
|
-
}] : void 0);
|
|
866
|
+
})] : void 0);
|
|
669
867
|
return {
|
|
670
868
|
...rest,
|
|
671
|
-
content: entries
|
|
869
|
+
content: entries
|
|
672
870
|
};
|
|
673
871
|
},
|
|
674
872
|
children: ["content"],
|
|
@@ -681,12 +879,67 @@ const responseDef = defineNode({
|
|
|
681
879
|
* ```ts
|
|
682
880
|
* const response = createResponse({
|
|
683
881
|
* statusCode: '200',
|
|
684
|
-
* content: [{ contentType: 'application/json', schema: createSchema({ type: 'object', properties: [] }) }],
|
|
882
|
+
* content: [createContent({ contentType: 'application/json', schema: createSchema({ type: 'object', properties: [] }) })],
|
|
685
883
|
* })
|
|
686
884
|
* ```
|
|
687
885
|
*/
|
|
688
886
|
const createResponse = responseDef.create;
|
|
689
887
|
//#endregion
|
|
888
|
+
//#region src/nodes/schema.ts
|
|
889
|
+
/**
|
|
890
|
+
* Maps schema `type` to its underlying `primitive`.
|
|
891
|
+
* Primitive types map to themselves and special string formats map to `'string'`.
|
|
892
|
+
* Any type not listed here (such as `ref`, `enum`, `union`, `intersection`, `tuple`, `ipv4`, `ipv6`, `blob`) has no `primitive`.
|
|
893
|
+
*/
|
|
894
|
+
const TYPE_TO_PRIMITIVE = {
|
|
895
|
+
string: "string",
|
|
896
|
+
number: "number",
|
|
897
|
+
integer: "integer",
|
|
898
|
+
bigint: "bigint",
|
|
899
|
+
boolean: "boolean",
|
|
900
|
+
null: "null",
|
|
901
|
+
any: "any",
|
|
902
|
+
unknown: "unknown",
|
|
903
|
+
void: "void",
|
|
904
|
+
never: "never",
|
|
905
|
+
object: "object",
|
|
906
|
+
array: "array",
|
|
907
|
+
date: "date",
|
|
908
|
+
uuid: "string",
|
|
909
|
+
email: "string",
|
|
910
|
+
url: "string",
|
|
911
|
+
datetime: "string",
|
|
912
|
+
time: "string"
|
|
913
|
+
};
|
|
914
|
+
/**
|
|
915
|
+
* Definition for the {@link SchemaNode}. Object schemas default `properties` to an
|
|
916
|
+
* empty array, and `primitive` is inferred from `type` when not explicitly provided.
|
|
917
|
+
*/
|
|
918
|
+
const schemaDef = defineNode({
|
|
919
|
+
kind: "Schema",
|
|
920
|
+
build: (props) => {
|
|
921
|
+
if (props.type === "object") return {
|
|
922
|
+
properties: [],
|
|
923
|
+
primitive: "object",
|
|
924
|
+
...props
|
|
925
|
+
};
|
|
926
|
+
return {
|
|
927
|
+
primitive: TYPE_TO_PRIMITIVE[props.type],
|
|
928
|
+
...props
|
|
929
|
+
};
|
|
930
|
+
},
|
|
931
|
+
children: [
|
|
932
|
+
"properties",
|
|
933
|
+
"items",
|
|
934
|
+
"members",
|
|
935
|
+
"additionalProperties"
|
|
936
|
+
],
|
|
937
|
+
visitorKey: "schema"
|
|
938
|
+
});
|
|
939
|
+
function createSchema(props) {
|
|
940
|
+
return schemaDef.create(props);
|
|
941
|
+
}
|
|
942
|
+
//#endregion
|
|
690
943
|
Object.defineProperty(exports, "__exportAll", {
|
|
691
944
|
enumerable: true,
|
|
692
945
|
get: function() {
|
|
@@ -699,12 +952,6 @@ Object.defineProperty(exports, "__name", {
|
|
|
699
952
|
return __name;
|
|
700
953
|
}
|
|
701
954
|
});
|
|
702
|
-
Object.defineProperty(exports, "__toESM", {
|
|
703
|
-
enumerable: true,
|
|
704
|
-
get: function() {
|
|
705
|
-
return __toESM;
|
|
706
|
-
}
|
|
707
|
-
});
|
|
708
955
|
Object.defineProperty(exports, "arrowFunctionDef", {
|
|
709
956
|
enumerable: true,
|
|
710
957
|
get: function() {
|
|
@@ -765,6 +1012,12 @@ Object.defineProperty(exports, "createExport", {
|
|
|
765
1012
|
return createExport;
|
|
766
1013
|
}
|
|
767
1014
|
});
|
|
1015
|
+
Object.defineProperty(exports, "createFile", {
|
|
1016
|
+
enumerable: true,
|
|
1017
|
+
get: function() {
|
|
1018
|
+
return createFile;
|
|
1019
|
+
}
|
|
1020
|
+
});
|
|
768
1021
|
Object.defineProperty(exports, "createFunction", {
|
|
769
1022
|
enumerable: true,
|
|
770
1023
|
get: function() {
|
|
@@ -891,6 +1144,12 @@ Object.defineProperty(exports, "exportDef", {
|
|
|
891
1144
|
return exportDef;
|
|
892
1145
|
}
|
|
893
1146
|
});
|
|
1147
|
+
Object.defineProperty(exports, "extractStringsFromNodes", {
|
|
1148
|
+
enumerable: true,
|
|
1149
|
+
get: function() {
|
|
1150
|
+
return extractStringsFromNodes;
|
|
1151
|
+
}
|
|
1152
|
+
});
|
|
894
1153
|
Object.defineProperty(exports, "fileDef", {
|
|
895
1154
|
enumerable: true,
|
|
896
1155
|
get: function() {
|
|
@@ -951,6 +1210,12 @@ Object.defineProperty(exports, "operationDef", {
|
|
|
951
1210
|
return operationDef;
|
|
952
1211
|
}
|
|
953
1212
|
});
|
|
1213
|
+
Object.defineProperty(exports, "optionality", {
|
|
1214
|
+
enumerable: true,
|
|
1215
|
+
get: function() {
|
|
1216
|
+
return optionality;
|
|
1217
|
+
}
|
|
1218
|
+
});
|
|
954
1219
|
Object.defineProperty(exports, "outputDef", {
|
|
955
1220
|
enumerable: true,
|
|
956
1221
|
get: function() {
|
|
@@ -999,12 +1264,6 @@ Object.defineProperty(exports, "sourceDef", {
|
|
|
999
1264
|
return sourceDef;
|
|
1000
1265
|
}
|
|
1001
1266
|
});
|
|
1002
|
-
Object.defineProperty(exports, "syncOptionality", {
|
|
1003
|
-
enumerable: true,
|
|
1004
|
-
get: function() {
|
|
1005
|
-
return syncOptionality;
|
|
1006
|
-
}
|
|
1007
|
-
});
|
|
1008
1267
|
Object.defineProperty(exports, "textDef", {
|
|
1009
1268
|
enumerable: true,
|
|
1010
1269
|
get: function() {
|
|
@@ -1023,5 +1282,11 @@ Object.defineProperty(exports, "typeLiteralDef", {
|
|
|
1023
1282
|
return typeLiteralDef;
|
|
1024
1283
|
}
|
|
1025
1284
|
});
|
|
1285
|
+
Object.defineProperty(exports, "visitorKeys", {
|
|
1286
|
+
enumerable: true,
|
|
1287
|
+
get: function() {
|
|
1288
|
+
return visitorKeys;
|
|
1289
|
+
}
|
|
1290
|
+
});
|
|
1026
1291
|
|
|
1027
|
-
//# sourceMappingURL=
|
|
1292
|
+
//# sourceMappingURL=schema-BkvrrOAr.cjs.map
|