vite-plugin-openapi-codegen 3.2.1 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs CHANGED
@@ -268,13 +268,45 @@ function collectOperations(spec, pathPrefix = "/api/", stripPrefix = true) {
268
268
  });
269
269
  }
270
270
  }
271
- return excludeInternalOperations(entries, spec);
271
+ const publicEntries = excludeInternalOperations(entries, spec);
272
+ if (entries.length > 0 && publicEntries.length === 0) throw new Error(`All ${entries.length} operation(s) matching prefix "${pathPrefix}" are internal-only and were excluded`);
273
+ const excludedCount = entries.length - publicEntries.length;
274
+ if (excludedCount > 0) console.info(`[openapi-codegen] excluded ${excludedCount} internal-only operation(s) from generated artifacts.`);
275
+ return publicEntries;
272
276
  }
273
277
  function excludeInternalOperations(entries, spec) {
274
278
  const securitySchemes = spec.components?.securitySchemes;
275
279
  if (!securitySchemes) return entries;
276
280
  return entries.filter((entry) => readSecurityRequirement(entry, securitySchemes, spec.security)?.kind !== "internal");
277
281
  }
282
+ function excludeInternalOperationsFromSpec(spec) {
283
+ const securitySchemes = spec.components?.securitySchemes;
284
+ if (!securitySchemes || !spec.paths) return {
285
+ excludedCount: 0,
286
+ spec
287
+ };
288
+ const clone = structuredClone(spec);
289
+ let excludedCount = 0;
290
+ for (const [path, pathItem] of Object.entries(clone.paths ?? {})) {
291
+ let removedFromPath = 0;
292
+ for (const method of HTTP_METHODS) {
293
+ const operation = pathItem[method];
294
+ if (!operation) continue;
295
+ if (readSecurityRequirement({
296
+ operation,
297
+ operationId: operation.operationId ?? `${method.toUpperCase()} ${path}`
298
+ }, securitySchemes, clone.security)?.kind !== "internal") continue;
299
+ delete pathItem[method];
300
+ removedFromPath += 1;
301
+ }
302
+ excludedCount += removedFromPath;
303
+ if (removedFromPath > 0 && !HTTP_METHODS.some((method) => pathItem[method])) delete clone.paths?.[path];
304
+ }
305
+ return {
306
+ excludedCount,
307
+ spec: clone
308
+ };
309
+ }
278
310
  function readSecurityRequirement(entry, securitySchemes, topLevelSecurity) {
279
311
  const security = entry.operation.security ?? topLevelSecurity;
280
312
  if (security === void 0) return null;
@@ -646,9 +678,10 @@ function resolveHttpClientConfig(config) {
646
678
  };
647
679
  }
648
680
  const GENERATED_HEADER = ["// This file is auto-generated by vite-plugin-openapi-codegen.", "// Do not edit manually. Changes will be overwritten on next build."];
