@scalar/openapi-parser 0.10.0 → 0.10.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @scalar/openapi-parser
2
2
 
3
+ ## 0.10.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 3791738: fix(openapi-parser): correct schema upgrade for "format: binary"
8
+
9
+ ## 0.10.1
10
+
11
+ ### Patch Changes
12
+
13
+ - c263aaf: feat: better deal with empty OpenAPI documents
14
+
3
15
  ## 0.10.0
4
16
 
5
17
  ### Minor Changes
@@ -23,8 +23,7 @@ const getSiblings =
23
23
  const concatAll =
24
24
  /* ::<T> */
25
25
 
26
-
27
- (xs /*: $ReadOnlyArray<T> */) =>
26
+ (xs /*: $ReadOnlyArray<T> */) =>
28
27
  (ys /* : $ReadOnlyArray<T> */) /* : $ReadOnlyArray<T> */ =>
29
28
  ys.reduce((zs, z) => zs.concat(z), xs);
30
29
 
@@ -1,6 +1,7 @@
1
- import type { AnyObject, DetailsResult } from '../types';
1
+ import type { UnknownObject } from '@scalar/types/utils';
2
+ import type { DetailsResult } from '../types';
2
3
  /**
3
4
  * Get versions of the OpenAPI document.
4
5
  */
5
- export declare function details(specification: AnyObject): DetailsResult;
6
+ export declare function details(specification: UnknownObject): DetailsResult;
6
7
  //# sourceMappingURL=details.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"details.d.ts","sourceRoot":"","sources":["../../src/utils/details.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExD;;GAEG;AACH,wBAAgB,OAAO,CAAC,aAAa,EAAE,SAAS,GAAG,aAAa,CAmB/D"}
