orval 8.22.0 → 8.23.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.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { c as description, i as startWatcher, l as name, n as loadConfigFile, r as generateSpec, s as normalizeOptions, t as findConfigFile, u as version } from "../config-CotJKggp.mjs";
2
+ import { c as description, i as startWatcher, l as name, n as loadConfigFile, r as generateSpec, s as normalizeOptions, t as findConfigFile, u as version } from "../config-18E5SVPo.mjs";
3
3
  import path from "node:path";
4
4
  import { Option, program } from "@commander-js/extra-typings";
5
5
  import { ErrorWithTag, OutputClient, OutputMode, SupportedFormatter, getWarningCount, isString, log, logError, resetWarnings, setVerbose, startMessage } from "@orval/core";
@@ -1,11 +1,11 @@
1
1
  import { createRequire } from "node:module";
2
2
  import path from "node:path";
3
- import { DefaultTag, FormDataArrayHandling, GetterPropType, NamingConvention, OutputClient, OutputHttpClient, OutputMockType, OutputMode, PropertySortOrder, RefComponentSuffix, SupportedFormatter, asyncReduce, buildDynamicScope, buildSchemaTagMap, collectReferencedComponents, conventionName, createSuccessMessage, dynamicImport, fixCrossDirectoryImports, fixRegularSchemaImports, generateComponentDefinition, generateDependencyImports, generateMutator, generateParameterDefinition, generateSchemasDefinition, generateVerbsOptions, getBaseUrlRuntimeImports, getFileInfo, getFullRoute, getImportExtension, getMockFileExtensionByTypeName, getRefInfo, getRoute, isBoolean, isComponentRef, isFunction, isNullish, isObject, isReference, isString, isUrl, jsDoc, kebab, log, logError, logVerbose, logWarning, pascal, removeFilesAndEmptyFolders, resolveInstalledVersions, resolveRef, resolveValue, splitSchemasByType, upath, writeGeneratedFile, writeSchemas, writeSchemasTagsSplit, writeSingleMode, writeSplitMode, writeSplitTagsMode, writeTagsMode } from "@orval/core";
3
+ import { DefaultTag, FormDataArrayHandling, GetterPropType, NamingConvention, OutputClient, OutputHttpClient, OutputMockType, OutputMode, PropertySortOrder, RefComponentSuffix, SupportedFormatter, asyncReduce, buildDynamicScope, buildSchemaTagMap, collectReferencedComponents, conventionName, createSuccessMessage, dynamicImport, fixCrossDirectoryImports, fixRegularSchemaImports, generateComponentDefinition, generateDependencyImports, generateMutator, generateParameterDefinition, generateSchemasDefinition, generateVerbsOptions, getBaseUrlRuntimeImports, getFileInfo, getFullRoute, getImportExtension, getMockFileExtensionByTypeName, getRefInfo, getRoute, isBoolean, isComponentRef, isFunction, isNullish, isObject, isReference, isString, isUrl, jsDoc, kebab, log, logError, logVerbose, logWarning, pascal, removeFilesAndEmptyFolders, resolveInstalledVersions, resolveRef, resolveValue, splitSchemasByType, upath, writeGeneratedFile, writeSchemas, writeSchemasTagsSplit, writeSingleMode, writeSplitMode, writeSplitTagsMode, writeTagsMode, writeTagsOperationsMode, writeTagsOperationsSplitMode } from "@orval/core";
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
7
  import fs, { access, readFile } from "node:fs/promises";
8
- import { isNullish as isNullish$1, pick, unique } from "remeda";
8
+ import { isNullish as isNullish$1, pick } from "remeda";
9
9
  import jsYaml from "js-yaml";
10
10
  import * as mock from "@orval/mock";
11
11
  import { dedupeStrictMockTypeDeclarations, generateFakerForSchemas, generateMockImports, getDefaultMockOptionsForType } from "@orval/mock";
@@ -29,7 +29,7 @@ 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.22.0";
32
+ var version = "8.23.0";
33
33
  var description = "A swagger client generator for typescript";
34
34
  //#endregion
35
35
  //#region src/client.ts
