@scalar/openapi-parser 0.25.4 → 0.25.6

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.
Files changed (140) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/configuration/index.js +24 -24
  3. package/dist/index.js +24 -45
  4. package/dist/lib/Validator/Validator.js +125 -108
  5. package/dist/plugins/fetch-urls/fetch-urls.js +39 -38
  6. package/dist/plugins/fetch-urls/index.js +1 -6
  7. package/dist/plugins/read-files/index.js +1 -5
  8. package/dist/plugins/read-files/read-files.js +53 -51
  9. package/dist/schemas/v2.0/schema.js +1373 -1377
  10. package/dist/schemas/v3.0/schema.js +1411 -1415
  11. package/dist/schemas/v3.1/schema.js +1196 -1200
  12. package/dist/schemas/v3.2/schema.js +1417 -1421
  13. package/dist/types/index.js +1 -1
  14. package/dist/utils/betterAjvErrors/helpers.js +138 -112
  15. package/dist/utils/betterAjvErrors/index.js +11 -15
  16. package/dist/utils/betterAjvErrors/utils.js +17 -30
  17. package/dist/utils/betterAjvErrors/validation-errors/additional-prop.js +14 -18
  18. package/dist/utils/betterAjvErrors/validation-errors/base.js +20 -21
  19. package/dist/utils/betterAjvErrors/validation-errors/default.js +14 -18
  20. package/dist/utils/betterAjvErrors/validation-errors/enum.js +33 -37
  21. package/dist/utils/betterAjvErrors/validation-errors/index.js +6 -15
  22. package/dist/utils/betterAjvErrors/validation-errors/pattern.js +14 -18
  23. package/dist/utils/betterAjvErrors/validation-errors/required.js +13 -17
  24. package/dist/utils/betterAjvErrors/validation-errors/unevaluated-prop.js +14 -18
  25. package/dist/utils/dereference.js +22 -18
  26. package/dist/utils/details.js +28 -29
  27. package/dist/utils/filter.js +13 -14
  28. package/dist/utils/get-entrypoint.js +5 -6
  29. package/dist/utils/get-list-of-references.js +20 -16
  30. package/dist/utils/get-segments-from-path.js +13 -9
  31. package/dist/utils/is-filesystem.js +8 -6
  32. package/dist/utils/is-json.js +8 -11
  33. package/dist/utils/is-yaml.js +15 -17
  34. package/dist/utils/join/index.js +1 -5
  35. package/dist/utils/join/join.js +267 -153
  36. package/dist/utils/join/merge-objects.js +35 -18
  37. package/dist/utils/load/index.js +1 -5
  38. package/dist/utils/load/load.js +114 -90
  39. package/dist/utils/make-filesystem.js +20 -21
  40. package/dist/utils/normalize.js +32 -29
  41. package/dist/utils/openapi/actions/details.js +9 -10
  42. package/dist/utils/openapi/actions/files.js +7 -8
  43. package/dist/utils/openapi/actions/get.js +9 -10
  44. package/dist/utils/openapi/actions/toJson.js +9 -10
  45. package/dist/utils/openapi/actions/toYaml.js +9 -10
  46. package/dist/utils/openapi/commands/dereferenceCommand.js +25 -26
  47. package/dist/utils/openapi/commands/filterCommand.js +24 -25
  48. package/dist/utils/openapi/commands/loadCommand.js +40 -41
  49. package/dist/utils/openapi/commands/upgradeCommand.js +27 -28
  50. package/dist/utils/openapi/commands/validateCommand.js +31 -32
  51. package/dist/utils/openapi/openapi.js +16 -14
  52. package/dist/utils/openapi/openapi.test-d.js +13 -13
  53. package/dist/utils/openapi/utils/queueTask.js +8 -9
  54. package/dist/utils/openapi/utils/workThroughQueue.js +64 -50
  55. package/dist/utils/resolve-references.js +168 -110
  56. package/dist/utils/to-json.js +1 -5
  57. package/dist/utils/to-yaml.js +2 -6
  58. package/dist/utils/transform/sanitize.js +22 -22
  59. package/dist/utils/transform/utils/addInfoObject.js +9 -14
  60. package/dist/utils/transform/utils/addLatestOpenApiVersion.js +4 -9
  61. package/dist/utils/transform/utils/addMissingTags.js +26 -27
  62. package/dist/utils/transform/utils/normalizeSecuritySchemes.js +39 -37
  63. package/dist/utils/transform/utils/rejectSwaggerDocuments.js +5 -9
  64. package/dist/utils/transform-errors.js +62 -55
  65. package/dist/utils/traverse.js +21 -22
  66. package/dist/utils/unescape-json-pointer.js +8 -6
  67. package/dist/utils/upgrade.js +19 -22
  68. package/dist/utils/validate-path-parameters.js +79 -80
  69. package/dist/utils/validate.js +23 -19
  70. package/package.json +9 -14
  71. package/dist/configuration/index.js.map +0 -7
  72. package/dist/declarations.d.js +0 -1
  73. package/dist/declarations.d.js.map +0 -7
  74. package/dist/index.js.map +0 -7
  75. package/dist/lib/Validator/Validator.js.map +0 -7
  76. package/dist/plugins/fetch-urls/fetch-urls.js.map +0 -7
  77. package/dist/plugins/fetch-urls/index.js.map +0 -7
  78. package/dist/plugins/read-files/index.js.map +0 -7
  79. package/dist/plugins/read-files/read-files.js.map +0 -7
  80. package/dist/schemas/v2.0/schema.js.map +0 -7
  81. package/dist/schemas/v3.0/schema.js.map +0 -7
  82. package/dist/schemas/v3.1/schema.js.map +0 -7
  83. package/dist/schemas/v3.2/schema.js.map +0 -7
  84. package/dist/types/index.js.map +0 -7
  85. package/dist/utils/betterAjvErrors/helpers.js.map +0 -7
  86. package/dist/utils/betterAjvErrors/index.js.map +0 -7
  87. package/dist/utils/betterAjvErrors/utils.js.map +0 -7
  88. package/dist/utils/betterAjvErrors/validation-errors/additional-prop.js.map +0 -7
  89. package/dist/utils/betterAjvErrors/validation-errors/base.js.map +0 -7
  90. package/dist/utils/betterAjvErrors/validation-errors/default.js.map +0 -7
  91. package/dist/utils/betterAjvErrors/validation-errors/enum.js.map +0 -7
  92. package/dist/utils/betterAjvErrors/validation-errors/index.js.map +0 -7
  93. package/dist/utils/betterAjvErrors/validation-errors/pattern.js.map +0 -7
  94. package/dist/utils/betterAjvErrors/validation-errors/required.js.map +0 -7
  95. package/dist/utils/betterAjvErrors/validation-errors/unevaluated-prop.js.map +0 -7
  96. package/dist/utils/dereference.js.map +0 -7
  97. package/dist/utils/details.js.map +0 -7
  98. package/dist/utils/filter.js.map +0 -7
  99. package/dist/utils/get-entrypoint.js.map +0 -7
  100. package/dist/utils/get-list-of-references.js.map +0 -7
  101. package/dist/utils/get-segments-from-path.js.map +0 -7
  102. package/dist/utils/is-filesystem.js.map +0 -7
  103. package/dist/utils/is-json.js.map +0 -7
  104. package/dist/utils/is-yaml.js.map +0 -7
  105. package/dist/utils/join/index.js.map +0 -7
  106. package/dist/utils/join/join.js.map +0 -7
  107. package/dist/utils/join/merge-objects.js.map +0 -7
  108. package/dist/utils/load/index.js.map +0 -7
  109. package/dist/utils/load/load.js.map +0 -7
  110. package/dist/utils/make-filesystem.js.map +0 -7
  111. package/dist/utils/normalize.js.map +0 -7
  112. package/dist/utils/openapi/actions/details.js.map +0 -7
  113. package/dist/utils/openapi/actions/files.js.map +0 -7
  114. package/dist/utils/openapi/actions/get.js.map +0 -7
  115. package/dist/utils/openapi/actions/toJson.js.map +0 -7
  116. package/dist/utils/openapi/actions/toYaml.js.map +0 -7
  117. package/dist/utils/openapi/commands/dereferenceCommand.js.map +0 -7
  118. package/dist/utils/openapi/commands/filterCommand.js.map +0 -7
  119. package/dist/utils/openapi/commands/loadCommand.js.map +0 -7
  120. package/dist/utils/openapi/commands/upgradeCommand.js.map +0 -7
  121. package/dist/utils/openapi/commands/validateCommand.js.map +0 -7
  122. package/dist/utils/openapi/openapi.js.map +0 -7
  123. package/dist/utils/openapi/openapi.test-d.js.map +0 -7
  124. package/dist/utils/openapi/utils/queueTask.js.map +0 -7
  125. package/dist/utils/openapi/utils/workThroughQueue.js.map +0 -7
  126. package/dist/utils/resolve-references.js.map +0 -7
  127. package/dist/utils/to-json.js.map +0 -7
  128. package/dist/utils/to-yaml.js.map +0 -7
  129. package/dist/utils/transform/sanitize.js.map +0 -7
  130. package/dist/utils/transform/utils/addInfoObject.js.map +0 -7
  131. package/dist/utils/transform/utils/addLatestOpenApiVersion.js.map +0 -7
  132. package/dist/utils/transform/utils/addMissingTags.js.map +0 -7
  133. package/dist/utils/transform/utils/normalizeSecuritySchemes.js.map +0 -7
  134. package/dist/utils/transform/utils/rejectSwaggerDocuments.js.map +0 -7
  135. package/dist/utils/transform-errors.js.map +0 -7
  136. package/dist/utils/traverse.js.map +0 -7
  137. package/dist/utils/unescape-json-pointer.js.map +0 -7
  138. package/dist/utils/upgrade.js.map +0 -7
  139. package/dist/utils/validate-path-parameters.js.map +0 -7
  140. package/dist/utils/validate.js.map +0 -7