1
+ {"version":3,"file":"details.d.ts","sourceRoot":"","sources":["../../src/utils/details.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAGxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAE7C;;GAEG;AACH,wBAAgB,OAAO,CAAC,aAAa,EAAE,aAAa,GAAG,aAAa,CA2BnE"}
@@ -4,6 +4,13 @@ import { OpenApiVersions } from '../configuration/index.js';
4
4
  * Get versions of the OpenAPI document.
5
5
  */
6
6
  function details(specification) {
7
+ if (specification === null) {
8
+ return {
9
+ version: undefined,
10
+ specificationType: undefined,
11
+ specificationVersion: undefined,
12
+ };
13
+ }
7
14
  for (const version of new Set(OpenApiVersions)) {
8
15
  const specificationType = version === '2.0' ? 'swagger' : 'openapi';
9
16
  const value = specification[specificationType];
@@ -1,8 +1,9 @@
1
- import type { AnyObject, Filesystem } from '../types';
1
+ import type { UnknownObject } from '@scalar/types/utils';
2
+ import type { Filesystem } from '../types';
2
3
  /**
3
4
  * Normalize the OpenAPI document (YAML, JSON, object) to a JavaScript object.
4
5
  *
5
6
  * Doesn’t modify the object if it’s a `Filesystem` (multiple files) already.
6
7
  */
7
- export declare function normalize(specification: string | AnyObject | Filesystem): AnyObject | Filesystem;
8
+ export declare function normalize(specification: string | UnknownObject | Filesystem): UnknownObject | Filesystem;
8
9
  //# sourceMappingURL=normalize.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../src/utils/normalize.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAGrD;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,GAC7C,SAAS,GAAG,UAAU,CAgBxB"}
1
+ {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../src/utils/normalize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAGxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAG1C;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,aAAa,EAAE,MAAM,GAAG,aAAa,GAAG,UAAU,GACjD,aAAa,GAAG,UAAU,CAwB5B"}
@@ -7,10 +7,13 @@ import { isFilesystem } from './isFilesystem.js';
7
7
  * Doesn’t modify the object if it’s a `Filesystem` (multiple files) already.
8
8
  */
9
9
  function normalize(specification) {
10
- if (isFilesystem(specification)) {
11
- return specification;
10
+ if (specification === null) {
11
+ return {};
12
12
  }
13
13
  if (typeof specification === 'string') {
14
+ if (specification.trim() === '') {
15
+ return {};
16
+ }
14
17
  try {
15
18
  return JSON.parse(specification);
16
19
  }
@@ -20,6 +23,9 @@ function normalize(specification) {
20
23
  });
21
24
  }
22
25
  }
26
+ if (isFilesystem(specification)) {
27
+ return specification;
28
+ }
23
29
  return specification;
24
30
  }
25
31
 
@@ -1 +1 @@
1
- {"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../../src/utils/upgrade.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAExD,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAMpE;;GAEG;AACH,wBAAgB,OAAO,CACrB,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,GACrC,aAAa,CAAC,WAAW,CAAC,QAAQ,CAAC,CAcrC"}
1
+ {"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../../src/utils/upgrade.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAExD,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAMpE;;GAEG;AACH,wBAAgB,OAAO,CACrB,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,GACrC,aAAa,CAAC,WAAW,CAAC,QAAQ,CAAC,CAoBrC"}
@@ -7,6 +7,12 @@ import { upgradeFromTwoToThree } from './upgradeFromTwoToThree.js';
7
7
  * Upgrade specification to OpenAPI 3.1.0
8
8
  */
9
9
  function upgrade(value) {
10
+ if (!value) {
11
+ return {
12
+ specification: null,
13
+ version: '3.1',
14
+ };
15
+ }
10
16
  const upgraders = [upgradeFromTwoToThree, upgradeFromThreeToThreeOne];
11
17
  // TODO: Run upgrade over the whole filesystem
12
18
  const result = upgraders.reduce((currentSpecification, upgrader) => upgrader(currentSpecification), getEntrypoint(makeFilesystem(value)).specification);
@@ -1,10 +1,31 @@
1
- import type { AnyObject } from '../types';
1
+ import type { OpenAPIV3_1 } from '@scalar/openapi-types';
2
+ import type { UnknownObject } from '@scalar/types/utils';
2
3
  /**
3
- * Upgrade from OpenAPI 3.0.x to 3.1.0
4
+ * Upgrade from OpenAPI 3.0.x to 3.1.1
4
5
  *
5
6
  * https://www.openapis.org/blog/2021/02/16/migrating-from-openapi-3-0-to-3-1-0
6
7
  */
7
- export declare function upgradeFromThreeToThreeOne(originalSpecification: AnyObject): AnyObject;
8
+ export declare function upgradeFromThreeToThreeOne(originalSpecification: UnknownObject): (Omit<Omit<import("@scalar/openapi-types").OpenAPIV3.Document<{}>, "paths" | "components">, keyof {
9
+ [customExtension: `x-${string}`]: any;
10
+ [key: string]: any;
11
+ }> & {
12
+ openapi?: "3.1.0" | "3.1.1";
13
+ swagger?: undefined;
14
+ info?: OpenAPIV3_1.InfoObject;
15
+ jsonSchemaDialect?: string;
16
+ servers?: OpenAPIV3_1.ServerObject[];
17
+ } & Pick<{
18
+ paths?: OpenAPIV3_1.PathsObject<{}, {}>;
19
+ webhooks?: Record<string, OpenAPIV3_1.PathItemObject | OpenAPIV3_1.ReferenceObject>;
20
+ components?: OpenAPIV3_1.ComponentsObject;
21
+ }, "paths"> & Omit<Partial<{
22
+ paths?: OpenAPIV3_1.PathsObject<{}, {}>;
23
+ webhooks?: Record<string, OpenAPIV3_1.PathItemObject | OpenAPIV3_1.ReferenceObject>;
24
+ components?: OpenAPIV3_1.ComponentsObject;
25
+ }>, "paths"> & {
26
+ [customExtension: `x-${string}`]: any;
27
+ [key: string]: any;
28
+ }) | UnknownObject;
8
29
  /** Determine if the current path is within a schema */
9
30
  export declare function isSchemaPath(path: string[]): boolean;
10
31
  //# sourceMappingURL=upgradeFromThreeToThreeOne.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"upgradeFromThreeToThreeOne.d.ts","sourceRoot":"","sources":["../../src/utils/upgradeFromThreeToThreeOne.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAGzC;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,qBAAqB,EAAE,SAAS,aA6G1E;AAED,uDAAuD;AACvD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAsBpD"}
1
+ {"version":3,"file":"upgradeFromThreeToThreeOne.d.ts","sourceRoot":"","sources":["../../src/utils/upgradeFromThreeToThreeOne.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAIxD;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,qBAAqB,EAAE,aAAa;;;;;;;;;;;;;;;;;;;;mBAmIrC;AAED,uDAAuD;AACvD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAsBpD"}
@@ -1,14 +1,16 @@
1
1
  import { traverse } from './traverse.js';
2
2
 
3
3
  /**
4
- * Upgrade from OpenAPI 3.0.x to 3.1.0
4
+ * Upgrade from OpenAPI 3.0.x to 3.1.1
5
5
  *
6
6
  * https://www.openapis.org/blog/2021/02/16/migrating-from-openapi-3-0-to-3-1-0
7
7
  */
8
8
  function upgradeFromThreeToThreeOne(originalSpecification) {
9
9
  let specification = originalSpecification;
10
10
  // Version
11
- if (specification.openapi?.startsWith('3.0')) {
11
+ if (specification !== null &&
12
+ typeof specification.openapi === 'string' &&
13
+ specification.openapi.startsWith('3.0')) {
12
14
  specification.openapi = '3.1.1';
13
15
  }
14
16
  else {
@@ -61,25 +63,38 @@ function upgradeFromThreeToThreeOne(originalSpecification) {
61
63
  return schema;
62
64
  });
63
65
  // Multipart file uploads with a binary file
64
- specification = traverse(specification, (schema) => {
66
+ specification = traverse(specification, (schema, path) => {
65
67
  if (schema.type === 'object' && schema.properties !== undefined) {
66
- // Types
67
- const entries = Object.entries(schema.properties);
68
- for (const [_, value] of entries) {
69
- if (typeof value === 'object' &&
70
- value.type === 'string' &&
71
- value.format === 'binary') {
72
- value.contentEncoding = 'application/octet-stream';
73
- delete value.format;
68
+ // Check if this is a multipart request body schema
69
+ const parentPath = path.slice(0, -1);
70
+ const isMultipart = parentPath.some((segment, index) => {
71
+ return (segment === 'content' && path[index + 1] === 'multipart/form-data');
72
+ });
73
+ if (isMultipart) {
74
+ // Types
75
+ const entries = Object.entries(schema.properties);
76
+ for (const [_, value] of entries) {
77
+ if (typeof value === 'object' &&
78
+ value.type === 'string' &&
79
+ value.format === 'binary') {
80
+ value.contentMediaType = 'application/octet-stream';
81
+ delete value.format;
82
+ }
74
83
  }
75
84
  }
76
85
  }
77
86
  return schema;
78
87
  });
79
88
  // Uploading a binary file in a POST request
80
- specification = traverse(specification, (schema) => {
89
+ specification = traverse(specification, (schema, path) => {
90
+ if (path.includes('content') && path.includes('application/octet-stream')) {
91
+ return {};
92
+ }
81
93
  if (schema.type === 'string' && schema.format === 'binary') {
82
- return undefined;
94
+ return {
95
+ type: 'string',
96
+ contentMediaType: 'application/octet-stream',
97
+ };
83
98
  }
84
99
  return schema;
85
100
  });
@@ -1,8 +1,9 @@
1
- import type { AnyObject } from '../types';
1
+ import type { OpenAPIV3 } from '@scalar/openapi-types';
2
+ import type { UnknownObject } from '@scalar/types/utils';
2
3
  /**
3
4
  * Upgrade Swagger 2.0 to OpenAPI 3.0
4
5
  *
5
6
  * https://swagger.io/blog/news/whats-new-in-openapi-3-0/
6
7
  */
7
- export declare function upgradeFromTwoToThree(specification: AnyObject): AnyObject;
8
+ export declare function upgradeFromTwoToThree(originalSpecification: UnknownObject): OpenAPIV3.Document<{}> | UnknownObject;
8
9
  //# sourceMappingURL=upgradeFromTwoToThree.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"upgradeFromTwoToThree.d.ts","sourceRoot":"","sources":["../../src/utils/upgradeFromTwoToThree.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAGzC;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,SAAS,aA4O7D"}
1
+ {"version":3,"file":"upgradeFromTwoToThree.d.ts","sourceRoot":"","sources":["../../src/utils/upgradeFromTwoToThree.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,SAAS,EAAE,MAAM,uBAAuB,CAAA;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAIxD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,qBAAqB,EAAE,aAAa,0CAkQzE"}
@@ -5,9 +5,12 @@ import { traverse } from './traverse.js';
5
5
  *
6
6
  * https://swagger.io/blog/news/whats-new-in-openapi-3-0/
7
7
  */
8
- function upgradeFromTwoToThree(specification) {
8
+ function upgradeFromTwoToThree(originalSpecification) {
9
+ let specification = originalSpecification;
9
10
  // Version
10
- if (specification.swagger?.startsWith('2.0')) {
11
+ if (specification !== null &&
12
+ typeof specification.swagger === 'string' &&
13
+ specification.swagger?.startsWith('2.0')) {
11
14
  specification.openapi = '3.0.4';
12
15
  delete specification.swagger;
13
16
  }
@@ -18,7 +21,7 @@ function upgradeFromTwoToThree(specification) {
18
21
  console.warn(`[upgradeFromTwoToThree] The upgrade from Swagger 2.0 to OpenAPI 3.0 documents is experimental and lacks features.`);
19
22
  // Servers
20
23
  if (specification.host) {
21
- const schemes = specification.schemes?.length
24
+ const schemes = Array.isArray(specification.schemes) && specification.schemes?.length
22
25
  ? specification.schemes
23
26
  : ['http'];
24
27
  specification.servers = schemes.map((scheme) => ({
@@ -30,10 +33,9 @@ function upgradeFromTwoToThree(specification) {
30
33
  }
31
34
  // Schemas
32
35
  if (specification.definitions) {
33
- if (typeof specification.components !== 'object') {
34
- specification.components = {};
35
- }
36
- specification.components.schemas = specification.definitions;
36
+ specification.components = Object.assign({}, specification.components, {
37
+ schemas: specification.definitions,
38
+ });
37
39
  delete specification.definitions;
38
40
  // Rewrite $refs to definitions
39
41
  specification = traverse(specification, (schema) => {
@@ -44,7 +46,7 @@ function upgradeFromTwoToThree(specification) {
44
46
  });
45
47
  }
46
48
  // Paths
47
- if (specification.paths) {
49
+ if (typeof specification.paths === 'object') {
48
50
  for (const path in specification.paths) {
49
51
  if (Object.hasOwn(specification.paths, path)) {
50
52
  const pathItem = specification.paths[path];
@@ -145,24 +147,28 @@ function upgradeFromTwoToThree(specification) {
145
147
  if (typeof specification.components !== 'object') {
146
148
  specification.components = {};
147
149
  }
148
- specification.components.securitySchemes = {};
150
+ // Assert that components is of type OpenAPIV3.ComponentsObject
151
+ specification.components =
152
+ specification.components;
153
+ Object.assign(specification.components, { securitySchemes: {} });
149
154
  for (const [key, securityScheme] of Object.entries(specification.securityDefinitions)) {
150
155
  if (typeof securityScheme === 'object') {
151
156
  if ('type' in securityScheme && securityScheme.type === 'oauth2') {
152
157
  const { flow, authorizationUrl, tokenUrl, scopes } = securityScheme;
153
- specification.components.securitySchemes[key] = {
154
- type: 'oauth2',
155
- flows: {
156
- [flow]: {
157
- ...(authorizationUrl && { authorizationUrl }),
158
- ...(tokenUrl && { tokenUrl }),
159
- ...(scopes && { scopes }),
158
+ // Assert that securitySchemes is of type OpenAPIV3.SecuritySchemeObject
159
+ Object.assign(specification.components
160
+ .securitySchemes, {
161
+ [key]: {
162
+ type: 'oauth2',
163
+ flows: {
164
+ [flow]: Object.assign({}, authorizationUrl && { authorizationUrl }, tokenUrl && { tokenUrl }, scopes && { scopes }),
160
165
  },
161
166
  },
162
- };
167
+ });
163
168
  }
164
169
  else {
165
- specification.components.securitySchemes[key] = securityScheme;
170
+ Object.assign(specification.components
171
+ .securitySchemes, { [key]: securityScheme });
166
172
  }
167
173
  }
168
174
  }
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "bugs": "https://github.com/scalar/scalar/issues/new/choose",
8
8
  "repository": {
9
9
  "type": "git",
10
- "url": "https://github.com/scalar/scalar.git",
10
+ "url": "git+https://github.com/scalar/scalar.git",
11
11
  "directory": "packages/openapi-parser"
12
12
  },
13
13
  "keywords": [
@@ -17,7 +17,7 @@
17
17
  "parser",
18
18
  "typescript"
19
19
  ],
20
- "version": "0.10.0",
20
+ "version": "0.10.2",
21
21
  "engines": {
22
22
  "node": ">=18"
23
23
  },
@@ -59,13 +59,14 @@
59
59
  "@apidevtools/swagger-parser": "^10.1.0",
60
60
  "@babel/code-frame": "^7.24.7",
61
61
  "@google-cloud/storage": "^7.12.1",
62
- "@types/node": "^20.14.10",
62
+ "@types/node": "^20.17.10",
63
63
  "glob": "^10.3.10",
64
64
  "json-to-ast": "^2.1.0",
65
65
  "just-diff": "^6.0.2",
66
66
  "tinybench": "^2.8.0",
67
+ "@scalar/openapi-types": "0.1.5",
67
68
  "@scalar/build-tooling": "0.1.12",
68
- "@scalar/openapi-types": "0.1.5"
69
+ "@scalar/types": "0.0.25"
69
70
  },
70
71
  "scripts": {
71
72
  "build": "scalar-build-rollup",