@orval/core 8.12.3 → 8.13.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/dist/index.d.mts +170 -3
- package/dist/index.mjs +907 -50
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -143,6 +143,16 @@ const TEMPLATE_TAG_REGEX = /\${(.+?)}/g;
|
|
|
143
143
|
function isReference(obj) {
|
|
144
144
|
return !isNullish$1(obj) && Object.hasOwn(obj, "$ref");
|
|
145
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Discriminator helper for {@link OpenApiDynamicReferenceObject}.
|
|
148
|
+
*
|
|
149
|
+
* Returns `true` when `obj` has a `$dynamicRef` string property,
|
|
150
|
+
* indicating it is an OpenAPI 3.1 dynamic reference rather than a
|
|
151
|
+
* static `$ref`.
|
|
152
|
+
*/
|
|
153
|
+
function isDynamicReference(obj) {
|
|
154
|
+
return !isNullish$1(obj) && Object.hasOwn(obj, "$dynamicRef") && typeof obj.$dynamicRef === "string";
|
|
155
|
+
}
|
|
146
156
|
function isDirectory(pathValue) {
|
|
147
157
|
return !nodePath.extname(pathValue);
|
|
148
158
|
}
|
|
@@ -741,13 +751,21 @@ function count(str = "", key) {
|
|
|
741
751
|
var path_exports = /* @__PURE__ */ __exportAll({
|
|
742
752
|
getRelativeImportPath: () => getRelativeImportPath,
|
|
743
753
|
getSchemaFileName: () => getSchemaFileName,
|
|
754
|
+
isAbsolute: () => isAbsolute,
|
|
744
755
|
join: () => join,
|
|
745
756
|
joinSafe: () => joinSafe,
|
|
746
757
|
normalizeSafe: () => normalizeSafe,
|
|
747
758
|
relativeSafe: () => relativeSafe,
|
|
759
|
+
resolve: () => resolve,
|
|
748
760
|
separator: () => "/",
|
|
749
761
|
toUnix: () => toUnix
|
|
750
762
|
});
|
|
763
|
+
function isAbsolute(value) {
|
|
764
|
+
return nodePath.isAbsolute(value);
|
|
765
|
+
}
|
|
766
|
+
function resolve(...args) {
|
|
767
|
+
return toUnix(nodePath.resolve(...args));
|
|
768
|
+
}
|
|
751
769
|
function toUnix(value) {
|
|
752
770
|
value = value.replaceAll("\\", "/");
|
|
753
771
|
value = value.replaceAll(/(?<!^)\/+/g, "/");
|
|
@@ -1357,6 +1375,16 @@ function getRefInfo($ref, context) {
|
|
|
1357
1375
|
refPaths
|
|
1358
1376
|
};
|
|
1359
1377
|
}
|
|
1378
|
+
/**
|
|
1379
|
+
* Extracts the anchor name from a fragment-only `$dynamicRef` (e.g. `#category` → `category`).
|
|
1380
|
+
*
|
|
1381
|
+
* Returns `undefined` for external-document `$dynamicRef` values (e.g. `other.json#anchor`)
|
|
1382
|
+
* which are not supported.
|
|
1383
|
+
*/
|
|
1384
|
+
function getDynamicAnchorName(dynamicRef) {
|
|
1385
|
+
if (!dynamicRef.startsWith("#") || dynamicRef.length <= 1) return;
|
|
1386
|
+
return dynamicRef.slice(1);
|
|
1387
|
+
}
|
|
1360
1388
|
//#endregion
|
|
1361
1389
|
//#region src/getters/imports.ts
|
|
1362
1390
|
function getAliasedImports({ name, resolvedValue, context }) {
|
|
@@ -1514,7 +1542,9 @@ function combineSchemas({ name, schema, separator, context, nullable, formDataCo
|
|
|
1514
1542
|
const originalProps = resolvedValue.originalSchema.properties;
|
|
1515
1543
|
if (resolvedValue.type === "object" && originalProps) resolvedData.allProperties.push(...Object.keys(originalProps));
|
|
1516
1544
|
}
|
|
1517
|
-
|
|
1545
|
+
const isAllEnums = resolvedData.isEnum.every(Boolean);
|
|
1546
|
+
const isNullableEnumComposition = (separator === "anyOf" || separator === "oneOf") && !isAllEnums && resolvedData.isEnum.some(Boolean) && resolvedData.isEnum.every((isEnum, index) => isEnum && !resolvedData.isRef[index] || resolvedData.types[index] === "null");
|
|
1547
|
+
if (isAllEnums && name && items.length > 1 && context.output.override.enumGenerationType !== EnumGeneration.UNION) {
|
|
1518
1548
|
const { value: combinedEnumValue, valueImports, hasNull } = getCombinedEnumValue(resolvedData.values.map((value, index) => ({
|
|
1519
1549
|
value,
|
|
1520
1550
|
isRef: resolvedData.isRef[index],
|
|
@@ -1575,7 +1605,7 @@ function combineSchemas({ name, schema, separator, context, nullable, formDataCo
|
|
|
1575
1605
|
imports: resolvedValue ? [...resolvedData.imports, ...resolvedValue.imports] : resolvedData.imports,
|
|
1576
1606
|
schemas: resolvedValue ? [...resolvedData.schemas, ...resolvedValue.schemas] : resolvedData.schemas,
|
|
1577
1607
|
dependencies: resolvedValue ? [...resolvedData.dependencies, ...resolvedValue.dependencies] : resolvedData.dependencies,
|
|
1578
|
-
isEnum:
|
|
1608
|
+
isEnum: isNullableEnumComposition,
|
|
1579
1609
|
type: "object",
|
|
1580
1610
|
isRef: false,
|
|
1581
1611
|
hasReadonlyProps: resolvedData.hasReadonlyProps || (resolvedValue?.hasReadonlyProps ?? false),
|
|
@@ -2041,16 +2071,33 @@ function getScalar({ item, name, context, formDataContext }) {
|
|
|
2041
2071
|
examples: resolveExampleRefs(schemaExamples, context)
|
|
2042
2072
|
};
|
|
2043
2073
|
}
|
|
2044
|
-
case "null":
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2074
|
+
case "null": {
|
|
2075
|
+
const itemAllOf = item.allOf;
|
|
2076
|
+
const itemOneOf = item.oneOf;
|
|
2077
|
+
const itemAnyOf = item.anyOf;
|
|
2078
|
+
let separator;
|
|
2079
|
+
if (itemAllOf?.length) separator = "allOf";
|
|
2080
|
+
else if (itemOneOf?.length) separator = "oneOf";
|
|
2081
|
+
else if (itemAnyOf?.length) separator = "anyOf";
|
|
2082
|
+
if (separator) return combineSchemas({
|
|
2083
|
+
schema: Object.fromEntries(Object.entries(item).filter(([key]) => key !== "type")),
|
|
2084
|
+
name,
|
|
2085
|
+
separator,
|
|
2086
|
+
context,
|
|
2087
|
+
nullable: nullable || " | null",
|
|
2088
|
+
formDataContext
|
|
2089
|
+
});
|
|
2090
|
+
return {
|
|
2091
|
+
value: "null",
|
|
2092
|
+
isEnum: false,
|
|
2093
|
+
type: "null",
|
|
2094
|
+
imports: [],
|
|
2095
|
+
schemas: [],
|
|
2096
|
+
isRef: false,
|
|
2097
|
+
hasReadonlyProps: schemaReadOnly ?? false,
|
|
2098
|
+
dependencies: []
|
|
2099
|
+
};
|
|
2100
|
+
}
|
|
2054
2101
|
default: {
|
|
2055
2102
|
if (isArray(itemType)) return combineSchemas({
|
|
2056
2103
|
schema: { anyOf: itemType.map((type) => Object.assign({}, item, { type })) },
|
|
@@ -2088,6 +2135,28 @@ function getScalar({ item, name, context, formDataContext }) {
|
|
|
2088
2135
|
}
|
|
2089
2136
|
//#endregion
|
|
2090
2137
|
//#region src/resolvers/ref.ts
|
|
2138
|
+
/** Convert a `$dynamicAnchor` name to a valid TypeScript generic parameter identifier. */
|
|
2139
|
+
function dynamicAnchorToParamName(anchor) {
|
|
2140
|
+
return sanitize(anchor, {
|
|
2141
|
+
underscore: "_",
|
|
2142
|
+
whitespace: "_",
|
|
2143
|
+
dash: "_",
|
|
2144
|
+
es5keyword: true,
|
|
2145
|
+
es5IdentifierName: true
|
|
2146
|
+
});
|
|
2147
|
+
}
|
|
2148
|
+
function dynamicAnchorsToUniqueParamNames(anchors) {
|
|
2149
|
+
const result = /* @__PURE__ */ new Map();
|
|
2150
|
+
const usedNames = /* @__PURE__ */ new Map();
|
|
2151
|
+
for (const anchor of anchors) {
|
|
2152
|
+
const base = dynamicAnchorToParamName(anchor);
|
|
2153
|
+
const count = usedNames.get(base) ?? 0;
|
|
2154
|
+
usedNames.set(base, count + 1);
|
|
2155
|
+
const paramName = count === 0 ? base : `${base}${count + 1}`;
|
|
2156
|
+
result.set(anchor, paramName);
|
|
2157
|
+
}
|
|
2158
|
+
return result;
|
|
2159
|
+
}
|
|
2091
2160
|
const REF_NOT_FOUND_PREFIX = "Oops... 🍻. Ref not found";
|
|
2092
2161
|
/**
|
|
2093
2162
|
* Recursively resolves a `$ref` in an OpenAPI document, following
|
|
@@ -2137,15 +2206,100 @@ function resolveRef(schema, context, imports = []) {
|
|
|
2137
2206
|
schemaName: originalName
|
|
2138
2207
|
}]);
|
|
2139
2208
|
}
|
|
2209
|
+
/** Check whether a schema reference has at least one `$defs` entry with both `$dynamicAnchor` and `$ref`. */
|
|
2210
|
+
function isBoundAlias(schema) {
|
|
2211
|
+
const defs = schema.$defs;
|
|
2212
|
+
if (!defs || typeof defs !== "object") return false;
|
|
2213
|
+
for (const defSchema of Object.values(defs)) {
|
|
2214
|
+
if (!defSchema || typeof defSchema !== "object") continue;
|
|
2215
|
+
const rec = defSchema;
|
|
2216
|
+
if (typeof rec.$dynamicAnchor === "string" && typeof rec.$ref === "string") return true;
|
|
2217
|
+
}
|
|
2218
|
+
return false;
|
|
2219
|
+
}
|
|
2140
2220
|
/**
|
|
2141
|
-
*
|
|
2142
|
-
*
|
|
2143
|
-
* Preserves OpenAPI 3.0 `nullable` and 3.1 type-array (`["object", "null"]`)
|
|
2144
|
-
* hints from the referencing schema onto the resolved target.
|
|
2145
|
-
*
|
|
2146
|
-
* @see https://spec.openapis.org/oas/v3.0.3#fixed-fields-18 (nullable)
|
|
2147
|
-
* @see https://spec.openapis.org/oas/v3.1.0#schema-object (type as array)
|
|
2221
|
+
* Extract bound-alias information from a schema that references a generic template
|
|
2222
|
+
* and binds `$dynamicAnchor` entries to concrete types via `$defs`.
|
|
2148
2223
|
*/
|
|
2224
|
+
function extractBoundAliasInfo(schema, context) {
|
|
2225
|
+
let bindingElement;
|
|
2226
|
+
let extraSchemas;
|
|
2227
|
+
if (isReference(schema) && isBoundAlias(schema)) bindingElement = schema;
|
|
2228
|
+
else {
|
|
2229
|
+
const allOf = schema.allOf;
|
|
2230
|
+
if (Array.isArray(allOf)) for (let i = 0; i < allOf.length; i++) {
|
|
2231
|
+
const element = allOf[i];
|
|
2232
|
+
if (isReference(element) && isBoundAlias(element)) {
|
|
2233
|
+
bindingElement = element;
|
|
2234
|
+
extraSchemas = allOf.filter((_, j) => j !== i);
|
|
2235
|
+
break;
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
if (!bindingElement) return void 0;
|
|
2240
|
+
const defs = bindingElement.$defs;
|
|
2241
|
+
if (!defs || typeof defs !== "object") return void 0;
|
|
2242
|
+
const bindingByAnchor = /* @__PURE__ */ new Map();
|
|
2243
|
+
for (const defSchema of Object.values(defs)) {
|
|
2244
|
+
if (!defSchema || typeof defSchema !== "object") continue;
|
|
2245
|
+
const rec = defSchema;
|
|
2246
|
+
if (rec.$dynamicAnchor === void 0) continue;
|
|
2247
|
+
const ref = rec.$ref;
|
|
2248
|
+
if (!ref || !isComponentRef(ref)) continue;
|
|
2249
|
+
const anchor = rec.$dynamicAnchor;
|
|
2250
|
+
const { name, originalName } = getRefInfo(ref, context);
|
|
2251
|
+
bindingByAnchor.set(anchor, {
|
|
2252
|
+
typeName: name,
|
|
2253
|
+
originalName
|
|
2254
|
+
});
|
|
2255
|
+
}
|
|
2256
|
+
if (bindingByAnchor.size === 0) return void 0;
|
|
2257
|
+
const refPath = bindingElement.$ref;
|
|
2258
|
+
if (typeof refPath !== "string") return void 0;
|
|
2259
|
+
const { name: genericName, refPaths: templateRefPaths } = getRefInfo(refPath, context);
|
|
2260
|
+
const templateDefs = (templateRefPaths ? prop(context.spec, ...templateRefPaths) : void 0)?.$defs;
|
|
2261
|
+
const typeArgs = [];
|
|
2262
|
+
const genericParams = [];
|
|
2263
|
+
const imports = [];
|
|
2264
|
+
if (templateDefs && typeof templateDefs === "object") {
|
|
2265
|
+
const templateAnchors = [];
|
|
2266
|
+
for (const defSchema of Object.values(templateDefs)) {
|
|
2267
|
+
if (!defSchema || typeof defSchema !== "object") continue;
|
|
2268
|
+
const rec = defSchema;
|
|
2269
|
+
if (rec.$dynamicAnchor === void 0 || rec.$ref !== void 0) continue;
|
|
2270
|
+
templateAnchors.push(rec.$dynamicAnchor);
|
|
2271
|
+
}
|
|
2272
|
+
const uniqueNames = dynamicAnchorsToUniqueParamNames(templateAnchors);
|
|
2273
|
+
for (const anchor of templateAnchors) {
|
|
2274
|
+
const binding = bindingByAnchor.get(anchor);
|
|
2275
|
+
if (binding) {
|
|
2276
|
+
typeArgs.push(binding.typeName);
|
|
2277
|
+
imports.push({
|
|
2278
|
+
name: binding.typeName,
|
|
2279
|
+
schemaName: binding.originalName
|
|
2280
|
+
});
|
|
2281
|
+
} else {
|
|
2282
|
+
const paramName = uniqueNames.get(anchor) ?? dynamicAnchorToParamName(anchor);
|
|
2283
|
+
typeArgs.push(paramName);
|
|
2284
|
+
genericParams.push(paramName);
|
|
2285
|
+
}
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
if (typeArgs.length === 0) for (const { typeName, originalName } of bindingByAnchor.values()) {
|
|
2289
|
+
typeArgs.push(typeName);
|
|
2290
|
+
imports.push({
|
|
2291
|
+
name: typeName,
|
|
2292
|
+
schemaName: originalName
|
|
2293
|
+
});
|
|
2294
|
+
}
|
|
2295
|
+
return {
|
|
2296
|
+
genericName,
|
|
2297
|
+
genericParams,
|
|
2298
|
+
typeArgs,
|
|
2299
|
+
imports,
|
|
2300
|
+
extraSchemas
|
|
2301
|
+
};
|
|
2302
|
+
}
|
|
2149
2303
|
function getSchema$1(schema, context) {
|
|
2150
2304
|
if (!schema.$ref) throw new Error(`${REF_NOT_FOUND_PREFIX}: missing $ref`);
|
|
2151
2305
|
const refInfo = getRefInfo(schema.$ref, context);
|
|
@@ -2172,6 +2326,104 @@ function getSchema$1(schema, context) {
|
|
|
2172
2326
|
refInfo
|
|
2173
2327
|
};
|
|
2174
2328
|
}
|
|
2329
|
+
function encodeJsonPointerSegment(segment) {
|
|
2330
|
+
return segment.replaceAll("~", "~0").replaceAll("/", "~1");
|
|
2331
|
+
}
|
|
2332
|
+
/**
|
|
2333
|
+
* Build the dynamic scope for a schema: maps `$dynamicAnchor` names to concrete
|
|
2334
|
+
* type entries for self-referential resolution, `$defs` bindings, and sibling anchors.
|
|
2335
|
+
*/
|
|
2336
|
+
function buildDynamicScope(schemaName, schema, context) {
|
|
2337
|
+
const scope = {};
|
|
2338
|
+
const getSchemaScopeEntry = (name) => {
|
|
2339
|
+
const refInfo = getRefInfo(`#/components/schemas/${encodeJsonPointerSegment(name)}`, context);
|
|
2340
|
+
return {
|
|
2341
|
+
name: refInfo.name,
|
|
2342
|
+
schemaName: refInfo.originalName
|
|
2343
|
+
};
|
|
2344
|
+
};
|
|
2345
|
+
const schemaRecord = schema;
|
|
2346
|
+
if (typeof schemaRecord.$dynamicAnchor === "string") scope[schemaRecord.$dynamicAnchor] = getSchemaScopeEntry(schemaName);
|
|
2347
|
+
const defs = schemaRecord.$defs;
|
|
2348
|
+
if (defs && typeof defs === "object") {
|
|
2349
|
+
const unboundAnchors = [];
|
|
2350
|
+
for (const [, defSchema] of Object.entries(defs)) {
|
|
2351
|
+
if (!defSchema || typeof defSchema !== "object") continue;
|
|
2352
|
+
const defRecord = defSchema;
|
|
2353
|
+
if (typeof defRecord.$dynamicAnchor === "string") {
|
|
2354
|
+
const anchorName = defRecord.$dynamicAnchor;
|
|
2355
|
+
const refInDef = defSchema.$ref;
|
|
2356
|
+
if (refInDef?.startsWith("#/components/schemas/")) {
|
|
2357
|
+
const { name, originalName } = getRefInfo(refInDef, context);
|
|
2358
|
+
scope[anchorName] = {
|
|
2359
|
+
name,
|
|
2360
|
+
schemaName: originalName
|
|
2361
|
+
};
|
|
2362
|
+
} else if (!refInDef) unboundAnchors.push(anchorName);
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
if (unboundAnchors.length > 0) {
|
|
2366
|
+
const uniqueNames = dynamicAnchorsToUniqueParamNames(unboundAnchors);
|
|
2367
|
+
for (const anchor of unboundAnchors) {
|
|
2368
|
+
const paramName = uniqueNames.get(anchor);
|
|
2369
|
+
if (paramName === void 0) continue;
|
|
2370
|
+
scope[anchor] = {
|
|
2371
|
+
name: paramName,
|
|
2372
|
+
schemaName: paramName,
|
|
2373
|
+
isParameter: true
|
|
2374
|
+
};
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2378
|
+
return scope;
|
|
2379
|
+
}
|
|
2380
|
+
/**
|
|
2381
|
+
* Resolve a `$dynamicRef` anchor to its concrete type using the current dynamic scope.
|
|
2382
|
+
* Returns `{ schema: {}, resolvedTypeName: 'unknown' }` when no scope override exists.
|
|
2383
|
+
*/
|
|
2384
|
+
function resolveDynamicRef(anchorName, context, imports = []) {
|
|
2385
|
+
let scopeEntry = (context.dynamicScope ?? {})[anchorName];
|
|
2386
|
+
if (!scopeEntry) {
|
|
2387
|
+
const schemas = context.spec.components?.schemas;
|
|
2388
|
+
if (schemas && typeof schemas === "object") for (const [schemaName, schemaObj] of Object.entries(schemas)) {
|
|
2389
|
+
if (!schemaObj || typeof schemaObj !== "object") continue;
|
|
2390
|
+
if (schemaObj.$dynamicAnchor === anchorName) {
|
|
2391
|
+
const refInfo = getRefInfo(`#/components/schemas/${encodeJsonPointerSegment(schemaName)}`, context);
|
|
2392
|
+
scopeEntry = {
|
|
2393
|
+
name: refInfo.name,
|
|
2394
|
+
schemaName: refInfo.originalName
|
|
2395
|
+
};
|
|
2396
|
+
break;
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2399
|
+
}
|
|
2400
|
+
if (!scopeEntry) return {
|
|
2401
|
+
schema: {},
|
|
2402
|
+
imports,
|
|
2403
|
+
resolvedTypeName: "unknown"
|
|
2404
|
+
};
|
|
2405
|
+
if (scopeEntry.isParameter) return {
|
|
2406
|
+
schema: {},
|
|
2407
|
+
imports,
|
|
2408
|
+
resolvedTypeName: scopeEntry.name
|
|
2409
|
+
};
|
|
2410
|
+
const resolvedTypeName = scopeEntry.name;
|
|
2411
|
+
const schemaRef = `#/components/schemas/${encodeJsonPointerSegment(scopeEntry.schemaName)}`;
|
|
2412
|
+
try {
|
|
2413
|
+
const { schema: resolvedSchema, imports: resolvedImports } = resolveRef({ $ref: schemaRef }, context, imports);
|
|
2414
|
+
return {
|
|
2415
|
+
schema: resolvedSchema,
|
|
2416
|
+
imports: resolvedImports,
|
|
2417
|
+
resolvedTypeName
|
|
2418
|
+
};
|
|
2419
|
+
} catch {
|
|
2420
|
+
return {
|
|
2421
|
+
schema: {},
|
|
2422
|
+
imports,
|
|
2423
|
+
resolvedTypeName: "unknown"
|
|
2424
|
+
};
|
|
2425
|
+
}
|
|
2426
|
+
}
|
|
2175
2427
|
/** Recursively resolves `$ref` entries in an examples array or record. */
|
|
2176
2428
|
function resolveExampleRefs(examples, context) {
|
|
2177
2429
|
if (!examples) return;
|
|
@@ -2189,8 +2441,119 @@ function resolveExampleRefs(examples, context) {
|
|
|
2189
2441
|
}
|
|
2190
2442
|
//#endregion
|
|
2191
2443
|
//#region src/resolvers/value.ts
|
|
2444
|
+
const schemaArrayKeys = [
|
|
2445
|
+
"allOf",
|
|
2446
|
+
"anyOf",
|
|
2447
|
+
"oneOf",
|
|
2448
|
+
"prefixItems"
|
|
2449
|
+
];
|
|
2450
|
+
const schemaObjectKeys = [
|
|
2451
|
+
"additionalProperties",
|
|
2452
|
+
"contains",
|
|
2453
|
+
"else",
|
|
2454
|
+
"if",
|
|
2455
|
+
"items",
|
|
2456
|
+
"not",
|
|
2457
|
+
"propertyNames",
|
|
2458
|
+
"then",
|
|
2459
|
+
"unevaluatedItems",
|
|
2460
|
+
"unevaluatedProperties"
|
|
2461
|
+
];
|
|
2462
|
+
const schemaMapKeys = [
|
|
2463
|
+
"$defs",
|
|
2464
|
+
"dependentSchemas",
|
|
2465
|
+
"patternProperties",
|
|
2466
|
+
"properties"
|
|
2467
|
+
];
|
|
2468
|
+
/**
|
|
2469
|
+
* Recursively walks a schema value and returns `true` if any nested
|
|
2470
|
+
* `$dynamicRef` resolves — via the current `context.dynamicScope` — to a
|
|
2471
|
+
* schema *other* than `refName`.
|
|
2472
|
+
*
|
|
2473
|
+
* Used by `resolveValue` to decide whether a `$ref`'d schema must be
|
|
2474
|
+
* instantiated with its bound type arguments rather than referenced by name.
|
|
2475
|
+
*
|
|
2476
|
+
* @param value - The schema node (or sub-node) to inspect.
|
|
2477
|
+
* @param context - Current resolution context, including the dynamic scope.
|
|
2478
|
+
* @param refName - The resolved name of the enclosing `$ref` schema; dynamic
|
|
2479
|
+
* refs that resolve to this same name are considered
|
|
2480
|
+
* self-references and do not count as "scope-affected".
|
|
2481
|
+
* @param seen - Cycle-guard; tracks already-visited objects.
|
|
2482
|
+
*/
|
|
2483
|
+
function hasScopeAffectedDynamicRef(value, context, refName, seen = /* @__PURE__ */ new WeakSet()) {
|
|
2484
|
+
if (!value || typeof value !== "object") return false;
|
|
2485
|
+
if (!context.dynamicScope || Object.keys(context.dynamicScope).length === 0) return false;
|
|
2486
|
+
if (seen.has(value)) return false;
|
|
2487
|
+
seen.add(value);
|
|
2488
|
+
if (isDynamicReference(value) && value.$dynamicRef.startsWith("#")) {
|
|
2489
|
+
const anchorName = getDynamicAnchorName(value.$dynamicRef);
|
|
2490
|
+
if (anchorName) {
|
|
2491
|
+
const scopeEntry = context.dynamicScope[anchorName];
|
|
2492
|
+
if (scopeEntry && scopeEntry.name !== refName) return true;
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
const schema = value;
|
|
2496
|
+
for (const key of schemaArrayKeys) {
|
|
2497
|
+
const items = schema[key];
|
|
2498
|
+
if (Array.isArray(items) && items.some((item) => hasScopeAffectedDynamicRef(item, context, refName, seen))) return true;
|
|
2499
|
+
}
|
|
2500
|
+
for (const key of schemaObjectKeys) if (hasScopeAffectedDynamicRef(schema[key], context, refName, seen)) return true;
|
|
2501
|
+
for (const key of schemaMapKeys) {
|
|
2502
|
+
const schemaMap = schema[key];
|
|
2503
|
+
if (schemaMap && typeof schemaMap === "object" && Object.values(schemaMap).some((item) => hasScopeAffectedDynamicRef(item, context, refName, seen))) return true;
|
|
2504
|
+
}
|
|
2505
|
+
return false;
|
|
2506
|
+
}
|
|
2507
|
+
function makeUnknownValue(originalSchema) {
|
|
2508
|
+
return {
|
|
2509
|
+
value: "unknown",
|
|
2510
|
+
imports: [],
|
|
2511
|
+
type: "unknown",
|
|
2512
|
+
isEnum: false,
|
|
2513
|
+
schemas: [],
|
|
2514
|
+
isRef: false,
|
|
2515
|
+
hasReadonlyProps: false,
|
|
2516
|
+
originalSchema,
|
|
2517
|
+
dependencies: []
|
|
2518
|
+
};
|
|
2519
|
+
}
|
|
2520
|
+
/**
|
|
2521
|
+
* Resolves an OpenAPI schema or reference object to a {@link ResolverValue}
|
|
2522
|
+
* that carries the TypeScript type string, required imports, and metadata.
|
|
2523
|
+
*
|
|
2524
|
+
* Handles all schema forms in priority order:
|
|
2525
|
+
* 1. **Bound generic alias** — a `$ref` with `$defs` overrides; emits an
|
|
2526
|
+
* instantiated generic expression such as `Paginated<User>`.
|
|
2527
|
+
* 2. **Component `$ref`** — a named `$ref` pointing to `#/components/…`;
|
|
2528
|
+
* emits the schema name as a reference import.
|
|
2529
|
+
* 3. **Non-component `$ref`** — an anonymous or path-level ref; inlines the
|
|
2530
|
+
* resolved schema via {@link getScalar} (cycle-safe).
|
|
2531
|
+
* 4. **`$dynamicRef`** — resolved via the active dynamic scope; falls back to
|
|
2532
|
+
* `unknown` when the anchor is absent or the ref is a bare `#`.
|
|
2533
|
+
* 5. **Plain schema** — delegates to {@link getScalar} for all other cases
|
|
2534
|
+
* (primitives, objects, arrays, enums, …).
|
|
2535
|
+
*/
|
|
2192
2536
|
function resolveValue({ schema, name, context, formDataContext }) {
|
|
2193
2537
|
if (isReference(schema)) {
|
|
2538
|
+
const alias = extractBoundAliasInfo(schema, context);
|
|
2539
|
+
if (alias) {
|
|
2540
|
+
const value = `${alias.genericName}<${alias.typeArgs.join(", ")}>`;
|
|
2541
|
+
const allImports = [{
|
|
2542
|
+
name: alias.genericName,
|
|
2543
|
+
schemaName: alias.genericName
|
|
2544
|
+
}, ...alias.imports];
|
|
2545
|
+
return {
|
|
2546
|
+
value,
|
|
2547
|
+
imports: allImports,
|
|
2548
|
+
type: "object",
|
|
2549
|
+
schemas: [],
|
|
2550
|
+
isEnum: false,
|
|
2551
|
+
originalSchema: schema,
|
|
2552
|
+
hasReadonlyProps: false,
|
|
2553
|
+
isRef: true,
|
|
2554
|
+
dependencies: allImports.map((i) => i.name)
|
|
2555
|
+
};
|
|
2556
|
+
}
|
|
2194
2557
|
const refValue = schema.$ref;
|
|
2195
2558
|
const { schema: schemaObject, imports } = resolveRef(schema, context);
|
|
2196
2559
|
if (refValue && !isComponentRef(refValue)) {
|
|
@@ -2232,6 +2595,19 @@ function resolveValue({ schema, name, context, formDataContext }) {
|
|
|
2232
2595
|
const resolvedImport = imports[0];
|
|
2233
2596
|
let hasReadonlyProps = false;
|
|
2234
2597
|
const refName = resolvedImport.name;
|
|
2598
|
+
if (!context.parents?.includes(refName) && hasScopeAffectedDynamicRef(schemaObject, context, refName)) return {
|
|
2599
|
+
...getScalar({
|
|
2600
|
+
item: schemaObject,
|
|
2601
|
+
name: name ?? refName,
|
|
2602
|
+
context: {
|
|
2603
|
+
...context,
|
|
2604
|
+
parents: [...context.parents ?? [], refName]
|
|
2605
|
+
},
|
|
2606
|
+
formDataContext
|
|
2607
|
+
}),
|
|
2608
|
+
originalSchema: schemaObject,
|
|
2609
|
+
isRef: false
|
|
2610
|
+
};
|
|
2235
2611
|
if (!context.parents?.includes(refName)) hasReadonlyProps = getScalar({
|
|
2236
2612
|
item: schemaObject,
|
|
2237
2613
|
name: refName,
|
|
@@ -2258,6 +2634,25 @@ function resolveValue({ schema, name, context, formDataContext }) {
|
|
|
2258
2634
|
dependencies: [resolvedImport.name]
|
|
2259
2635
|
};
|
|
2260
2636
|
}
|
|
2637
|
+
if (isDynamicReference(schema)) {
|
|
2638
|
+
const dynamicRef = schema.$dynamicRef;
|
|
2639
|
+
if (!dynamicRef.startsWith("#")) return makeUnknownValue(schema);
|
|
2640
|
+
const anchorName = getDynamicAnchorName(dynamicRef);
|
|
2641
|
+
if (!anchorName) return makeUnknownValue(schema);
|
|
2642
|
+
const { imports: resolvedImports, resolvedTypeName } = resolveDynamicRef(anchorName, context);
|
|
2643
|
+
if (resolvedTypeName === "unknown") return makeUnknownValue(schema);
|
|
2644
|
+
return {
|
|
2645
|
+
value: resolvedTypeName,
|
|
2646
|
+
imports: resolvedImports,
|
|
2647
|
+
type: "object",
|
|
2648
|
+
isEnum: false,
|
|
2649
|
+
schemas: [],
|
|
2650
|
+
isRef: true,
|
|
2651
|
+
hasReadonlyProps: false,
|
|
2652
|
+
originalSchema: schema,
|
|
2653
|
+
dependencies: [resolvedTypeName]
|
|
2654
|
+
};
|
|
2655
|
+
}
|
|
2261
2656
|
return {
|
|
2262
2657
|
...getScalar({
|
|
2263
2658
|
item: schema,
|
|
@@ -2349,7 +2744,8 @@ function resolveObject({ schema, propName, combined = false, context, formDataCo
|
|
|
2349
2744
|
propName,
|
|
2350
2745
|
combined,
|
|
2351
2746
|
projectName: context.projectName ?? context.output.target,
|
|
2352
|
-
formDataContext
|
|
2747
|
+
formDataContext,
|
|
2748
|
+
dynamicScope: context.dynamicScope
|
|
2353
2749
|
});
|
|
2354
2750
|
if (resolveObjectCacheMap.has(hashKey)) return resolveObjectCacheMap.get(hashKey);
|
|
2355
2751
|
const result = resolveObjectOriginal({
|
|
@@ -3018,6 +3414,61 @@ function resolveDiscriminators(schemas, context) {
|
|
|
3018
3414
|
}
|
|
3019
3415
|
}
|
|
3020
3416
|
}
|
|
3417
|
+
for (const [parentName, parentSchema] of Object.entries(transformedSchemas)) {
|
|
3418
|
+
if (isBoolean$1(parentSchema)) continue;
|
|
3419
|
+
if (!parentSchema.oneOf || !parentSchema.discriminator?.mapping) continue;
|
|
3420
|
+
const { mapping, propertyName } = parentSchema.discriminator;
|
|
3421
|
+
if (!propertyName) continue;
|
|
3422
|
+
const parentProperties = parentSchema.properties;
|
|
3423
|
+
const parentRequired = parentSchema.required;
|
|
3424
|
+
const inheritableProps = {};
|
|
3425
|
+
if (parentProperties) {
|
|
3426
|
+
for (const [key, value] of Object.entries(parentProperties)) if (key !== propertyName) inheritableProps[key] = value;
|
|
3427
|
+
}
|
|
3428
|
+
const inheritableRequired = parentRequired?.filter((key) => key !== propertyName);
|
|
3429
|
+
const hasInheritableProps = Object.keys(inheritableProps).length > 0;
|
|
3430
|
+
for (const mappingValue of Object.values(mapping)) {
|
|
3431
|
+
let variantSchema;
|
|
3432
|
+
try {
|
|
3433
|
+
const { originalName } = getRefInfo(mappingValue, context);
|
|
3434
|
+
variantSchema = transformedSchemas[pascal(originalName)] ?? transformedSchemas[originalName];
|
|
3435
|
+
} catch {
|
|
3436
|
+
variantSchema = transformedSchemas[mappingValue];
|
|
3437
|
+
}
|
|
3438
|
+
if (!variantSchema || isBoolean$1(variantSchema)) continue;
|
|
3439
|
+
const variantAllOf = variantSchema.allOf;
|
|
3440
|
+
if (!variantAllOf) continue;
|
|
3441
|
+
const rewritten = [];
|
|
3442
|
+
for (const item of variantAllOf) {
|
|
3443
|
+
if (!isReference(item) || !item.$ref) {
|
|
3444
|
+
rewritten.push(item);
|
|
3445
|
+
continue;
|
|
3446
|
+
}
|
|
3447
|
+
let refOriginalName;
|
|
3448
|
+
try {
|
|
3449
|
+
refOriginalName = getRefInfo(item.$ref, context).originalName;
|
|
3450
|
+
} catch {
|
|
3451
|
+
refOriginalName = void 0;
|
|
3452
|
+
}
|
|
3453
|
+
if (!(refOriginalName === parentName || refOriginalName !== void 0 && pascal(refOriginalName) === pascal(parentName))) {
|
|
3454
|
+
rewritten.push(item);
|
|
3455
|
+
continue;
|
|
3456
|
+
}
|
|
3457
|
+
const inlinedParent = { ...parentSchema };
|
|
3458
|
+
delete inlinedParent.oneOf;
|
|
3459
|
+
delete inlinedParent.discriminator;
|
|
3460
|
+
delete inlinedParent.allOf;
|
|
3461
|
+
delete inlinedParent.anyOf;
|
|
3462
|
+
if (hasInheritableProps) inlinedParent.properties = { ...inheritableProps };
|
|
3463
|
+
else delete inlinedParent.properties;
|
|
3464
|
+
if (inheritableRequired && inheritableRequired.length > 0) inlinedParent.required = [...inheritableRequired];
|
|
3465
|
+
else delete inlinedParent.required;
|
|
3466
|
+
if (Object.keys(inlinedParent).filter((key) => key !== "type").length > 0) rewritten.push(inlinedParent);
|
|
3467
|
+
}
|
|
3468
|
+
if (rewritten.length === 0) delete variantSchema.allOf;
|
|
3469
|
+
else variantSchema.allOf = rewritten;
|
|
3470
|
+
}
|
|
3471
|
+
}
|
|
3021
3472
|
return transformedSchemas;
|
|
3022
3473
|
}
|
|
3023
3474
|
//#endregion
|
|
@@ -3270,7 +3721,8 @@ function getQueryParamsTypes(queryParams, operationName, context) {
|
|
|
3270
3721
|
};
|
|
3271
3722
|
if (resolvedValue.isEnum && !resolvedValue.isRef) {
|
|
3272
3723
|
const enumName = queryName;
|
|
3273
|
-
const
|
|
3724
|
+
const parameterAsSchema = parameter;
|
|
3725
|
+
const enumValue = getEnum(resolvedValue.value, enumName, getEnumNames(resolvedValue.originalSchema) ?? getEnumNames(parameterAsSchema), context.output.override.enumGenerationType, getEnumDescriptions(resolvedValue.originalSchema) ?? getEnumDescriptions(parameterAsSchema), context.output.override.namingConvention.enum);
|
|
3274
3726
|
return {
|
|
3275
3727
|
name,
|
|
3276
3728
|
required,
|
|
@@ -3312,6 +3764,7 @@ function getQueryParams({ queryParams, operationName, context, suffix = "params"
|
|
|
3312
3764
|
},
|
|
3313
3765
|
deps: schemas,
|
|
3314
3766
|
isOptional: allOptional,
|
|
3767
|
+
paramNames: types.map(({ name }) => name),
|
|
3315
3768
|
requiredNullableKeys,
|
|
3316
3769
|
...nonPrimitiveKeys.length > 0 ? { nonPrimitiveKeys } : {}
|
|
3317
3770
|
};
|
|
@@ -3470,6 +3923,231 @@ function generateComponentDefinition(responses = {}, context, suffix) {
|
|
|
3470
3923
|
return generatorSchemas;
|
|
3471
3924
|
}
|
|
3472
3925
|
//#endregion
|
|
3926
|
+
//#region src/generators/factory.ts
|
|
3927
|
+
const circularRefCache = /* @__PURE__ */ new WeakMap();
|
|
3928
|
+
function getSchemasPath(context) {
|
|
3929
|
+
const { schemas, target } = context.output;
|
|
3930
|
+
if (schemas) return normalizeSafe(isString(schemas) ? schemas : schemas.path);
|
|
3931
|
+
const { dirname, filename } = getFileInfo(target);
|
|
3932
|
+
return joinSafe(dirname, filename + ".schemas");
|
|
3933
|
+
}
|
|
3934
|
+
function getSchemaImportPath(refName, context) {
|
|
3935
|
+
if (context.output.factoryMethods?.mode === "single") return;
|
|
3936
|
+
let outputDir = context.output.factoryMethods?.outputDirectory;
|
|
3937
|
+
let schemasPath = getSchemasPath(context);
|
|
3938
|
+
if (context.output.workspace) {
|
|
3939
|
+
if (outputDir && !isAbsolute(outputDir)) outputDir = resolve(context.output.workspace, outputDir);
|
|
3940
|
+
if (schemasPath && !isAbsolute(schemasPath)) schemasPath = resolve(context.output.workspace, schemasPath);
|
|
3941
|
+
}
|
|
3942
|
+
return joinSafe(outputDir ? relativeSafe(outputDir, schemasPath) : "./", conventionName(refName, context.output.namingConvention));
|
|
3943
|
+
}
|
|
3944
|
+
function isReference$1(schema) {
|
|
3945
|
+
return "$ref" in schema;
|
|
3946
|
+
}
|
|
3947
|
+
function getResolvedRef(schema, context) {
|
|
3948
|
+
return resolveRef(schema, context);
|
|
3949
|
+
}
|
|
3950
|
+
function getProperties(schema) {
|
|
3951
|
+
return schema.properties ?? {};
|
|
3952
|
+
}
|
|
3953
|
+
function getItems(schema) {
|
|
3954
|
+
return schema.items;
|
|
3955
|
+
}
|
|
3956
|
+
function getAdditionalProperties(schema) {
|
|
3957
|
+
return schema.additionalProperties;
|
|
3958
|
+
}
|
|
3959
|
+
function getSchemas(schemas) {
|
|
3960
|
+
return schemas;
|
|
3961
|
+
}
|
|
3962
|
+
function getExtendedProps(schema) {
|
|
3963
|
+
const extended = schema;
|
|
3964
|
+
return {
|
|
3965
|
+
constValue: extended.const,
|
|
3966
|
+
prefixItems: extended.prefixItems,
|
|
3967
|
+
minItems: extended.minItems
|
|
3968
|
+
};
|
|
3969
|
+
}
|
|
3970
|
+
function generateFactory(schema, name, context) {
|
|
3971
|
+
if (!canGenerateSchema(schema) || !context.output.factoryMethods) return void 0;
|
|
3972
|
+
const { functionNamePrefix, mode } = context.output.factoryMethods;
|
|
3973
|
+
const factoryName = `${functionNamePrefix}${pascal(name)}`;
|
|
3974
|
+
const imports = [];
|
|
3975
|
+
const payload = buildPayload(schema, context, [name], imports);
|
|
3976
|
+
if (mode !== "single") {
|
|
3977
|
+
const schemaImportPath = getSchemaImportPath(name, context);
|
|
3978
|
+
imports.push({
|
|
3979
|
+
name,
|
|
3980
|
+
importPath: schemaImportPath
|
|
3981
|
+
});
|
|
3982
|
+
}
|
|
3983
|
+
return {
|
|
3984
|
+
model: `export function ${factoryName}(): ${name} {\n return ${payload};\n}\n`,
|
|
3985
|
+
imports
|
|
3986
|
+
};
|
|
3987
|
+
}
|
|
3988
|
+
function canGenerateSchema(schema) {
|
|
3989
|
+
return schema.type === "object" || schema.type === "array" || !!schema.properties || !!schema.allOf || !!schema.oneOf || !!schema.anyOf || !!schema.items || !!schema.enum;
|
|
3990
|
+
}
|
|
3991
|
+
function hasCircularReference(target, sourceName, context, visited = /* @__PURE__ */ new Set()) {
|
|
3992
|
+
if (isReference$1(target)) {
|
|
3993
|
+
const { imports, schema } = getResolvedRef(target, context);
|
|
3994
|
+
const refName = imports[0]?.name;
|
|
3995
|
+
if (refName === sourceName) return true;
|
|
3996
|
+
if (refName && visited.has(refName)) return false;
|
|
3997
|
+
if (refName) visited.add(refName);
|
|
3998
|
+
let cache = circularRefCache.get(context);
|
|
3999
|
+
if (!cache) {
|
|
4000
|
+
cache = /* @__PURE__ */ new Map();
|
|
4001
|
+
circularRefCache.set(context, cache);
|
|
4002
|
+
}
|
|
4003
|
+
const cacheKey = refName ? `${sourceName}::${refName}` : void 0;
|
|
4004
|
+
if (cacheKey) {
|
|
4005
|
+
const cached = cache.get(cacheKey);
|
|
4006
|
+
if (cached !== void 0) return cached;
|
|
4007
|
+
}
|
|
4008
|
+
const result = hasCircularReference(schema, sourceName, context, visited);
|
|
4009
|
+
if (cacheKey) cache.set(cacheKey, result);
|
|
4010
|
+
return result;
|
|
4011
|
+
}
|
|
4012
|
+
const check = (schemas) => schemas?.some((s) => hasCircularReference(s, sourceName, context, visited)) ?? false;
|
|
4013
|
+
const items = getItems(target);
|
|
4014
|
+
const additionalProperties = getAdditionalProperties(target);
|
|
4015
|
+
return check(getSchemas(target.allOf)) || check(getSchemas(target.oneOf)) || check(getSchemas(target.anyOf)) || Object.values(getProperties(target)).some((s) => hasCircularReference(s, sourceName, context, visited)) || !!items && hasCircularReference(items, sourceName, context, visited) || typeof additionalProperties === "object" && hasCircularReference(additionalProperties, sourceName, context, visited);
|
|
4016
|
+
}
|
|
4017
|
+
function buildPayload(target, context, parents, imports) {
|
|
4018
|
+
if (isReference$1(target)) return buildRefPayload(target, context, parents, imports);
|
|
4019
|
+
const schema = target;
|
|
4020
|
+
if (schema.allOf) return buildAllOfPayload(getSchemas(schema.allOf) ?? [], context, parents, imports);
|
|
4021
|
+
if (schema.oneOf) return buildFirstOfPayload(getSchemas(schema.oneOf) ?? [], context, parents, imports);
|
|
4022
|
+
if (schema.anyOf) return buildFirstOfPayload(getSchemas(schema.anyOf) ?? [], context, parents, imports);
|
|
4023
|
+
const { constValue } = getExtendedProps(schema);
|
|
4024
|
+
if (constValue !== void 0) return formatValue(constValue);
|
|
4025
|
+
if (schema.default !== void 0) return buildDefaultPayload(schema, context);
|
|
4026
|
+
const schemaType = inferSchemaType(schema);
|
|
4027
|
+
if (schemaType === "object" || schema.properties) return buildObjectPayload(schema, context, parents, imports);
|
|
4028
|
+
if (schemaType === "array") return buildArrayPayload(schema, context, parents, imports);
|
|
4029
|
+
return buildPrimitivePayload(schema, schemaType, context);
|
|
4030
|
+
}
|
|
4031
|
+
function buildRefPayload(schema, context, parents, imports) {
|
|
4032
|
+
const { schema: resolved, imports: refImports } = getResolvedRef(schema, context);
|
|
4033
|
+
const refName = refImports[0]?.name;
|
|
4034
|
+
if (!refName) return "{}";
|
|
4035
|
+
if (parents.includes(refName) || hasCircularReference(resolved, parents[0], context)) {
|
|
4036
|
+
imports.push({
|
|
4037
|
+
name: refName,
|
|
4038
|
+
importPath: getSchemaImportPath(refName, context)
|
|
4039
|
+
});
|
|
4040
|
+
return `{} as ${refName}`;
|
|
4041
|
+
}
|
|
4042
|
+
const { functionNamePrefix = "create", mode = "single" } = context.output.factoryMethods ?? {};
|
|
4043
|
+
const refFactoryName = `${functionNamePrefix}${pascal(refName)}`;
|
|
4044
|
+
if (mode !== "single-split") {
|
|
4045
|
+
const importPath = resolveImportPath(mode, refName, context);
|
|
4046
|
+
imports.push({
|
|
4047
|
+
name: refFactoryName,
|
|
4048
|
+
importPath,
|
|
4049
|
+
isConstant: true
|
|
4050
|
+
});
|
|
4051
|
+
}
|
|
4052
|
+
imports.push({
|
|
4053
|
+
name: refName,
|
|
4054
|
+
importPath: getSchemaImportPath(refName, context)
|
|
4055
|
+
});
|
|
4056
|
+
return `${refFactoryName}()`;
|
|
4057
|
+
}
|
|
4058
|
+
function resolveImportPath(mode, refName, context) {
|
|
4059
|
+
const baseName = conventionName(refName, context.output.namingConvention);
|
|
4060
|
+
switch (mode) {
|
|
4061
|
+
case "split": return `./${baseName}.factory`;
|
|
4062
|
+
case "single-split": return `./${conventionName("factoryMethods", context.output.namingConvention)}`;
|
|
4063
|
+
case "single": return `./${baseName}`;
|
|
4064
|
+
}
|
|
4065
|
+
}
|
|
4066
|
+
function buildAllOfPayload(allOf, context, parents, imports) {
|
|
4067
|
+
const payloads = allOf.map((s) => buildPayload(s, context, parents, imports));
|
|
4068
|
+
return payloads.length > 0 ? `Object.assign({}, ${payloads.join(", ")})` : "{}";
|
|
4069
|
+
}
|
|
4070
|
+
function buildFirstOfPayload(schemas, context, parents, imports) {
|
|
4071
|
+
const first = schemas[0];
|
|
4072
|
+
return first ? buildPayload(first, context, parents, imports) : "{}";
|
|
4073
|
+
}
|
|
4074
|
+
function buildObjectPayload(schema, context, parents, imports) {
|
|
4075
|
+
const { includeOptionalProperty = false } = context.output.factoryMethods ?? {};
|
|
4076
|
+
const props = getProperties(schema);
|
|
4077
|
+
const requiredProps = schema.required ?? [];
|
|
4078
|
+
const entries = Object.entries(props);
|
|
4079
|
+
if (context.output.propertySortOrder === PropertySortOrder.ALPHABETICAL) entries.sort(([a], [b]) => a.localeCompare(b));
|
|
4080
|
+
const includeOptional = includeOptionalProperty;
|
|
4081
|
+
const lines = [];
|
|
4082
|
+
for (const [key, prop] of entries) {
|
|
4083
|
+
const isRequired = requiredProps.includes(key);
|
|
4084
|
+
const resolved = isReference$1(prop) ? getResolvedRef(prop, context).schema : prop;
|
|
4085
|
+
const isReadOnly = !!prop.readOnly || !!resolved.readOnly;
|
|
4086
|
+
const isWriteOnly = !!prop.writeOnly || !!resolved.writeOnly;
|
|
4087
|
+
if (!isRequired) {
|
|
4088
|
+
if (isReadOnly) continue;
|
|
4089
|
+
if (!isWriteOnly && !includeOptional) continue;
|
|
4090
|
+
}
|
|
4091
|
+
const payload = buildPayload(prop, context, parents, imports);
|
|
4092
|
+
const safeKey = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key) ? key : JSON.stringify(key);
|
|
4093
|
+
lines.push(`${safeKey}: ${payload}`);
|
|
4094
|
+
}
|
|
4095
|
+
return `{\n ${lines.join(",\n ")}\n }`;
|
|
4096
|
+
}
|
|
4097
|
+
function buildArrayPayload(schema, context, parents, imports) {
|
|
4098
|
+
const { prefixItems, minItems } = getExtendedProps(schema);
|
|
4099
|
+
const items = getItems(schema);
|
|
4100
|
+
if (prefixItems && prefixItems.length > 0) return `[${prefixItems.map((item) => buildPayload(item, context, parents, imports)).join(", ")}]`;
|
|
4101
|
+
if (minItems && items) {
|
|
4102
|
+
const MAX_MIN_ITEMS = 50;
|
|
4103
|
+
if (minItems > MAX_MIN_ITEMS) logWarning(`Warning: minItems is ${minItems}, capping at ${MAX_MIN_ITEMS} to prevent massive payload.`);
|
|
4104
|
+
const count = Math.min(minItems, MAX_MIN_ITEMS);
|
|
4105
|
+
const itemPayload = buildPayload(items, context, parents, imports);
|
|
4106
|
+
return `[${Array.from({ length: count }).fill(itemPayload).join(", ")}]`;
|
|
4107
|
+
}
|
|
4108
|
+
return "[]";
|
|
4109
|
+
}
|
|
4110
|
+
function inferSchemaType(schema) {
|
|
4111
|
+
let type = schema.type;
|
|
4112
|
+
if (Array.isArray(type)) {
|
|
4113
|
+
const nonNull = type.filter((t) => t !== "null");
|
|
4114
|
+
type = nonNull.length > 0 ? nonNull[0] : "null";
|
|
4115
|
+
}
|
|
4116
|
+
if (!type && schema.items) return "array";
|
|
4117
|
+
if (!type && schema.enum) {
|
|
4118
|
+
const first = schema.enum[0];
|
|
4119
|
+
if (typeof first === "number") return "number";
|
|
4120
|
+
if (typeof first === "boolean") return "boolean";
|
|
4121
|
+
return "string";
|
|
4122
|
+
}
|
|
4123
|
+
return type;
|
|
4124
|
+
}
|
|
4125
|
+
function buildDefaultPayload(schema, context) {
|
|
4126
|
+
if (context.output.override.useDates && typeof schema.default === "string" && (schema.format === "date" || schema.format === "date-time")) return `new Date('${schema.default}')`;
|
|
4127
|
+
return formatValue(schema.default);
|
|
4128
|
+
}
|
|
4129
|
+
function buildPrimitivePayload(schema, schemaType, context) {
|
|
4130
|
+
if (schemaType === "null") return "null";
|
|
4131
|
+
const enumValues = schema.enum;
|
|
4132
|
+
if (schemaType === "boolean") return enumValues && enumValues.length > 0 ? String(enumValues[0]) : "false";
|
|
4133
|
+
if (schemaType === "number" || schemaType === "integer") return enumValues && enumValues.length > 0 ? String(enumValues[0]) : "0";
|
|
4134
|
+
if (schemaType === "string") {
|
|
4135
|
+
if (enumValues && enumValues.length > 0) {
|
|
4136
|
+
const first = enumValues[0];
|
|
4137
|
+
return typeof first === "string" ? JSON.stringify(first) : String(first);
|
|
4138
|
+
}
|
|
4139
|
+
if (schema.format === "date" || schema.format === "date-time") return context.output.override.useDates ? "new Date(0)" : `'${(/* @__PURE__ */ new Date(0)).toISOString()}'`;
|
|
4140
|
+
return "''";
|
|
4141
|
+
}
|
|
4142
|
+
return "undefined as unknown";
|
|
4143
|
+
}
|
|
4144
|
+
function formatValue(val) {
|
|
4145
|
+
if (val === null) return "null";
|
|
4146
|
+
if (typeof val === "string") return JSON.stringify(val);
|
|
4147
|
+
if (typeof val === "object") return JSON.stringify(val);
|
|
4148
|
+
return String(val);
|
|
4149
|
+
}
|
|
4150
|
+
//#endregion
|
|
3473
4151
|
//#region src/generators/imports.ts
|
|
3474
4152
|
function generateImports({ imports, namingConvention = NamingConvention.CAMEL_CASE, importExtension = "" }) {
|
|
3475
4153
|
if (imports.length === 0) return "";
|
|
@@ -4160,7 +4838,7 @@ function generateParameterDefinition(parameters = {}, context, suffix) {
|
|
|
4160
4838
|
* @param name interface name
|
|
4161
4839
|
* @param schema
|
|
4162
4840
|
*/
|
|
4163
|
-
function generateInterface({ name, schema, context }) {
|
|
4841
|
+
function generateInterface({ name, schema, context, genericParams }) {
|
|
4164
4842
|
const scalar = getScalar({
|
|
4165
4843
|
item: schema,
|
|
4166
4844
|
name,
|
|
@@ -4168,6 +4846,7 @@ function generateInterface({ name, schema, context }) {
|
|
|
4168
4846
|
});
|
|
4169
4847
|
const isEmptyObject = scalar.value === "{}";
|
|
4170
4848
|
const shouldUseTypeAlias = context.output.override.useTypeOverInterfaces ?? scalar.useTypeAlias;
|
|
4849
|
+
const genericSuffix = genericParams && genericParams.length > 0 ? `<${genericParams.join(", ")}>` : "";
|
|
4171
4850
|
let model = "";
|
|
4172
4851
|
model += jsDoc(schema);
|
|
4173
4852
|
if (isEmptyObject) model += "// eslint-disable-next-line @typescript-eslint/no-empty-interface\n";
|
|
@@ -4175,12 +4854,12 @@ function generateInterface({ name, schema, context }) {
|
|
|
4175
4854
|
const properties = schema.properties;
|
|
4176
4855
|
if (properties && Object.values(properties).length > 0 && Object.values(properties).every((item) => "const" in item)) {
|
|
4177
4856
|
const mappedScalarValue = scalar.value.replaceAll(";", ",").replaceAll("?:", ":");
|
|
4178
|
-
model += `export const ${name}Value = ${mappedScalarValue} as const;\nexport type ${name} = typeof ${name}Value;\n`;
|
|
4857
|
+
model += `export const ${name}Value = ${mappedScalarValue} as const;\nexport type ${name}${genericSuffix} = typeof ${name}Value;\n`;
|
|
4179
4858
|
} else {
|
|
4180
4859
|
const blankInterfaceValue = scalar.value === "unknown" ? "{}" : scalar.value;
|
|
4181
|
-
model += `export interface ${name} ${blankInterfaceValue}\n`;
|
|
4860
|
+
model += `export interface ${name}${genericSuffix} ${blankInterfaceValue}\n`;
|
|
4182
4861
|
}
|
|
4183
|
-
} else model += `export type ${name} = ${scalar.value};\n`;
|
|
4862
|
+
} else model += `export type ${name}${genericSuffix} = ${scalar.value};\n`;
|
|
4184
4863
|
const externalModulesImportsOnly = scalar.imports.filter((importName) => importName.alias ? importName.alias !== name : importName.name !== name);
|
|
4185
4864
|
return [...scalar.schemas, {
|
|
4186
4865
|
name,
|
|
@@ -4214,6 +4893,17 @@ function generateSchemasDefinition(schemas = {}, context, suffix, filters) {
|
|
|
4214
4893
|
const normalizedName = conventionName(schema.name, context.output.namingConvention);
|
|
4215
4894
|
if (!seenNames.has(normalizedName)) {
|
|
4216
4895
|
seenNames.add(normalizedName);
|
|
4896
|
+
if (context.output.factoryMethods && schema.schema) {
|
|
4897
|
+
const factoryData = generateFactory(schema.schema, schema.name, context);
|
|
4898
|
+
if (factoryData) if (context.output.factoryMethods.mode === "single") {
|
|
4899
|
+
schema.model += `\n${factoryData.model}`;
|
|
4900
|
+
for (const imp of factoryData.imports) if (!schema.imports.some((existing) => existing.name === imp.name)) schema.imports.push(imp);
|
|
4901
|
+
} else {
|
|
4902
|
+
schema.factory = factoryData.model;
|
|
4903
|
+
schema.factoryImports = factoryData.imports;
|
|
4904
|
+
schema.factoryMode = context.output.factoryMethods.mode;
|
|
4905
|
+
}
|
|
4906
|
+
}
|
|
4217
4907
|
deduplicatedModels.push(schema);
|
|
4218
4908
|
}
|
|
4219
4909
|
}
|
|
@@ -4258,6 +4948,21 @@ function shouldCreateInterface(schema) {
|
|
|
4258
4948
|
const isNullable = isArray(schema.type) && schema.type.includes("null");
|
|
4259
4949
|
return (!schema.type || schema.type === "object") && !schema.allOf && !schema.oneOf && !schema.anyOf && isDereferenced(schema) && !schema.enum && !isNullable;
|
|
4260
4950
|
}
|
|
4951
|
+
function collectGenericParams(schema) {
|
|
4952
|
+
const defs = schema.$defs;
|
|
4953
|
+
if (!defs || typeof defs !== "object") return [];
|
|
4954
|
+
const anchors = [];
|
|
4955
|
+
for (const defSchema of Object.values(defs)) {
|
|
4956
|
+
if (!defSchema || typeof defSchema !== "object") continue;
|
|
4957
|
+
const rec = defSchema;
|
|
4958
|
+
if (rec.$dynamicAnchor !== void 0 && rec.$ref === void 0) anchors.push(rec.$dynamicAnchor);
|
|
4959
|
+
}
|
|
4960
|
+
const uniqueNames = dynamicAnchorsToUniqueParamNames(anchors);
|
|
4961
|
+
return anchors.map((anchor) => ({
|
|
4962
|
+
anchorName: anchor,
|
|
4963
|
+
paramName: uniqueNames.get(anchor) ?? dynamicAnchorToParamName(anchor)
|
|
4964
|
+
}));
|
|
4965
|
+
}
|
|
4261
4966
|
function generateSchemaDefinitions(schemaName, schema, context, suffix) {
|
|
4262
4967
|
const sanitizedSchemaName = sanitize(`${pascal(schemaName)}${suffix}`, {
|
|
4263
4968
|
underscore: "_",
|
|
@@ -4272,22 +4977,82 @@ function generateSchemaDefinitions(schemaName, schema, context, suffix) {
|
|
|
4272
4977
|
imports: [],
|
|
4273
4978
|
schema
|
|
4274
4979
|
}];
|
|
4980
|
+
const alias = extractBoundAliasInfo(schema, context);
|
|
4981
|
+
if (alias) {
|
|
4982
|
+
const genericParams = alias.genericParams.map((paramName) => ({
|
|
4983
|
+
anchorName: paramName,
|
|
4984
|
+
paramName
|
|
4985
|
+
}));
|
|
4986
|
+
const genericSuffix = genericParams.length > 0 ? `<${genericParams.map((p) => p.paramName).join(", ")}>` : "";
|
|
4987
|
+
const typeArgsStr = alias.typeArgs.join(", ");
|
|
4988
|
+
const genericPart = `${alias.genericName}<${typeArgsStr}>`;
|
|
4989
|
+
const schemaType = schema.type;
|
|
4990
|
+
const nullable = Array.isArray(schemaType) && schemaType.includes("null") || schema.nullable === true ? " | null" : "";
|
|
4991
|
+
let model;
|
|
4992
|
+
const allImports = [{
|
|
4993
|
+
name: alias.genericName,
|
|
4994
|
+
schemaName: alias.genericName
|
|
4995
|
+
}, ...alias.imports];
|
|
4996
|
+
if (alias.extraSchemas && alias.extraSchemas.length > 0) {
|
|
4997
|
+
const aliasScopedContext = {
|
|
4998
|
+
...context,
|
|
4999
|
+
dynamicScope: buildDynamicScope(schemaName, schema, context)
|
|
5000
|
+
};
|
|
5001
|
+
const subSchemas = [];
|
|
5002
|
+
model = `export type ${sanitizedSchemaName}${genericSuffix} = (${[genericPart, ...alias.extraSchemas.map((extraSchema) => {
|
|
5003
|
+
const resolved = resolveValue({
|
|
5004
|
+
schema: extraSchema,
|
|
5005
|
+
name: sanitizedSchemaName,
|
|
5006
|
+
context: aliasScopedContext
|
|
5007
|
+
});
|
|
5008
|
+
for (const imp of resolved.imports) {
|
|
5009
|
+
const impSchemaName = imp.schemaName ?? imp.name;
|
|
5010
|
+
if (!allImports.some((a) => a.name === imp.name && a.schemaName === impSchemaName)) allImports.push({
|
|
5011
|
+
name: imp.name,
|
|
5012
|
+
schemaName: impSchemaName
|
|
5013
|
+
});
|
|
5014
|
+
}
|
|
5015
|
+
for (const sub of resolved.schemas) if (sub.name !== sanitizedSchemaName) subSchemas.push(sub);
|
|
5016
|
+
return resolved.value;
|
|
5017
|
+
})].join(" & ")})${nullable};\n`;
|
|
5018
|
+
return [...subSchemas, {
|
|
5019
|
+
name: sanitizedSchemaName,
|
|
5020
|
+
model,
|
|
5021
|
+
imports: allImports,
|
|
5022
|
+
dependencies: allImports.map((i) => i.name),
|
|
5023
|
+
schema
|
|
5024
|
+
}];
|
|
5025
|
+
} else model = `export type ${sanitizedSchemaName}${genericSuffix} = ${genericPart}${nullable};\n`;
|
|
5026
|
+
return [{
|
|
5027
|
+
name: sanitizedSchemaName,
|
|
5028
|
+
model,
|
|
5029
|
+
imports: allImports,
|
|
5030
|
+
dependencies: allImports.map((i) => i.name),
|
|
5031
|
+
schema
|
|
5032
|
+
}];
|
|
5033
|
+
}
|
|
5034
|
+
const scopedContext = isBoolean(schema) ? context : {
|
|
5035
|
+
...context,
|
|
5036
|
+
dynamicScope: buildDynamicScope(schemaName, schema, context)
|
|
5037
|
+
};
|
|
5038
|
+
const genericParams = collectGenericParams(schema);
|
|
4275
5039
|
if (shouldCreateInterface(schema)) return generateInterface({
|
|
4276
5040
|
name: sanitizedSchemaName,
|
|
4277
5041
|
schema,
|
|
4278
|
-
context
|
|
5042
|
+
context: scopedContext,
|
|
5043
|
+
genericParams: genericParams.length > 0 ? genericParams.map((p) => p.paramName) : void 0
|
|
4279
5044
|
});
|
|
4280
5045
|
const resolvedValue = resolveValue({
|
|
4281
5046
|
schema,
|
|
4282
5047
|
name: sanitizedSchemaName,
|
|
4283
|
-
context
|
|
5048
|
+
context: scopedContext
|
|
4284
5049
|
});
|
|
4285
5050
|
let output = "";
|
|
4286
5051
|
let imports = resolvedValue.imports;
|
|
4287
5052
|
output += jsDoc(schema);
|
|
4288
5053
|
if (resolvedValue.isEnum && !resolvedValue.isRef) output += getEnum(resolvedValue.value, sanitizedSchemaName, getEnumNames(resolvedValue.originalSchema), context.output.override.enumGenerationType, getEnumDescriptions(resolvedValue.originalSchema), context.output.override.namingConvention.enum);
|
|
4289
5054
|
else if (sanitizedSchemaName === resolvedValue.value && resolvedValue.isRef) {
|
|
4290
|
-
const { schema: referredSchema } = resolveRef(schema,
|
|
5055
|
+
const { schema: referredSchema } = resolveRef(schema, scopedContext);
|
|
4291
5056
|
if (!shouldCreateInterface(referredSchema)) {
|
|
4292
5057
|
const imp = resolvedValue.imports.find((imp) => imp.name === sanitizedSchemaName);
|
|
4293
5058
|
if (imp) {
|
|
@@ -4308,7 +5073,8 @@ function generateSchemaDefinitions(schemaName, schema, context, suffix) {
|
|
|
4308
5073
|
resolvedValue.dependencies.push(...schema.dependencies ?? []);
|
|
4309
5074
|
return false;
|
|
4310
5075
|
});
|
|
4311
|
-
|
|
5076
|
+
const genericSuffix = genericParams.length > 0 ? `<${genericParams.map((p) => p.paramName).join(", ")}>` : "";
|
|
5077
|
+
output += `export type ${sanitizedSchemaName}${genericSuffix} = ${resolvedValue.value};\n`;
|
|
4312
5078
|
}
|
|
4313
5079
|
return [...resolvedValue.schemas, {
|
|
4314
5080
|
name: sanitizedSchemaName,
|
|
@@ -4620,33 +5386,54 @@ function getCanonicalMap(schemaGroups, schemaPath, namingConvention, fileExtensi
|
|
|
4620
5386
|
canonicalNameMap
|
|
4621
5387
|
};
|
|
4622
5388
|
}
|
|
4623
|
-
function normalizeCanonicalImportPaths(schemas, canonicalPathMap, canonicalNameMap, schemaPath, namingConvention, fileExtension, tsconfig) {
|
|
5389
|
+
function normalizeCanonicalImportPaths(schemas, canonicalPathMap, canonicalNameMap, schemaPath, namingConvention, fileExtension, tsconfig, factoryOutputDirectory) {
|
|
4624
5390
|
const importExtension = getImportExtension(fileExtension, tsconfig);
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
5391
|
+
const factoryDir = factoryOutputDirectory ?? schemaPath;
|
|
5392
|
+
for (const schema of schemas) {
|
|
5393
|
+
schema.imports = schema.imports.map((imp) => {
|
|
5394
|
+
const canonicalByName = canonicalNameMap.get(imp.name);
|
|
5395
|
+
const resolvedImportKey = resolveImportKey(schemaPath, imp.importPath ?? `./${conventionName(imp.name, namingConvention)}`, fileExtension);
|
|
5396
|
+
const canonicalByPath = canonicalPathMap.get(resolvedImportKey);
|
|
5397
|
+
const canonical = canonicalByName ?? canonicalByPath;
|
|
5398
|
+
if (!canonical?.importPath) return imp;
|
|
5399
|
+
const relative = relativeSafe(schemaPath, canonical.importPath.replaceAll("\\", "/"));
|
|
5400
|
+
const importPath = `${relative.endsWith(fileExtension) ? relative.slice(0, -fileExtension.length) : relative.replace(/\.ts$/, "")}${importExtension}`;
|
|
5401
|
+
return {
|
|
5402
|
+
...imp,
|
|
5403
|
+
importPath
|
|
5404
|
+
};
|
|
5405
|
+
});
|
|
5406
|
+
if (schema.factoryImports) schema.factoryImports = schema.factoryImports.map((imp) => {
|
|
5407
|
+
const canonicalByName = canonicalNameMap.get(imp.name);
|
|
5408
|
+
const resolvedImportKey = resolveImportKey(factoryDir, imp.importPath ?? `./${conventionName(imp.name, namingConvention)}`, fileExtension);
|
|
5409
|
+
const canonicalByPath = canonicalPathMap.get(resolvedImportKey);
|
|
5410
|
+
const canonical = canonicalByName ?? canonicalByPath;
|
|
5411
|
+
if (!canonical?.importPath) return imp;
|
|
5412
|
+
const relative = relativeSafe(factoryDir, canonical.importPath.replaceAll("\\", "/"));
|
|
5413
|
+
const importPath = `${relative.endsWith(fileExtension) ? relative.slice(0, -fileExtension.length) : relative.replace(/\.ts$/, "")}${importExtension}`;
|
|
5414
|
+
return {
|
|
5415
|
+
...imp,
|
|
5416
|
+
importPath
|
|
5417
|
+
};
|
|
5418
|
+
});
|
|
5419
|
+
}
|
|
4638
5420
|
}
|
|
4639
5421
|
function mergeSchemaGroup(schemas) {
|
|
4640
5422
|
const baseSchemaName = schemas[0].name;
|
|
4641
5423
|
const baseSchema = schemas[0].schema;
|
|
4642
5424
|
const mergedImports = [...new Map(schemas.flatMap((schema) => schema.imports).map((imp) => [JSON.stringify(imp), imp])).values()];
|
|
4643
5425
|
const mergedDependencies = [...new Set(schemas.flatMap((schema) => schema.dependencies ?? []))];
|
|
5426
|
+
const mergedFactory = schemas.map((s) => s.factory).filter(Boolean).join("\n");
|
|
5427
|
+
const mergedFactoryImports = [...new Map(schemas.flatMap((schema) => schema.factoryImports ?? []).map((imp) => [JSON.stringify(imp), imp])).values()];
|
|
4644
5428
|
return {
|
|
4645
5429
|
name: baseSchemaName,
|
|
4646
5430
|
schema: baseSchema,
|
|
4647
5431
|
model: schemas.map((schema) => schema.model).join("\n"),
|
|
4648
5432
|
imports: mergedImports,
|
|
4649
|
-
dependencies: mergedDependencies
|
|
5433
|
+
dependencies: mergedDependencies,
|
|
5434
|
+
factory: mergedFactory || void 0,
|
|
5435
|
+
factoryImports: mergedFactoryImports,
|
|
5436
|
+
factoryMode: schemas[0].factoryMode
|
|
4650
5437
|
};
|
|
4651
5438
|
}
|
|
4652
5439
|
function resolveImportKey(schemaPath, importPath, fileExtension) {
|
|
@@ -4688,10 +5475,39 @@ async function writeSchema({ path, schema, target, namingConvention, fileExtensi
|
|
|
4688
5475
|
throw new Error(`Oups... 🍻. An Error occurred while writing schema ${name} => ${String(error)}`, { cause: error });
|
|
4689
5476
|
}
|
|
4690
5477
|
}
|
|
4691
|
-
async function
|
|
5478
|
+
async function emitFactoryForSchema(schema, namingConvention, header, factoryDir, fileExtension, helpers) {
|
|
5479
|
+
if (schema.factory && schema.factoryMode) {
|
|
5480
|
+
const mode = schema.factoryMode;
|
|
5481
|
+
if (mode === "split") {
|
|
5482
|
+
const factoryName = `${conventionName(schema.name, namingConvention)}.factory`;
|
|
5483
|
+
helpers.separateFactoryNames.push(factoryName);
|
|
5484
|
+
const factoryFile = `${header}\n${generateImports({
|
|
5485
|
+
imports: schema.factoryImports ?? [],
|
|
5486
|
+
namingConvention
|
|
5487
|
+
})}\n\n${schema.factory}`;
|
|
5488
|
+
await writeGeneratedFile(getPath(factoryDir, factoryName, fileExtension), factoryFile);
|
|
5489
|
+
} else if (mode === "single-split") {
|
|
5490
|
+
helpers.isCombined.value = true;
|
|
5491
|
+
helpers.combinedFactoryContent.value += `${schema.factory}\n`;
|
|
5492
|
+
helpers.combinedFactoryImports.push(...schema.factoryImports ?? []);
|
|
5493
|
+
}
|
|
5494
|
+
}
|
|
5495
|
+
}
|
|
5496
|
+
async function writeSchemas({ schemaPath, schemas, target, namingConvention, fileExtension, header, indexFiles, tsconfig, factoryOutputDirectory }) {
|
|
4692
5497
|
const schemaGroups = getSchemaGroups(schemaPath, schemas, namingConvention, fileExtension);
|
|
4693
5498
|
const { canonicalPathMap, canonicalNameMap } = getCanonicalMap(schemaGroups, schemaPath, namingConvention, fileExtension);
|
|
4694
|
-
normalizeCanonicalImportPaths(schemas, canonicalPathMap, canonicalNameMap, schemaPath, namingConvention, fileExtension, tsconfig);
|
|
5499
|
+
normalizeCanonicalImportPaths(schemas, canonicalPathMap, canonicalNameMap, schemaPath, namingConvention, fileExtension, tsconfig, factoryOutputDirectory);
|
|
5500
|
+
const factoryDir = factoryOutputDirectory ?? schemaPath;
|
|
5501
|
+
const combinedFactoryContent = { value: "" };
|
|
5502
|
+
const combinedFactoryImports = [];
|
|
5503
|
+
const isCombined = { value: false };
|
|
5504
|
+
const separateFactoryNames = [];
|
|
5505
|
+
const factoryHelpers = {
|
|
5506
|
+
separateFactoryNames,
|
|
5507
|
+
combinedFactoryContent,
|
|
5508
|
+
combinedFactoryImports,
|
|
5509
|
+
isCombined
|
|
5510
|
+
};
|
|
4695
5511
|
for (const groupSchemas of Object.values(schemaGroups)) {
|
|
4696
5512
|
if (groupSchemas.length === 1) {
|
|
4697
5513
|
await writeSchema({
|
|
@@ -4703,17 +5519,29 @@ async function writeSchemas({ schemaPath, schemas, target, namingConvention, fil
|
|
|
4703
5519
|
header,
|
|
4704
5520
|
tsconfig
|
|
4705
5521
|
});
|
|
5522
|
+
const singleSchema = groupSchemas[0];
|
|
5523
|
+
await emitFactoryForSchema(singleSchema, namingConvention, header, factoryDir, fileExtension, factoryHelpers);
|
|
4706
5524
|
continue;
|
|
4707
5525
|
}
|
|
5526
|
+
const mergedSchema = mergeSchemaGroup(groupSchemas);
|
|
4708
5527
|
await writeSchema({
|
|
4709
5528
|
path: schemaPath,
|
|
4710
|
-
schema:
|
|
5529
|
+
schema: mergedSchema,
|
|
4711
5530
|
target,
|
|
4712
5531
|
namingConvention,
|
|
4713
5532
|
fileExtension,
|
|
4714
5533
|
header,
|
|
4715
5534
|
tsconfig
|
|
4716
5535
|
});
|
|
5536
|
+
await emitFactoryForSchema(mergedSchema, namingConvention, header, factoryDir, fileExtension, factoryHelpers);
|
|
5537
|
+
}
|
|
5538
|
+
if (isCombined.value) {
|
|
5539
|
+
const factoryFileName = conventionName("factoryMethods", namingConvention);
|
|
5540
|
+
const factoryFile = `${header}\n${generateImports({
|
|
5541
|
+
imports: combinedFactoryImports,
|
|
5542
|
+
namingConvention
|
|
5543
|
+
})}\n\n${combinedFactoryContent.value}`;
|
|
5544
|
+
await writeGeneratedFile(getPath(factoryDir, factoryFileName, fileExtension), factoryFile);
|
|
4717
5545
|
}
|
|
4718
5546
|
if (indexFiles) {
|
|
4719
5547
|
const schemaFilePath = nodePath.join(schemaPath, `index.ts`);
|
|
@@ -4721,7 +5549,25 @@ async function writeSchemas({ schemaPath, schemas, target, namingConvention, fil
|
|
|
4721
5549
|
const ext = getImportExtension(fileExtension, tsconfig);
|
|
4722
5550
|
const conventionNamesSet = new Set(Object.values(schemaGroups).map((group) => conventionName(group[0].name, namingConvention)));
|
|
4723
5551
|
try {
|
|
4724
|
-
|
|
5552
|
+
const currentExports = [...conventionNamesSet].map((schemaName) => `export * from './${schemaName}${ext}';`);
|
|
5553
|
+
if (factoryOutputDirectory && normalizeSafe(factoryOutputDirectory) !== normalizeSafe(schemaPath) && (isCombined.value || separateFactoryNames.length > 0)) {
|
|
5554
|
+
const factoryIndexFilePath = nodePath.join(factoryOutputDirectory, `index.ts`);
|
|
5555
|
+
await fs$1.ensureFile(factoryIndexFilePath);
|
|
5556
|
+
const factoryExports = [];
|
|
5557
|
+
if (isCombined.value) {
|
|
5558
|
+
const factoryFileName = conventionName("factoryMethods", namingConvention);
|
|
5559
|
+
factoryExports.push(`export * from './${factoryFileName}${ext}';`);
|
|
5560
|
+
}
|
|
5561
|
+
for (const fName of separateFactoryNames) factoryExports.push(`export * from './${fName}${ext}';`);
|
|
5562
|
+
await writeGeneratedFile(factoryIndexFilePath, `${header}\n${factoryExports.join("\n")}\n`);
|
|
5563
|
+
} else {
|
|
5564
|
+
if (isCombined.value) {
|
|
5565
|
+
const factoryFileName = conventionName("factoryMethods", namingConvention);
|
|
5566
|
+
currentExports.push(`export * from './${factoryFileName}${ext}';`);
|
|
5567
|
+
}
|
|
5568
|
+
for (const fName of separateFactoryNames) currentExports.push(`export * from './${fName}${ext}';`);
|
|
5569
|
+
}
|
|
5570
|
+
await writeGeneratedFile(schemaFilePath, `${header}\n${[...new Set(currentExports)].toSorted((a, b) => a.localeCompare(b, "en", { numeric: true })).join("\n")}\n`);
|
|
4725
5571
|
} catch (error) {
|
|
4726
5572
|
throw new Error(`Oups... 🍻. An Error occurred while writing schema index file ${schemaFilePath} => ${String(error)}`, { cause: error });
|
|
4727
5573
|
}
|
|
@@ -4731,6 +5577,13 @@ async function writeSchemas({ schemaPath, schemas, target, namingConvention, fil
|
|
|
4731
5577
|
//#region src/writers/generate-imports-for-builder.ts
|
|
4732
5578
|
function generateImportsForBuilder(output, imports, relativeSchemasPath) {
|
|
4733
5579
|
const isZodSchemaOutput = isObject(output.schemas) && output.schemas.type === "zod";
|
|
5580
|
+
const schemaFactoryImports = imports.filter((i) => i.schemaFactory);
|
|
5581
|
+
const schemaFactoryImportExtension = getImportExtension(output.fileExtension, output.tsconfig);
|
|
5582
|
+
const schemaFactoryDeps = schemaFactoryImports.length > 0 ? [{
|
|
5583
|
+
exports: uniqueBy(schemaFactoryImports, (entry) => `${entry.name}|${entry.alias ?? ""}`),
|
|
5584
|
+
dependency: joinSafe(relativeSchemasPath, `index.faker${schemaFactoryImportExtension}`)
|
|
5585
|
+
}] : [];
|
|
5586
|
+
imports = imports.filter((i) => !i.schemaFactory);
|
|
4734
5587
|
let schemaImports;
|
|
4735
5588
|
if (output.indexFiles) schemaImports = isZodSchemaOutput ? [{
|
|
4736
5589
|
exports: imports.filter((i) => !i.importPath),
|
|
@@ -4757,7 +5610,11 @@ function generateImportsForBuilder(output, imports, relativeSchemasPath) {
|
|
|
4757
5610
|
dependency: i.importPath
|
|
4758
5611
|
};
|
|
4759
5612
|
});
|
|
4760
|
-
return [
|
|
5613
|
+
return [
|
|
5614
|
+
...schemaImports,
|
|
5615
|
+
...schemaFactoryDeps,
|
|
5616
|
+
...otherImports
|
|
5617
|
+
];
|
|
4761
5618
|
}
|
|
4762
5619
|
//#endregion
|
|
4763
5620
|
//#region src/writers/mock-outputs.ts
|
|
@@ -5475,6 +6332,6 @@ async function writeTagsMode({ builder, output, projectName, header, needSchema,
|
|
|
5475
6332
|
}))).flat();
|
|
5476
6333
|
}
|
|
5477
6334
|
//#endregion
|
|
5478
|
-
export { BODY_TYPE_NAME, DefaultTag, EnumGeneration, ErrorWithTag, FormDataArrayHandling, GetterPropType, LogLevels, NAMED_COMPONENT_SECTIONS, NamingConvention, OutputClient, OutputHttpClient, OutputMockType, OutputMode, PropertySortOrder, RefComponentSuffix, SchemaType, SupportedFormatter, TEMPLATE_TAG_REGEX, URL_REGEX, VERBS_WITH_BODY, Verbs, addDependency, asyncReduce, buildAngularParamsFilterExpression, camel, collectReferencedComponents, combineSchemas, compareVersions, conventionName, count, createDebugger, createLogger, createSuccessMessage, createTypeAliasIfNeeded, dedupeUnionType, dynamicImport, escape, escapeRegExp, filterByContentType, filteredVerbs, fixCrossDirectoryImports, fixRegularSchemaImports, generalJSTypes, generalJSTypesWithArray, generateAxiosOptions, generateBodyMutatorConfig, generateBodyOptions, generateComponentDefinition, generateDependencyImports, generateFormDataAndUrlEncodedFunction, generateImports, generateModelInline, generateModelsInline, generateMutator, generateMutatorConfig, generateMutatorImports, generateMutatorRequestOptions, generateOptions, generateParameterDefinition, generateQueryParamsAxiosConfig, generateSchemasDefinition, generateTarget, generateTargetForTags, generateVerbImports, generateVerbOptions, generateVerbsOptions, getAngularFilteredParamsCallExpression, getAngularFilteredParamsExpression, getAngularFilteredParamsHelperBody, getArray, getBaseUrlRuntimeImports, getBodiesByContentType, getBody, getCombinedEnumValue, getDefaultContentType, getEnum, getEnumDescriptions, getEnumImplementation, getEnumNames, getEnumUnionFromSchema, getExtension, getFileInfo, getFormDataFieldFileType, getFullRoute, getImportExtension, getIsBodyVerb, getKey, getMockFileExtensionByTypeName, getNumberWord, getObject, getOperationId, getOrvalGeneratedTypes, getParameters, getParams, getParamsInPath, getPropertySafe, getProps, getQueryParams, getRefInfo, getResReqTypes, getResponse, getResponseTypeCategory, getRoute, getRouteAsArray, getScalar, getSuccessResponseType, getTypedResponse, getWarningCount, isBinaryContentType, isBinaryScalarSchema, isBoolean, isComponentRef, isDirectory, isFakerMock, isFunction, isModule, isMswMock, isNullish, isNumber, isNumeric, isObject, isReference, isSchema, isString, isStringLike, isSyntheticDefaultImportsAllow, isUrl, isVerb, isVerbose, jsDoc, jsStringEscape, kebab, keyValuePairsToJsDoc, log, logError, logVerbose, logWarning, makeRouteSafe, mergeDeep, mismatchArgsMessage, pascal, removeFilesAndEmptyFolders, resetWarnings, resolveDiscriminators, resolveExampleRefs, resolveInstalledVersion, resolveInstalledVersions, resolveObject, resolveRef, resolveValue, sanitize, setVerbose, snake, sortByPriority, splitSchemasByType, startMessage, stringify, toObjectString, path_exports as upath, upper, wrapRouteParameters, writeModelInline, writeModelsInline, writeSchema, writeSchemas, writeSingleMode, writeSplitMode, writeSplitTagsMode, writeTagsMode };
|
|
6335
|
+
export { BODY_TYPE_NAME, DefaultTag, EnumGeneration, ErrorWithTag, FormDataArrayHandling, GetterPropType, LogLevels, NAMED_COMPONENT_SECTIONS, NamingConvention, OutputClient, OutputHttpClient, OutputMockType, OutputMode, PropertySortOrder, RefComponentSuffix, SchemaType, SupportedFormatter, TEMPLATE_TAG_REGEX, URL_REGEX, VERBS_WITH_BODY, Verbs, addDependency, asyncReduce, buildAngularParamsFilterExpression, buildDynamicScope, camel, collectReferencedComponents, combineSchemas, compareVersions, conventionName, count, createDebugger, createLogger, createSuccessMessage, createTypeAliasIfNeeded, dedupeUnionType, dynamicAnchorToParamName, dynamicAnchorsToUniqueParamNames, dynamicImport, escape, escapeRegExp, extractBoundAliasInfo, filterByContentType, filteredVerbs, fixCrossDirectoryImports, fixRegularSchemaImports, generalJSTypes, generalJSTypesWithArray, generateAxiosOptions, generateBodyMutatorConfig, generateBodyOptions, generateComponentDefinition, generateDependencyImports, generateFactory, generateFormDataAndUrlEncodedFunction, generateImports, generateModelInline, generateModelsInline, generateMutator, generateMutatorConfig, generateMutatorImports, generateMutatorRequestOptions, generateOptions, generateParameterDefinition, generateQueryParamsAxiosConfig, generateSchemasDefinition, generateTarget, generateTargetForTags, generateVerbImports, generateVerbOptions, generateVerbsOptions, getAngularFilteredParamsCallExpression, getAngularFilteredParamsExpression, getAngularFilteredParamsHelperBody, getArray, getBaseUrlRuntimeImports, getBodiesByContentType, getBody, getCombinedEnumValue, getDefaultContentType, getDynamicAnchorName, getEnum, getEnumDescriptions, getEnumImplementation, getEnumNames, getEnumUnionFromSchema, getExtension, getFileInfo, getFormDataFieldFileType, getFullRoute, getImportExtension, getIsBodyVerb, getKey, getMockFileExtensionByTypeName, getNumberWord, getObject, getOperationId, getOrvalGeneratedTypes, getParameters, getParams, getParamsInPath, getPropertySafe, getProps, getQueryParams, getRefInfo, getResReqTypes, getResponse, getResponseTypeCategory, getRoute, getRouteAsArray, getScalar, getSuccessResponseType, getTypedResponse, getWarningCount, isBinaryContentType, isBinaryScalarSchema, isBoolean, isComponentRef, isDirectory, isDynamicReference, isFakerMock, isFunction, isModule, isMswMock, isNullish, isNumber, isNumeric, isObject, isReference, isSchema, isString, isStringLike, isSyntheticDefaultImportsAllow, isUrl, isVerb, isVerbose, jsDoc, jsStringEscape, kebab, keyValuePairsToJsDoc, log, logError, logVerbose, logWarning, makeRouteSafe, mergeDeep, mismatchArgsMessage, pascal, removeFilesAndEmptyFolders, resetWarnings, resolveDiscriminators, resolveDynamicRef, resolveExampleRefs, resolveInstalledVersion, resolveInstalledVersions, resolveObject, resolveRef, resolveValue, sanitize, setVerbose, snake, sortByPriority, splitSchemasByType, startMessage, stringify, toObjectString, path_exports as upath, upper, wrapRouteParameters, writeGeneratedFile, writeModelInline, writeModelsInline, writeSchema, writeSchemas, writeSingleMode, writeSplitMode, writeSplitTagsMode, writeTagsMode };
|
|
5479
6336
|
|
|
5480
6337
|
//# sourceMappingURL=index.mjs.map
|