@@ -1,23 +1,23 @@
1
- import { addInfoObject } from "./utils/addInfoObject.js";
2
- import { addLatestOpenApiVersion } from "./utils/addLatestOpenApiVersion.js";
3
- import { addMissingTags } from "./utils/addMissingTags.js";
4
- import { normalizeSecuritySchemes } from "./utils/normalizeSecuritySchemes.js";
5
- import { rejectSwaggerDocuments } from "./utils/rejectSwaggerDocuments.js";
6
- import { DEFAULT_TITLE } from "./utils/addInfoObject.js";
7
- import { DEFAULT_OPENAPI_VERSION } from "./utils/addLatestOpenApiVersion.js";
8
- function sanitize(definition) {
9
- const transformers = [
10
- rejectSwaggerDocuments,
11
- addLatestOpenApiVersion,
12
- addInfoObject,
13
- addMissingTags,
14
- normalizeSecuritySchemes
15
- ];
16
- return transformers.reduce((doc, transformer) => transformer(doc), definition);
1
+ import { addInfoObject } from './utils/addInfoObject.js';
2
+ import { addLatestOpenApiVersion } from './utils/addLatestOpenApiVersion.js';
3
+ import { addMissingTags } from './utils/addMissingTags.js';
4
+ import { normalizeSecuritySchemes } from './utils/normalizeSecuritySchemes.js';
5
+ import { rejectSwaggerDocuments } from './utils/rejectSwaggerDocuments.js';
6
+ // biome-ignore lint/performance/noBarrelFile: re-exports utilities
7
+ export { DEFAULT_TITLE } from './utils/addInfoObject.js';
8
+ export { DEFAULT_OPENAPI_VERSION } from './utils/addLatestOpenApiVersion.js';
9
+ /**
10
+ * Make an OpenAPI document a valid and clean OpenAPI document
11
+ *
12
+ * @deprecated We're about to drop this from the package.
13
+ */
14
+ export function sanitize(definition) {
15
+ const transformers = [
16
+ rejectSwaggerDocuments,
17
+ addLatestOpenApiVersion,
18
+ addInfoObject,
19
+ addMissingTags,
20
+ normalizeSecuritySchemes,
21
+ ];
22
+ return transformers.reduce((doc, transformer) => transformer(doc), definition);
17
23
  }
18
- export {
19
- DEFAULT_OPENAPI_VERSION,
20
- DEFAULT_TITLE,
21
- sanitize
22
- };
23
- //# sourceMappingURL=sanitize.js.map
@@ -1,15 +1,10 @@
1
- const DEFAULT_TITLE = "API";
2
- const DEFAULT_VERSION = "1.0";
3
- const addInfoObject = (definition) => ({
4
- ...definition,
5
- info: {
6
- ...definition.info,
7
- title: definition.info?.title ?? DEFAULT_TITLE,
8
- version: definition.info?.version ?? DEFAULT_VERSION
9
- }
1
+ export const DEFAULT_TITLE = 'API';
2
+ const DEFAULT_VERSION = '1.0';
3
+ export const addInfoObject = (definition) => ({
4
+ ...definition,
5
+ info: {
6
+ ...definition.info,
7
+ title: definition.info?.title ?? DEFAULT_TITLE,
8
+ version: definition.info?.version ?? DEFAULT_VERSION,
9
+ },
10
10
  });
11
- export {
12
- DEFAULT_TITLE,
13
- addInfoObject
14
- };
15
- //# sourceMappingURL=addInfoObject.js.map
@@ -1,10 +1,5 @@
1
- const DEFAULT_OPENAPI_VERSION = "3.1.1";
2
- const addLatestOpenApiVersion = (definition) => ({
3
- openapi: definition.openapi ?? DEFAULT_OPENAPI_VERSION,
4
- ...definition
1
+ export const DEFAULT_OPENAPI_VERSION = '3.1.1';
2
+ export const addLatestOpenApiVersion = (definition) => ({
3
+ openapi: definition.openapi ?? DEFAULT_OPENAPI_VERSION,
4
+ ...definition,
5
5
  });
6
- export {
7
- DEFAULT_OPENAPI_VERSION,
8
- addLatestOpenApiVersion
9
- };
10
- //# sourceMappingURL=addLatestOpenApiVersion.js.map
@@ -1,30 +1,29 @@
1
- const addMissingTags = (definition) => {
2
- if (!definition.paths) {
3
- return definition;
4
- }
5
- const usedTags = /* @__PURE__ */ new Set();
6
- for (const path of Object.values(definition.paths)) {
7
- if (typeof path === "object" && path !== null) {
8
- for (const operation of Object.values(path)) {
9
- if (typeof operation === "object" && operation !== null && "tags" in operation) {
10
- const tags = operation.tags;
11
- if (Array.isArray(tags)) {
12
- tags.forEach((tag) => usedTags.add(String(tag)));
13
- }
1
+ export const addMissingTags = (definition) => {
2
+ if (!definition.paths) {
3
+ return definition;
4
+ }
5
+ // Collect all unique tags used in operations
6
+ const usedTags = new Set();
7
+ for (const path of Object.values(definition.paths)) {
8
+ if (typeof path === 'object' && path !== null) {
9
+ for (const operation of Object.values(path)) {
10
+ if (typeof operation === 'object' && operation !== null && 'tags' in operation) {
11
+ const tags = operation.tags;
12
+ if (Array.isArray(tags)) {
13
+ tags.forEach((tag) => usedTags.add(String(tag)));
14
+ }
15
+ }
16
+ }
14
17
  }
15
- }
16
18
  }
17
- }
18
- const existingTags = new Set(
19
- (Array.isArray(definition.tags) ? definition.tags : []).map((tag) => typeof tag === "object" && tag !== null ? String(tag.name) : null).filter(Boolean)
20
- );
21
- const missingTags = [...usedTags].filter((tag) => !existingTags.has(tag)).map((name) => ({ name }));
22
- return {
23
- ...definition,
24
- tags: [...Array.isArray(definition.tags) ? definition.tags : [], ...missingTags]
25
- };
26
- };
27
- export {
28
- addMissingTags
19
+ // Convert tags to array of tag objects if not already present
20
+ const existingTags = new Set((Array.isArray(definition.tags) ? definition.tags : [])
21
+ .map((tag) => (typeof tag === 'object' && tag !== null ? String(tag.name) : null))
22
+ .filter(Boolean));
23
+ // Add missing tags
24
+ const missingTags = [...usedTags].filter((tag) => !existingTags.has(tag)).map((name) => ({ name }));
25
+ return {
26
+ ...definition,
27
+ tags: [...(Array.isArray(definition.tags) ? definition.tags : []), ...missingTags],
28
+ };
29
29
  };
30
- //# sourceMappingURL=addMissingTags.js.map
@@ -1,42 +1,44 @@
1
- const normalizeSecuritySchemes = (definition) => {
2
- if (!definition.components?.securitySchemes) {
3
- return definition;
4
- }
5
- const securitySchemes = { ...definition.components.securitySchemes };
6
- for (const scheme of Object.values(securitySchemes)) {
7
- if (typeof scheme === "object" && scheme !== null && "type" in scheme) {
8
- const type = String(scheme.type).toLowerCase();
9
- scheme.type = {
10
- apikey: "apiKey",
11
- oauth2: "oauth2",
12
- http: "http",
13
- mutualtls: "mutualTLS",
14
- openidconnect: "openIdConnect"
15
- }[type] ?? type;
1
+ export const normalizeSecuritySchemes = (definition) => {
2
+ if (!definition.components?.securitySchemes) {
3
+ return definition;
16
4
  }
17
- }
18
- for (const scheme of Object.values(securitySchemes)) {
19
- if (typeof scheme === "object" && scheme !== null && "type" in scheme && scheme.type === "oauth2" && "flows" in scheme) {
20
- const flows = scheme.flows;
21
- for (const flow of Object.values(flows)) {
22
- if (typeof flow === "object" && flow !== null && "scopes" in flow && Array.isArray(flow.scopes)) {
23
- flow.scopes = flow.scopes.reduce((acc, scope) => {
24
- acc[scope] = "";
25
- return acc;
26
- }, {});
5
+ const securitySchemes = { ...definition.components.securitySchemes };
6
+ for (const scheme of Object.values(securitySchemes)) {
7
+ if (typeof scheme === 'object' && scheme !== null && 'type' in scheme) {
8
+ const type = String(scheme.type).toLowerCase();
9
+ scheme.type =
10
+ {
11
+ apikey: 'apiKey',
12
+ oauth2: 'oauth2',
13
+ http: 'http',
14
+ mutualtls: 'mutualTLS',
15
+ openidconnect: 'openIdConnect',
16
+ }[type] ?? type;
27
17
  }
28
- }
29
18
  }
30
- }
31
- return {
32
- ...definition,
33
- components: {
34
- ...definition.components,
35
- securitySchemes
19
+ // Convert array scopes to objects
20
+ for (const scheme of Object.values(securitySchemes)) {
21
+ if (typeof scheme === 'object' &&
22
+ scheme !== null &&
23
+ 'type' in scheme &&
24
+ scheme.type === 'oauth2' &&
25
+ 'flows' in scheme) {
26
+ const flows = scheme.flows;
27
+ for (const flow of Object.values(flows)) {
28
+ if (typeof flow === 'object' && flow !== null && 'scopes' in flow && Array.isArray(flow.scopes)) {
29
+ flow.scopes = flow.scopes.reduce((acc, scope) => {
30
+ acc[scope] = '';
31
+ return acc;
32
+ }, {});
33
+ }
34
+ }
35
+ }
36
36
  }
37
- };
38
- };
39
- export {
40
- normalizeSecuritySchemes
37
+ return {
38
+ ...definition,
39
+ components: {
40
+ ...definition.components,
41
+ securitySchemes,
42
+ },
43
+ };
41
44
  };
42
- //# sourceMappingURL=normalizeSecuritySchemes.js.map
@@ -1,10 +1,6 @@
1
- const rejectSwaggerDocuments = (defintion) => {
2
- if ("swagger" in defintion) {
3
- throw new Error("Swagger 2.0 documents are not supported. Please upgrade to OpenAPI 3.x.");
4
- }
5
- return defintion;
1
+ export const rejectSwaggerDocuments = (defintion) => {
2
+ if ('swagger' in defintion) {
3
+ throw new Error('Swagger 2.0 documents are not supported. Please upgrade to OpenAPI 3.x.');
4
+ }
5
+ return defintion;
6
6
  };
7
- export {
8
- rejectSwaggerDocuments
9
- };
10
- //# sourceMappingURL=rejectSwaggerDocuments.js.map
@@ -1,58 +1,65 @@
1
- import { betterAjvErrors } from "./betterAjvErrors/index.js";
2
- function transformErrors(specification, errors) {
3
- if (typeof errors === "string") {
4
- return [
5
- {
6
- message: errors
7
- }
8
- ];
9
- }
10
- if (!specification || typeof specification !== "object") {
11
- return [
12
- {
13
- message: "Invalid specification"
14
- }
15
- ];
16
- }
17
- let processedErrors;
18
- try {
19
- processedErrors = betterAjvErrors(specification, null, errors, {
20
- indent: 2
21
- }).map((error) => {
22
- error.message = error.message.trim();
23
- return error;
24
- });
25
- } catch (error) {
26
- console.error(error);
27
- if (Array.isArray(errors)) {
28
- return errors.map((err) => {
29
- let message = err.message || "Validation error";
30
- if (err.keyword === "additionalProperties" && err.params?.additionalProperty) {
31
- message = `Property ${err.params.additionalProperty} is not expected to be here`;
32
- }
33
- return {
34
- message,
35
- path: err.dataPath || err.instancePath
36
- };
37
- });
1
+ import { betterAjvErrors } from './betterAjvErrors/index.js';
2
+ /**
3
+ * Transforms ajv errors, finds the positions in the schema and returns an enriched format.
4
+ */
5
+ export function transformErrors(specification, errors) {
6
+ // TODO: This should work with multiple files
7
+ if (typeof errors === 'string') {
8
+ return [
9
+ {
10
+ message: errors,
11
+ },
12
+ ];
38
13
  }
39
- return [
40
- {
41
- message: "Validation failed"
42
- }
43
- ];
44
- }
45
- const seen = /* @__PURE__ */ new Set();
46
- return processedErrors.filter((error) => {
47
- const key = `${error.message}||${error.path}`;
48
- if (seen.has(key)) {
49
- return false;
14
+ // If specification is null or invalid, betterAjvErrors cannot process it
15
+ // This can happen when reference resolution fails
16
+ if (!specification || typeof specification !== 'object') {
17
+ return [
18
+ {
19
+ message: 'Invalid specification',
20
+ },
21
+ ];
50
22
  }
51
- seen.add(key);
52
- return true;
53
- });
23
+ // Wrap betterAjvErrors in a try-catch since it can fail with malformed schemas
24
+ let processedErrors;
25
+ try {
26
+ processedErrors = betterAjvErrors(specification, null, errors, {
27
+ indent: 2,
28
+ }).map((error) => {
29
+ error.message = error.message.trim();
30
+ return error;
31
+ });
32
+ }
33
+ catch (error) {
34
+ console.error(error);
35
+ // If betterAjvErrors fails, fall back to raw AJV errors
36
+ if (Array.isArray(errors)) {
37
+ return errors.map((err) => {
38
+ let message = err.message || 'Validation error';
39
+ // For additionalProperties errors, include the property name
40
+ if (err.keyword === 'additionalProperties' && err.params?.additionalProperty) {
41
+ message = `Property ${err.params.additionalProperty} is not expected to be here`;
42
+ }
43
+ return {
44
+ message,
45
+ path: err.dataPath || err.instancePath,
46
+ };
47
+ });
48
+ }
49
+ return [
50
+ {
51
+ message: 'Validation failed',
52
+ },
53
+ ];
54
+ }
55
+ // Deduplicate errors with the same message and path
56
+ const seen = new Set();
57
+ return processedErrors.filter((error) => {
58
+ const key = `${error.message}||${error.path}`;
59
+ if (seen.has(key)) {
60
+ return false;
61
+ }
62
+ seen.add(key);
63
+ return true;
64
+ });
54
65
  }
55
- export {
56
- transformErrors
57
- };
58
- //# sourceMappingURL=transform-errors.js.map
@@ -1,25 +1,24 @@
1
- function traverse(content, transform, path = []) {
2
- const result = {};
3
- for (const [key, value] of Object.entries(content)) {
4
- const currentPath = [...path, key];
5
- if (Array.isArray(value)) {
6
- result[key] = value.map((item, index) => {
7
- if (typeof item === "object" && !Array.isArray(item) && item !== null) {
8
- return traverse(item, transform, [...currentPath, index.toString()]);
1
+ /**
2
+ * Recursively traverses the content and applies the transform function to each node.
3
+ */
4
+ export function traverse(content, transform, path = []) {
5
+ const result = {};
6
+ for (const [key, value] of Object.entries(content)) {
7
+ const currentPath = [...path, key];
8
+ if (Array.isArray(value)) {
9
+ result[key] = value.map((item, index) => {
10
+ if (typeof item === 'object' && !Array.isArray(item) && item !== null) {
11
+ return traverse(item, transform, [...currentPath, index.toString()]);
12
+ }
13
+ return item;
14
+ });
15
+ continue;
9
16
  }
10
- return item;
11
- });
12
- continue;
13
- }
14
- if (typeof value === "object" && value !== null) {
15
- result[key] = traverse(value, transform, currentPath);
16
- continue;
17
+ if (typeof value === 'object' && value !== null) {
18
+ result[key] = traverse(value, transform, currentPath);
19
+ continue;
20
+ }
21
+ result[key] = value;
17
22
  }
18
- result[key] = value;
19
- }
20
- return transform(result, path);
23
+ return transform(result, path);
21
24
  }
22
- export {
23
- traverse
24
- };
25
- //# sourceMappingURL=traverse.js.map
@@ -1,7 +1,9 @@
1
- function unescapeJsonPointer(uri) {
2
- return decodeURI(uri.replace(/~1/g, "/").replace(/~0/g, "~"));
1
+ /**
2
+ * Unescape JSON pointer
3
+ *
4
+ * Examples:
5
+ * /foo~1bar~0baz -> /foo/bar~baz
6
+ */
7
+ export function unescapeJsonPointer(uri) {
8
+ return decodeURI(uri.replace(/~1/g, '/').replace(/~0/g, '~'));
3
9
  }
4
- export {
5
- unescapeJsonPointer
6
- };
7
- //# sourceMappingURL=unescape-json-pointer.js.map
@@ -1,25 +1,22 @@
1
- import { upgrade as originalUpgrade } from "@scalar/openapi-upgrader";
2
- import { getEntrypoint } from "./get-entrypoint.js";
3
- import { isFilesystem } from "./is-filesystem.js";
4
- import { normalize } from "./normalize.js";
5
- function upgrade(value) {
6
- if (!value) {
1
+ import { upgrade as originalUpgrade } from '@scalar/openapi-upgrader';
2
+ import { getEntrypoint } from './get-entrypoint.js';
3
+ import { isFilesystem } from './is-filesystem.js';
4
+ import { normalize } from './normalize.js';
5
+ /**
6
+ * Upgrade specification to OpenAPI 3.1.0
7
+ */
8
+ export function upgrade(value) {
9
+ if (!value) {
10
+ return {
11
+ specification: null,
12
+ version: '3.1',
13
+ };
14
+ }
15
+ // TODO: Run upgrade over the whole filesystem
16
+ const document = originalUpgrade(isFilesystem(value) ? getEntrypoint(value).specification : normalize(value), '3.1');
7
17
  return {
8
- specification: null,
9
- version: "3.1"
18
+ specification: document,
19
+ // TODO: Make dynamic
20
+ version: '3.1',
10
21
  };
11
- }
12
- const document = originalUpgrade(
13
- isFilesystem(value) ? getEntrypoint(value).specification : normalize(value),
14
- "3.1"
15
- );
16
- return {
17
- specification: document,
18
- // TODO: Make dynamic
19
- version: "3.1"
20
- };
21
22
  }
22
- export {
23
- upgrade
24
- };
25
- //# sourceMappingURL=upgrade.js.map
@@ -1,95 +1,94 @@
1
- const OPERATION_KEYS = /* @__PURE__ */ new Set(["get", "put", "post", "delete", "options", "head", "patch", "trace"]);
1
+ const OPERATION_KEYS = new Set(['get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace']);
2
2
  const PATH_PARAMETER_PATTERN = /{([^}]+)}/g;
3
- function validatePathParameters(specification) {
4
- const paths = specification?.paths;
5
- if (!paths || typeof paths !== "object") {
6
- return [];
7
- }
8
- const errors = [];
9
- for (const [pathName, pathItem] of Object.entries(paths)) {
10
- if (!isRecord(pathItem)) {
11
- continue;
3
+ /**
4
+ * Validates path-template semantics that are not enforced by the JSON schema.
5
+ */
6
+ export function validatePathParameters(specification) {
7
+ const paths = specification?.paths;
8
+ if (!paths || typeof paths !== 'object') {
9
+ return [];
12
10
  }
13
- const operations = Object.entries(pathItem).filter(
14
- ([key, value]) => OPERATION_KEYS.has(key) && isRecord(value)
15
- );
16
- if (operations.length === 0) {
17
- continue;
18
- }
19
- const templateParameters = new Set(getTemplateParameterNames(pathName));
20
- const pathLevelParameters = getPathParameters(pathItem.parameters, ["paths", pathName, "parameters"]);
21
- for (const parameter of pathLevelParameters) {
22
- if (!templateParameters.has(parameter.name)) {
23
- errors.push({
24
- path: parameter.path,
25
- message: `Path parameter "${parameter.name}" must have the corresponding {${parameter.name}} segment in the "${pathName}" path`
26
- });
27
- }
28
- }
29
- for (const [operationKey, operation] of operations) {
30
- const operationParameters = getPathParameters(operation.parameters, [
31
- "paths",
32
- pathName,
33
- operationKey,
34
- "parameters"
35
- ]);
36
- for (const parameter of operationParameters) {
37
- if (!templateParameters.has(parameter.name)) {
38
- errors.push({
39
- path: parameter.path,
40
- message: `Path parameter "${parameter.name}" must have the corresponding {${parameter.name}} segment in the "${pathName}" path`
41
- });
11
+ const errors = [];
12
+ for (const [pathName, pathItem] of Object.entries(paths)) {
13
+ if (!isRecord(pathItem)) {
14
+ continue;
15
+ }
16
+ const operations = Object.entries(pathItem).filter(([key, value]) => OPERATION_KEYS.has(key) && isRecord(value));
17
+ // Preserve the repo's current behaviour for empty path items.
18
+ if (operations.length === 0) {
19
+ continue;
20
+ }
21
+ const templateParameters = new Set(getTemplateParameterNames(pathName));
22
+ const pathLevelParameters = getPathParameters(pathItem.parameters, ['paths', pathName, 'parameters']);
23
+ for (const parameter of pathLevelParameters) {
24
+ if (!templateParameters.has(parameter.name)) {
25
+ errors.push({
26
+ path: parameter.path,
27
+ message: `Path parameter "${parameter.name}" must have the corresponding {${parameter.name}} segment in the "${pathName}" path`,
28
+ });
29
+ }
42
30
  }
43
- }
44
- const effectiveParameters = new Set(
45
- [...pathLevelParameters, ...operationParameters].map((parameter) => parameter.name)
46
- );
47
- for (const templateParameter of templateParameters) {
48
- if (!effectiveParameters.has(templateParameter)) {
49
- errors.push({
50
- path: ["paths", pathName, operationKey],
51
- message: `Declared path parameter "${templateParameter}" needs to be defined as a path parameter at either the path or operation level`
52
- });
31
+ for (const [operationKey, operation] of operations) {
32
+ const operationParameters = getPathParameters(operation.parameters, [
33
+ 'paths',
34
+ pathName,
35
+ operationKey,
36
+ 'parameters',
37
+ ]);
38
+ for (const parameter of operationParameters) {
39
+ if (!templateParameters.has(parameter.name)) {
40
+ errors.push({
41
+ path: parameter.path,
42
+ message: `Path parameter "${parameter.name}" must have the corresponding {${parameter.name}} segment in the "${pathName}" path`,
43
+ });
44
+ }
45
+ }
46
+ const effectiveParameters = new Set([...pathLevelParameters, ...operationParameters].map((parameter) => parameter.name));
47
+ for (const templateParameter of templateParameters) {
48
+ if (!effectiveParameters.has(templateParameter)) {
49
+ errors.push({
50
+ path: ['paths', pathName, operationKey],
51
+ message: `Declared path parameter "${templateParameter}" needs to be defined as a path parameter at either the path or operation level`,
52
+ });
53
+ }
54
+ }
53
55
  }
54
- }
55
56
  }
56
- }
57
- return deduplicateErrors(errors);
57
+ return deduplicateErrors(errors);
58
58
  }
59
59
  function getTemplateParameterNames(pathName) {
60
- return [...pathName.matchAll(PATH_PARAMETER_PATTERN)].map((match) => match[1]);
60
+ return [...pathName.matchAll(PATH_PARAMETER_PATTERN)].map((match) => normalizeTemplateParameterName(match[1]));
61
+ }
62
+ function normalizeTemplateParameterName(name) {
63
+ return name.endsWith('+') ? name.slice(0, -1) : name;
61
64
  }
62
65
  function getPathParameters(parameters, pathPrefix) {
63
- if (!Array.isArray(parameters)) {
64
- return [];
65
- }
66
- return parameters.flatMap((parameter, index) => {
67
- if (!isRecord(parameter) || parameter.in !== "path" || typeof parameter.name !== "string") {
68
- return [];
66
+ if (!Array.isArray(parameters)) {
67
+ return [];
69
68
  }
70
- return [
71
- {
72
- name: parameter.name,
73
- path: [...pathPrefix, String(index), "name"]
74
- }
75
- ];
76
- });
69
+ return parameters.flatMap((parameter, index) => {
70
+ if (!isRecord(parameter) || parameter.in !== 'path' || typeof parameter.name !== 'string') {
71
+ return [];
72
+ }
73
+ return [
74
+ {
75
+ name: parameter.name,
76
+ path: [...pathPrefix, String(index), 'name'],
77
+ },
78
+ ];
79
+ });
77
80
  }
78
81
  function deduplicateErrors(errors) {
79
- const seen = /* @__PURE__ */ new Set();
80
- return errors.filter((error) => {
81
- const key = `${error.message}||${error.path?.join(".") ?? ""}`;
82
- if (seen.has(key)) {
83
- return false;
84
- }
85
- seen.add(key);
86
- return true;
87
- });
82
+ const seen = new Set();
83
+ return errors.filter((error) => {
84
+ const key = `${error.message}||${error.path?.join('.') ?? ''}`;
85
+ if (seen.has(key)) {
86
+ return false;
87
+ }
88
+ seen.add(key);
89
+ return true;
90
+ });
88
91
  }
89
92
  function isRecord(value) {
90
- return typeof value === "object" && value !== null && !Array.isArray(value);
93
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
91
94
  }
92
- export {
93
- validatePathParameters
94
- };
95
- //# sourceMappingURL=validate-path-parameters.js.map