@@ -545,6 +545,7 @@ function createFormData(workspace, formData) {
545
545
  function normalizeSchemasOption(schemas, workspace) {
546
546
  if (!schemas) return;
547
547
  if (isString(schemas)) return normalizePath(schemas, workspace);
548
+ if (!isString(schemas.path) || schemas.path.trim() === "") throw new Error(styleText("red", `\`schemas.path\` is required when \`schemas\` is an object (e.g. \`schemas: { path: './model', type: 'zod' }\`). To generate schemas alongside the target instead, omit \`schemas\` or set \`schemas: false\`.`));
548
549
  validatePackageSpecifier(schemas.importPath, "schemas.importPath");
549
550
  return {
550
551
  path: normalizePath(schemas.path, workspace),
@@ -607,7 +608,8 @@ function normalizeEffectOptions(effect) {
607
608
  response: effect?.generate?.response ?? true
608
609
  },
609
610
  generateEachHttpStatus: effect?.generateEachHttpStatus ?? false,
610
- useBrandedTypes: effect?.useBrandedTypes ?? false
611
+ useBrandedTypes: effect?.useBrandedTypes ?? false,
612
+ exactOptional: effect?.exactOptional ?? false
611
613
  };
612
614
  }
613
615
  async function normalizeOptions(optionsExport, workspace = process.cwd(), globalOptions = {}) {
@@ -784,6 +786,7 @@ async function normalizeOptions(optionsExport, workspace = process.cwd(), global
784
786
  generateReusableSchemas: outputOptions.override?.zod?.generateReusableSchemas ?? false,
785
787
  generateMeta: outputOptions.override?.zod?.generateMeta ?? false,
786
788
  generateDiscriminatedUnion: outputOptions.override?.zod?.generateDiscriminatedUnion ?? false,
789
+ exactOptional: outputOptions.override?.zod?.exactOptional ?? false,
787
790
  dateTimeOptions: outputOptions.override?.zod?.dateTimeOptions ?? { offset: true },
788
791
  timeOptions: outputOptions.override?.zod?.timeOptions ?? {}
789
792
  },
@@ -1527,6 +1530,30 @@ async function collectFilePaths(paths) {
1527
1530
  return results;
1528
1531
  }
1529
1532
  //#endregion
1533
+ //#region src/utils/barrel.ts
1534
+ const RE_EXPORT_SPECIFIER = /export\s+\*\s+from\s*['"]([^'"]+)['"]/g;
1535
+ /**
1536
+ * Extract the set of `export * from '...'` module specifiers from barrel
1537
+ * content. Quote-agnostic (matches both `'` and `"`) so it is unaffected by a
1538
+ * formatter changing quote style between generations.
1539
+ */
1540
+ function readReExportSpecifiers(content) {
1541
+ return new Set([...content.matchAll(RE_EXPORT_SPECIFIER)].map((m) => m[1]));
1542
+ }
1543
+ /**
1544
+ * Return the deduplicated list of specifiers for a barrel by unioning the
1545
+ * freshly generated `specifiers` with whatever re-exports already exist on
1546
+ * disk. Merging on the bare specifier (rather than the formatted line) makes
1547
+ * the barrel idempotent across regenerations regardless of how an external
1548
+ * formatter rewrites quotes, semicolons, or whitespace. On-disk order is
1549
+ * preserved and new specifiers are appended — matching the previous append
1550
+ * ordering — so callers control any sorting they want.
1551
+ */
1552
+ async function mergeBarrelSpecifiers(filePath, specifiers) {
1553
+ const existing = await fs$2.pathExists(filePath) ? readReExportSpecifiers(await fs$2.readFile(filePath, "utf8")) : /* @__PURE__ */ new Set();
1554
+ return [...new Set([...existing, ...specifiers])];
1555
+ }
1556
+ //#endregion
1530
1557
  //#region src/utils/execute-hook.ts
1531
1558
  const executeHook = async (name, commands = [], args = []) => {
1532
1559
  log(styleText("white", `Running ${name} hook...`));
@@ -1650,7 +1677,7 @@ const generateReusableSchemaSet = (refs, context, options) => {
1650
1677
  operationId: "",
1651
1678
  location: "schema",
1652
1679
  schemaName: name
1653
- } : void 0, options.variant);
1680
+ } : void 0, options.variant, options.exactOptional);
1654
1681
  entries.push({
1655
1682
  ref,
1656
1683
  name,
@@ -1915,19 +1942,11 @@ const groupSchemasByFilePath = (schemas) => {
1915
1942
  async function writeZodSchemaIndex(schemasPath, fileExtension, header, schemaNames, namingConvention, shouldMergeExisting = false, tsconfig) {
1916
1943
  const importFileExtension = getImportExtension(fileExtension, tsconfig);
1917
1944
  const indexPath = path.join(schemasPath, `index.ts`);
1918
- let existingExports = "";
1919
- if (shouldMergeExisting && await fs$2.pathExists(indexPath)) {
1920
- const existingContent = await fs$2.readFile(indexPath, "utf8");
1921
- const headerMatch = /^(\/\*\*[\s\S]*?\*\/\n)?/.exec(existingContent);
1922
- const headerPart = headerMatch ? headerMatch[0] : "";
1923
- existingExports = existingContent.slice(headerPart.length).trim();
1924
- }
1925
- const newExports = schemaNames.map((schemaName) => {
1926
- return `export * from './${conventionName(schemaName, namingConvention)}${importFileExtension}';`;
1927
- }).toSorted().join("\n");
1928
- const allExports = existingExports ? `${existingExports}\n${newExports}` : newExports;
1929
- const uniqueExports = [...new Set(allExports.split("\n"))].filter((line) => line.trim()).toSorted().join("\n");
1930
- await fs$2.outputFile(indexPath, `${header}\n${uniqueExports}\n`);
1945
+ const newSpecifiers = [...new Set(schemaNames.map((schemaName) => {
1946
+ return `./${conventionName(schemaName, namingConvention)}${importFileExtension}`;
1947
+ }))];
1948
+ const exports = (shouldMergeExisting ? await mergeBarrelSpecifiers(indexPath, newSpecifiers) : newSpecifiers).toSorted().map((specifier) => `export * from '${specifier}';`).join("\n");
1949
+ await fs$2.outputFile(indexPath, `${header}\n${exports}\n`);
1931
1950
  }
1932
1951
  async function writeZodSchemaTagsSplitBarrel(schemasPath, fileExtension, header, componentDirs, verbDirs, namingConvention, tsconfig) {
1933
1952
  const importExt = getImportExtension(fileExtension, tsconfig);
@@ -1975,7 +1994,7 @@ function generateZodSchemasInline(builder, output, includeZodImport = true, para
1975
1994
  const parsedZodDefinition = parseZodValidationSchemaDefinition(generateZodValidationSchemaDefinition(dereference(schemaObject, context), context, name, strict, isZodV4, {
1976
1995
  required: true,
1977
1996
  emitMeta: output.override.zod.generateMeta
1978
- }), context, coerce, strict, isZodV4, void 0, void 0, output.override.zod.variant);
1997
+ }), context, coerce, strict, isZodV4, void 0, void 0, output.override.zod.variant, output.override.zod.exactOptional);
1979
1998
  schemas.push({
1980
1999
  schemaName: name,
1981
2000
  consts: parsedZodDefinition.consts,
@@ -2009,6 +2028,7 @@ function generateZodSchemasInlineReusable(builder, output, includeZodImport = tr
2009
2028
  coerce,
2010
2029
  variant: output.override.zod.variant,
2011
2030
  generateMeta: output.override.zod.generateMeta,
2031
+ exactOptional: output.override.zod.exactOptional,
2012
2032
  paramsMutator
2013
2033
  })).map((entry) => renderReusableSchemaEntry(entry, context, output.override.zod.variant).content).join("\n\n");
2014
2034
  const zodImport = includeZodImport ? `${getZodSchemaImportStatement(output.override.zod.variant)}\n` : "";
@@ -2042,7 +2062,7 @@ async function writeZodSchemas(builder, schemasPath, fileExtension, header, outp
2042
2062
  const parsedZodDefinition = parseZodValidationSchemaDefinition(generateZodValidationSchemaDefinition(dereference(schemaObject, context), context, name, strict, isZodV4, {
2043
2063
  required: true,
2044
2064
  emitMeta: output.override.zod.generateMeta
2045
- }), context, coerce, strict, isZodV4, void 0, void 0, output.override.zod.variant);
2065
+ }), context, coerce, strict, isZodV4, void 0, void 0, output.override.zod.variant, output.override.zod.exactOptional);
2046
2066
  schemasToWrite.push({
2047
2067
  schemaName: name,
2048
2068
  filePath,
@@ -2092,6 +2112,7 @@ async function writeZodSchemasReusable(builder, schemasPath, fileExtension, head
2092
2112
  coerce,
2093
2113
  variant: output.override.zod.variant,
2094
2114
  generateMeta: output.override.zod.generateMeta,
2115
+ exactOptional: output.override.zod.exactOptional,
2095
2116
  paramsMutator
2096
2117
  }));
