orval 8.21.0 → 8.22.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.
@@ -4,7 +4,9 @@ import { DefaultTag, FormDataArrayHandling, GetterPropType, NamingConvention, Ou
4
4
  import { bundle } from "@scalar/json-magic/bundle";
5
5
  import { fetchUrls, parseJson, parseYaml, readFiles } from "@scalar/json-magic/bundle/plugins/node";
6
6
  import { upgrade, validate } from "@scalar/openapi-parser";
7
+ import fs, { access, readFile } from "node:fs/promises";
7
8
  import { isNullish as isNullish$1, pick, unique } from "remeda";
9
+ import jsYaml from "js-yaml";
8
10
  import * as mock from "@orval/mock";
9
11
  import { dedupeStrictMockTypeDeclarations, generateFakerForSchemas, generateMockImports, getDefaultMockOptionsForType } from "@orval/mock";
10
12
  import angular from "@orval/angular";
@@ -17,19 +19,17 @@ import query from "@orval/query";
17
19
  import solidStart from "@orval/solid-start";
18
20
  import swr from "@orval/swr";
19
21
  import zod, { assertZodTarget, dereference, generateFormDataZodSchema, generateZodValidationSchemaDefinition, getZodImportSource, getZodTypeName, parseZodValidationSchemaDefinition, resolveIsZodV4 } from "@orval/zod";
20
- import { ExecaError, execa } from "execa";
21
- import fs from "fs-extra";
22
- import fs$1, { access } from "node:fs/promises";
22
+ import fs$1, { existsSync } from "node:fs";
23
23
  import { styleText } from "node:util";
24
- import { parseArgsStringToArgv } from "string-argv";
25
- import fs$2, { existsSync } from "node:fs";
26
24
  import { findUp, findUpMultiple } from "find-up";
27
- import yaml from "js-yaml";
25
+ import fs$2 from "fs-extra";
28
26
  import { parseTsconfig } from "get-tsconfig";
27
+ import { ExecaError, execa } from "execa";
28
+ import { parseArgsStringToArgv } from "string-argv";
29
29
  import { createJiti } from "jiti";
30
30
  //#region package.json
31
31
  var name = "orval";
32
- var version = "8.21.0";
32
+ var version = "8.22.0";
33
33
  var description = "A swagger client generator for typescript";
34
34
  //#endregion
35
35
  //#region src/client.ts
@@ -348,594 +348,246 @@ function getApiSchemas({ input, output, target, workspace, spec }) {
348
348
  ];
349
349
  }
350
350
  //#endregion