649
- async function generateApiTypes(source, outputDir, useTypeAliases) {
681
+ async function generateApiTypes(input, outputDir, useTypeAliases) {
650
682
  const { default: openapiTS, astToString } = await import("openapi-typescript");
651
- const contents = astToString(await openapiTS(source, useTypeAliases ? {
683
+ const { excludedCount, spec } = excludeInternalOperationsFromSpec(input.spec);
684
+ const contents = astToString(await openapiTS(excludedCount > 0 ? spec : input.apiTypesSource, useTypeAliases ? {
652
685
  rootTypes: true,
653
686
  rootTypesKeepCasing: true,
654
687
  rootTypesNoSchemaPrefix: true
@@ -769,11 +802,13 @@ function parseOpenAPISpec(sourceText, inputLabel) {
769
802
  async function generateOpenAPIArtifacts(root, options) {
770
803
  const outputDir = resolve(root, options.output);
771
804
  mkdirSync(outputDir, { recursive: true });
772
- const { apiTypesSource, spec } = await loadOpenAPIInput(root, options.input);
773
- const operations = collectOperations(spec, options.pathPrefix ?? "/api/", options.stripPrefix ?? true);
774
- const artifacts = renderGeneratedArtifacts(spec, options, operations);
805
+ const input = await loadOpenAPIInput(root, options.input);
806
+ const pathPrefix = options.pathPrefix ?? "/api/";
807
+ const stripPrefix = options.stripPrefix ?? true;
808
+ const operations = collectOperations(input.spec, pathPrefix, stripPrefix);
809
+ const artifacts = renderGeneratedArtifacts(input.spec, options, operations);
775
810
  warnOnParameterLocationMismatch(operations);
776
- await generateApiTypes(apiTypesSource, outputDir, options.typeAliases ?? false);
811
+ await generateApiTypes(input, outputDir, options.typeAliases ?? false);
777
812
  if (artifacts.apiTypes) writeFileSync(resolve(outputDir, "api-types.d.ts"), artifacts.apiTypes, { flag: "a" });
778
813
  if (artifacts.accessPolicies) writeFileSync(resolve(outputDir, "access-policies.ts"), artifacts.accessPolicies);
779
814
  writeFileSync(resolve(outputDir, "api.ts"), artifacts.api);
package/dist/index.mjs CHANGED
@@ -266,13 +266,45 @@ function collectOperations(spec, pathPrefix = "/api/", stripPrefix = true) {
266
266
  });
267
267
  }
268
268
  }
269
- return excludeInternalOperations(entries, spec);
269
+ const publicEntries = excludeInternalOperations(entries, spec);
270
+ if (entries.length > 0 && publicEntries.length === 0) throw new Error(`All ${entries.length} operation(s) matching prefix "${pathPrefix}" are internal-only and were excluded`);
271
+ const excludedCount = entries.length - publicEntries.length;
272
+ if (excludedCount > 0) console.info(`[openapi-codegen] excluded ${excludedCount} internal-only operation(s) from generated artifacts.`);
273
+ return publicEntries;
270
274
  }
271
275
  function excludeInternalOperations(entries, spec) {
272
276
  const securitySchemes = spec.components?.securitySchemes;
273
277
  if (!securitySchemes) return entries;
274
278
  return entries.filter((entry) => readSecurityRequirement(entry, securitySchemes, spec.security)?.kind !== "internal");
275
279
  }
280
+ function excludeInternalOperationsFromSpec(spec) {
281
+ const securitySchemes = spec.components?.securitySchemes;
282
+ if (!securitySchemes || !spec.paths) return {
283
+ excludedCount: 0,
284
+ spec
285
+ };
286
+ const clone = structuredClone(spec);
287
+ let excludedCount = 0;
288
+ for (const [path, pathItem] of Object.entries(clone.paths ?? {})) {
289
+ let removedFromPath = 0;
290
+ for (const method of HTTP_METHODS) {
291
+ const operation = pathItem[method];
292
+ if (!operation) continue;
293
+ if (readSecurityRequirement({
294
+ operation,
295
+ operationId: operation.operationId ?? `${method.toUpperCase()} ${path}`
296
+ }, securitySchemes, clone.security)?.kind !== "internal") continue;
297
+ delete pathItem[method];
298
+ removedFromPath += 1;
299
+ }
300
+ excludedCount += removedFromPath;
301
+ if (removedFromPath > 0 && !HTTP_METHODS.some((method) => pathItem[method])) delete clone.paths?.[path];
302
+ }
303
+ return {
304
+ excludedCount,
305
+ spec: clone
306
+ };
307
+ }
276
308
  function readSecurityRequirement(entry, securitySchemes, topLevelSecurity) {
277
309
  const security = entry.operation.security ?? topLevelSecurity;
278
310
  if (security === void 0) return null;
@@ -644,9 +676,10 @@ function resolveHttpClientConfig(config) {
644
676
  };
645
677
  }
646
678
  const GENERATED_HEADER = ["// This file is auto-generated by vite-plugin-openapi-codegen.", "// Do not edit manually. Changes will be overwritten on next build."];
647
- async function generateApiTypes(source, outputDir, useTypeAliases) {
679
+ async function generateApiTypes(input, outputDir, useTypeAliases) {
648
680
  const { default: openapiTS, astToString } = await import("openapi-typescript");
649
- const contents = astToString(await openapiTS(source, useTypeAliases ? {
681
+ const { excludedCount, spec } = excludeInternalOperationsFromSpec(input.spec);
682
+ const contents = astToString(await openapiTS(excludedCount > 0 ? spec : input.apiTypesSource, useTypeAliases ? {
650
683
  rootTypes: true,
651
684
  rootTypesKeepCasing: true,
652
685
  rootTypesNoSchemaPrefix: true
@@ -767,11 +800,13 @@ function parseOpenAPISpec(sourceText, inputLabel) {
767
800
  async function generateOpenAPIArtifacts(root, options) {
768
801
  const outputDir = resolve(root, options.output);
769
802
  mkdirSync(outputDir, { recursive: true });
770
- const { apiTypesSource, spec } = await loadOpenAPIInput(root, options.input);
771
- const operations = collectOperations(spec, options.pathPrefix ?? "/api/", options.stripPrefix ?? true);
772
- const artifacts = renderGeneratedArtifacts(spec, options, operations);
803
+ const input = await loadOpenAPIInput(root, options.input);
804
+ const pathPrefix = options.pathPrefix ?? "/api/";
805
+ const stripPrefix = options.stripPrefix ?? true;
806
+ const operations = collectOperations(input.spec, pathPrefix, stripPrefix);
807
+ const artifacts = renderGeneratedArtifacts(input.spec, options, operations);
773
808
  warnOnParameterLocationMismatch(operations);
774
- await generateApiTypes(apiTypesSource, outputDir, options.typeAliases ?? false);
809
+ await generateApiTypes(input, outputDir, options.typeAliases ?? false);
775
810
  if (artifacts.apiTypes) writeFileSync(resolve(outputDir, "api-types.d.ts"), artifacts.apiTypes, { flag: "a" });
776
811
  if (artifacts.accessPolicies) writeFileSync(resolve(outputDir, "access-policies.ts"), artifacts.accessPolicies);
777
812
  writeFileSync(resolve(outputDir, "api.ts"), artifacts.api);
@@ -790,7 +825,7 @@ function openapiCodegen(options) {
790
825
  },
791
826
  async buildStart() {
792
827
  if (command === "serve" && options.generateOnDev !== false) {
793
- runDevelopmentGeneration(root, options, { onError: resolvePluginErrorRaiser(this) });
828
+ runDevelopmentGeneration(root, options, { onError: resolvePluginErrorRaiser(this) }).catch(() => {});
794
829
  return;
795
830
  }
796
831
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-openapi-codegen",
3
- "version": "3.2.1",
3
+ "version": "3.3.0",
4
4
  "description": "Vite plugin that generates typed API clients and route builders from OpenAPI specs",
5
5
  "keywords": [
6
6
  "api-client",