@sdk-it/spec 0.37.1 → 0.39.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 +1 @@
1
- {"version":3,"file":"ir.d.ts","sourceRoot":"","sources":["../../src/lib/ir.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,KAAK,iBAAiB,EAAiB,MAAM,cAAc,CAAC;AAMrE,OAAO,KAAK,EAAE,EAAE,EAAwB,MAAM,YAAY,CAAC;AAiC3D,wBAAgB,IAAI,CAAC,MAAM,EAAE,iBAAiB,EAAE,OAAO,UAAQ,GAAG,EAAE,CAsGnE"}
1
+ {"version":3,"file":"ir.d.ts","sourceRoot":"","sources":["../../src/lib/ir.ts"],"names":[],"mappings":"AAYA,OAAO,EACL,KAAK,iBAAiB,EAEvB,MAAM,cAAc,CAAC;AAMtB,OAAO,KAAK,EAAE,EAAE,EAAwB,MAAM,YAAY,CAAC;AAiC3D,wBAAgB,IAAI,CAAC,MAAM,EAAE,iBAAiB,EAAE,OAAO,UAAQ,GAAG,EAAE,CAsGnE"}
package/dist/lib/ir.js CHANGED
@@ -1,8 +1,10 @@
1
1
  import { methods } from "@sdk-it/core/paths.js";
2
2
  import { resolveRef } from "@sdk-it/core/ref.js";
3
- import { camelcase, snakecase } from "@sdk-it/core/utils.js";
3
+ import { snakecase } from "@sdk-it/core/utils.js";
4
4
  import { toResource } from "./guess/guess-resource.js";
5
- import { coeraceConfig } from "./options.js";
5
+ import {
6
+ coeraceConfig as coerceConfig
7
+ } from "./options.js";
6
8
  import { extractOverviewDocs } from "./overview-docs/overview-docs.js";
7
9
  import { toPagination } from "./pagination/pagination.js";
8
10
  import { tuneRequestBody } from "./tune-request-body.js";
@@ -28,25 +30,25 @@ function findUniqueOperationId(usedOperationIds, initialId, choices, formatter)
28
30
  return uniqueOperationId;
29
31
  }