351
- //#region src/import-specs.ts
352
- async function resolveSpec(input, { parserOptions, transformer, workspace, unsafeDisableValidation = false }) {
353
- const dereferencedData = await bundleAndDereferenceExternalRefs(input, parserOptions);
354
- let transformedData = dereferencedData;
355
- if (transformer) {
356
- const applied = await applyInputTransformer(dereferencedData, transformer, workspace);
357
- transformedData = hasExternalRef(applied) ? await bundleAndDereferenceExternalRefs(applied, parserOptions, isString(input) ? input : void 0) : applied;
351
+ //#region src/utils/package-json.ts
352
+ const loadPackageJson = async (packageJson, workspace = process.cwd()) => {
353
+ if (!packageJson) {
354
+ const pkgPath = await findUp(["package.json"], { cwd: workspace });
355
+ if (pkgPath) {
356
+ const pkg = await dynamicImport(pkgPath, workspace);
357
+ if (isPackageJson(pkg)) return resolveAndAttachVersions(await maybeReplaceCatalog(pkg, workspace), workspace, pkgPath);
358
+ else throw new Error("Invalid package.json file");
359
+ }
360
+ return;
358
361
  }
359
- if (unsafeDisableValidation) logWarning("🚨 OpenAPI spec validation is disabled.\n Code generation with invalid specs is not guaranteed to work and may break in minor updates.\n Bug reports with validation disabled will not be accepted.");
360
- else {
361
- validateComponentKeys(transformedData);
362
- const { valid, errors } = await validate(transformedData);
363
- if (!valid) throw new Error(`OpenAPI spec validation failed:\n${JSON.stringify(errors, void 0, 2)}`);
362
+ const normalizedPath = normalizePath(packageJson, workspace);
363
+ if (fs$2.existsSync(normalizedPath)) {
364
+ const pkg = await dynamicImport(normalizedPath);
365
+ if (isPackageJson(pkg)) return resolveAndAttachVersions(await maybeReplaceCatalog(pkg, workspace), workspace, normalizedPath);
366
+ else throw new Error(`Invalid package.json file: ${normalizedPath}`);
364
367
  }
365
- const { specification } = upgrade(transformedData);
366
- return specification;
367
- }
368
- async function applyInputTransformer(data, transformer, workspace) {
369
- const transformerFn = await dynamicImport(transformer, workspace);
370
- const result = await transformerFn(data);
371
- if (!isObject(result)) {
372
- const source = isString(transformer) ? transformer : transformerFn.name || "<inline function>";
373
- throw new Error(`input.override.transformer must return an OpenAPI document object; got ${result === void 0 ? "undefined" : typeof result} from ${source}. Ensure your transformer returns the (possibly modified) spec.`);
368
+ };
369
+ const isPackageJson = (obj) => isObject(obj);
370
+ const resolvedCache = /* @__PURE__ */ new Map();
371
+ const resolveAndAttachVersions = (pkg, workspace, cacheKey) => {
372
+ const cached = resolvedCache.get(cacheKey);
373
+ if (cached) {
374
+ pkg.resolvedVersions = cached;
375
+ return pkg;
374
376
  }
375
- return result;
376
- }
377
+ const resolved = resolveInstalledVersions(pkg, workspace);
378
+ if (Object.keys(resolved).length > 0) {
379
+ pkg.resolvedVersions = resolved;
380
+ resolvedCache.set(cacheKey, resolved);
381
+ for (const [name, version] of Object.entries(resolved)) logVerbose(styleText("dim", `Detected ${styleText("white", name)} v${styleText("white", version)}`));
382
+ }
383
+ return pkg;
384
+ };
385
+ const hasCatalogReferences = (pkg) => {
386
+ return [
387
+ ...Object.entries(pkg.dependencies ?? {}),
388
+ ...Object.entries(pkg.devDependencies ?? {}),
389
+ ...Object.entries(pkg.peerDependencies ?? {})
390
+ ].some(([, value]) => isString(value) && value.startsWith("catalog:"));
391
+ };
392
+ const loadPnpmWorkspaceCatalog = async (workspace) => {
393
+ const filePath = await findUp("pnpm-workspace.yaml", { cwd: workspace });
394
+ if (!filePath) return void 0;
395
+ try {
396
+ const file = await fs$2.readFile(filePath, "utf8");
397
+ const data = jsYaml.load(file);
398
+ if (!data?.catalog && !data?.catalogs) return void 0;
399
+ return {
400
+ catalog: data.catalog,
401
+ catalogs: data.catalogs
402
+ };
403
+ } catch {
404
+ return;
405
+ }
406
+ };
407
+ const loadPackageJsonCatalog = async (workspace) => {
408
+ const filePaths = await findUpMultiple("package.json", { cwd: workspace });
409
+ for (const filePath of filePaths) try {
410
+ const pkg = await fs$2.readJson(filePath);
411
+ if (pkg.catalog || pkg.catalogs) return {
412
+ catalog: pkg.catalog,
413
+ catalogs: pkg.catalogs
414
+ };
415
+ } catch {}
416
+ };
417
+ const loadYarnrcCatalog = async (workspace) => {
418
+ const filePath = await findUp(".yarnrc.yml", { cwd: workspace });
419
+ if (!filePath) return void 0;
420
+ try {
421
+ const file = await fs$2.readFile(filePath, "utf8");
422
+ const data = jsYaml.load(file);
423
+ if (!data?.catalog && !data?.catalogs) return void 0;
424
+ return {
425
+ catalog: data.catalog,
426
+ catalogs: data.catalogs
427
+ };
428
+ } catch {
429
+ return;
430
+ }
431
+ };
432
+ const maybeReplaceCatalog = async (pkg, workspace) => {
433
+ if (!hasCatalogReferences(pkg)) return pkg;
434
+ const catalogData = await loadPnpmWorkspaceCatalog(workspace) ?? await loadPackageJsonCatalog(workspace) ?? await loadYarnrcCatalog(workspace);
435
+ if (!catalogData) {
436
+ logWarning("⚠️ package.json contains catalog: references, but no catalog source was found (checked: pnpm-workspace.yaml, package.json, .yarnrc.yml).");
437
+ return pkg;
438
+ }
439
+ performSubstitution(pkg.dependencies, catalogData);
440
+ performSubstitution(pkg.devDependencies, catalogData);
441
+ performSubstitution(pkg.peerDependencies, catalogData);
442
+ return pkg;
443
+ };
444
+ const performSubstitution = (dependencies, catalogData) => {
445
+ if (!dependencies) return;
446
+ for (const [packageName, version] of Object.entries(dependencies)) if (version === "catalog:" || version === "catalog:default") {
447
+ if (!catalogData.catalog) {
448
+ logWarning(`⚠️ catalog: substitution for the package '${packageName}' failed as there is no default catalog.`);
449
+ continue;
450
+ }
451
+ const sub = catalogData.catalog[packageName];
452
+ if (!sub) {
453
+ logWarning(`⚠️ catalog: substitution for the package '${packageName}' failed as there is no matching package in the default catalog.`);
454
+ continue;
455
+ }
456
+ dependencies[packageName] = sub;
457
+ } else if (version.startsWith("catalog:")) {
458
+ const catalogName = version.slice(8);
459
+ const catalog = catalogData.catalogs?.[catalogName];
460
+ if (!catalog) {
461
+ logWarning(`⚠️ '${version}' substitution for the package '${packageName}' failed as there is no matching catalog named '${catalogName}'. (available named catalogs are: ${Object.keys(catalogData.catalogs ?? {}).join(", ")})`);
462
+ continue;
463
+ }
464
+ const sub = catalog[packageName];
465
+ if (!sub) {
466
+ logWarning(`⚠️ '${version}' substitution for the package '${packageName}' failed as there is no package in the catalog named '${catalogName}'. (packages in the catalog are: ${Object.keys(catalog).join(", ")})`);
467
+ continue;
468
+ }
469
+ dependencies[packageName] = sub;
470
+ }
471
+ };
472
+ //#endregion
473
+ //#region src/utils/tsconfig.ts
474
+ const convertTarget = (config) => {
475
+ if (!config.compilerOptions?.target) return {
476
+ baseUrl: config.compilerOptions?.baseUrl,
477
+ ...config
478
+ };
479
+ const lowercaseTarget = config.compilerOptions.target.toLowerCase();
480
+ return {
481
+ baseUrl: config.compilerOptions.baseUrl,
482
+ ...config,
483
+ compilerOptions: {
484
+ ...config.compilerOptions,
485
+ target: lowercaseTarget
486
+ }
487
+ };
488
+ };
489
+ const loadTsconfig = async (tsconfig, workspace = process.cwd()) => {
490
+ if (isNullish(tsconfig)) {
491
+ const configPath = await findUp(["tsconfig.json", "jsconfig.json"], { cwd: workspace });
492
+ if (configPath) return convertTarget(parseTsconfig(configPath));
493
+ return;
494
+ }
495
+ if (isString(tsconfig)) {
496
+ const normalizedPath = normalizePath(tsconfig, workspace);
497
+ if (fs$2.existsSync(normalizedPath)) return convertTarget(parseTsconfig(normalizedPath));
498
+ return;
499
+ }
500
+ if (isObject(tsconfig)) return tsconfig;
501
+ };
502
+ //#endregion
503
+ //#region src/utils/options.ts
504
+ const INPUT_TARGET_FETCH_TIMEOUT_MS = 1e4;
377
505
  /**
378
- * Bundle external references into the document and then resolve the `x-ext`
379
- * entries that `@scalar/json-magic` produces. Shared by the initial pass and
380
- * the post-transformer pass (#3327); `origin` lets the second pass resolve refs
381
- * relative to the original spec file when the input is an in-memory object.
506
+ * Type helper to make it easier to use orval.config.ts
507
+ * accepts a direct {@link ConfigExternal} object.
382
508
  */
383
- async function bundleAndDereferenceExternalRefs(input, parserOptions, origin) {
384
- return dereferenceExternalRef(await bundle(input, {
385
- plugins: [
386
- readFiles(),
387
- fetchUrls({ headers: parserOptions?.headers }),
388
- parseJson(),
389
- parseYaml()
390
- ],
391
- treeShake: false,
392
- ...origin ? { origin } : {}
393
- }));
509
+ function defineConfig(options) {
510
+ return options;
394
511
  }
395
512
  /**
396
- * Report whether any `$ref` in the document points to an external document.
397
- * Per the JSON Reference rules a ref is external when it does not start with
398
- * `#` (an in-document pointer). Used to decide whether a transformer introduced
399
- * new external refs that need a second bundle pass (#3327) — when it did not,
400
- * the already-bundled spec is returned untouched.
513
+ * Type helper to make it easier to write input transformers.
514
+ * accepts a direct {@link InputTransformerFn} function.
401
515
  */
402
- function hasExternalRef(obj) {
403
- if (Array.isArray(obj)) return obj.some((item) => hasExternalRef(item));
404
- if (isObject(obj)) {
405
- if ("$ref" in obj && isString(obj.$ref) && !obj.$ref.startsWith("#")) return true;
406
- return Object.values(obj).some((value) => hasExternalRef(value));
407
- }
408
- return false;
516
+ function defineTransformer(transformer) {
517
+ return transformer;
409
518
  }
410
- async function importSpecs(workspace, options, projectName) {
411
- const { input, output } = options;
412
- return importOpenApi({
413
- spec: await resolveSpec(input.target, {
414
- parserOptions: input.parserOptions,
415
- transformer: input.override.transformer,
416
- workspace,
417
- unsafeDisableValidation: input.unsafeDisableValidation
418
- }),
419
- input,
420
- output,
421
- target: isString(input.target) ? input.target : workspace,
422
- workspace,
423
- projectName
424
- });
519
+ function createFormData(workspace, formData) {
520
+ const defaultArrayHandling = FormDataArrayHandling.SERIALIZE;
521
+ if (formData === void 0) return {
522
+ disabled: false,
523
+ arrayHandling: defaultArrayHandling
524
+ };
525
+ if (isBoolean(formData)) return {
526
+ disabled: !formData,
527
+ arrayHandling: defaultArrayHandling
528
+ };
529
+ if (isString(formData)) return {
530
+ disabled: false,
531
+ mutator: normalizeMutator(workspace, formData),
532
+ arrayHandling: defaultArrayHandling
533
+ };
534
+ if ("mutator" in formData || "arrayHandling" in formData) return {
535
+ disabled: false,
536
+ mutator: normalizeMutator(workspace, formData.mutator),
537
+ arrayHandling: formData.arrayHandling ?? defaultArrayHandling
538
+ };
539
+ return {
540
+ disabled: false,
541
+ mutator: normalizeMutator(workspace, formData),
542
+ arrayHandling: defaultArrayHandling
543
+ };
544
+ }
545
+ function normalizeSchemasOption(schemas, workspace) {
546
+ if (!schemas) return;
547
+ if (isString(schemas)) return normalizePath(schemas, workspace);
548
+ validatePackageSpecifier(schemas.importPath, "schemas.importPath");
549
+ return {
550
+ path: normalizePath(schemas.path, workspace),
551
+ type: schemas.type ?? "typescript",
552
+ importPath: schemas.importPath,
553
+ splitByTags: schemas.splitByTags ?? false
554
+ };
425
555
  }
426
- const COMPONENT_KEY_PATTERN = /^[a-zA-Z0-9.\-_]+$/;
427
- const COMPONENT_SECTIONS = [
428
- "schemas",
429
- "responses",
430
- "parameters",
431
- "examples",
432
- "requestBodies",
433
- "headers",
434
- "securitySchemes",
435
- "links",
436
- "callbacks",
437
- "pathItems"
438
- ];
439
556
  /**
440
- * Validate that all component keys conform to the OAS regex: ^[a-zA-Z0-9.\-_]+$
441
- * @see https://spec.openapis.org/oas/v3.0.3.html#fixed-fields-5
442
- * @see https://spec.openapis.org/oas/v3.1.0#fixed-fields-5
443
- */
444
- function validateComponentKeys(data) {
445
- const components = data.components;
446
- if (!isObject(components)) return;
447
- const invalidKeys = [];
448
- for (const section of COMPONENT_SECTIONS) {
449
- const sectionObj = components[section];
450
- if (!isObject(sectionObj)) continue;
451
- for (const key of Object.keys(sectionObj)) if (!COMPONENT_KEY_PATTERN.test(key)) invalidKeys.push(`components.${section}.${key}`);
452
- }
453
- if (invalidKeys.length > 0) throw new Error(`Invalid component key${invalidKeys.length > 1 ? "s" : ""} found. OpenAPI component keys must match the pattern ${COMPONENT_KEY_PATTERN} (non-ASCII characters are not allowed per the spec).\n See: https://spec.openapis.org/oas/v3.0.3.html#components-object\n Invalid keys:\n` + invalidKeys.map((k) => ` - ${k}`).join("\n"));
454
- }
455
- /**
456
- * The plugins from `@scalar/json-magic` does not dereference $ref.
457
- * Instead it fetches them and puts them under x-ext, and changes the $ref to point to #x-ext/<name>.
458
- * This function:
459
- * 1. Merges external schemas into main spec's components.schemas (with collision handling)
460
- * 2. Replaces x-ext refs with standard component refs or inlined content
461
- */
462
- function dereferenceExternalRef(data) {
463
- const extensions = data["x-ext"] ?? {};
464
- const schemaNameMappings = mergeExternalSchemas(data, extensions);
465
- const result = {};
466
- for (const [key, value] of Object.entries(data)) if (key !== "x-ext") result[key] = replaceXExtRefs(value, extensions, schemaNameMappings);
467
- return result;
468
- }
469
- /**
470
- * Merge external document schemas into main spec's components.schemas
471
- * Returns mapping of original schema names to final names (with suffixes for collisions)
472
- */
473
- function mergeExternalSchemas(data, extensions) {
474
- const schemaNameMappings = {};
475
- if (Object.keys(extensions).length === 0) return schemaNameMappings;
476
- data.components ??= {};
477
- const mainComponents = data.components;
478
- mainComponents.schemas ??= {};
479
- const mainSchemas = mainComponents.schemas;
480
- for (const [extKey, extDoc] of Object.entries(extensions)) {
481
- schemaNameMappings[extKey] = {};
482
- if (isObject(extDoc) && "components" in extDoc) {
483
- const extComponents = extDoc.components;
484
- if (isObject(extComponents) && "schemas" in extComponents) {
485
- const extSchemas = extComponents.schemas;
486
- for (const [schemaName, schema] of Object.entries(extSchemas)) {
487
- const existingSchema = mainSchemas[schemaName];
488
- const isXExtRef = isObject(existingSchema) && "$ref" in existingSchema && isString(existingSchema.$ref) && existingSchema.$ref.startsWith("#/x-ext/");
489
- let finalSchemaName = schemaName;
490
- if (schemaName in mainSchemas && !isXExtRef) {
491
- finalSchemaName = `${schemaName}_${extKey.replaceAll(/[^a-zA-Z0-9]/g, "_")}`;
492
- schemaNameMappings[extKey][schemaName] = finalSchemaName;
493
- } else schemaNameMappings[extKey][schemaName] = schemaName;
494
- mainSchemas[finalSchemaName] = scrubUnwantedKeys(schema);
495
- }
496
- }
497
- }
498
- }
499
- for (const [extKey, mapping] of Object.entries(schemaNameMappings)) for (const [, finalName] of Object.entries(mapping)) {
500
- const schema = mainSchemas[finalName];
501
- if (schema) mainSchemas[finalName] = updateInternalRefs(schema, extKey, schemaNameMappings);
502
- }
503
- return schemaNameMappings;
504
- }
505
- /**
506
- * Remove unwanted keys like $schema and $id from objects
507
- */
508
- function scrubUnwantedKeys(obj) {
509
- const UNWANTED_KEYS = new Set(["$schema", "$id"]);
510
- if (obj === null || obj === void 0) return obj;
511
- if (Array.isArray(obj)) return obj.map((x) => scrubUnwantedKeys(x));
512
- if (isObject(obj)) {
513
- const rec = obj;
514
- const out = {};
515
- for (const [k, v] of Object.entries(rec)) {
516
- if (UNWANTED_KEYS.has(k)) continue;
517
- out[k] = scrubUnwantedKeys(v);
518
- }
519
- return out;
520
- }
521
- return obj;
522
- }
523
- /**
524
- * Update internal refs within an external schema to use suffixed names
525
- */
526
- function updateInternalRefs(obj, extKey, schemaNameMappings) {
527
- if (obj === null || obj === void 0) return obj;
528
- if (Array.isArray(obj)) return obj.map((element) => updateInternalRefs(element, extKey, schemaNameMappings));
529
- if (isObject(obj)) {
530
- const record = obj;
531
- if ("$ref" in record && isString(record.$ref)) {
532
- const refValue = record.$ref;
533
- if (refValue.startsWith("#/components/schemas/")) {
534
- const schemaName = refValue.replace("#/components/schemas/", "");
535
- const mappedName = schemaNameMappings[extKey][schemaName];
536
- if (mappedName) return { $ref: `#/components/schemas/${mappedName}` };
537
- }
538
- }
539
- const result = {};
540
- for (const [key, value] of Object.entries(record)) result[key] = updateInternalRefs(value, extKey, schemaNameMappings);
541
- return result;
542
- }
543
- return obj;
544
- }
545
- /**
546
- * Decode a single JSON Pointer reference token taken from an x-ext `$ref`.
547
- *
548
- * The token carries two layers of encoding: it sits in a URI fragment, so it
549
- * may be percent-encoded (e.g. `%7B` for `{` in templated paths), and it is a
550
- * JSON Pointer token, so `~1`/`~0` stand for `/`/`~` (RFC 6901). Percent-
551
- * encoding is the outer layer and is removed first; a malformed sequence is
552
- * left as-is rather than throwing. Without this, tokens such as `~1pets`
553
- * never match the real `/pets` key and the external `$ref` fails to resolve.
554
- */
555
- function decodeRefToken(token) {
556
- let decoded = token;
557
- try {
558
- decoded = decodeURIComponent(token);
559
- } catch {}
560
- return decoded.replaceAll("~1", "/").replaceAll("~0", "~");
561
- }
562
- /**
563
- * Replace x-ext refs with standard component refs, or inline the content.
564
- * `inliningRefs` tracks the inline chain to break cycles in recursive
565
- * external schemas that aren't under `components.schemas` (#1642).
566
- */
567
- function replaceXExtRefs(obj, extensions, schemaNameMappings, inliningRefs = /* @__PURE__ */ new Set()) {
568
- if (isNullish$1(obj)) return obj;
569
- if (Array.isArray(obj)) return obj.map((element) => replaceXExtRefs(element, extensions, schemaNameMappings, inliningRefs));
570
- if (isObject(obj)) {
571
- const record = obj;
572
- if ("$ref" in record && isString(record.$ref)) {
573
- const refValue = record.$ref;
574
- if (refValue.startsWith("#/x-ext/")) {
575
- const parts = refValue.replace("#/x-ext/", "").split("/");
576
- const extKey = parts.shift();
577
- if (extKey) {
578
- if (parts.length >= 3 && parts[0] === "components" && parts[1] === "schemas") {
579
- const schemaName = parts.slice(2).join("/");
580
- return { $ref: `#/components/schemas/${schemaNameMappings[extKey][schemaName] || schemaName}` };
581
- }
582
- if (inliningRefs.has(refValue)) {
583
- logWarning(`Detected a circular external $ref while inlining "${refValue}". Replacing with an empty schema to avoid infinite recursion. Move the schema under "components.schemas" in its source file or pre-bundle the spec to keep the recursion intact.`);
584
- return {};
585
- }
586
- let refObj = extensions[extKey];
587
- for (const rawPart of parts) {
588
- const p = decodeRefToken(rawPart);
589
- if (refObj && (isObject(refObj) || Array.isArray(refObj)) && p in refObj) refObj = refObj[p];
590
- else {
591
- refObj = void 0;
592
- break;
593
- }
594
- }
595
- if (refObj) {
596
- const cleaned = scrubUnwantedKeys(refObj);
597
- const nextInlining = new Set(inliningRefs);
598
- nextInlining.add(refValue);
599
- return replaceXExtRefs(cleaned, extensions, schemaNameMappings, nextInlining);
600
- }
601
- }
602
- }
603
- }
604
- const result = {};
605
- for (const [key, value] of Object.entries(record)) result[key] = replaceXExtRefs(value, extensions, schemaNameMappings, inliningRefs);
606
- return result;
607
- }
608
- return obj;
609
- }
610
- //#endregion
611
- //#region src/formatters/prettier.ts
612
- /**
613
- * Format files with prettier.
614
- * Tries the programmatic API first (project dependency),
615
- * then falls back to the globally installed CLI.
557
+ * Validates that a config value is a valid package specifier (bare specifier
558
+ * or sub-path import like `@acme/models` / `@acme/models/fakers`). Rejects
559
+ * empty, whitespace-only, relative (`./`, `../`), and absolute paths with a
560
+ * clear, actionable error message. No-op when the value is `undefined`.
616
561
  */
617
- async function formatWithPrettier(paths, projectTitle) {
618
- const prettier = await tryImportPrettier();
619
- if (prettier) {
620
- const filePaths = [...new Set(await collectFilePaths(paths))];
621
- if (filePaths.length === 0) return;
622
- const config = await prettier.resolveConfig(filePaths[0]) ?? {};
623
- await Promise.all(filePaths.map(async (filePath) => {
624
- try {
625
- const content = await fs$1.readFile(filePath, "utf8");
626
- const formatted = await prettier.format(content, {
627
- ...config,
628
- filepath: filePath
629
- });
630
- await fs$1.writeFile(filePath, formatted);
631
- } catch (error) {
632
- if (isMissingFileError(error)) return;
633
- if (error instanceof Error) if (error.name === "UndefinedParserError") {} else logWarning(`⚠️ ${projectTitle ? `${projectTitle} - ` : ""}Failed to format file ${filePath}: ${error.toString()}`);
634
- else logWarning(`⚠️ ${projectTitle ? `${projectTitle} - ` : ""}Failed to format file ${filePath}: unknown error`);
635
- }
636
- }));
637
- return;
638
- }
639
- try {
640
- await execa("prettier", ["--write", ...paths]);
641
- } catch {
642
- logWarning(`⚠️ ${projectTitle ? `${projectTitle} - ` : ""}prettier not found. Install it as a project dependency or globally.`);
643
- }
562
+ function validatePackageSpecifier(value, fieldName) {
563
+ if (value === void 0) return;
564
+ if (!value) throw new Error(`\`${fieldName}\` must be a non-empty package specifier (e.g. '@acme/models'). Received an empty string.`);
565
+ if (value.trim() === "") throw new Error(`\`${fieldName}\` must be a non-empty package specifier (e.g. '@acme/models'). Received a whitespace-only string.`);
566
+ if (value.trim() !== value) throw new Error(`\`${fieldName}\` must be a non-empty package specifier (e.g. '@acme/models'). Received a value with leading or trailing whitespace: "${value}"`);
567
+ if (value.startsWith(".")) throw new Error(`\`${fieldName}\` must be a package specifier (e.g. '@acme/models'), not a relative path. Received: "${value}"`);
568
+ if (path.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\")) throw new Error(`\`${fieldName}\` must be a package specifier (e.g. '@acme/models'), not an absolute path. Received: "${value}"`);
644
569
  }
645
- function isMissingFileError(error) {
646
- return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
570
+ function looksLikePackageSpecifier(value) {
571
+ return !!value && value.trim() === value && !value.startsWith(".") && !path.isAbsolute(value) && !/^[A-Za-z]:[\\/]/.test(value) && !value.startsWith("\\\\");
647
572
  }
648
- /**
649
- * Try to import prettier from the project's dependencies.
650
- * Returns undefined if prettier is not installed.
651
- */
652
- async function tryImportPrettier() {
573
+ function resolvePackageSpecifier(workspace, value) {
653
574
  try {
654
- return await import("prettier");
575
+ return createRequire(path.join(workspace, "package.json")).resolve(value);
655
576
  } catch {
656
577
  return;
657
578
  }
658
579
  }
659
- /**
660
- * Recursively collect absolute file paths from a mix of files and directories.
661
- */
662
- async function collectFilePaths(paths) {
663
- const results = [];
664
- for (const p of paths) {
665
- const absolute = path.resolve(p);
666
- try {
667
- const stat = await fs$1.stat(absolute);
668
- if (stat.isFile()) results.push(absolute);
669
- else if (stat.isDirectory()) {
670
- const subFiles = await collectFilePaths((await fs$1.readdir(absolute)).map((entry) => path.join(absolute, entry)));
671
- results.push(...subFiles);
672
- }
673
- } catch {}
674
- }
675
- return results;
676
- }
677
- //#endregion
678
- //#region src/utils/execute-hook.ts
679
- const executeHook = async (name, commands = [], args = []) => {
680
- log(styleText("white", `Running ${name} hook...`));
681
- for (const command of commands) try {
682
- if (isString(command)) await executeCommand(command, args);
683
- else if (isFunction(command)) await command(args);
684
- else if (isObject(command)) await executeObjectCommand(command, args);
685
- } catch (error) {
686
- logError(error, `Failed to run ${name} hook`);
687
- }
688
- };
689
- async function executeCommand(command, args) {
690
- const [cmd, ..._args] = [...parseArgsStringToArgv(command), ...args];
691
- await execa(cmd, _args);
692
- }
693
- async function executeObjectCommand(command, args) {
694
- if (command.injectGeneratedDirsAndFiles === false) args = [];
695
- if (isString(command.command)) await executeCommand(command.command, args);
696
- else if (isFunction(command.command)) await command.command();
697
- }
698
- //#endregion
699
- //#region src/utils/package-json.ts
700
- const loadPackageJson = async (packageJson, workspace = process.cwd()) => {
701
- if (!packageJson) {
702
- const pkgPath = await findUp(["package.json"], { cwd: workspace });
703
- if (pkgPath) {
704
- const pkg = await dynamicImport(pkgPath, workspace);
705
- if (isPackageJson(pkg)) return resolveAndAttachVersions(await maybeReplaceCatalog(pkg, workspace), workspace, pkgPath);
706
- else throw new Error("Invalid package.json file");
707
- }
708
- return;
709
- }
710
- const normalizedPath = normalizePath(packageJson, workspace);
711
- if (fs.existsSync(normalizedPath)) {
712
- const pkg = await dynamicImport(normalizedPath);
713
- if (isPackageJson(pkg)) return resolveAndAttachVersions(await maybeReplaceCatalog(pkg, workspace), workspace, normalizedPath);
714
- else throw new Error(`Invalid package.json file: ${normalizedPath}`);
715
- }
716
- };
717
- const isPackageJson = (obj) => isObject(obj);
718
- const resolvedCache = /* @__PURE__ */ new Map();
719
- const resolveAndAttachVersions = (pkg, workspace, cacheKey) => {
720
- const cached = resolvedCache.get(cacheKey);
721
- if (cached) {
722
- pkg.resolvedVersions = cached;
723
- return pkg;
724
- }
725
- const resolved = resolveInstalledVersions(pkg, workspace);
726
- if (Object.keys(resolved).length > 0) {
727
- pkg.resolvedVersions = resolved;
728
- resolvedCache.set(cacheKey, resolved);
729
- for (const [name, version] of Object.entries(resolved)) logVerbose(styleText("dim", `Detected ${styleText("white", name)} v${styleText("white", version)}`));
730
- }
731
- return pkg;
732
- };
733
- const hasCatalogReferences = (pkg) => {
734
- return [
735
- ...Object.entries(pkg.dependencies ?? {}),
736
- ...Object.entries(pkg.devDependencies ?? {}),
737
- ...Object.entries(pkg.peerDependencies ?? {})
738
- ].some(([, value]) => isString(value) && value.startsWith("catalog:"));
739
- };
740
- const loadPnpmWorkspaceCatalog = async (workspace) => {
741
- const filePath = await findUp("pnpm-workspace.yaml", { cwd: workspace });
742
- if (!filePath) return void 0;
743
- try {
744
- const file = await fs.readFile(filePath, "utf8");
745
- const data = yaml.load(file);
746
- if (!data?.catalog && !data?.catalogs) return void 0;
747
- return {
748
- catalog: data.catalog,
749
- catalogs: data.catalogs
750
- };
751
- } catch {
752
- return;
753
- }
754
- };
755
- const loadPackageJsonCatalog = async (workspace) => {
756
- const filePaths = await findUpMultiple("package.json", { cwd: workspace });
757
- for (const filePath of filePaths) try {
758
- const pkg = await fs.readJson(filePath);
759
- if (pkg.catalog || pkg.catalogs) return {
760
- catalog: pkg.catalog,
761
- catalogs: pkg.catalogs
762
- };
763
- } catch {}
764
- };
765
- const loadYarnrcCatalog = async (workspace) => {
766
- const filePath = await findUp(".yarnrc.yml", { cwd: workspace });
767
- if (!filePath) return void 0;
768
- try {
769
- const file = await fs.readFile(filePath, "utf8");
770
- const data = yaml.load(file);
771
- if (!data?.catalog && !data?.catalogs) return void 0;
772
- return {
773
- catalog: data.catalog,
774
- catalogs: data.catalogs
775
- };
776
- } catch {
777
- return;
778
- }
779
- };
780
- const maybeReplaceCatalog = async (pkg, workspace) => {
781
- if (!hasCatalogReferences(pkg)) return pkg;
782
- const catalogData = await loadPnpmWorkspaceCatalog(workspace) ?? await loadPackageJsonCatalog(workspace) ?? await loadYarnrcCatalog(workspace);
783
- if (!catalogData) {
784
- logWarning("⚠️ package.json contains catalog: references, but no catalog source was found (checked: pnpm-workspace.yaml, package.json, .yarnrc.yml).");
785
- return pkg;
786
- }
787
- performSubstitution(pkg.dependencies, catalogData);
788
- performSubstitution(pkg.devDependencies, catalogData);
789
- performSubstitution(pkg.peerDependencies, catalogData);
790
- return pkg;
791
- };
792
- const performSubstitution = (dependencies, catalogData) => {
793
- if (!dependencies) return;
794
- for (const [packageName, version] of Object.entries(dependencies)) if (version === "catalog:" || version === "catalog:default") {
795
- if (!catalogData.catalog) {
796
- logWarning(`⚠️ catalog: substitution for the package '${packageName}' failed as there is no default catalog.`);
797
- continue;
798
- }
799
- const sub = catalogData.catalog[packageName];
800
- if (!sub) {
801
- logWarning(`⚠️ catalog: substitution for the package '${packageName}' failed as there is no matching package in the default catalog.`);
802
- continue;
803
- }
804
- dependencies[packageName] = sub;
805
- } else if (version.startsWith("catalog:")) {
806
- const catalogName = version.slice(8);
807
- const catalog = catalogData.catalogs?.[catalogName];
808
- if (!catalog) {
809
- logWarning(`⚠️ '${version}' substitution for the package '${packageName}' failed as there is no matching catalog named '${catalogName}'. (available named catalogs are: ${Object.keys(catalogData.catalogs ?? {}).join(", ")})`);
810
- continue;
811
- }
812
- const sub = catalog[packageName];
813
- if (!sub) {
814
- logWarning(`⚠️ '${version}' substitution for the package '${packageName}' failed as there is no package in the catalog named '${catalogName}'. (packages in the catalog are: ${Object.keys(catalog).join(", ")})`);
815
- continue;
816
- }
817
- dependencies[packageName] = sub;
818
- }
819
- };
820
- //#endregion
821
- //#region src/utils/tsconfig.ts
822
- const convertTarget = (config) => {
823
- if (!config.compilerOptions?.target) return {
824
- baseUrl: config.compilerOptions?.baseUrl,
825
- ...config
826
- };
827
- const lowercaseTarget = config.compilerOptions.target.toLowerCase();
828
- return {
829
- baseUrl: config.compilerOptions.baseUrl,
830
- ...config,
831
- compilerOptions: {
832
- ...config.compilerOptions,
833
- target: lowercaseTarget
834
- }
835
- };
836
- };
837
- const loadTsconfig = async (tsconfig, workspace = process.cwd()) => {
838
- if (isNullish(tsconfig)) {
839
- const configPath = await findUp(["tsconfig.json", "jsconfig.json"], { cwd: workspace });
840
- if (configPath) return convertTarget(parseTsconfig(configPath));
841
- return;
842
- }
843
- if (isString(tsconfig)) {
844
- const normalizedPath = normalizePath(tsconfig, workspace);
845
- if (fs.existsSync(normalizedPath)) return convertTarget(parseTsconfig(normalizedPath));
846
- return;
847
- }
848
- if (isObject(tsconfig)) return tsconfig;
849
- };
850
- //#endregion
851
- //#region src/utils/options.ts
852
- const INPUT_TARGET_FETCH_TIMEOUT_MS = 1e4;
853
- /**
854
- * Type helper to make it easier to use orval.config.ts
855
- * accepts a direct {@link ConfigExternal} object.
856
- */
857
- function defineConfig(options) {
858
- return options;
859
- }
860
- /**
861
- * Type helper to make it easier to write input transformers.
862
- * accepts a direct {@link InputTransformerFn} function.
863
- */
864
- function defineTransformer(transformer) {
865
- return transformer;
866
- }
867
- function createFormData(workspace, formData) {
868
- const defaultArrayHandling = FormDataArrayHandling.SERIALIZE;
869
- if (formData === void 0) return {
870
- disabled: false,
871
- arrayHandling: defaultArrayHandling
872
- };
873
- if (isBoolean(formData)) return {
874
- disabled: !formData,
875
- arrayHandling: defaultArrayHandling
876
- };
877
- if (isString(formData)) return {
878
- disabled: false,
879
- mutator: normalizeMutator(workspace, formData),
880
- arrayHandling: defaultArrayHandling
881
- };
882
- if ("mutator" in formData || "arrayHandling" in formData) return {
883
- disabled: false,
884
- mutator: normalizeMutator(workspace, formData.mutator),
885
- arrayHandling: formData.arrayHandling ?? defaultArrayHandling
886
- };
887
- return {
888
- disabled: false,
889
- mutator: normalizeMutator(workspace, formData),
890
- arrayHandling: defaultArrayHandling
891
- };
892
- }
893
- function normalizeSchemasOption(schemas, workspace) {
894
- if (!schemas) return;
895
- if (isString(schemas)) return normalizePath(schemas, workspace);
896
- validatePackageSpecifier(schemas.importPath, "schemas.importPath");
897
- return {
898
- path: normalizePath(schemas.path, workspace),
899
- type: schemas.type ?? "typescript",
900
- importPath: schemas.importPath,
901
- splitByTags: schemas.splitByTags ?? false
902
- };
903
- }
904
- /**
905
- * Validates that a config value is a valid package specifier (bare specifier
906
- * or sub-path import like `@acme/models` / `@acme/models/fakers`). Rejects
907
- * empty, whitespace-only, relative (`./`, `../`), and absolute paths with a
908
- * clear, actionable error message. No-op when the value is `undefined`.
909
- */
910
- function validatePackageSpecifier(value, fieldName) {
911
- if (value === void 0) return;
912
- if (!value) throw new Error(`\`${fieldName}\` must be a non-empty package specifier (e.g. '@acme/models'). Received an empty string.`);
913
- if (value.trim() === "") throw new Error(`\`${fieldName}\` must be a non-empty package specifier (e.g. '@acme/models'). Received a whitespace-only string.`);
914
- if (value.trim() !== value) throw new Error(`\`${fieldName}\` must be a non-empty package specifier (e.g. '@acme/models'). Received a value with leading or trailing whitespace: "${value}"`);
915
- if (value.startsWith(".")) throw new Error(`\`${fieldName}\` must be a package specifier (e.g. '@acme/models'), not a relative path. Received: "${value}"`);
916
- if (path.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\")) throw new Error(`\`${fieldName}\` must be a package specifier (e.g. '@acme/models'), not an absolute path. Received: "${value}"`);
917
- }
918
- function looksLikePackageSpecifier(value) {
919
- return !!value && value.trim() === value && !value.startsWith(".") && !path.isAbsolute(value) && !/^[A-Za-z]:[\\/]/.test(value) && !value.startsWith("\\\\");
920
- }
921
- function resolvePackageSpecifier(workspace, value) {
922
- try {
923
- return createRequire(path.join(workspace, "package.json")).resolve(value);
924
- } catch {
925
- return;
926
- }
927
- }
928
- function isPackageSpecifierCandidate(workspace, value) {
929
- if (!looksLikePackageSpecifier(value)) return false;
930
- if (existsSync(path.resolve(workspace, value))) return false;
931
- if (value.startsWith("@")) return true;
932
- const [packageName] = value.split("/");
933
- if (!value.includes("/")) return true;
934
- for (let dir = workspace;;) {
935
- if (existsSync(path.join(dir, "node_modules", packageName))) return true;
936
- const parent = path.dirname(dir);
937
- if (parent === dir) return false;
938
- dir = parent;
580
+ function isPackageSpecifierCandidate(workspace, value) {
581
+ if (!looksLikePackageSpecifier(value)) return false;
582
+ if (existsSync(path.resolve(workspace, value))) return false;
583
+ if (value.startsWith("@")) return true;
584
+ const [packageName] = value.split("/");
585
+ if (!value.includes("/")) return true;
586
+ for (let dir = workspace;;) {
587
+ if (existsSync(path.join(dir, "node_modules", packageName))) return true;
588
+ const parent = path.dirname(dir);
589
+ if (parent === dir) return false;
590
+ dir = parent;
939
591
  }
940
592
  }
941
593
  function normalizeEffectOptions(effect) {
@@ -1222,215 +874,678 @@ async function resolveFirstValidTarget(targets, workspace, parserOptions) {
1222
874
  method: "HEAD",
1223
875
  headers
1224
876
  });
1225
- if (headResponse.ok) return target;
1226
- if (headResponse.status === 405 || headResponse.status === 501) {
1227
- if ((await fetchWithTimeout(target, {
1228
- method: "GET",
1229
- headers
1230
- })).ok) return target;
1231
- }
1232
- } catch {
1233
- continue;
877
+ if (headResponse.ok) return target;
878
+ if (headResponse.status === 405 || headResponse.status === 501) {
879
+ if ((await fetchWithTimeout(target, {
880
+ method: "GET",
881
+ headers
882
+ })).ok) return target;
883
+ }
884
+ } catch {
885
+ continue;
886
+ }
887
+ continue;
888
+ }
889
+ const resolvedTarget = normalizePath(target, workspace);
890
+ try {
891
+ await access(resolvedTarget);
892
+ return resolvedTarget;
893
+ } catch {
894
+ continue;
895
+ }
896
+ }
897
+ throw new Error(styleText("red", `None of the input targets could be resolved:\n${targets.map((target) => ` - ${target}`).join("\n")}`));
898
+ }
899
+ function getHeadersForUrl(url, headersConfig) {
900
+ if (!headersConfig) return {};
901
+ const { hostname } = new URL(url);
902
+ const matchedHeaders = {};
903
+ for (const headerEntry of headersConfig) if (headerEntry.domains.some((domain) => hostname === domain || hostname.endsWith(`.${domain}`))) Object.assign(matchedHeaders, headerEntry.headers);
904
+ return matchedHeaders;
905
+ }
906
+ async function fetchWithTimeout(target, init) {
907
+ const controller = new AbortController();
908
+ const timeoutId = setTimeout(() => {
909
+ controller.abort();
910
+ }, INPUT_TARGET_FETCH_TIMEOUT_MS);
911
+ try {
912
+ return await fetch(target, {
913
+ ...init,
914
+ signal: controller.signal
915
+ });
916
+ } finally {
917
+ clearTimeout(timeoutId);
918
+ }
919
+ }
920
+ function normalizePathOrUrl(path, workspace) {
921
+ if (isString(path) && !isUrl(path)) return normalizePath(path, workspace);
922
+ return path;
923
+ }
924
+ function normalizePath(path$1, workspace) {
925
+ if (!isString(path$1)) return path$1;
926
+ return path.resolve(workspace, path$1);
927
+ }
928
+ function normalizeOperationsAndTags(operationsOrTags, workspace, global, source) {
929
+ const unsupportedZodKeys = [
930
+ "version",
931
+ "variant",
932
+ "dateTimeOptions",
933
+ "timeOptions",
934
+ "generateEachHttpStatus",
935
+ "generateReusableSchemas",
936
+ "generateMeta",
937
+ "generateDiscriminatedUnion"
938
+ ];
939
+ return Object.fromEntries(Object.entries(operationsOrTags).map(([key, { transformer, mutator, formData, formUrlEncoded, paramsSerializer, paramsFilter, query, angular, zod, effect, ...rest }]) => {
940
+ const unsupportedOperationZodKeys = zod && unsupportedZodKeys.filter((unsupportedKey) => zod[unsupportedKey] !== void 0);
941
+ if (unsupportedOperationZodKeys && unsupportedOperationZodKeys.length) logWarning(`⚠️ override.${source}.${key}.zod only supports strict, generate, coerce, preprocess, params, and useBrandedTypes. Ignoring unsupported ${unsupportedOperationZodKeys.length === 1 ? "field" : "fields"}: ${unsupportedOperationZodKeys.map((unsupportedKey) => `zod.${unsupportedKey}`).join(", ")}.`);
942
+ const hasSupportedOperationZodConfig = !!zod && (zod.strict !== void 0 || zod.generate !== void 0 || zod.coerce !== void 0 || zod.preprocess !== void 0 || zod.params !== void 0 || zod.useBrandedTypes !== void 0);
943
+ return [key, {
944
+ ...rest,
945
+ ...angular ? { angular: {
946
+ provideIn: angular.provideIn ?? "root",
947
+ client: angular.retrievalClient ?? angular.client ?? "httpClient",
948
+ runtimeValidation: angular.runtimeValidation ?? false,
949
+ queryObjectSerialization: angular.queryObjectSerialization ?? "spec",
950
+ ...angular.httpResource ? { httpResource: angular.httpResource } : {}
951
+ } } : {},
952
+ ...query ? { query: normalizeQueryOptions(query, workspace, global.query) } : {},
953
+ ...hasSupportedOperationZodConfig && zod ? { zod: {
954
+ strict: {
955
+ param: zod.strict?.param ?? false,
956
+ query: zod.strict?.query ?? false,
957
+ header: zod.strict?.header ?? false,
958
+ body: zod.strict?.body ?? false,
959
+ response: zod.strict?.response ?? false
960
+ },
961
+ generate: {
962
+ param: zod.generate?.param ?? true,
963
+ query: zod.generate?.query ?? true,
964
+ header: zod.generate?.header ?? true,
965
+ body: zod.generate?.body ?? true,
966
+ response: zod.generate?.response ?? true
967
+ },
968
+ coerce: {
969
+ param: zod.coerce?.param ?? false,
970
+ query: zod.coerce?.query ?? false,
971
+ header: zod.coerce?.header ?? false,
972
+ body: zod.coerce?.body ?? false,
973
+ response: zod.coerce?.response ?? false
974
+ },
975
+ preprocess: {
976
+ ...zod.preprocess?.param ? { param: normalizeMutator(workspace, zod.preprocess.param) } : {},
977
+ ...zod.preprocess?.query ? { query: normalizeMutator(workspace, zod.preprocess.query) } : {},
978
+ ...zod.preprocess?.header ? { header: normalizeMutator(workspace, zod.preprocess.header) } : {},
979
+ ...zod.preprocess?.body ? { body: normalizeMutator(workspace, zod.preprocess.body) } : {},
980
+ ...zod.preprocess?.response ? { response: normalizeMutator(workspace, zod.preprocess.response) } : {}
981
+ },
982
+ ...zod.params ? { params: normalizeMutator(workspace, zod.params) } : {},
983
+ useBrandedTypes: zod.useBrandedTypes ?? false
984
+ } } : {},
985
+ ...effect ? { effect: normalizeEffectOptions(effect) } : {},
986
+ ...transformer ? { transformer: normalizePath(transformer, workspace) } : {},
987
+ ...mutator ? { mutator: normalizeMutator(workspace, mutator) } : {},
988
+ ...formData === void 0 ? {} : { formData: createFormData(workspace, formData) },
989
+ ...formUrlEncoded ? { formUrlEncoded: isBoolean(formUrlEncoded) ? formUrlEncoded : normalizeMutator(workspace, formUrlEncoded) } : {},
990
+ ...paramsSerializer ? { paramsSerializer: normalizeMutator(workspace, paramsSerializer) } : {},
991
+ ...paramsFilter ? { paramsFilter: normalizeMutator(workspace, paramsFilter) } : {}
992
+ }];
993
+ }));
994
+ }
995
+ function normalizeOutputMode(mode) {
996
+ if (!mode) return OutputMode.SINGLE;
997
+ if (!Object.values(OutputMode).includes(mode)) {
998
+ logWarning(`⚠️ Unknown provided mode => ${mode}`);
999
+ return OutputMode.SINGLE;
1000
+ }
1001
+ return mode;
1002
+ }
1003
+ function normalizeHooks(hooks) {
1004
+ const keys = Object.keys(hooks);
1005
+ const result = {};
1006
+ for (const key of keys) if (isString(hooks[key])) result[key] = [hooks[key]];
1007
+ else if (Array.isArray(hooks[key])) result[key] = hooks[key];
1008
+ else if (isFunction(hooks[key])) result[key] = [hooks[key]];
1009
+ else if (isObject(hooks[key])) result[key] = [hooks[key]];
1010
+ return result;
1011
+ }
1012
+ function normalizeHonoOptions(hono = {}, workspace) {
1013
+ return {
1014
+ ...hono.handlers ? { handlers: path.resolve(workspace, hono.handlers) } : {},
1015
+ handlerGenerationStrategy: hono.handlerGenerationStrategy ?? "smart",
1016
+ compositeRoute: hono.compositeRoute ? path.resolve(workspace, hono.compositeRoute) : "",
1017
+ validator: hono.validator ?? true,
1018
+ validatorOutputPath: hono.validatorOutputPath ? path.resolve(workspace, hono.validatorOutputPath) : ""
1019
+ };
1020
+ }
1021
+ function normalizeMcpServerOptions(server, workspace) {
1022
+ return {
1023
+ path: path.resolve(workspace, server.path),
1024
+ name: server.name,
1025
+ default: server.default ?? !server.name
1026
+ };
1027
+ }
1028
+ function normalizeMcpOptions(mcp = {}, workspace) {
1029
+ return mcp.server ? { server: normalizeMcpServerOptions(mcp.server, workspace) } : {};
1030
+ }
1031
+ function normalizeJSDocOptions(jsdoc = {}) {
1032
+ return { ...jsdoc };
1033
+ }
1034
+ function normalizeQueryOptions(queryOptions = {}, outputWorkspace, globalOptions = {}) {
1035
+ if (queryOptions.options) logWarning("⚠️ Using query options is deprecated and will be removed in a future major release. Please use queryOptions or mutationOptions instead.");
1036
+ return {
1037
+ ...isNullish(queryOptions.usePrefetch) ? {} : { usePrefetch: queryOptions.usePrefetch },
1038
+ ...isNullish(queryOptions.useInvalidate) ? {} : { useInvalidate: queryOptions.useInvalidate },
1039
+ ...isNullish(queryOptions.useSetQueryData) ? {} : { useSetQueryData: queryOptions.useSetQueryData },
1040
+ ...isNullish(queryOptions.useGetQueryData) ? {} : { useGetQueryData: queryOptions.useGetQueryData },
1041
+ ...isNullish(queryOptions.useQuery) ? {} : { useQuery: queryOptions.useQuery },
1042
+ ...isNullish(queryOptions.useSuspenseQuery) ? {} : { useSuspenseQuery: queryOptions.useSuspenseQuery },
1043
+ ...isNullish(queryOptions.useMutation) ? {} : { useMutation: queryOptions.useMutation },
1044
+ ...isNullish(queryOptions.useInfinite) ? {} : { useInfinite: queryOptions.useInfinite },
1045
+ ...isNullish(queryOptions.useSuspenseInfiniteQuery) ? {} : { useSuspenseInfiniteQuery: queryOptions.useSuspenseInfiniteQuery },
1046
+ ...queryOptions.useInfiniteQueryParam ? { useInfiniteQueryParam: queryOptions.useInfiniteQueryParam } : {},
1047
+ ...queryOptions.options ? { options: queryOptions.options } : {},
1048
+ ...globalOptions.queryKey ? { queryKey: globalOptions.queryKey } : {},
1049
+ ...queryOptions.queryKey ? { queryKey: normalizeMutator(outputWorkspace, queryOptions.queryKey) } : {},
1050
+ ...globalOptions.queryOptions ? { queryOptions: globalOptions.queryOptions } : {},
1051
+ ...queryOptions.queryOptions ? { queryOptions: normalizeMutator(outputWorkspace, queryOptions.queryOptions) } : {},
1052
+ ...globalOptions.mutationOptions ? { mutationOptions: globalOptions.mutationOptions } : {},
1053
+ ...queryOptions.mutationOptions ? { mutationOptions: normalizeMutator(outputWorkspace, queryOptions.mutationOptions) } : {},
1054
+ ...isNullish(globalOptions.shouldExportQueryKey) ? {} : { shouldExportQueryKey: globalOptions.shouldExportQueryKey },
1055
+ ...isNullish(queryOptions.shouldExportQueryKey) ? {} : { shouldExportQueryKey: queryOptions.shouldExportQueryKey },
1056
+ ...isNullish(globalOptions.shouldFilterQueryKey) ? {} : { shouldFilterQueryKey: globalOptions.shouldFilterQueryKey },
1057
+ ...isNullish(queryOptions.shouldFilterQueryKey) ? {} : { shouldFilterQueryKey: queryOptions.shouldFilterQueryKey },
1058
+ ...isNullish(globalOptions.queryKeyFilter) ? {} : { queryKeyFilter: globalOptions.queryKeyFilter },
1059
+ ...isNullish(queryOptions.queryKeyFilter) ? {} : { queryKeyFilter: queryOptions.queryKeyFilter },
1060
+ ...isNullish(globalOptions.shouldExportHttpClient) ? {} : { shouldExportHttpClient: globalOptions.shouldExportHttpClient },
1061
+ ...isNullish(queryOptions.shouldExportHttpClient) ? {} : { shouldExportHttpClient: queryOptions.shouldExportHttpClient },
1062
+ ...isNullish(globalOptions.shouldExportMutatorHooks) ? {} : { shouldExportMutatorHooks: globalOptions.shouldExportMutatorHooks },
1063
+ ...isNullish(queryOptions.shouldExportMutatorHooks) ? {} : { shouldExportMutatorHooks: queryOptions.shouldExportMutatorHooks },
1064
+ ...isNullish(globalOptions.shouldSplitQueryKey) ? {} : { shouldSplitQueryKey: globalOptions.shouldSplitQueryKey },
1065
+ ...isNullish(queryOptions.shouldSplitQueryKey) ? {} : { shouldSplitQueryKey: queryOptions.shouldSplitQueryKey },
1066
+ ...isNullish(globalOptions.signal) ? {} : { signal: globalOptions.signal },
1067
+ ...isNullish(globalOptions.useOperationIdAsQueryKey) ? {} : { useOperationIdAsQueryKey: globalOptions.useOperationIdAsQueryKey },
1068
+ ...isNullish(queryOptions.useOperationIdAsQueryKey) ? {} : { useOperationIdAsQueryKey: queryOptions.useOperationIdAsQueryKey },
1069
+ ...isNullish(globalOptions.signal) ? {} : { signal: globalOptions.signal },
1070
+ ...isNullish(queryOptions.signal) ? {} : { signal: queryOptions.signal },
1071
+ ...isNullish(globalOptions.version) ? {} : { version: globalOptions.version },
1072
+ ...isNullish(queryOptions.version) ? {} : { version: queryOptions.version },
1073
+ ...queryOptions.mutationInvalidates ? { mutationInvalidates: queryOptions.mutationInvalidates } : {},
1074
+ ...isNullish(globalOptions.runtimeValidation) ? {} : { runtimeValidation: globalOptions.runtimeValidation },
1075
+ ...isNullish(queryOptions.runtimeValidation) ? {} : { runtimeValidation: queryOptions.runtimeValidation }
1076
+ };
1077
+ }
1078
+ function getDefaultFilesHeader({ title, description, version: version$1 } = {}) {
1079
+ return [
1080
+ `Generated by ${name} v${version} 🍺`,
1081
+ `Do not edit manually.`,
1082
+ ...title ? [title] : [],
1083
+ ...description ? [description] : [],
1084
+ ...version$1 ? [`OpenAPI spec version: ${version$1}`] : []
1085
+ ];
1086
+ }
1087
+ //#endregion
1088
+ //#region src/import-specs.ts
1089
+ async function resolveSpec(input, { parserOptions, transformer, workspace, unsafeDisableValidation = false }) {
1090
+ const allowedRefs = parserOptions?.externalRefs?.allow ?? [];
1091
+ const isWildcard = allowedRefs.includes("*");
1092
+ const { data: specData, origin } = await loadSpec(input, parserOptions?.headers);
1093
+ if (!isWildcard) {
1094
+ const disallowed = collectExternalRefs(specData).filter((ref) => !isAllowedRef(ref, allowedRefs, origin));
1095
+ if (disallowed.length > 0) throw new Error(formatDisallowedRefsError(disallowed, allowedRefs));
1096
+ } else {
1097
+ const docs = [...new Set(collectExternalRefs(specData).map(getRefDocument))];
1098
+ if (docs.length > 0) logWarning(`External $ref documents being resolved:\n` + docs.map((d) => ` - ${d}`).join("\n"));
1099
+ }
1100
+ const dereferencedData = await bundleAndDereferenceExternalRefs(specData, parserOptions, origin, isWildcard, allowedRefs);
1101
+ let transformedData = dereferencedData;
1102
+ if (transformer) {
1103
+ const applied = await applyInputTransformer(dereferencedData, transformer, workspace);
1104
+ transformedData = collectExternalRefs(applied).length > 0 ? await bundleAndDereferenceExternalRefs(applied, parserOptions, origin, isWildcard, allowedRefs) : applied;
1105
+ }
1106
+ if (unsafeDisableValidation) logWarning("🚨 OpenAPI spec validation is disabled.\n Code generation with invalid specs is not guaranteed to work and may break in minor updates.\n Bug reports with validation disabled will not be accepted.");
1107
+ else {
1108
+ validateComponentKeys(transformedData);
1109
+ const { valid, errors } = await validate(transformedData);
1110
+ if (!valid) throw new Error(`OpenAPI spec validation failed:\n${JSON.stringify(errors, void 0, 2)}`);
1111
+ }
1112
+ const { specification } = upgrade(transformedData);
1113
+ return specification;
1114
+ }
1115
+ async function applyInputTransformer(data, transformer, workspace) {
1116
+ const transformerFn = await dynamicImport(transformer, workspace);
1117
+ const result = await transformerFn(data);
1118
+ if (!isObject(result)) {
1119
+ const source = isString(transformer) ? transformer : transformerFn.name || "<inline function>";
1120
+ throw new Error(`input.override.transformer must return an OpenAPI document object; got ${result === void 0 ? "undefined" : typeof result} from ${source}. Ensure your transformer returns the (possibly modified) spec.`);
1121
+ }
1122
+ return result;
1123
+ }
1124
+ /**
1125
+ * Bundle external references into the document and then resolve the `x-ext`
1126
+ * entries that `@scalar/json-magic` produces. Shared by the initial pass and
1127
+ * the post-transformer pass (#3327); `origin` lets the second pass resolve refs
1128
+ * relative to the original spec file when the input is an in-memory object.
1129
+ */
1130
+ async function bundleAndDereferenceExternalRefs(input, parserOptions, origin, isWildcard = false, allowedExternalRefs = []) {
1131
+ return dereferenceExternalRef(await bundle(input, {
1132
+ plugins: [
1133
+ createSafeFileLoader(origin, isWildcard, allowedExternalRefs),
1134
+ createSafeUrlLoader(origin, isWildcard, allowedExternalRefs, parserOptions?.headers),
1135
+ parseJson(),
1136
+ parseYaml()
1137
+ ],
1138
+ treeShake: false,
1139
+ ...origin ? { origin } : {}
1140
+ }));
1141
+ }
1142
+ /**
1143
+ * Load the top-level spec into an inline object so we can scan it for external
1144
+ * `$ref`s before `bundle()` resolves them. The top-level target is trusted
1145
+ * (user-configured `input.target`); only `$ref` values inside the spec are
1146
+ * untrusted.
1147
+ */
1148
+ function parseSpec(text) {
1149
+ const result = jsYaml.load(text);
1150
+ if (!isObject(result)) throw new Error("OpenAPI spec must be a valid JSON/YAML object.");
1151
+ return result;
1152
+ }
1153
+ async function loadSpec(input, headers) {
1154
+ if (!isString(input)) return { data: input };
1155
+ if (isUrl(input)) {
1156
+ const response = await fetch(input, { headers: getHeadersForUrl(input, headers) });
1157
+ if (!response.ok) throw new Error(`Failed to fetch OpenAPI spec from ${input}: ${response.status} ${response.statusText}`);
1158
+ return {
1159
+ data: parseSpec(await response.text()),
1160
+ origin: input
1161
+ };
1162
+ }
1163
+ return {
1164
+ data: parseSpec(await readFile(input, "utf-8")),
1165
+ origin: input
1166
+ };
1167
+ }
1168
+ /**
1169
+ * Strip the JSON pointer fragment (`#/...`) from a `$ref` value, leaving only
1170
+ * the document target (file path or URL).
1171
+ */
1172
+ function getRefDocument(ref) {
1173
+ const hashIndex = ref.indexOf("#");
1174
+ return hashIndex === -1 ? ref : ref.slice(0, hashIndex);
1175
+ }
1176
+ /**
1177
+ * Collect all external `$ref` document targets from a spec object. Returns
1178
+ * deduplicated ref strings in their raw form (before fragment stripping).
1179
+ */
1180
+ function collectExternalRefs(obj) {
1181
+ const refs = /* @__PURE__ */ new Set();
1182
+ function walk(val) {
1183
+ if (Array.isArray(val)) {
1184
+ val.forEach(walk);
1185
+ return;
1186
+ }
1187
+ if (isObject(val)) {
1188
+ if ("$ref" in val && isString(val.$ref) && !val.$ref.startsWith("#")) refs.add(val.$ref);
1189
+ Object.values(val).forEach(walk);
1190
+ }
1191
+ }
1192
+ walk(obj);
1193
+ return [...refs];
1194
+ }
1195
+ /**
1196
+ * Resolve a ref document target (the part before `#`) to a canonical path or
1197
+ * URL, so it can be compared against allow-list entries that were resolved the
1198
+ * same way.
1199
+ */
1200
+ function resolveRefTarget(ref, origin) {
1201
+ const doc = getRefDocument(ref);
1202
+ if (isUrl(doc)) return new URL(doc).href;
1203
+ if (origin && isUrl(origin)) return new URL(doc, origin).href;
1204
+ if (origin) return path.resolve(path.dirname(origin), doc);
1205
+ return path.resolve(doc);
1206
+ }
1207
+ /**
1208
+ * Check whether a `$ref` is allowed by the user's allow-list. Both the ref and
1209
+ * the allow-list entries are resolved against the spec origin so that
1210
+ * `./schemas/pet.yaml` in the spec matches `./schemas/pet.yaml` in the config.
1211
+ */
1212
+ function isAllowedRef(ref, allowedExternalRefs, origin) {
1213
+ const resolved = resolveRefTarget(ref, origin);
1214
+ return allowedExternalRefs.some((entry) => resolveRefTarget(entry, origin) === resolved);
1215
+ }
1216
+ function formatDisallowedRefsError(disallowed, currentAllowed) {
1217
+ const docs = [...new Set(disallowed.map(getRefDocument))];
1218
+ const all = [...new Set([...currentAllowed, ...docs])];
1219
+ const configSnippet = JSON.stringify({ input: { parserOptions: { externalRefs: { allow: all } } } }, null, 2);
1220
+ return `External \$ref targets are not allowed by default.
1221
+ Add them to your config, or use externalRefs.allow: ['*'] to allow all.
1222
+
1223
+ Disallowed refs:\n${disallowed.map((r) => ` - ${r}`).join("\n")}\n\nSuggested config:\n${configSnippet}`;
1224
+ }
1225
+ /**
1226
+ * Wrap `readFiles()` so every file read is checked against the allow-list.
1227
+ * The top-level spec file (matching `origin`) is always allowed; subsequent
1228
+ * reads must match an explicit entry or the wildcard.
1229
+ */
1230
+ function createSafeFileLoader(origin, isWildcard, allowedExternalRefs) {
1231
+ const base = readFiles();
1232
+ return {
1233
+ type: "loader",
1234
+ validate: base.validate,
1235
+ async exec(value) {
1236
+ if (isWildcard) return base.exec(value);
1237
+ if (origin && path.resolve(value) === path.resolve(origin)) return base.exec(value);
1238
+ if (!isAllowedRef(value, allowedExternalRefs, origin)) throw new Error(`Refused to read external file: ${value}\nAdd it to externalRefs.allow or use ['*'] to allow all.`);
1239
+ return base.exec(value);
1240
+ }
1241
+ };
1242
+ }
1243
+ /**
1244
+ * Wrap `fetchUrls()` so every URL fetch is checked against the allow-list.
1245
+ * The top-level spec URL (matching `origin`) is always allowed; subsequent
1246
+ * fetches must match an explicit entry or the wildcard.
1247
+ */
1248
+ function createSafeUrlLoader(origin, isWildcard, allowedExternalRefs, headers) {
1249
+ const base = fetchUrls({ headers });
1250
+ return {
1251
+ type: "loader",
1252
+ validate: base.validate,
1253
+ async exec(value) {
1254
+ if (isWildcard) return base.exec(value);
1255
+ const resolved = resolveRefTarget(value, origin);
1256
+ if (origin && resolved === resolveRefTarget(origin)) return base.exec(value);
1257
+ if (!isAllowedRef(value, allowedExternalRefs, origin)) throw new Error(`Refused to fetch external URL: ${value}\nAdd it to externalRefs.allow or use ['*'] to allow all.`);
1258
+ return base.exec(value);
1259
+ }
1260
+ };
1261
+ }
1262
+ async function importSpecs(workspace, options, projectName) {
1263
+ const { input, output } = options;
1264
+ return importOpenApi({
1265
+ spec: await resolveSpec(input.target, {
1266
+ parserOptions: input.parserOptions,
1267
+ transformer: input.override.transformer,
1268
+ workspace,
1269
+ unsafeDisableValidation: input.unsafeDisableValidation
1270
+ }),
1271
+ input,
1272
+ output,
1273
+ target: isString(input.target) ? input.target : workspace,
1274
+ workspace,
1275
+ projectName
1276
+ });
1277
+ }
1278
+ const COMPONENT_KEY_PATTERN = /^[a-zA-Z0-9.\-_]+$/;
1279
+ const COMPONENT_SECTIONS = [
1280
+ "schemas",
1281
+ "responses",
1282
+ "parameters",
1283
+ "examples",
1284
+ "requestBodies",
1285
+ "headers",
1286
+ "securitySchemes",
1287
+ "links",
1288
+ "callbacks",
1289
+ "pathItems"
1290
+ ];
1291
+ /**
1292
+ * Validate that all component keys conform to the OAS regex: ^[a-zA-Z0-9.\-_]+$
1293
+ * @see https://spec.openapis.org/oas/v3.0.3.html#fixed-fields-5
1294
+ * @see https://spec.openapis.org/oas/v3.1.0#fixed-fields-5
1295
+ */
1296
+ function validateComponentKeys(data) {
1297
+ const components = data.components;
1298
+ if (!isObject(components)) return;
1299
+ const invalidKeys = [];
1300
+ for (const section of COMPONENT_SECTIONS) {
1301
+ const sectionObj = components[section];
1302
+ if (!isObject(sectionObj)) continue;
1303
+ for (const key of Object.keys(sectionObj)) if (!COMPONENT_KEY_PATTERN.test(key)) invalidKeys.push(`components.${section}.${key}`);
1304
+ }
1305
+ if (invalidKeys.length > 0) throw new Error(`Invalid component key${invalidKeys.length > 1 ? "s" : ""} found. OpenAPI component keys must match the pattern ${COMPONENT_KEY_PATTERN} (non-ASCII characters are not allowed per the spec).\n See: https://spec.openapis.org/oas/v3.0.3.html#components-object\n Invalid keys:\n` + invalidKeys.map((k) => ` - ${k}`).join("\n"));
1306
+ }
1307
+ /**
1308
+ * The plugins from `@scalar/json-magic` does not dereference $ref.
1309
+ * Instead it fetches them and puts them under x-ext, and changes the $ref to point to #x-ext/<name>.
1310
+ * This function:
1311
+ * 1. Merges external schemas into main spec's components.schemas (with collision handling)
1312
+ * 2. Replaces x-ext refs with standard component refs or inlined content
1313
+ */
1314
+ function dereferenceExternalRef(data) {
1315
+ const extensions = data["x-ext"] ?? {};
1316
+ const schemaNameMappings = mergeExternalSchemas(data, extensions);
1317
+ const result = {};
1318
+ for (const [key, value] of Object.entries(data)) if (key !== "x-ext") result[key] = replaceXExtRefs(value, extensions, schemaNameMappings);
1319
+ return result;
1320
+ }
1321
+ /**
1322
+ * Merge external document schemas into main spec's components.schemas
1323
+ * Returns mapping of original schema names to final names (with suffixes for collisions)
1324
+ */
1325
+ function mergeExternalSchemas(data, extensions) {
1326
+ const schemaNameMappings = {};
1327
+ if (Object.keys(extensions).length === 0) return schemaNameMappings;
1328
+ data.components ??= {};
1329
+ const mainComponents = data.components;
1330
+ mainComponents.schemas ??= {};
1331
+ const mainSchemas = mainComponents.schemas;
1332
+ for (const [extKey, extDoc] of Object.entries(extensions)) {
1333
+ schemaNameMappings[extKey] = {};
1334
+ if (isObject(extDoc) && "components" in extDoc) {
1335
+ const extComponents = extDoc.components;
1336
+ if (isObject(extComponents) && "schemas" in extComponents) {
1337
+ const extSchemas = extComponents.schemas;
1338
+ for (const [schemaName, schema] of Object.entries(extSchemas)) {
1339
+ const existingSchema = mainSchemas[schemaName];
1340
+ const isXExtRef = isObject(existingSchema) && "$ref" in existingSchema && isString(existingSchema.$ref) && existingSchema.$ref.startsWith("#/x-ext/");
1341
+ let finalSchemaName = schemaName;
1342
+ if (schemaName in mainSchemas && !isXExtRef) {
1343
+ finalSchemaName = `${schemaName}_${extKey.replaceAll(/[^a-zA-Z0-9]/g, "_")}`;
1344
+ schemaNameMappings[extKey][schemaName] = finalSchemaName;
1345
+ } else schemaNameMappings[extKey][schemaName] = schemaName;
1346
+ mainSchemas[finalSchemaName] = scrubUnwantedKeys(schema);
1347
+ }
1348
+ }
1349
+ }
1350
+ }
1351
+ for (const [extKey, mapping] of Object.entries(schemaNameMappings)) for (const [, finalName] of Object.entries(mapping)) {
1352
+ const schema = mainSchemas[finalName];
1353
+ if (schema) mainSchemas[finalName] = updateInternalRefs(schema, extKey, schemaNameMappings);
1354
+ }
1355
+ return schemaNameMappings;
1356
+ }
1357
+ /**
1358
+ * Remove unwanted keys like $schema and $id from objects
1359
+ */
1360
+ function scrubUnwantedKeys(obj) {
1361
+ const UNWANTED_KEYS = new Set(["$schema", "$id"]);
1362
+ if (obj === null || obj === void 0) return obj;
1363
+ if (Array.isArray(obj)) return obj.map((x) => scrubUnwantedKeys(x));
1364
+ if (isObject(obj)) {
1365
+ const rec = obj;
1366
+ const out = {};
1367
+ for (const [k, v] of Object.entries(rec)) {
1368
+ if (UNWANTED_KEYS.has(k)) continue;
1369
+ out[k] = scrubUnwantedKeys(v);
1370
+ }
1371
+ return out;
1372
+ }
1373
+ return obj;
1374
+ }
1375
+ /**
1376
+ * Update internal refs within an external schema to use suffixed names
1377
+ */
1378
+ function updateInternalRefs(obj, extKey, schemaNameMappings) {
1379
+ if (obj === null || obj === void 0) return obj;
1380
+ if (Array.isArray(obj)) return obj.map((element) => updateInternalRefs(element, extKey, schemaNameMappings));
1381
+ if (isObject(obj)) {
1382
+ const record = obj;
1383
+ if ("$ref" in record && isString(record.$ref)) {
1384
+ const refValue = record.$ref;
1385
+ if (refValue.startsWith("#/components/schemas/")) {
1386
+ const schemaName = refValue.replace("#/components/schemas/", "");
1387
+ const mappedName = schemaNameMappings[extKey][schemaName];
1388
+ if (mappedName) return { $ref: `#/components/schemas/${mappedName}` };
1389
+ }
1390
+ }
1391
+ const result = {};
1392
+ for (const [key, value] of Object.entries(record)) result[key] = updateInternalRefs(value, extKey, schemaNameMappings);
1393
+ return result;
1394
+ }
1395
+ return obj;
1396
+ }
1397
+ /**
1398
+ * Decode a single JSON Pointer reference token taken from an x-ext `$ref`.
1399
+ *
1400
+ * The token carries two layers of encoding: it sits in a URI fragment, so it
1401
+ * may be percent-encoded (e.g. `%7B` for `{` in templated paths), and it is a
1402
+ * JSON Pointer token, so `~1`/`~0` stand for `/`/`~` (RFC 6901). Percent-
1403
+ * encoding is the outer layer and is removed first; a malformed sequence is
1404
+ * left as-is rather than throwing. Without this, tokens such as `~1pets`
1405
+ * never match the real `/pets` key and the external `$ref` fails to resolve.
1406
+ */
1407
+ function decodeRefToken(token) {
1408
+ let decoded = token;
1409
+ try {
1410
+ decoded = decodeURIComponent(token);
1411
+ } catch {}
1412
+ return decoded.replaceAll("~1", "/").replaceAll("~0", "~");
1413
+ }
1414
+ /**
1415
+ * Replace x-ext refs with standard component refs, or inline the content.
1416
+ * `inliningRefs` tracks the inline chain to break cycles in recursive
1417
+ * external schemas that aren't under `components.schemas` (#1642).
1418
+ */
1419
+ function replaceXExtRefs(obj, extensions, schemaNameMappings, inliningRefs = /* @__PURE__ */ new Set()) {
1420
+ if (isNullish$1(obj)) return obj;
1421
+ if (Array.isArray(obj)) return obj.map((element) => replaceXExtRefs(element, extensions, schemaNameMappings, inliningRefs));
1422
+ if (isObject(obj)) {
1423
+ const record = obj;
1424
+ if ("$ref" in record && isString(record.$ref)) {
1425
+ const refValue = record.$ref;
1426
+ if (refValue.startsWith("#/x-ext/")) {
1427
+ const parts = refValue.replace("#/x-ext/", "").split("/");
1428
+ const extKey = parts.shift();
1429
+ if (extKey) {
1430
+ if (parts.length >= 3 && parts[0] === "components" && parts[1] === "schemas") {
1431
+ const schemaName = parts.slice(2).join("/");
1432
+ return { $ref: `#/components/schemas/${schemaNameMappings[extKey][schemaName] || schemaName}` };
1433
+ }
1434
+ if (inliningRefs.has(refValue)) {
1435
+ logWarning(`Detected a circular external $ref while inlining "${refValue}". Replacing with an empty schema to avoid infinite recursion. Move the schema under "components.schemas" in its source file or pre-bundle the spec to keep the recursion intact.`);
1436
+ return {};
1437
+ }
1438
+ let refObj = extensions[extKey];
1439
+ for (const rawPart of parts) {
1440
+ const p = decodeRefToken(rawPart);
1441
+ if (refObj && (isObject(refObj) || Array.isArray(refObj)) && p in refObj) refObj = refObj[p];
1442
+ else {
1443
+ refObj = void 0;
1444
+ break;
1445
+ }
1446
+ }
1447
+ if (refObj) {
1448
+ const cleaned = scrubUnwantedKeys(refObj);
1449
+ const nextInlining = new Set(inliningRefs);
1450
+ nextInlining.add(refValue);
1451
+ return replaceXExtRefs(cleaned, extensions, schemaNameMappings, nextInlining);
1452
+ }
1453
+ }
1454
+ }
1455
+ }
1456
+ const result = {};
1457
+ for (const [key, value] of Object.entries(record)) result[key] = replaceXExtRefs(value, extensions, schemaNameMappings, inliningRefs);
1458
+ return result;
1459
+ }
1460
+ return obj;
1461
+ }
1462
+ //#endregion
1463
+ //#region src/formatters/prettier.ts
1464
+ /**
1465
+ * Format files with prettier.
1466
+ * Tries the programmatic API first (project dependency),
1467
+ * then falls back to the globally installed CLI.
1468
+ */
1469
+ async function formatWithPrettier(paths, projectTitle) {
1470
+ const prettier = await tryImportPrettier();
1471
+ if (prettier) {
1472
+ const filePaths = [...new Set(await collectFilePaths(paths))];
1473
+ if (filePaths.length === 0) return;
1474
+ const config = await prettier.resolveConfig(filePaths[0]) ?? {};
1475
+ await Promise.all(filePaths.map(async (filePath) => {
1476
+ try {
1477
+ const content = await fs.readFile(filePath, "utf8");
1478
+ const formatted = await prettier.format(content, {
1479
+ ...config,
1480
+ filepath: filePath
1481
+ });
1482
+ await fs.writeFile(filePath, formatted);
1483
+ } catch (error) {
1484
+ if (isMissingFileError(error)) return;
1485
+ if (error instanceof Error) if (error.name === "UndefinedParserError") {} else logWarning(`⚠️ ${projectTitle ? `${projectTitle} - ` : ""}Failed to format file ${filePath}: ${error.toString()}`);
1486
+ else logWarning(`⚠️ ${projectTitle ? `${projectTitle} - ` : ""}Failed to format file ${filePath}: unknown error`);
1234
1487
  }
1235
- continue;
1236
- }
1237
- const resolvedTarget = normalizePath(target, workspace);
1238
- try {
1239
- await access(resolvedTarget);
1240
- return resolvedTarget;
1241
- } catch {
1242
- continue;
1243
- }
1488
+ }));
1489
+ return;
1244
1490
  }
1245
- throw new Error(styleText("red", `None of the input targets could be resolved:\n${targets.map((target) => ` - ${target}`).join("\n")}`));
1246
- }
1247
- function getHeadersForUrl(url, headersConfig) {
1248
- if (!headersConfig) return {};
1249
- const { hostname } = new URL(url);
1250
- const matchedHeaders = {};
1251
- for (const headerEntry of headersConfig) if (headerEntry.domains.some((domain) => hostname === domain || hostname.endsWith(`.${domain}`))) Object.assign(matchedHeaders, headerEntry.headers);
1252
- return matchedHeaders;
1253
- }
1254
- async function fetchWithTimeout(target, init) {
1255
- const controller = new AbortController();
1256
- const timeoutId = setTimeout(() => {
1257
- controller.abort();
1258
- }, INPUT_TARGET_FETCH_TIMEOUT_MS);
1259
1491
  try {
1260
- return await fetch(target, {
1261
- ...init,
1262
- signal: controller.signal
1263
- });
1264
- } finally {
1265
- clearTimeout(timeoutId);
1492
+ await execa("prettier", ["--write", ...paths]);
1493
+ } catch {
1494
+ logWarning(`⚠️ ${projectTitle ? `${projectTitle} - ` : ""}prettier not found. Install it as a project dependency or globally.`);
1266
1495
  }
1267
1496
  }
1268
- function normalizePathOrUrl(path, workspace) {
1269
- if (isString(path) && !isUrl(path)) return normalizePath(path, workspace);
1270
- return path;
1271
- }
1272
- function normalizePath(path$1, workspace) {
1273
- if (!isString(path$1)) return path$1;
1274
- return path.resolve(workspace, path$1);
1275
- }
1276
- function normalizeOperationsAndTags(operationsOrTags, workspace, global, source) {
1277
- const unsupportedZodKeys = [
1278
- "version",
1279
- "variant",
1280
- "dateTimeOptions",
1281
- "timeOptions",
1282
- "generateEachHttpStatus",
1283
- "generateReusableSchemas",
1284
- "generateMeta",
1285
- "generateDiscriminatedUnion"
1286
- ];
1287
- return Object.fromEntries(Object.entries(operationsOrTags).map(([key, { transformer, mutator, formData, formUrlEncoded, paramsSerializer, paramsFilter, query, angular, zod, effect, ...rest }]) => {
1288
- const unsupportedOperationZodKeys = zod && unsupportedZodKeys.filter((unsupportedKey) => zod[unsupportedKey] !== void 0);
1289
- if (unsupportedOperationZodKeys && unsupportedOperationZodKeys.length) logWarning(`⚠️ override.${source}.${key}.zod only supports strict, generate, coerce, preprocess, params, and useBrandedTypes. Ignoring unsupported ${unsupportedOperationZodKeys.length === 1 ? "field" : "fields"}: ${unsupportedOperationZodKeys.map((unsupportedKey) => `zod.${unsupportedKey}`).join(", ")}.`);
1290
- const hasSupportedOperationZodConfig = !!zod && (zod.strict !== void 0 || zod.generate !== void 0 || zod.coerce !== void 0 || zod.preprocess !== void 0 || zod.params !== void 0 || zod.useBrandedTypes !== void 0);
1291
- return [key, {
1292
- ...rest,
1293
- ...angular ? { angular: {
1294
- provideIn: angular.provideIn ?? "root",
1295
- client: angular.retrievalClient ?? angular.client ?? "httpClient",
1296
- runtimeValidation: angular.runtimeValidation ?? false,
1297
- queryObjectSerialization: angular.queryObjectSerialization ?? "spec",
1298
- ...angular.httpResource ? { httpResource: angular.httpResource } : {}
1299
- } } : {},
1300
- ...query ? { query: normalizeQueryOptions(query, workspace, global.query) } : {},
1301
- ...hasSupportedOperationZodConfig && zod ? { zod: {
1302
- strict: {
1303
- param: zod.strict?.param ?? false,
1304
- query: zod.strict?.query ?? false,
1305
- header: zod.strict?.header ?? false,
1306
- body: zod.strict?.body ?? false,
1307
- response: zod.strict?.response ?? false
1308
- },
1309
- generate: {
1310
- param: zod.generate?.param ?? true,
1311
- query: zod.generate?.query ?? true,
1312
- header: zod.generate?.header ?? true,
1313
- body: zod.generate?.body ?? true,
1314
- response: zod.generate?.response ?? true
1315
- },
1316
- coerce: {
1317
- param: zod.coerce?.param ?? false,
1318
- query: zod.coerce?.query ?? false,
1319
- header: zod.coerce?.header ?? false,
1320
- body: zod.coerce?.body ?? false,
1321
- response: zod.coerce?.response ?? false
1322
- },
1323
- preprocess: {
1324
- ...zod.preprocess?.param ? { param: normalizeMutator(workspace, zod.preprocess.param) } : {},
1325
- ...zod.preprocess?.query ? { query: normalizeMutator(workspace, zod.preprocess.query) } : {},
1326
- ...zod.preprocess?.header ? { header: normalizeMutator(workspace, zod.preprocess.header) } : {},
1327
- ...zod.preprocess?.body ? { body: normalizeMutator(workspace, zod.preprocess.body) } : {},
1328
- ...zod.preprocess?.response ? { response: normalizeMutator(workspace, zod.preprocess.response) } : {}
1329
- },
1330
- ...zod.params ? { params: normalizeMutator(workspace, zod.params) } : {},
1331
- useBrandedTypes: zod.useBrandedTypes ?? false
1332
- } } : {},
1333
- ...effect ? { effect: normalizeEffectOptions(effect) } : {},
1334
- ...transformer ? { transformer: normalizePath(transformer, workspace) } : {},
1335
- ...mutator ? { mutator: normalizeMutator(workspace, mutator) } : {},
1336
- ...formData === void 0 ? {} : { formData: createFormData(workspace, formData) },
1337
- ...formUrlEncoded ? { formUrlEncoded: isBoolean(formUrlEncoded) ? formUrlEncoded : normalizeMutator(workspace, formUrlEncoded) } : {},
1338
- ...paramsSerializer ? { paramsSerializer: normalizeMutator(workspace, paramsSerializer) } : {},
1339
- ...paramsFilter ? { paramsFilter: normalizeMutator(workspace, paramsFilter) } : {}
1340
- }];
1341
- }));
1497
+ function isMissingFileError(error) {
1498
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
1342
1499
  }
1343
- function normalizeOutputMode(mode) {
1344
- if (!mode) return OutputMode.SINGLE;
1345
- if (!Object.values(OutputMode).includes(mode)) {
1346
- logWarning(`⚠️ Unknown provided mode => ${mode}`);
1347
- return OutputMode.SINGLE;
1500
+ /**
1501
+ * Try to import prettier from the project's dependencies.
1502
+ * Returns undefined if prettier is not installed.
1503
+ */
1504
+ async function tryImportPrettier() {
1505
+ try {
1506
+ return await import("prettier");
1507
+ } catch {
1508
+ return;
1348
1509
  }
1349
- return mode;
1350
- }
1351
- function normalizeHooks(hooks) {
1352
- const keys = Object.keys(hooks);
1353
- const result = {};
1354
- for (const key of keys) if (isString(hooks[key])) result[key] = [hooks[key]];
1355
- else if (Array.isArray(hooks[key])) result[key] = hooks[key];
1356
- else if (isFunction(hooks[key])) result[key] = [hooks[key]];
1357
- else if (isObject(hooks[key])) result[key] = [hooks[key]];
1358
- return result;
1359
- }
1360
- function normalizeHonoOptions(hono = {}, workspace) {
1361
- return {
1362
- ...hono.handlers ? { handlers: path.resolve(workspace, hono.handlers) } : {},
1363
- handlerGenerationStrategy: hono.handlerGenerationStrategy ?? "smart",
1364
- compositeRoute: hono.compositeRoute ? path.resolve(workspace, hono.compositeRoute) : "",
1365
- validator: hono.validator ?? true,
1366
- validatorOutputPath: hono.validatorOutputPath ? path.resolve(workspace, hono.validatorOutputPath) : ""
1367
- };
1368
- }
1369
- function normalizeMcpServerOptions(server, workspace) {
1370
- return {
1371
- path: path.resolve(workspace, server.path),
1372
- name: server.name,
1373
- default: server.default ?? !server.name
1374
- };
1375
- }
1376
- function normalizeMcpOptions(mcp = {}, workspace) {
1377
- return mcp.server ? { server: normalizeMcpServerOptions(mcp.server, workspace) } : {};
1378
1510
  }
1379
- function normalizeJSDocOptions(jsdoc = {}) {
1380
- return { ...jsdoc };
1511
+ /**
1512
+ * Recursively collect absolute file paths from a mix of files and directories.
1513
+ */
1514
+ async function collectFilePaths(paths) {
1515
+ const results = [];
1516
+ for (const p of paths) {
1517
+ const absolute = path.resolve(p);
1518
+ try {
1519
+ const stat = await fs.stat(absolute);
1520
+ if (stat.isFile()) results.push(absolute);
1521
+ else if (stat.isDirectory()) {
1522
+ const subFiles = await collectFilePaths((await fs.readdir(absolute)).map((entry) => path.join(absolute, entry)));
1523
+ results.push(...subFiles);
1524
+ }
1525
+ } catch {}
1526
+ }
1527
+ return results;
1381
1528
  }
1382
- function normalizeQueryOptions(queryOptions = {}, outputWorkspace, globalOptions = {}) {
1383
- if (queryOptions.options) logWarning("⚠️ Using query options is deprecated and will be removed in a future major release. Please use queryOptions or mutationOptions instead.");
1384
- return {
1385
- ...isNullish(queryOptions.usePrefetch) ? {} : { usePrefetch: queryOptions.usePrefetch },
1386
- ...isNullish(queryOptions.useInvalidate) ? {} : { useInvalidate: queryOptions.useInvalidate },
1387
- ...isNullish(queryOptions.useSetQueryData) ? {} : { useSetQueryData: queryOptions.useSetQueryData },
1388
- ...isNullish(queryOptions.useGetQueryData) ? {} : { useGetQueryData: queryOptions.useGetQueryData },
1389
- ...isNullish(queryOptions.useQuery) ? {} : { useQuery: queryOptions.useQuery },
1390
- ...isNullish(queryOptions.useSuspenseQuery) ? {} : { useSuspenseQuery: queryOptions.useSuspenseQuery },
1391
- ...isNullish(queryOptions.useMutation) ? {} : { useMutation: queryOptions.useMutation },
1392
- ...isNullish(queryOptions.useInfinite) ? {} : { useInfinite: queryOptions.useInfinite },
1393
- ...isNullish(queryOptions.useSuspenseInfiniteQuery) ? {} : { useSuspenseInfiniteQuery: queryOptions.useSuspenseInfiniteQuery },
1394
- ...queryOptions.useInfiniteQueryParam ? { useInfiniteQueryParam: queryOptions.useInfiniteQueryParam } : {},
1395
- ...queryOptions.options ? { options: queryOptions.options } : {},
1396
- ...globalOptions.queryKey ? { queryKey: globalOptions.queryKey } : {},
1397
- ...queryOptions.queryKey ? { queryKey: normalizeMutator(outputWorkspace, queryOptions.queryKey) } : {},
1398
- ...globalOptions.queryOptions ? { queryOptions: globalOptions.queryOptions } : {},
1399
- ...queryOptions.queryOptions ? { queryOptions: normalizeMutator(outputWorkspace, queryOptions.queryOptions) } : {},
1400
- ...globalOptions.mutationOptions ? { mutationOptions: globalOptions.mutationOptions } : {},
1401
- ...queryOptions.mutationOptions ? { mutationOptions: normalizeMutator(outputWorkspace, queryOptions.mutationOptions) } : {},
1402
- ...isNullish(globalOptions.shouldExportQueryKey) ? {} : { shouldExportQueryKey: globalOptions.shouldExportQueryKey },
1403
- ...isNullish(queryOptions.shouldExportQueryKey) ? {} : { shouldExportQueryKey: queryOptions.shouldExportQueryKey },
1404
- ...isNullish(globalOptions.shouldFilterQueryKey) ? {} : { shouldFilterQueryKey: globalOptions.shouldFilterQueryKey },
1405
- ...isNullish(queryOptions.shouldFilterQueryKey) ? {} : { shouldFilterQueryKey: queryOptions.shouldFilterQueryKey },
1406
- ...isNullish(globalOptions.queryKeyFilter) ? {} : { queryKeyFilter: globalOptions.queryKeyFilter },
1407
- ...isNullish(queryOptions.queryKeyFilter) ? {} : { queryKeyFilter: queryOptions.queryKeyFilter },
1408
- ...isNullish(globalOptions.shouldExportHttpClient) ? {} : { shouldExportHttpClient: globalOptions.shouldExportHttpClient },
1409
- ...isNullish(queryOptions.shouldExportHttpClient) ? {} : { shouldExportHttpClient: queryOptions.shouldExportHttpClient },
1410
- ...isNullish(globalOptions.shouldExportMutatorHooks) ? {} : { shouldExportMutatorHooks: globalOptions.shouldExportMutatorHooks },
1411
- ...isNullish(queryOptions.shouldExportMutatorHooks) ? {} : { shouldExportMutatorHooks: queryOptions.shouldExportMutatorHooks },
1412
- ...isNullish(globalOptions.shouldSplitQueryKey) ? {} : { shouldSplitQueryKey: globalOptions.shouldSplitQueryKey },
1413
- ...isNullish(queryOptions.shouldSplitQueryKey) ? {} : { shouldSplitQueryKey: queryOptions.shouldSplitQueryKey },
1414
- ...isNullish(globalOptions.signal) ? {} : { signal: globalOptions.signal },
1415
- ...isNullish(globalOptions.useOperationIdAsQueryKey) ? {} : { useOperationIdAsQueryKey: globalOptions.useOperationIdAsQueryKey },
1416
- ...isNullish(queryOptions.useOperationIdAsQueryKey) ? {} : { useOperationIdAsQueryKey: queryOptions.useOperationIdAsQueryKey },
1417
- ...isNullish(globalOptions.signal) ? {} : { signal: globalOptions.signal },
1418
- ...isNullish(queryOptions.signal) ? {} : { signal: queryOptions.signal },
1419
- ...isNullish(globalOptions.version) ? {} : { version: globalOptions.version },
1420
- ...isNullish(queryOptions.version) ? {} : { version: queryOptions.version },
1421
- ...queryOptions.mutationInvalidates ? { mutationInvalidates: queryOptions.mutationInvalidates } : {},
1422
- ...isNullish(globalOptions.runtimeValidation) ? {} : { runtimeValidation: globalOptions.runtimeValidation },
1423
- ...isNullish(queryOptions.runtimeValidation) ? {} : { runtimeValidation: queryOptions.runtimeValidation }
1424
- };
1529
+ //#endregion
1530
+ //#region src/utils/execute-hook.ts
1531
+ const executeHook = async (name, commands = [], args = []) => {
1532
+ log(styleText("white", `Running ${name} hook...`));
1533
+ for (const command of commands) try {
1534
+ if (isString(command)) await executeCommand(command, args);
1535
+ else if (isFunction(command)) await command(args);
1536
+ else if (isObject(command)) await executeObjectCommand(command, args);
1537
+ } catch (error) {
1538
+ logError(error, `Failed to run ${name} hook`);
1539
+ }
1540
+ };
1541
+ async function executeCommand(command, args) {
1542
+ const [cmd, ..._args] = [...parseArgsStringToArgv(command), ...args];
1543
+ await execa(cmd, _args);
1425
1544
  }
1426
- function getDefaultFilesHeader({ title, description, version: version$1 } = {}) {
1427
- return [
1428
- `Generated by ${name} v${version} 🍺`,
1429
- `Do not edit manually.`,
1430
- ...title ? [title] : [],
1431
- ...description ? [description] : [],
1432
- ...version$1 ? [`OpenAPI spec version: ${version$1}`] : []
1433
- ];
1545
+ async function executeObjectCommand(command, args) {
1546
+ if (command.injectGeneratedDirsAndFiles === false) args = [];
1547
+ if (isString(command.command)) await executeCommand(command.command, args);
1548
+ else if (isFunction(command.command)) await command.command();
1434
1549
  }
1435
1550
  //#endregion
1436
1551
  //#region src/utils/watcher.ts
@@ -1801,8 +1916,8 @@ async function writeZodSchemaIndex(schemasPath, fileExtension, header, schemaNam
1801
1916
  const importFileExtension = getImportExtension(fileExtension, tsconfig);
1802
1917
  const indexPath = path.join(schemasPath, `index.ts`);
1803
1918
  let existingExports = "";
1804
- if (shouldMergeExisting && await fs.pathExists(indexPath)) {
1805
- const existingContent = await fs.readFile(indexPath, "utf8");
1919
+ if (shouldMergeExisting && await fs$2.pathExists(indexPath)) {
1920
+ const existingContent = await fs$2.readFile(indexPath, "utf8");
1806
1921
  const headerMatch = /^(\/\*\*[\s\S]*?\*\/\n)?/.exec(existingContent);
1807
1922
  const headerPart = headerMatch ? headerMatch[0] : "";
1808
1923
  existingExports = existingContent.slice(headerPart.length).trim();
@@ -1812,7 +1927,7 @@ async function writeZodSchemaIndex(schemasPath, fileExtension, header, schemaNam
1812
1927
  }).toSorted().join("\n");
1813
1928
  const allExports = existingExports ? `${existingExports}\n${newExports}` : newExports;
1814
1929
  const uniqueExports = [...new Set(allExports.split("\n"))].filter((line) => line.trim()).toSorted().join("\n");
1815
- await fs.outputFile(indexPath, `${header}\n${uniqueExports}\n`);
1930
+ await fs$2.outputFile(indexPath, `${header}\n${uniqueExports}\n`);
1816
1931
  }
1817
1932
  async function writeZodSchemaTagsSplitBarrel(schemasPath, fileExtension, header, componentDirs, verbDirs, namingConvention, tsconfig) {
1818
1933
  const importExt = getImportExtension(fileExtension, tsconfig);
@@ -1835,7 +1950,7 @@ async function writeZodSchemaTagsSplitBarrel(schemasPath, fileExtension, header,
1835
1950
  const allExports = [...rootExports, ...tagExports];
1836
1951
  const rootIndexPath = path.join(schemasPath, "index.ts");
1837
1952
  const content = `${header}\n${allExports.join("\n")}\n`;
1838
- await fs.outputFile(rootIndexPath, content);
1953
+ await fs$2.outputFile(rootIndexPath, content);
1839
1954
  }
1840
1955
  function generateZodSchemasInline(builder, output, includeZodImport = true, paramsMutator, includeParamsImport = false) {
1841
1956
  if (output.override.zod.generateReusableSchemas === true) return generateZodSchemasInlineReusable(builder, output, includeZodImport, paramsMutator, includeParamsImport);
@@ -1938,7 +2053,7 @@ async function writeZodSchemas(builder, schemasPath, fileExtension, header, outp
1938
2053
  const groupedSchemasToWrite = groupSchemasByFilePath(schemasToWrite);
1939
2054
  for (const schemaGroup of groupedSchemasToWrite) {
1940
2055
  const fileContent = generateZodSchemaFileContent(header, schemaGroup, output.override.zod.variant);
1941
- await fs.outputFile(schemaGroup[0].filePath, fileContent);
2056
+ await fs$2.outputFile(schemaGroup[0].filePath, fileContent);
1942
2057
  }
1943
2058
  const writtenSchemaNames = groupedSchemasToWrite.map((schemaGroup) => schemaGroup[0].schemaName);
1944
2059
  if (output.indexFiles && !isSplit) await writeZodSchemaIndex(schemasPath, fileExtension, header, writtenSchemaNames, output.namingConvention, false, output.tsconfig);
@@ -2005,7 +2120,7 @@ async function writeZodSchemasReusable(builder, schemasPath, fileExtension, head
2005
2120
  }) : void 0;
2006
2121
  const imports = [...mutatorImportStr ? [mutatorImportStr] : [], ...refImports ? [refImports] : []].join("\n");
2007
2122
  const fileContent = `${header}${getZodSchemaImportStatement(output.override.zod.variant)}\n` + (imports ? `${imports}\n\n` : "\n") + `${rendered.content}\n`;
2008
- await fs.outputFile(filePath, fileContent);
2123
+ await fs$2.outputFile(filePath, fileContent);
2009
2124
  }
2010
2125
  if (output.indexFiles && !isSplit && rewritten.length > 0) await writeZodSchemaIndex(schemasPath, fileExtension, header, rewritten.map((e) => e.name), output.namingConvention, true, output.tsconfig);
2011
2126
  if (isSplit) {
@@ -2127,7 +2242,7 @@ async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension,
2127
2242
  const groupedSchemasToWrite = groupSchemasByFilePath(schemasToWrite);
2128
2243
  for (const schemaGroup of groupedSchemasToWrite) {
2129
2244
  const fileContent = generateZodSchemaFileContent(header, schemaGroup, output.override.zod.variant);
2130
- await fs.outputFile(schemaGroup[0].filePath, fileContent);
2245
+ await fs$2.outputFile(schemaGroup[0].filePath, fileContent);
2131
2246
  }
2132
2247
  const writtenSchemaNames = groupedSchemasToWrite.map((schemaGroup) => schemaGroup[0].schemaName);
2133
2248
  if (output.indexFiles && !isSplit && uniqueVerbsSchemas.length > 0) await writeZodSchemaIndex(schemasPath, fileExtension, header, writtenSchemaNames, output.namingConvention, true, output.tsconfig);
@@ -2177,7 +2292,7 @@ function getComparableFilePath(filePath) {
2177
2292
  const resolvedPath = path.resolve(filePath);
2178
2293
  let comparablePath = resolvedPath;
2179
2294
  try {
2180
- comparablePath = fs.realpathSync(resolvedPath);
2295
+ comparablePath = fs$2.realpathSync(resolvedPath);
2181
2296
  } catch (error) {
2182
2297
  if (error.code !== "ENOENT") throw error;
2183
2298
  }
@@ -2207,12 +2322,12 @@ async function addOperationSchemasReExport(schemaPath, operationSchemasPath, hea
2207
2322
  const schemaIndexPath = path.join(schemaPath, `index.ts`);
2208
2323
  const esmImportPath = upath.getRelativeImportPath(schemaIndexPath, operationSchemasPath);
2209
2324
  const exportLine = `export * from '${esmImportPath}';\n`;
2210
- if (await fs.pathExists(schemaIndexPath)) {
2211
- const existingContent = await fs.readFile(schemaIndexPath, "utf8");
2212
- if (!new RegExp(String.raw`export\s*\*\s*from\s*['"]${esmImportPath.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`)}['"]`).test(existingContent)) await fs.appendFile(schemaIndexPath, exportLine);
2325
+ if (await fs$2.pathExists(schemaIndexPath)) {
2326
+ const existingContent = await fs$2.readFile(schemaIndexPath, "utf8");
2327
+ if (!new RegExp(String.raw`export\s*\*\s*from\s*['"]${esmImportPath.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`)}['"]`).test(existingContent)) await fs$2.appendFile(schemaIndexPath, exportLine);
2213
2328
  } else {
2214
2329
  const content = header && header.trim().length > 0 ? `${header}\n${exportLine}` : exportLine;
2215
- await fs.outputFile(schemaIndexPath, content);
2330
+ await fs$2.outputFile(schemaIndexPath, content);
2216
2331
  }
2217
2332
  }
2218
2333
  /**
@@ -2465,16 +2580,16 @@ async function writeSpecs(builder, workspace, options, projectName) {
2465
2580
  }
2466
2581
  if (output.operationSchemas) imports.push(upath.getRelativeImportPath(indexFile, getFileInfo(output.operationSchemas).dirname));
2467
2582
  if (output.indexFiles) {
2468
- if (await fs.pathExists(indexFile)) {
2469
- const data = await fs.readFile(indexFile, "utf8");
2583
+ if (await fs$2.pathExists(indexFile)) {
2584
+ const data = await fs$2.readFile(indexFile, "utf8");
2470
2585
  const importsNotDeclared = imports.filter((imp) => !data.includes(`export * from '${imp}'`));
2471
- await fs.appendFile(indexFile, unique(importsNotDeclared).map((imp) => `export * from '${imp}';\n`).join(""));
2472
- } else await fs.outputFile(indexFile, unique(imports).map((imp) => `export * from '${imp}';`).join("\n") + "\n");
2586
+ await fs$2.appendFile(indexFile, unique(importsNotDeclared).map((imp) => `export * from '${imp}';\n`).join(""));
2587
+ } else await fs$2.outputFile(indexFile, unique(imports).map((imp) => `export * from '${imp}';`).join("\n") + "\n");
2473
2588
  implementationPaths = [indexFile, ...implementationPathsForIndex];
2474
2589
  }
2475
2590
  }
2476
2591
  if (builder.extraFiles.length > 0) {
2477
- await Promise.all(builder.extraFiles.map(async (file) => fs.outputFile(file.path, file.content)));
2592
+ await Promise.all(builder.extraFiles.map(async (file) => fs$2.outputFile(file.path, file.content)));
2478
2593
  implementationPaths = [...implementationPaths, ...builder.extraFiles.map((file) => file.path)];
2479
2594
  }
2480
2595
  const paths = [
@@ -2577,7 +2692,7 @@ async function generateSpec(workspace, options, projectName) {
2577
2692
  function findConfigFile(configFilePath) {
2578
2693
  if (configFilePath) {
2579
2694
  const absolutePath = path.isAbsolute(configFilePath) ? configFilePath : path.resolve(process.cwd(), configFilePath);
2580
- if (!fs$2.existsSync(absolutePath)) throw new Error(`Config file ${configFilePath} does not exist`);
2695
+ if (!fs$1.existsSync(absolutePath)) throw new Error(`Config file ${configFilePath} does not exist`);
2581
2696
  return absolutePath;
2582
2697
  }
2583
2698
  const root = process.cwd();
@@ -2588,7 +2703,7 @@ function findConfigFile(configFilePath) {
2588
2703
  ".mts"
2589
2704
  ]) {
2590
2705
  const fullPath = path.resolve(root, `orval.config${ext}`);
2591
- if (fs$2.existsSync(fullPath)) return fullPath;
2706
+ if (fs$1.existsSync(fullPath)) return fullPath;
2592
2707
  }
2593
2708
  throw new Error(`No config file found in ${root}`);
2594
2709
  }
@@ -2610,4 +2725,4 @@ async function loadConfigFile(configFilePath) {
2610
2725
  //#endregion
2611
2726
  export { defineConfig as a, description as c, startWatcher as i, name as l, loadConfigFile as n, defineTransformer as o, generateSpec as r, normalizeOptions as s, findConfigFile as t, version as u };
2612
2727
 
2613
- //# sourceMappingURL=config-DGhExJ4J.mjs.map
2728
+ //# sourceMappingURL=config-CotJKggp.mjs.map