2097
2118
  const componentNames = new Set(Object.keys(builder.spec.components?.schemas ?? {}).map((schemaName) => resolveSchemaName(`#/components/schemas/${schemaName}`, context)));
@@ -2220,7 +2241,7 @@ async function writeZodSchemasFromVerbs(verbOptions, schemasPath, fileExtension,
2220
2241
  const parsedZodDefinition = parseZodValidationSchemaDefinition("bodyContentType" in entry && entry.bodyContentType === "multipart/form-data" ? generateFormDataZodSchema(schema, zodContext, name, strict, isZodV4, "encoding" in entry ? entry.encoding : void 0, useReusableSchemas) : generateZodValidationSchemaDefinition(schema, zodContext, name, strict, isZodV4, {
2221
2242
  required: true,
2222
2243
  useReusableSchemas
2223
- }), zodContext, coerce, strict, isZodV4, void 0, void 0, output.override.zod.variant);
2244
+ }), zodContext, coerce, strict, isZodV4, void 0, void 0, output.override.zod.variant, output.override.zod.exactOptional);
2224
2245
  let zodExpression = parsedZodDefinition.zod;
2225
2246
  let importStatements;
2226
2247
  if (useReusableSchemas && parsedZodDefinition.usedRefs.size > 0) {
@@ -2323,8 +2344,7 @@ async function addOperationSchemasReExport(schemaPath, operationSchemasPath, hea
2323
2344
  const esmImportPath = upath.getRelativeImportPath(schemaIndexPath, operationSchemasPath);
2324
2345
  const exportLine = `export * from '${esmImportPath}';\n`;
2325
2346
  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);
2347
+ if (!readReExportSpecifiers(await fs$2.readFile(schemaIndexPath, "utf8")).has(esmImportPath)) await fs$2.appendFile(schemaIndexPath, exportLine);
2328
2348
  } else {
2329
2349
  const content = header && header.trim().length > 0 ? `${header}\n${exportLine}` : exportLine;
2330
2350
  await fs$2.outputFile(schemaIndexPath, content);
@@ -2431,9 +2451,15 @@ function shouldGenerateSchemas(output, hasOperations) {
2431
2451
  function getImplementationPathsForIndex(output, implementationPaths, indexFile) {
2432
2452
  const shouldExcludeSelf = output.indexFiles;
2433
2453
  const paths = shouldExcludeSelf ? excludeFilePath(implementationPaths, indexFile) : implementationPaths;
2434
- if (!(shouldExcludeSelf && output.mode === OutputMode.SPLIT && getComparableFilePath(output.target) === getComparableFilePath(indexFile))) return paths;
2454
+ if (shouldExcludeSelf && output.mode === OutputMode.SPLIT && getComparableFilePath(output.target) === getComparableFilePath(indexFile)) {
2455
+ const targetInfo = getFileInfo(output.target, { extension: output.fileExtension });
2456
+ return excludeFilePath(paths, path.join(targetInfo.dirname, `${targetInfo.filename}.schemas${output.fileExtension}`));
2457
+ }
2458
+ if (!(output.mode === OutputMode.TAGS_OPERATIONS || output.mode === OutputMode.TAGS_OPERATIONS_SPLIT) || !shouldExcludeSelf) return paths;
2435
2459
  const targetInfo = getFileInfo(output.target, { extension: output.fileExtension });
2436
- return excludeFilePath(paths, path.join(targetInfo.dirname, `${targetInfo.filename}.schemas${output.fileExtension}`));
2460
+ const rootBarrel = path.join(targetInfo.dirname, `index${output.fileExtension}`);
2461
+ const globalSchemas = path.join(targetInfo.dirname, `${targetInfo.filename}.schemas${output.fileExtension}`);
2462
+ return paths.filter((p) => getComparableFilePath(p) === getComparableFilePath(rootBarrel) || getComparableFilePath(p) === getComparableFilePath(globalSchemas));
2437
2463
  }
2438
2464
  async function writeSpecs(builder, workspace, options, projectName) {
2439
2465
  const { info, schemas, target } = builder;
@@ -2569,8 +2595,7 @@ async function writeSpecs(builder, workspace, options, projectName) {
2569
2595
  const indexFile = path.join(workspacePath, "index.ts");
2570
2596
  const mockExtensions = output.mock.generators.map((g) => getMockFileExtensionByTypeName(g));
2571
2597
  const importExtension = getImportExtension(output.fileExtension, output.tsconfig);
2572
- const implementationPathsForIndex = getImplementationPathsForIndex(output, implementationPaths, indexFile);
2573
- const imports = implementationPathsForIndex.filter((p) => mockExtensions.length === 0 || !mockExtensions.some((ext) => p.endsWith(`.${ext}.ts`))).map((p) => {
2598
+ const imports = getImplementationPathsForIndex(output, implementationPaths, indexFile).filter((p) => mockExtensions.length === 0 || !mockExtensions.some((ext) => p.endsWith(`.${ext}.ts`))).map((p) => {
2574
2599
  const relative = upath.getRelativeImportPath(indexFile, p, true);
2575
2600
  return (relative.endsWith(output.fileExtension) ? relative.slice(0, -output.fileExtension.length) : relative.replace(/\.[^/.]+$/, "")) + importExtension;
2576
2601
  });
@@ -2581,11 +2606,11 @@ async function writeSpecs(builder, workspace, options, projectName) {
2581
2606
  if (output.operationSchemas) imports.push(upath.getRelativeImportPath(indexFile, getFileInfo(output.operationSchemas).dirname));
2582
2607
  if (output.indexFiles) {
2583
2608
  if (await fs$2.pathExists(indexFile)) {
2584
- const data = await fs$2.readFile(indexFile, "utf8");
2585
- const importsNotDeclared = imports.filter((imp) => !data.includes(`export * from '${imp}'`));
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");
2588
- implementationPaths = [indexFile, ...implementationPathsForIndex];
2609
+ const declared = readReExportSpecifiers(await fs$2.readFile(indexFile, "utf8"));
2610
+ const toAdd = [...new Set(imports.filter((imp) => !declared.has(imp)))];
2611
+ if (toAdd.length > 0) await fs$2.appendFile(indexFile, toAdd.map((imp) => `export * from '${imp}';\n`).join(""));
2612
+ } else await fs$2.outputFile(indexFile, `${[...new Set(imports)].map((imp) => `export * from '${imp}';`).join("\n")}\n`);
2613
+ implementationPaths = [indexFile, ...excludeFilePath(implementationPaths, indexFile)];
2589
2614
  }
2590
2615
  }
2591
2616
  if (builder.extraFiles.length > 0) {
@@ -2636,6 +2661,8 @@ function getWriteMode(mode) {
2636
2661
  case OutputMode.SPLIT: return writeSplitMode;
2637
2662
  case OutputMode.TAGS: return writeTagsMode;
2638
2663
  case OutputMode.TAGS_SPLIT: return writeSplitTagsMode;
2664
+ case OutputMode.TAGS_OPERATIONS: return writeTagsOperationsMode;
2665
+ case OutputMode.TAGS_OPERATIONS_SPLIT: return writeTagsOperationsSplitMode;
2639
2666
  default: return writeSingleMode;
2640
2667
  }
2641
2668
  }
@@ -2725,4 +2752,4 @@ async function loadConfigFile(configFilePath) {
2725
2752
  //#endregion
2726
2753
  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 };
2727
2754
 
2728
- //# sourceMappingURL=config-CotJKggp.mjs.map
2755
+ //# sourceMappingURL=config-18E5SVPo.mjs.map