30
32
  function toIR(config, verbose = false) {
31
- const coearcedConfig = coeraceConfig(config);
33
+ const coercedConfig = coerceConfig(config);
32
34
  if ("x-sdk-augmented" in config.spec) {
33
35
  return config.spec;
34
36
  }
35
37
  const paths = {};
36
38
  const usedOperationIds = /* @__PURE__ */ new Set();
37
- for (const [path, pathItem] of Object.entries(coearcedConfig.spec.paths)) {
39
+ for (const [path, pathItem] of Object.entries(coercedConfig.spec.paths)) {
38
40
  const fixedPath = path.replace(/:([^/]+)/g, "{$1}");
39
41
  for (const [method, operation] of Object.entries(pathItem)) {
40
42
  if (!methods.includes(method)) {
41
43
  continue;
42
44
  }
43
45
  const { name } = toResource(operation, fixedPath, method);
44
- const operationTag = coearcedConfig.tag(operation, fixedPath);
46
+ const operationTag = coercedConfig.tag(operation, fixedPath);
45
47
  const operationId = findUniqueOperationId(
46
48
  usedOperationIds,
47
- coearcedConfig.operationId(operation, fixedPath, method),
49
+ coercedConfig.operationId(operation, fixedPath, method),
48
50
  [operationTag, method, fixedPath.split("/").filter(Boolean).join("")],
49
- (id) => coearcedConfig.operationId(
51
+ (id) => coercedConfig.operationId(
50
52
  { ...operation, operationId: id },
51
53
  fixedPath,
52
54
  method
@@ -56,7 +58,7 @@ function toIR(config, verbose = false) {
56
58
  const parameters = [
57
59
  ...pathItem.parameters ?? [],
58
60
  ...operation.parameters ?? []
59
- ].map((it) => resolveRef(coearcedConfig.spec, it));
61
+ ].map((it) => resolveRef(coercedConfig.spec, it));
60
62
  const tunedOperation = {
61
63
  ...operation,
62
64
  parameters,
@@ -66,13 +68,13 @@ function toIR(config, verbose = false) {
66
68
  // todo: do not transfer casing unless tag cannot be valid identifier
67
69
  operationId,
68
70
  responses: resolveResponses(
69
- coearcedConfig.spec,
71
+ coercedConfig.spec,
70
72
  operationId,
71
73
  operation,
72
- coearcedConfig.responses
74
+ coercedConfig.responses
73
75
  ),
74
76
  requestBody: tuneRequestBody(
75
- coearcedConfig.spec,
77
+ coercedConfig.spec,
76
78
  operationId,
77
79
  // camelcase(`${name} ${operationTag}`),
78
80
  operation,
@@ -80,10 +82,10 @@ function toIR(config, verbose = false) {
80
82
  operation.security ?? []
81
83
  )
82
84
  };
83
- if (coearcedConfig.pagination.enabled) {
84
- if (coearcedConfig.pagination.guess) {
85
+ if (coercedConfig.pagination.enabled) {
86
+ if (coercedConfig.pagination.guess) {
85
87
  tunedOperation["x-pagination"] = toPagination(
86
- coearcedConfig.spec,
88
+ coercedConfig.spec,
87
89
  tunedOperation
88
90
  );
89
91
  }
@@ -99,21 +101,21 @@ function toIR(config, verbose = false) {
99
101
  }
100
102
  }
101
103
  fixSpec(
102
- coearcedConfig.spec,
103
- Object.values(coearcedConfig.spec.components.schemas)
104
+ coercedConfig.spec,
105
+ Object.values(coercedConfig.spec.components.schemas)
104
106
  );
105
107
  if (verbose) {
106
108
  const newRefs = [];
107
109
  expandSpec(
108
- coearcedConfig.spec,
109
- coearcedConfig.spec.components.schemas,
110
+ coercedConfig.spec,
111
+ coercedConfig.spec.components.schemas,
110
112
  newRefs
111
113
  );
112
114
  }
113
115
  return {
114
- ...coearcedConfig.spec,
116
+ ...coercedConfig.spec,
115
117
  paths,
116
- "x-docs": extractOverviewDocs(coearcedConfig.spec),
118
+ "x-docs": extractOverviewDocs(coercedConfig.spec),
117
119
  "x-sdk-augmented": true
118
120
  };
119
121
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/ir.ts"],
4
- "sourcesContent": ["import type {\n OperationObject,\n ParameterObject,\n PathsObject,\n SchemaObject,\n} from 'openapi3-ts/oas31';\n\nimport { type Method, methods } from '@sdk-it/core/paths.js';\nimport { resolveRef } from '@sdk-it/core/ref.js';\nimport { camelcase, snakecase } from '@sdk-it/core/utils.js';\n\nimport { toResource } from './guess/guess-resource.js';\nimport { type GenerateSdkConfig, coeraceConfig } from './options.js';\nimport { extractOverviewDocs } from './overview-docs/overview-docs.js';\nimport { toPagination } from './pagination/pagination.js';\nimport { tuneRequestBody } from './tune-request-body.js';\nimport { resolveResponses } from './tune-response.js';\nimport { expandSpec, fixSpec } from './tune.js';\nimport type { IR, TunedOperationObject } from './types.js';\n\nfunction findUniqueOperationId(\n usedOperationIds: Set<string>,\n initialId: string,\n choices: string[],\n formatter: (id: string) => string,\n) {\n let counter = 1;\n let uniqueOperationId = formatter(initialId);\n\n while (usedOperationIds.has(uniqueOperationId)) {\n // Try each prepend option\n const prependIndex = Math.min(counter - 1, choices.length - 1);\n const prefix = choices[prependIndex];\n\n if (prependIndex < choices.length - 1) {\n // Using one of the prepend options\n uniqueOperationId = formatter(\n `${prefix}${initialId.charAt(0).toUpperCase() + initialId.slice(1)}`,\n );\n } else {\n // If we've exhausted all prepend options, start adding numbers\n uniqueOperationId = formatter(\n `${prefix}${initialId.charAt(0).toUpperCase() + initialId.slice(1)}${counter - choices.length + 1}`,\n );\n }\n counter++;\n }\n\n return uniqueOperationId;\n}\n\nexport function toIR(config: GenerateSdkConfig, verbose = false): IR {\n const coearcedConfig = coeraceConfig(config);\n if ('x-sdk-augmented' in config.spec) {\n return config.spec as IR; // Already augmented\n }\n\n const paths: PathsObject = {};\n const usedOperationIds = new Set<string>();\n\n for (const [path, pathItem] of Object.entries(coearcedConfig.spec.paths)) {\n // Convert Express-style routes (:param) to OpenAPI-style routes ({param})\n const fixedPath = path.replace(/:([^/]+)/g, '{$1}');\n for (const [method, operation] of Object.entries(pathItem) as [\n Method,\n OperationObject,\n ][]) {\n if (!methods.includes(method)) {\n continue;\n }\n const { name } = toResource(operation, fixedPath, method);\n const operationTag = coearcedConfig.tag(operation, fixedPath);\n const operationId = findUniqueOperationId(\n usedOperationIds,\n coearcedConfig.operationId(operation, fixedPath, method),\n [operationTag, method, fixedPath.split('/').filter(Boolean).join('')],\n (id) =>\n coearcedConfig.operationId(\n { ...operation, operationId: id },\n fixedPath,\n method,\n ),\n );\n usedOperationIds.add(operationId);\n\n const parameters = [\n ...(pathItem.parameters ?? []),\n ...(operation.parameters ?? []),\n ].map((it) => resolveRef<ParameterObject>(coearcedConfig.spec, it));\n\n const tunedOperation: TunedOperationObject = {\n ...operation,\n parameters,\n 'x-fn-name': name,\n 'x-fn-group': operationTag,\n tags: [snakecase(operationTag)], // todo: do not transfer casing unless tag cannot be valid identifier\n operationId: operationId,\n responses: resolveResponses(\n coearcedConfig.spec,\n operationId,\n operation,\n coearcedConfig.responses,\n ),\n requestBody: tuneRequestBody(\n coearcedConfig.spec,\n operationId,\n // camelcase(`${name} ${operationTag}`),\n operation,\n parameters,\n operation.security ?? [],\n ),\n };\n\n if (coearcedConfig.pagination.enabled) {\n if (coearcedConfig.pagination.guess) {\n tunedOperation['x-pagination'] = toPagination(\n coearcedConfig.spec,\n tunedOperation,\n );\n }\n } else {\n delete tunedOperation['x-pagination'];\n }\n\n Object.assign(paths, {\n [fixedPath]: {\n ...paths[fixedPath],\n [method]: tunedOperation,\n },\n });\n }\n }\n\n fixSpec(\n coearcedConfig.spec,\n Object.values(coearcedConfig.spec.components.schemas),\n );\n\n if (verbose) {\n const newRefs: { name: string; value: SchemaObject }[] = [];\n expandSpec(\n coearcedConfig.spec,\n coearcedConfig.spec.components.schemas,\n newRefs,\n );\n }\n\n return {\n ...coearcedConfig.spec,\n paths,\n 'x-docs': extractOverviewDocs(coearcedConfig.spec),\n 'x-sdk-augmented': true,\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type {\n OperationObject,\n ParameterObject,\n PathsObject,\n SchemaObject,\n} from 'openapi3-ts/oas31';\n\nimport { type Method, methods } from '@sdk-it/core/paths.js';\nimport { resolveRef } from '@sdk-it/core/ref.js';\nimport { snakecase } from '@sdk-it/core/utils.js';\n\nimport { toResource } from './guess/guess-resource.js';\nimport {\n type GenerateSdkConfig,\n coeraceConfig as coerceConfig,\n} from './options.js';\nimport { extractOverviewDocs } from './overview-docs/overview-docs.js';\nimport { toPagination } from './pagination/pagination.js';\nimport { tuneRequestBody } from './tune-request-body.js';\nimport { resolveResponses } from './tune-response.js';\nimport { expandSpec, fixSpec } from './tune.js';\nimport type { IR, TunedOperationObject } from './types.js';\n\nfunction findUniqueOperationId(\n usedOperationIds: Set<string>,\n initialId: string,\n choices: string[],\n formatter: (id: string) => string,\n) {\n let counter = 1;\n let uniqueOperationId = formatter(initialId);\n\n while (usedOperationIds.has(uniqueOperationId)) {\n // Try each prepend option\n const prependIndex = Math.min(counter - 1, choices.length - 1);\n const prefix = choices[prependIndex];\n\n if (prependIndex < choices.length - 1) {\n // Using one of the prepend options\n uniqueOperationId = formatter(\n `${prefix}${initialId.charAt(0).toUpperCase() + initialId.slice(1)}`,\n );\n } else {\n // If we've exhausted all prepend options, start adding numbers\n uniqueOperationId = formatter(\n `${prefix}${initialId.charAt(0).toUpperCase() + initialId.slice(1)}${counter - choices.length + 1}`,\n );\n }\n counter++;\n }\n\n return uniqueOperationId;\n}\n\nexport function toIR(config: GenerateSdkConfig, verbose = false): IR {\n const coercedConfig = coerceConfig(config);\n if ('x-sdk-augmented' in config.spec) {\n return config.spec as IR; // Already augmented\n }\n\n const paths: PathsObject = {};\n const usedOperationIds = new Set<string>();\n\n for (const [path, pathItem] of Object.entries(coercedConfig.spec.paths)) {\n // Convert Express-style routes (:param) to OpenAPI-style routes ({param})\n const fixedPath = path.replace(/:([^/]+)/g, '{$1}');\n for (const [method, operation] of Object.entries(pathItem) as [\n Method,\n OperationObject,\n ][]) {\n if (!methods.includes(method)) {\n continue;\n }\n const { name } = toResource(operation, fixedPath, method);\n const operationTag = coercedConfig.tag(operation, fixedPath);\n const operationId = findUniqueOperationId(\n usedOperationIds,\n coercedConfig.operationId(operation, fixedPath, method),\n [operationTag, method, fixedPath.split('/').filter(Boolean).join('')],\n (id) =>\n coercedConfig.operationId(\n { ...operation, operationId: id },\n fixedPath,\n method,\n ),\n );\n usedOperationIds.add(operationId);\n\n const parameters = [\n ...(pathItem.parameters ?? []),\n ...(operation.parameters ?? []),\n ].map((it) => resolveRef<ParameterObject>(coercedConfig.spec, it));\n\n const tunedOperation: TunedOperationObject = {\n ...operation,\n parameters,\n 'x-fn-name': name,\n 'x-fn-group': operationTag,\n tags: [snakecase(operationTag)], // todo: do not transfer casing unless tag cannot be valid identifier\n operationId: operationId,\n responses: resolveResponses(\n coercedConfig.spec,\n operationId,\n operation,\n coercedConfig.responses,\n ),\n requestBody: tuneRequestBody(\n coercedConfig.spec,\n operationId,\n // camelcase(`${name} ${operationTag}`),\n operation,\n parameters,\n operation.security ?? [],\n ),\n };\n\n if (coercedConfig.pagination.enabled) {\n if (coercedConfig.pagination.guess) {\n tunedOperation['x-pagination'] = toPagination(\n coercedConfig.spec,\n tunedOperation,\n );\n }\n } else {\n delete tunedOperation['x-pagination'];\n }\n\n Object.assign(paths, {\n [fixedPath]: {\n ...paths[fixedPath],\n [method]: tunedOperation,\n },\n });\n }\n }\n\n fixSpec(\n coercedConfig.spec,\n Object.values(coercedConfig.spec.components.schemas),\n );\n\n if (verbose) {\n const newRefs: { name: string; value: SchemaObject }[] = [];\n expandSpec(\n coercedConfig.spec,\n coercedConfig.spec.components.schemas,\n newRefs,\n );\n }\n\n return {\n ...coercedConfig.spec,\n paths,\n 'x-docs': extractOverviewDocs(coercedConfig.spec),\n 'x-sdk-augmented': true,\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -67,7 +67,7 @@ export declare function coeraceConfig(config: GenerateSdkConfig): {
67
67
  operationId: (operation: OperationObject, path: string, method: string) => string;
68
68
  tag: (operation: OperationObject, path: string) => string;
69
69
  };
70
- export declare function coearcePaginationConfig(options: PaginationConfig | undefined | false): {
70
+ export declare function coercePaginationConfig(options: PaginationConfig | undefined | false): {
71
71
  guess: boolean;
72
72
  enabled: boolean;
73
73
  };
@@ -1 +1 @@
1
- {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/lib/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,eAAe,EACf,oBAAoB,EACrB,MAAM,mBAAmB,CAAC;AAO3B,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,aAAa,CAAC;IACpB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,UAAU,CAAC,EAAE,gBAAgB,GAAG,KAAK,CAAC;IACtC,WAAW,CAAC,EAAE,CACZ,SAAS,EAAE,eAAe,EAC1B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,KACX,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CAC5D;AACD,MAAM,WAAW,eAAe;IAC9B,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAIF,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,UAEnD;AAED,eAAO,MAAM,QAAQ,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAC/C,QAAQ,CAAC,IAAI,CAAC,iBAAiB,EAAE,aAAa,GAAG,KAAK,CAAC,CAkBxD,CAAC;AAEF,wBAAgB,aAAa,CAAC,MAAM,EAAE,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6BAzCxC,eAAe,QACpB,MAAM,UACJ,MAAM,KACX,MAAM;qBACO,eAAe,QAAQ,MAAM,KAAK,MAAM;EAqE3D;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,gBAAgB,GAAG,SAAS,GAAG,KAAK;;;EAmB9C"}
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/lib/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,eAAe,EACf,oBAAoB,EACrB,MAAM,mBAAmB,CAAC;AAO3B,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,aAAa,CAAC;IACpB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,UAAU,CAAC,EAAE,gBAAgB,GAAG,KAAK,CAAC;IACtC,WAAW,CAAC,EAAE,CACZ,SAAS,EAAE,eAAe,EAC1B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,KACX,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CAC5D;AACD,MAAM,WAAW,eAAe;IAC9B,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAIF,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,UAEnD;AAED,eAAO,MAAM,QAAQ,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAC/C,QAAQ,CAAC,IAAI,CAAC,iBAAiB,EAAE,aAAa,GAAG,KAAK,CAAC,CAkBxD,CAAC;AAEF,wBAAgB,aAAa,CAAC,MAAM,EAAE,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6BAzCxC,eAAe,QACpB,MAAM,UACJ,MAAM,KACX,MAAM;qBACO,eAAe,QAAQ,MAAM,KAAK,MAAM;EAqE3D;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,gBAAgB,GAAG,SAAS,GAAG,KAAK;;;EAmB9C"}
@@ -21,7 +21,7 @@ const defaults = {
21
21
  };
22
22
  function coeraceConfig(config) {
23
23
  return {
24
- pagination: coearcePaginationConfig(config.pagination),
24
+ pagination: coercePaginationConfig(config.pagination),
25
25
  responses: config.responses ?? {},
26
26
  spec: {
27
27
  ...config.spec,
@@ -52,7 +52,7 @@ function coeraceConfig(config) {
52
52
  tag: config.tag ?? defaults.tag
53
53
  };
54
54
  }
55
- function coearcePaginationConfig(options) {
55
+ function coercePaginationConfig(options) {
56
56
  if (options === void 0) {
57
57
  return {
58
58
  guess: true,
@@ -72,8 +72,8 @@ function coearcePaginationConfig(options) {
72
72
  }
73
73
  export {
74
74
  cleanOperationId,
75
- coearcePaginationConfig,
76
75
  coeraceConfig,
76
+ coercePaginationConfig,
77
77
  defaults
78
78
  };
79
79
  //# sourceMappingURL=options.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/options.ts"],
4
- "sourcesContent": ["import type {\n OpenAPIObject,\n OperationObject,\n SecuritySchemeObject,\n} from 'openapi3-ts/oas31';\n\nimport { camelcase, resolveRef } from '@sdk-it/core';\n\nimport { determineGenericTag, sanitizeTag } from './tag.js';\nimport type { IR } from './types.js';\n\nexport interface GenerateSdkConfig {\n spec: OpenAPIObject;\n responses?: ResponsesConfig;\n pagination?: PaginationConfig | false;\n operationId?: (\n operation: OperationObject,\n path: string,\n method: string,\n ) => string;\n tag?: (operation: OperationObject, path: string) => string;\n}\nexport interface ResponsesConfig {\n flattenErrorResponses?: boolean;\n}\n\nexport type PaginationConfig = {\n guess?: boolean;\n};\nfunction removeHyphensBeforeDigits(text: string): string {\n return text.replace(/-(?=\\d)/g, '');\n}\nexport function cleanOperationId(operationId: string) {\n return camelcase(operationId.split('#').pop()!);\n}\n\nexport const defaults: Partial<GenerateSdkConfig> &\n Required<Pick<GenerateSdkConfig, 'operationId' | 'tag'>> = {\n operationId: (operation, path, method) => {\n if (operation.operationId) {\n return cleanOperationId(operation.operationId);\n }\n\n return camelcase(\n [method, ...path.replace(/[\\\\/\\\\{\\\\}]/g, ' ').split(' ')]\n .filter(Boolean)\n .join(' ')\n .trim(),\n );\n },\n tag: (operation, path) => {\n return operation.tags?.[0]\n ? sanitizeTag(operation.tags?.[0])\n : determineGenericTag(path, operation);\n },\n};\n\nexport function coeraceConfig(config: GenerateSdkConfig) {\n return {\n pagination: coearcePaginationConfig(config.pagination),\n responses: config.responses ?? {},\n spec: {\n ...config.spec,\n components: {\n ...config.spec.components,\n schemas: config.spec.components?.schemas ?? {},\n securitySchemes: Object.fromEntries(\n Object.entries(config.spec.components?.securitySchemes ?? {}).map(\n ([name, schema]) => [\n name,\n resolveRef<SecuritySchemeObject>(config.spec, schema),\n ],\n ),\n ),\n },\n paths: config.spec.paths ?? {},\n 'x-docs': [],\n 'x-tagGroups': config.spec['x-tagGroups'] ?? [\n {\n name: 'API',\n tags: config.spec.tags?.map((tag) => tag.name) ?? [],\n },\n ],\n servers: config.spec.servers ?? [],\n tags: config.spec.tags ?? [],\n } satisfies IR,\n operationId: config.operationId ?? defaults.operationId,\n tag: config.tag ?? defaults.tag,\n };\n}\n\nexport function coearcePaginationConfig(\n options: PaginationConfig | undefined | false,\n) {\n if (options === undefined) {\n return {\n guess: true,\n enabled: true,\n };\n }\n if (options === false) {\n return {\n enabled: false,\n guess: false,\n };\n }\n // If options is true, we assume pagination is enabled with guessing\n return {\n guess: options.guess ?? true,\n enabled: true,\n };\n}\n"],
5
- "mappings": "AAMA,SAAS,WAAW,kBAAkB;AAEtC,SAAS,qBAAqB,mBAAmB;AAqBjD,SAAS,0BAA0B,MAAsB;AACvD,SAAO,KAAK,QAAQ,YAAY,EAAE;AACpC;AACO,SAAS,iBAAiB,aAAqB;AACpD,SAAO,UAAU,YAAY,MAAM,GAAG,EAAE,IAAI,CAAE;AAChD;AAEO,MAAM,WACgD;AAAA,EAC3D,aAAa,CAAC,WAAW,MAAM,WAAW;AACxC,QAAI,UAAU,aAAa;AACzB,aAAO,iBAAiB,UAAU,WAAW;AAAA,IAC/C;AAEA,WAAO;AAAA,MACL,CAAC,QAAQ,GAAG,KAAK,QAAQ,gBAAgB,GAAG,EAAE,MAAM,GAAG,CAAC,EACrD,OAAO,OAAO,EACd,KAAK,GAAG,EACR,KAAK;AAAA,IACV;AAAA,EACF;AAAA,EACA,KAAK,CAAC,WAAW,SAAS;AACxB,WAAO,UAAU,OAAO,CAAC,IACrB,YAAY,UAAU,OAAO,CAAC,CAAC,IAC/B,oBAAoB,MAAM,SAAS;AAAA,EACzC;AACF;AAEO,SAAS,cAAc,QAA2B;AACvD,SAAO;AAAA,IACL,YAAY,wBAAwB,OAAO,UAAU;AAAA,IACrD,WAAW,OAAO,aAAa,CAAC;AAAA,IAChC,MAAM;AAAA,MACJ,GAAG,OAAO;AAAA,MACV,YAAY;AAAA,QACV,GAAG,OAAO,KAAK;AAAA,QACf,SAAS,OAAO,KAAK,YAAY,WAAW,CAAC;AAAA,QAC7C,iBAAiB,OAAO;AAAA,UACtB,OAAO,QAAQ,OAAO,KAAK,YAAY,mBAAmB,CAAC,CAAC,EAAE;AAAA,YAC5D,CAAC,CAAC,MAAM,MAAM,MAAM;AAAA,cAClB;AAAA,cACA,WAAiC,OAAO,MAAM,MAAM;AAAA,YACtD;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,MACA,OAAO,OAAO,KAAK,SAAS,CAAC;AAAA,MAC7B,UAAU,CAAC;AAAA,MACX,eAAe,OAAO,KAAK,aAAa,KAAK;AAAA,QAC3C;AAAA,UACE,MAAM;AAAA,UACN,MAAM,OAAO,KAAK,MAAM,IAAI,CAAC,QAAQ,IAAI,IAAI,KAAK,CAAC;AAAA,QACrD;AAAA,MACF;AAAA,MACA,SAAS,OAAO,KAAK,WAAW,CAAC;AAAA,MACjC,MAAM,OAAO,KAAK,QAAQ,CAAC;AAAA,IAC7B;AAAA,IACA,aAAa,OAAO,eAAe,SAAS;AAAA,IAC5C,KAAK,OAAO,OAAO,SAAS;AAAA,EAC9B;AACF;AAEO,SAAS,wBACd,SACA;AACA,MAAI,YAAY,QAAW;AACzB,WAAO;AAAA,MACL,OAAO;AAAA,MACP,SAAS;AAAA,IACX;AAAA,EACF;AACA,MAAI,YAAY,OAAO;AACrB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO,QAAQ,SAAS;AAAA,IACxB,SAAS;AAAA,EACX;AACF;",
4
+ "sourcesContent": ["import type {\n OpenAPIObject,\n OperationObject,\n SecuritySchemeObject,\n} from 'openapi3-ts/oas31';\n\nimport { camelcase, resolveRef } from '@sdk-it/core';\n\nimport { determineGenericTag, sanitizeTag } from './tag.js';\nimport type { IR } from './types.js';\n\nexport interface GenerateSdkConfig {\n spec: OpenAPIObject;\n responses?: ResponsesConfig;\n pagination?: PaginationConfig | false;\n operationId?: (\n operation: OperationObject,\n path: string,\n method: string,\n ) => string;\n tag?: (operation: OperationObject, path: string) => string;\n}\nexport interface ResponsesConfig {\n flattenErrorResponses?: boolean;\n}\n\nexport type PaginationConfig = {\n guess?: boolean;\n};\nfunction removeHyphensBeforeDigits(text: string): string {\n return text.replace(/-(?=\\d)/g, '');\n}\nexport function cleanOperationId(operationId: string) {\n return camelcase(operationId.split('#').pop()!);\n}\n\nexport const defaults: Partial<GenerateSdkConfig> &\n Required<Pick<GenerateSdkConfig, 'operationId' | 'tag'>> = {\n operationId: (operation, path, method) => {\n if (operation.operationId) {\n return cleanOperationId(operation.operationId);\n }\n\n return camelcase(\n [method, ...path.replace(/[\\\\/\\\\{\\\\}]/g, ' ').split(' ')]\n .filter(Boolean)\n .join(' ')\n .trim(),\n );\n },\n tag: (operation, path) => {\n return operation.tags?.[0]\n ? sanitizeTag(operation.tags?.[0])\n : determineGenericTag(path, operation);\n },\n};\n\nexport function coeraceConfig(config: GenerateSdkConfig) {\n return {\n pagination: coercePaginationConfig(config.pagination),\n responses: config.responses ?? {},\n spec: {\n ...config.spec,\n components: {\n ...config.spec.components,\n schemas: config.spec.components?.schemas ?? {},\n securitySchemes: Object.fromEntries(\n Object.entries(config.spec.components?.securitySchemes ?? {}).map(\n ([name, schema]) => [\n name,\n resolveRef<SecuritySchemeObject>(config.spec, schema),\n ],\n ),\n ),\n },\n paths: config.spec.paths ?? {},\n 'x-docs': [],\n 'x-tagGroups': config.spec['x-tagGroups'] ?? [\n {\n name: 'API',\n tags: config.spec.tags?.map((tag) => tag.name) ?? [],\n },\n ],\n servers: config.spec.servers ?? [],\n tags: config.spec.tags ?? [],\n } satisfies IR,\n operationId: config.operationId ?? defaults.operationId,\n tag: config.tag ?? defaults.tag,\n };\n}\n\nexport function coercePaginationConfig(\n options: PaginationConfig | undefined | false,\n) {\n if (options === undefined) {\n return {\n guess: true,\n enabled: true,\n };\n }\n if (options === false) {\n return {\n enabled: false,\n guess: false,\n };\n }\n // If options is true, we assume pagination is enabled with guessing\n return {\n guess: options.guess ?? true,\n enabled: true,\n };\n}\n"],
5
+ "mappings": "AAMA,SAAS,WAAW,kBAAkB;AAEtC,SAAS,qBAAqB,mBAAmB;AAqBjD,SAAS,0BAA0B,MAAsB;AACvD,SAAO,KAAK,QAAQ,YAAY,EAAE;AACpC;AACO,SAAS,iBAAiB,aAAqB;AACpD,SAAO,UAAU,YAAY,MAAM,GAAG,EAAE,IAAI,CAAE;AAChD;AAEO,MAAM,WACgD;AAAA,EAC3D,aAAa,CAAC,WAAW,MAAM,WAAW;AACxC,QAAI,UAAU,aAAa;AACzB,aAAO,iBAAiB,UAAU,WAAW;AAAA,IAC/C;AAEA,WAAO;AAAA,MACL,CAAC,QAAQ,GAAG,KAAK,QAAQ,gBAAgB,GAAG,EAAE,MAAM,GAAG,CAAC,EACrD,OAAO,OAAO,EACd,KAAK,GAAG,EACR,KAAK;AAAA,IACV;AAAA,EACF;AAAA,EACA,KAAK,CAAC,WAAW,SAAS;AACxB,WAAO,UAAU,OAAO,CAAC,IACrB,YAAY,UAAU,OAAO,CAAC,CAAC,IAC/B,oBAAoB,MAAM,SAAS;AAAA,EACzC;AACF;AAEO,SAAS,cAAc,QAA2B;AACvD,SAAO;AAAA,IACL,YAAY,uBAAuB,OAAO,UAAU;AAAA,IACpD,WAAW,OAAO,aAAa,CAAC;AAAA,IAChC,MAAM;AAAA,MACJ,GAAG,OAAO;AAAA,MACV,YAAY;AAAA,QACV,GAAG,OAAO,KAAK;AAAA,QACf,SAAS,OAAO,KAAK,YAAY,WAAW,CAAC;AAAA,QAC7C,iBAAiB,OAAO;AAAA,UACtB,OAAO,QAAQ,OAAO,KAAK,YAAY,mBAAmB,CAAC,CAAC,EAAE;AAAA,YAC5D,CAAC,CAAC,MAAM,MAAM,MAAM;AAAA,cAClB;AAAA,cACA,WAAiC,OAAO,MAAM,MAAM;AAAA,YACtD;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,MACA,OAAO,OAAO,KAAK,SAAS,CAAC;AAAA,MAC7B,UAAU,CAAC;AAAA,MACX,eAAe,OAAO,KAAK,aAAa,KAAK;AAAA,QAC3C;AAAA,UACE,MAAM;AAAA,UACN,MAAM,OAAO,KAAK,MAAM,IAAI,CAAC,QAAQ,IAAI,IAAI,KAAK,CAAC;AAAA,QACrD;AAAA,MACF;AAAA,MACA,SAAS,OAAO,KAAK,WAAW,CAAC;AAAA,MACjC,MAAM,OAAO,KAAK,QAAQ,CAAC;AAAA,IAC7B;AAAA,IACA,aAAa,OAAO,eAAe,SAAS;AAAA,IAC5C,KAAK,OAAO,OAAO,SAAS;AAAA,EAC9B;AACF;AAEO,SAAS,uBACd,SACA;AACA,MAAI,YAAY,QAAW;AACzB,WAAO;AAAA,MACL,OAAO;AAAA,MACP,SAAS;AAAA,IACX;AAAA,EACF;AACA,MAAI,YAAY,OAAO;AACrB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO,QAAQ,SAAS;AAAA,IACxB,SAAS;AAAA,EACX;AACF;",
6
6
  "names": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"guess-pagination.d.ts","sourceRoot":"","sources":["../../../src/lib/pagination/guess-pagination.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,YAAY,EAEb,MAAM,mBAAmB,CAAC;AAK3B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGxD,UAAU,oBAAoB;IAC5B,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;CAC7C;AAED,MAAM,WAAW,sBAAuB,SAAQ,oBAAoB;IAClE,IAAI,EAAE,QAAQ,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAqB,SAAQ,oBAAoB;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB,EAAE,MAAM,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,sBAAuB,SAAQ,oBAAoB;IAClE,IAAI,EAAE,QAAQ,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAmB,SAAQ,oBAAoB;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,eAAe,GACvB,CAAC,CACG,sBAAsB,GACtB,oBAAoB,GACpB,sBAAsB,CACzB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,GACvC,kBAAkB,CAAC;AAIvB,eAAO,MAAM,oBAAoB,EAAE,MAAM,EAKxC,CAAC;AAEF,eAAO,MAAM,2BAA2B,EAAE,MAAM,EAU/C,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,MAAM,EAMvC,CAAC;AAGF,eAAO,MAAM,iBAAiB,EAAE,MAAM,EAUrC,CAAC;AAGF,eAAO,MAAM,cAAc,EAAE,MAAM,EAWlC,CAAC;AAGF,eAAO,MAAM,oBAAoB,EAAE,MAAM,EAUxC,CAAC;AA4IF;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,oBAAoB,EAC/B,IAAI,CAAC,EAAE,YAAY,EACnB,QAAQ,CAAC,EAAE,YAAY,GACtB,eAAe,CAqCjB"}
1
+ {"version":3,"file":"guess-pagination.d.ts","sourceRoot":"","sources":["../../../src/lib/pagination/guess-pagination.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,YAAY,EAEb,MAAM,mBAAmB,CAAC;AAM3B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGxD,UAAU,oBAAoB;IAC5B,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;CAC7C;AAED,MAAM,WAAW,sBAAuB,SAAQ,oBAAoB;IAClE,IAAI,EAAE,QAAQ,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAqB,SAAQ,oBAAoB;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB,EAAE,MAAM,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,sBAAuB,SAAQ,oBAAoB;IAClE,IAAI,EAAE,QAAQ,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAmB,SAAQ,oBAAoB;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,eAAe,GACvB,CAAC,CACG,sBAAsB,GACtB,oBAAoB,GACpB,sBAAsB,CACzB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,GACvC,kBAAkB,CAAC;AAIvB,eAAO,MAAM,oBAAoB,EAAE,MAAM,EAKxC,CAAC;AAEF,eAAO,MAAM,2BAA2B,EAAE,MAAM,EAU/C,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,MAAM,EAMvC,CAAC;AAGF,eAAO,MAAM,iBAAiB,EAAE,MAAM,EAUrC,CAAC;AAGF,eAAO,MAAM,cAAc,EAAE,MAAM,EAWlC,CAAC;AAGF,eAAO,MAAM,oBAAoB,EAAE,MAAM,EAUxC,CAAC;AA+JF;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,oBAAoB,EAC/B,IAAI,CAAC,EAAE,YAAY,EACnB,QAAQ,CAAC,EAAE,YAAY,GACtB,eAAe,CAqCjB"}
@@ -1,5 +1,6 @@
1
1
  import { isRef } from "@sdk-it/core/ref.js";
2
2
  import { isEmpty } from "@sdk-it/core/utils.js";
3
+ import { coerceTypes } from "../tune.js";
3
4
  import { getHasMoreName, getItemsName } from "./pagination-result.js";
4
5
  const OFFSET_PARAM_REGEXES = [
5
6
  /\boffset\b/i,
@@ -95,7 +96,7 @@ function findParamAndKeyword(queryParams, regexes, excludeParamName) {
95
96
  }
96
97
  return null;
97
98
  }
98
- function coearceParameters(parameters) {
99
+ function coerceParameters(parameters) {
99
100
  const cleanedParameters = [];
100
101
  for (const param of parameters) {
101
102
  if (!param.schema) {
@@ -104,6 +105,21 @@ function coearceParameters(parameters) {
104
105
  if (isRef(param.schema)) {
105
106
  continue;
106
107
  }
108
+ if (param.schema.anyOf || param.schema.oneOf || param.schema.allOf) {
109
+ const schemas = (param.schema.anyOf || param.schema.oneOf || param.schema.allOf || []).filter((it) => !isRef(it));
110
+ schemas.forEach((schema) => {
111
+ if (schema.type) {
112
+ cleanedParameters.push({
113
+ ...param,
114
+ schema: {
115
+ ...schema,
116
+ type: coerceTypes(schema)
117
+ }
118
+ });
119
+ }
120
+ });
121
+ continue;
122
+ }
107
123
  if (!param.schema.type) {
108
124
  continue;
109
125
  }
@@ -112,7 +128,7 @@ function coearceParameters(parameters) {
112
128
  ...param,
113
129
  schema: {
114
130
  ...param.schema,
115
- type: Array.isArray(param.schema.type) ? param.schema.type : [param.schema.type]
131
+ type: coerceTypes(param.schema)
116
132
  }
117
133
  });
118
134
  }
@@ -120,7 +136,7 @@ function coearceParameters(parameters) {
120
136
  return cleanedParameters;
121
137
  }
122
138
  function isOffsetPagination(operation, parameters) {
123
- const params = coearceParameters(parameters).filter(
139
+ const params = coerceParameters(parameters).filter(
124
140
  (it) => it.schema.type.includes("integer") || it.schema.type.includes("number")
125
141
  );
126
142
  const offsetMatch = findParamAndKeyword(params, OFFSET_PARAM_REGEXES);
@@ -140,7 +156,7 @@ function isOffsetPagination(operation, parameters) {
140
156
  };
141
157
  }
142
158
  function isPagePagination(operation, parameters) {
143
- const params = coearceParameters(parameters).filter(
159
+ const params = coerceParameters(parameters).filter(
144
160
  (it) => it.schema.type.includes("integer") || it.schema.type.includes("number")
145
161
  );
146
162
  if (params.length < 2) return null;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/pagination/guess-pagination.ts"],
4
- "sourcesContent": ["import type {\n ReferenceObject,\n SchemaObject,\n SchemasObject,\n} from 'openapi3-ts/oas31';\n\nimport { isRef } from '@sdk-it/core/ref.js';\nimport { isEmpty } from '@sdk-it/core/utils.js';\n\nimport type { TunedOperationObject } from '../types.js';\nimport { getHasMoreName, getItemsName } from './pagination-result.js';\n\ninterface PaginationResultBase {\n type: 'offset' | 'page' | 'cursor' | 'none';\n}\n\nexport interface OffsetPaginationResult extends PaginationResultBase {\n type: 'offset';\n offsetParamName: string;\n offsetKeyword: string; // The actual part of param name that matched\n limitParamName: string;\n limitKeyword: string; // The actual part of param name that matched\n}\n\nexport interface PagePaginationResult extends PaginationResultBase {\n type: 'page';\n pageNumberParamName: string;\n pageNumberKeyword: string;\n pageSizeParamName: string;\n pageSizeKeyword: string;\n}\n\nexport interface CursorPaginationResult extends PaginationResultBase {\n type: 'cursor';\n cursorParamName: string;\n cursorKeyword: string;\n limitParamName: string;\n limitKeyword: string;\n}\n\nexport interface NoPaginationResult extends PaginationResultBase {\n type: 'none';\n reason: string;\n}\n\nexport type PaginationGuess =\n | ((\n | OffsetPaginationResult\n | PagePaginationResult\n | CursorPaginationResult\n ) & { items: string; hasMore: string })\n | NoPaginationResult;\n\n// --- Keyword Regex Definitions ---\n\nexport const OFFSET_PARAM_REGEXES: RegExp[] = [\n /\\boffset\\b/i,\n /\\bskip\\b/i,\n /\\bstart(?:ing_at|_index)?\\b/i, // e.g., start, starting_at, start_index\n /\\bfrom\\b/i,\n];\n\nexport const GENERIC_LIMIT_PARAM_REGEXES: RegExp[] = [\n /\\blimit\\b/i,\n /\\bcount\\b/i,\n /\\b(?:page_?)?size\\b/i, // e.g., size, page_size, pagesize\n /\\bmax_results\\b/i,\n /\\bnum_results\\b/i,\n /\\bshow\\b/i, // Can sometimes mean limit\n /\\bper_?page\\b/i, // e.g., per_page, perpage\n /\\bper-page\\b/i,\n /\\btake\\b/i,\n];\n\nexport const PAGE_NUMBER_REGEXES: RegExp[] = [\n // /^(currentPage)?page$/i, // Exact match for \"page\"\n // /^currentPage$/i, // Exact match for \"currentPage\"\n /^p$/i, // Exact match for \"p\" (common shorthand)\n // /\\bpage_?(?:number|no|num|idx|index)\\b/i, // e.g., page_number, pageNumber, page_num, page_idx\n /^(current)?_?page(_?)(?:number|no|num|idx|index)?\\b/i,\n];\n\n// Regexes for parameters indicating page size (when used with page number)\nexport const PAGE_SIZE_REGEXES: RegExp[] = [\n /\\bpage_?size\\b/i, // e.g., page_size, pagesize\n /^size$/i, // Exact \"size\"\n // /\\bsize\\b/i, // Broader \"size\" - can be ambiguous, prefer more specific ones first\n /\\blimit\\b/i, // Limit is often used for page size\n /\\bcount\\b/i, // Count can also be used for page size\n /\\bper_?page\\b/i, // e.g., per_page, perpage\n /\\bper-page\\b/i,\n /\\bnum_?(?:items|records|results)\\b/i, // e.g., num_items, numitems\n /\\bresults_?per_?page\\b/i,\n];\n\n// Regexes for parameters indicating a cursor\nexport const CURSOR_REGEXES: RegExp[] = [\n /\\bmarker\\b/i,\n /\\bcursor\\b/i,\n /\\bafter(?:_?cursor)?\\b/i, // e.g., after, after_cursor\n /\\bbefore(?:_?cursor)?\\b/i, // e.g., before, before_cursor\n /\\b(next|prev|previous)_?(?:page_?)?token\\b/i, // e.g., next_page_token, nextPageToken, prev_token\n /\\b(next|prev|previous)_?cursor\\b/i, // e.g., next_cursor, previousCursor\n /\\bcontinuation(?:_?token)?\\b/i, // e.g., continuation, continuation_token\n /\\bpage(?:_?(token|id))?\\b/i, // e.g., after, after_cursor\n\n /\\bstart_?(?:key|cursor|token|after)\\b/i, // e.g., start_key, startCursor, startToken, startAfter\n];\n\n// Regexes for parameters indicating a limit when used with cursors\nexport const CURSOR_LIMIT_REGEXES: RegExp[] = [\n /\\blimit\\b/i,\n /\\bcount\\b/i,\n /\\bsize\\b/i, // General size\n /\\bfirst\\b/i, // Common in Relay-style cursor pagination (forward pagination)\n /\\blast\\b/i, // Common in Relay-style cursor pagination (backward pagination)\n /\\bpage_?size\\b/i, // Sometimes page_size is used with cursors\n /\\bnum_?(?:items|records|results)\\b/i, // e.g., num_items\n /\\bmax_?items\\b/i,\n /\\btake\\b/i,\n];\n\n// --- Helper Function ---\nfunction findParamAndKeyword(\n queryParams: { name: string }[],\n regexes: RegExp[],\n excludeParamName?: string,\n) {\n for (const param of queryParams) {\n if (param.name === excludeParamName) {\n continue;\n }\n for (const regex of regexes) {\n const match = param.name.match(regex);\n if (match) {\n return { param, keyword: match[0] }; // match[0] is the actual matched substring\n }\n }\n }\n return null;\n}\n\nfunction coearceParameters(\n parameters: { name: string; schema?: SchemaObject | ReferenceObject }[],\n) {\n const cleanedParameters: {\n name: string;\n schema: Omit<SchemaObject, 'type'> & {\n type: string[]; // Ensure type is always an array\n };\n }[] = [];\n for (const param of parameters) {\n if (!param.schema) {\n continue;\n }\n if (isRef(param.schema)) {\n continue;\n }\n if (!param.schema.type) {\n continue;\n }\n if (param.schema) {\n cleanedParameters.push({\n ...param,\n schema: {\n ...param.schema,\n type: Array.isArray(param.schema.type)\n ? param.schema.type\n : [param.schema.type],\n },\n });\n }\n }\n return cleanedParameters;\n}\n\nfunction isOffsetPagination(\n operation: TunedOperationObject,\n parameters: { name: string; schema?: SchemaObject | ReferenceObject }[],\n): OffsetPaginationResult | null {\n const params = coearceParameters(parameters).filter(\n (it) =>\n it.schema.type.includes('integer') || it.schema.type.includes('number'),\n );\n const offsetMatch = findParamAndKeyword(params, OFFSET_PARAM_REGEXES);\n\n if (!offsetMatch) return null;\n\n const limitMatch = findParamAndKeyword(\n params,\n GENERIC_LIMIT_PARAM_REGEXES,\n offsetMatch.param.name,\n );\n if (!limitMatch) return null;\n\n return {\n type: 'offset',\n offsetParamName: offsetMatch.param.name,\n offsetKeyword: offsetMatch.keyword,\n limitParamName: limitMatch.param.name,\n limitKeyword: limitMatch.keyword,\n };\n}\n\nfunction isPagePagination(\n operation: TunedOperationObject,\n parameters: { name: string; schema?: SchemaObject | ReferenceObject }[],\n): PagePaginationResult | null {\n const params = coearceParameters(parameters).filter(\n (it) =>\n it.schema.type.includes('integer') || it.schema.type.includes('number'),\n );\n\n if (params.length < 2) return null;\n\n const pageNoMatch = findParamAndKeyword(params, PAGE_NUMBER_REGEXES);\n if (!pageNoMatch) return null;\n\n const pageSizeMatch = findParamAndKeyword(\n params,\n PAGE_SIZE_REGEXES,\n pageNoMatch.param.name,\n );\n if (!pageSizeMatch) return null;\n\n return {\n type: 'page',\n pageNumberParamName: pageNoMatch.param.name,\n pageNumberKeyword: pageNoMatch.keyword,\n pageSizeParamName: pageSizeMatch.param.name,\n pageSizeKeyword: pageSizeMatch.keyword,\n };\n}\n\nfunction isCursorPagination(\n operation: TunedOperationObject,\n parameters: { name: string; schema?: SchemaObject | ReferenceObject }[] = [],\n): CursorPaginationResult | null {\n const queryParams = parameters;\n if (queryParams.length < 2) return null; // Need at least a cursor and a limit-like param\n\n const cursorMatch = findParamAndKeyword(queryParams, CURSOR_REGEXES);\n if (!cursorMatch) return null;\n\n const limitMatch = findParamAndKeyword(\n queryParams,\n CURSOR_LIMIT_REGEXES,\n cursorMatch.param.name,\n );\n if (!limitMatch) return null;\n\n return {\n type: 'cursor',\n cursorParamName: cursorMatch.param.name,\n cursorKeyword: cursorMatch.keyword,\n limitParamName: limitMatch.param.name,\n limitKeyword: limitMatch.keyword,\n };\n}\n\n/**\n * Guesses the pagination strategy of an OpenAPI operation based on its query parameters.\n * It checks for offset, page-based, and cursor-based pagination in that order.\n *\n * @param operation The OpenAPI operation object.\n * @returns A PaginationGuess object indicating the detected type and relevant parameters.\n */\nexport function guessPagination(\n operation: TunedOperationObject,\n body?: SchemaObject,\n response?: SchemaObject,\n): PaginationGuess {\n const bodyParameters =\n body && body.properties\n ? Object.entries(body.properties).map(([it, schema]) => ({\n name: it,\n schema,\n }))\n : [];\n const parameters = operation.parameters;\n\n if (isEmpty(operation.parameters) && isEmpty(bodyParameters)) {\n return { type: 'none', reason: 'no parameters' };\n }\n if (!response) {\n return { type: 'none', reason: 'no response' };\n }\n if (!response.properties) {\n return { type: 'none', reason: 'empty response' };\n }\n const properties = response.properties as SchemasObject;\n\n const itemsKey = getItemsName(properties);\n if (!itemsKey) {\n return { type: 'none', reason: 'no items key' };\n }\n const hasMoreKey = getHasMoreName(excludeKey(properties, itemsKey));\n\n if (!hasMoreKey) {\n return { type: 'none', reason: 'no hasMore key' };\n }\n const pagination =\n isOffsetPagination(operation, [...parameters, ...bodyParameters]) ||\n isPagePagination(operation, [...parameters, ...bodyParameters]) ||\n isCursorPagination(operation, [...parameters, ...bodyParameters]);\n return pagination\n ? { ...pagination, items: itemsKey, hasMore: hasMoreKey }\n : { type: 'none', reason: 'no pagination' };\n}\n\nfunction excludeKey<T extends Record<string, any>>(\n obj: T,\n key: string,\n): Omit<T, typeof key> {\n const { [key]: _, ...rest } = obj;\n return rest;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type {\n ReferenceObject,\n SchemaObject,\n SchemasObject,\n} from 'openapi3-ts/oas31';\n\nimport { isRef } from '@sdk-it/core/ref.js';\nimport { isEmpty } from '@sdk-it/core/utils.js';\n\nimport { coerceTypes } from '../tune.js';\nimport type { TunedOperationObject } from '../types.js';\nimport { getHasMoreName, getItemsName } from './pagination-result.js';\n\ninterface PaginationResultBase {\n type: 'offset' | 'page' | 'cursor' | 'none';\n}\n\nexport interface OffsetPaginationResult extends PaginationResultBase {\n type: 'offset';\n offsetParamName: string;\n offsetKeyword: string; // The actual part of param name that matched\n limitParamName: string;\n limitKeyword: string; // The actual part of param name that matched\n}\n\nexport interface PagePaginationResult extends PaginationResultBase {\n type: 'page';\n pageNumberParamName: string;\n pageNumberKeyword: string;\n pageSizeParamName: string;\n pageSizeKeyword: string;\n}\n\nexport interface CursorPaginationResult extends PaginationResultBase {\n type: 'cursor';\n cursorParamName: string;\n cursorKeyword: string;\n limitParamName: string;\n limitKeyword: string;\n}\n\nexport interface NoPaginationResult extends PaginationResultBase {\n type: 'none';\n reason: string;\n}\n\nexport type PaginationGuess =\n | ((\n | OffsetPaginationResult\n | PagePaginationResult\n | CursorPaginationResult\n ) & { items: string; hasMore: string })\n | NoPaginationResult;\n\n// --- Keyword Regex Definitions ---\n\nexport const OFFSET_PARAM_REGEXES: RegExp[] = [\n /\\boffset\\b/i,\n /\\bskip\\b/i,\n /\\bstart(?:ing_at|_index)?\\b/i, // e.g., start, starting_at, start_index\n /\\bfrom\\b/i,\n];\n\nexport const GENERIC_LIMIT_PARAM_REGEXES: RegExp[] = [\n /\\blimit\\b/i,\n /\\bcount\\b/i,\n /\\b(?:page_?)?size\\b/i, // e.g., size, page_size, pagesize\n /\\bmax_results\\b/i,\n /\\bnum_results\\b/i,\n /\\bshow\\b/i, // Can sometimes mean limit\n /\\bper_?page\\b/i, // e.g., per_page, perpage\n /\\bper-page\\b/i,\n /\\btake\\b/i,\n];\n\nexport const PAGE_NUMBER_REGEXES: RegExp[] = [\n // /^(currentPage)?page$/i, // Exact match for \"page\"\n // /^currentPage$/i, // Exact match for \"currentPage\"\n /^p$/i, // Exact match for \"p\" (common shorthand)\n // /\\bpage_?(?:number|no|num|idx|index)\\b/i, // e.g., page_number, pageNumber, page_num, page_idx\n /^(current)?_?page(_?)(?:number|no|num|idx|index)?\\b/i,\n];\n\n// Regexes for parameters indicating page size (when used with page number)\nexport const PAGE_SIZE_REGEXES: RegExp[] = [\n /\\bpage_?size\\b/i, // e.g., page_size, pagesize\n /^size$/i, // Exact \"size\"\n // /\\bsize\\b/i, // Broader \"size\" - can be ambiguous, prefer more specific ones first\n /\\blimit\\b/i, // Limit is often used for page size\n /\\bcount\\b/i, // Count can also be used for page size\n /\\bper_?page\\b/i, // e.g., per_page, perpage\n /\\bper-page\\b/i,\n /\\bnum_?(?:items|records|results)\\b/i, // e.g., num_items, numitems\n /\\bresults_?per_?page\\b/i,\n];\n\n// Regexes for parameters indicating a cursor\nexport const CURSOR_REGEXES: RegExp[] = [\n /\\bmarker\\b/i,\n /\\bcursor\\b/i,\n /\\bafter(?:_?cursor)?\\b/i, // e.g., after, after_cursor\n /\\bbefore(?:_?cursor)?\\b/i, // e.g., before, before_cursor\n /\\b(next|prev|previous)_?(?:page_?)?token\\b/i, // e.g., next_page_token, nextPageToken, prev_token\n /\\b(next|prev|previous)_?cursor\\b/i, // e.g., next_cursor, previousCursor\n /\\bcontinuation(?:_?token)?\\b/i, // e.g., continuation, continuation_token\n /\\bpage(?:_?(token|id))?\\b/i, // e.g., after, after_cursor\n\n /\\bstart_?(?:key|cursor|token|after)\\b/i, // e.g., start_key, startCursor, startToken, startAfter\n];\n\n// Regexes for parameters indicating a limit when used with cursors\nexport const CURSOR_LIMIT_REGEXES: RegExp[] = [\n /\\blimit\\b/i,\n /\\bcount\\b/i,\n /\\bsize\\b/i, // General size\n /\\bfirst\\b/i, // Common in Relay-style cursor pagination (forward pagination)\n /\\blast\\b/i, // Common in Relay-style cursor pagination (backward pagination)\n /\\bpage_?size\\b/i, // Sometimes page_size is used with cursors\n /\\bnum_?(?:items|records|results)\\b/i, // e.g., num_items\n /\\bmax_?items\\b/i,\n /\\btake\\b/i,\n];\n\n// --- Helper Function ---\nfunction findParamAndKeyword(\n queryParams: { name: string }[],\n regexes: RegExp[],\n excludeParamName?: string,\n) {\n for (const param of queryParams) {\n if (param.name === excludeParamName) {\n continue;\n }\n for (const regex of regexes) {\n const match = param.name.match(regex);\n if (match) {\n return { param, keyword: match[0] }; // match[0] is the actual matched substring\n }\n }\n }\n return null;\n}\n\nfunction coerceParameters(\n parameters: { name: string; schema?: SchemaObject | ReferenceObject }[],\n) {\n const cleanedParameters: {\n name: string;\n schema: Omit<SchemaObject, 'type'> & {\n type: string[]; // Ensure type is always an array\n };\n }[] = [];\n for (const param of parameters) {\n if (!param.schema) {\n continue;\n }\n if (isRef(param.schema)) {\n continue;\n }\n if (param.schema.anyOf || param.schema.oneOf || param.schema.allOf) {\n const schemas = (\n param.schema.anyOf ||\n param.schema.oneOf ||\n param.schema.allOf ||\n []\n ).filter((it): it is SchemaObject => !isRef(it));\n schemas.forEach((schema) => {\n if (schema.type) {\n cleanedParameters.push({\n ...param,\n schema: {\n ...schema,\n type: coerceTypes(schema),\n },\n });\n }\n });\n continue;\n }\n if (!param.schema.type) {\n continue;\n }\n if (param.schema) {\n cleanedParameters.push({\n ...param,\n schema: {\n ...param.schema,\n type: coerceTypes(param.schema),\n },\n });\n }\n }\n return cleanedParameters;\n}\n\nfunction isOffsetPagination(\n operation: TunedOperationObject,\n parameters: { name: string; schema?: SchemaObject | ReferenceObject }[],\n): OffsetPaginationResult | null {\n const params = coerceParameters(parameters).filter(\n (it) =>\n it.schema.type.includes('integer') || it.schema.type.includes('number'),\n );\n\n const offsetMatch = findParamAndKeyword(params, OFFSET_PARAM_REGEXES);\n\n if (!offsetMatch) return null;\n\n const limitMatch = findParamAndKeyword(\n params,\n GENERIC_LIMIT_PARAM_REGEXES,\n offsetMatch.param.name,\n );\n if (!limitMatch) return null;\n\n return {\n type: 'offset',\n offsetParamName: offsetMatch.param.name,\n offsetKeyword: offsetMatch.keyword,\n limitParamName: limitMatch.param.name,\n limitKeyword: limitMatch.keyword,\n };\n}\n\nfunction isPagePagination(\n operation: TunedOperationObject,\n parameters: { name: string; schema?: SchemaObject | ReferenceObject }[],\n): PagePaginationResult | null {\n const params = coerceParameters(parameters).filter(\n (it) =>\n it.schema.type.includes('integer') || it.schema.type.includes('number'),\n );\n\n if (params.length < 2) return null;\n\n const pageNoMatch = findParamAndKeyword(params, PAGE_NUMBER_REGEXES);\n if (!pageNoMatch) return null;\n\n const pageSizeMatch = findParamAndKeyword(\n params,\n PAGE_SIZE_REGEXES,\n pageNoMatch.param.name,\n );\n if (!pageSizeMatch) return null;\n\n return {\n type: 'page',\n pageNumberParamName: pageNoMatch.param.name,\n pageNumberKeyword: pageNoMatch.keyword,\n pageSizeParamName: pageSizeMatch.param.name,\n pageSizeKeyword: pageSizeMatch.keyword,\n };\n}\n\nfunction isCursorPagination(\n operation: TunedOperationObject,\n parameters: { name: string; schema?: SchemaObject | ReferenceObject }[] = [],\n): CursorPaginationResult | null {\n const queryParams = parameters;\n if (queryParams.length < 2) return null; // Need at least a cursor and a limit-like param\n\n const cursorMatch = findParamAndKeyword(queryParams, CURSOR_REGEXES);\n if (!cursorMatch) return null;\n\n const limitMatch = findParamAndKeyword(\n queryParams,\n CURSOR_LIMIT_REGEXES,\n cursorMatch.param.name,\n );\n if (!limitMatch) return null;\n\n return {\n type: 'cursor',\n cursorParamName: cursorMatch.param.name,\n cursorKeyword: cursorMatch.keyword,\n limitParamName: limitMatch.param.name,\n limitKeyword: limitMatch.keyword,\n };\n}\n\n/**\n * Guesses the pagination strategy of an OpenAPI operation based on its query parameters.\n * It checks for offset, page-based, and cursor-based pagination in that order.\n *\n * @param operation The OpenAPI operation object.\n * @returns A PaginationGuess object indicating the detected type and relevant parameters.\n */\nexport function guessPagination(\n operation: TunedOperationObject,\n body?: SchemaObject,\n response?: SchemaObject,\n): PaginationGuess {\n const bodyParameters =\n body && body.properties\n ? Object.entries(body.properties).map(([it, schema]) => ({\n name: it,\n schema,\n }))\n : [];\n const parameters = operation.parameters;\n\n if (isEmpty(operation.parameters) && isEmpty(bodyParameters)) {\n return { type: 'none', reason: 'no parameters' };\n }\n if (!response) {\n return { type: 'none', reason: 'no response' };\n }\n if (!response.properties) {\n return { type: 'none', reason: 'empty response' };\n }\n const properties = response.properties as SchemasObject;\n\n const itemsKey = getItemsName(properties);\n if (!itemsKey) {\n return { type: 'none', reason: 'no items key' };\n }\n const hasMoreKey = getHasMoreName(excludeKey(properties, itemsKey));\n\n if (!hasMoreKey) {\n return { type: 'none', reason: 'no hasMore key' };\n }\n const pagination =\n isOffsetPagination(operation, [...parameters, ...bodyParameters]) ||\n isPagePagination(operation, [...parameters, ...bodyParameters]) ||\n isCursorPagination(operation, [...parameters, ...bodyParameters]);\n return pagination\n ? { ...pagination, items: itemsKey, hasMore: hasMoreKey }\n : { type: 'none', reason: 'no pagination' };\n}\n\nfunction excludeKey<T extends Record<string, any>>(\n obj: T,\n key: string,\n): Omit<T, typeof key> {\n const { [key]: _, ...rest } = obj;\n return rest;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sdk-it/spec",
3
- "version": "0.37.1",
3
+ "version": "0.39.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -27,7 +27,7 @@
27
27
  "!**/*.test.*"
28
28
  ],
29
29
  "dependencies": {
30
- "@sdk-it/core": "0.37.1",
30
+ "@sdk-it/core": "0.39.0",
31
31
  "openapi3-ts": "4.5.0",
32
32
  "pluralize": "^8.0.0",
33
33
  "stringcase": "^4.3.1",