@sdk-it/spec 0.45.0 → 0.46.1

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 (128) hide show
  1. package/README.md +65 -0
  2. package/dist/index.d.ts +3 -3
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +3 -3
  5. package/dist/index.js.map +1 -1
  6. package/dist/lib/find-polymorphic-varients.d.ts.map +1 -1
  7. package/dist/lib/find-polymorphic-varients.js +6 -11
  8. package/dist/lib/find-polymorphic-varients.js.map +2 -2
  9. package/dist/lib/for-each-operation.d.ts +11 -3
  10. package/dist/lib/for-each-operation.d.ts.map +1 -1
  11. package/dist/lib/for-each-operation.js +23 -15
  12. package/dist/lib/for-each-operation.js.map +2 -2
  13. package/dist/lib/format-name.d.ts.map +1 -1
  14. package/dist/lib/format-name.js +0 -1
  15. package/dist/lib/format-name.js.map +2 -2
  16. package/dist/lib/ir.d.ts +2 -2
  17. package/dist/lib/ir.d.ts.map +1 -1
  18. package/dist/lib/ir.js +6 -120
  19. package/dist/lib/ir.js.map +2 -2
  20. package/dist/lib/is-primitive-schema.js +1 -1
  21. package/dist/lib/is-primitive-schema.js.map +1 -1
  22. package/dist/lib/is.d.ts +2 -0
  23. package/dist/lib/is.d.ts.map +1 -1
  24. package/dist/lib/is.js +6 -3
  25. package/dist/lib/is.js.map +2 -2
  26. package/dist/lib/loaders/postman/postman-converter.d.ts.map +1 -1
  27. package/dist/lib/loaders/postman/postman-converter.js +1 -11
  28. package/dist/lib/loaders/postman/postman-converter.js.map +2 -2
  29. package/dist/lib/options.d.ts +7 -45
  30. package/dist/lib/options.d.ts.map +1 -1
  31. package/dist/lib/options.js +26 -28
  32. package/dist/lib/options.js.map +2 -2
  33. package/dist/lib/overview-docs/overview-pagination.d.ts +1 -1
  34. package/dist/lib/overview-docs/overview-pagination.d.ts.map +1 -1
  35. package/dist/lib/overview-docs/overview-pagination.js +1 -1
  36. package/dist/lib/overview-docs/overview-pagination.js.map +2 -2
  37. package/dist/lib/pagination/guess-pagination.d.ts.map +1 -1
  38. package/dist/lib/pagination/guess-pagination.js +1 -1
  39. package/dist/lib/pagination/guess-pagination.js.map +2 -2
  40. package/dist/lib/pagination/pagination-result.d.ts.map +1 -1
  41. package/dist/lib/pagination/pagination-result.js +15 -5
  42. package/dist/lib/pagination/pagination-result.js.map +2 -2
  43. package/dist/lib/pagination/pagination.d.ts.map +1 -1
  44. package/dist/lib/pagination/pagination.js +7 -6
  45. package/dist/lib/pagination/pagination.js.map +2 -2
  46. package/dist/lib/processing-plugins/canonicalize-spec.d.ts +3 -0
  47. package/dist/lib/processing-plugins/canonicalize-spec.d.ts.map +1 -0
  48. package/dist/lib/processing-plugins/canonicalize-spec.js +29 -0
  49. package/dist/lib/processing-plugins/canonicalize-spec.js.map +7 -0
  50. package/dist/lib/processing-plugins/create-default-processing-plugins.d.ts +5 -0
  51. package/dist/lib/processing-plugins/create-default-processing-plugins.d.ts.map +1 -0
  52. package/dist/lib/processing-plugins/create-default-processing-plugins.js +30 -0
  53. package/dist/lib/processing-plugins/create-default-processing-plugins.js.map +7 -0
  54. package/dist/lib/processing-plugins/enrich-examples.d.ts +25 -0
  55. package/dist/lib/processing-plugins/enrich-examples.d.ts.map +1 -0
  56. package/dist/lib/processing-plugins/enrich-examples.js +93 -0
  57. package/dist/lib/processing-plugins/enrich-examples.js.map +7 -0
  58. package/dist/lib/processing-plugins/extract-inline-schemas.d.ts +3 -0
  59. package/dist/lib/processing-plugins/extract-inline-schemas.d.ts.map +1 -0
  60. package/dist/lib/processing-plugins/extract-inline-schemas.js +165 -0
  61. package/dist/lib/processing-plugins/extract-inline-schemas.js.map +7 -0
  62. package/dist/lib/processing-plugins/extract-overview-docs.d.ts +3 -0
  63. package/dist/lib/processing-plugins/extract-overview-docs.d.ts.map +1 -0
  64. package/dist/lib/processing-plugins/extract-overview-docs.js +13 -0
  65. package/dist/lib/processing-plugins/extract-overview-docs.js.map +7 -0
  66. package/dist/lib/processing-plugins/index.d.ts +14 -0
  67. package/dist/lib/processing-plugins/index.d.ts.map +1 -0
  68. package/dist/lib/processing-plugins/index.js +14 -0
  69. package/dist/lib/processing-plugins/index.js.map +7 -0
  70. package/dist/lib/processing-plugins/infer-pagination.d.ts +3 -0
  71. package/dist/lib/processing-plugins/infer-pagination.d.ts.map +1 -0
  72. package/dist/lib/processing-plugins/infer-pagination.js +21 -0
  73. package/dist/lib/processing-plugins/infer-pagination.js.map +7 -0
  74. package/dist/lib/processing-plugins/normalize-operation-ids.d.ts +3 -0
  75. package/dist/lib/processing-plugins/normalize-operation-ids.d.ts.map +1 -0
  76. package/dist/lib/processing-plugins/normalize-operation-ids.js +74 -0
  77. package/dist/lib/processing-plugins/normalize-operation-ids.js.map +7 -0
  78. package/dist/lib/processing-plugins/normalize-parameters.d.ts +3 -0
  79. package/dist/lib/processing-plugins/normalize-parameters.d.ts.map +1 -0
  80. package/dist/lib/processing-plugins/normalize-parameters.js +29 -0
  81. package/dist/lib/processing-plugins/normalize-parameters.js.map +7 -0
  82. package/dist/lib/processing-plugins/normalize-paths.d.ts +3 -0
  83. package/dist/lib/processing-plugins/normalize-paths.d.ts.map +1 -0
  84. package/dist/lib/processing-plugins/normalize-paths.js +67 -0
  85. package/dist/lib/processing-plugins/normalize-paths.js.map +7 -0
  86. package/dist/lib/processing-plugins/normalize-request-bodies.d.ts +6 -0
  87. package/dist/lib/processing-plugins/normalize-request-bodies.d.ts.map +1 -0
  88. package/dist/lib/processing-plugins/normalize-request-bodies.js +139 -0
  89. package/dist/lib/processing-plugins/normalize-request-bodies.js.map +7 -0
  90. package/dist/lib/processing-plugins/normalize-responses.d.ts +3 -0
  91. package/dist/lib/processing-plugins/normalize-responses.d.ts.map +1 -0
  92. package/dist/lib/{tune-response.js → processing-plugins/normalize-responses.js} +55 -25
  93. package/dist/lib/processing-plugins/normalize-responses.js.map +7 -0
  94. package/dist/lib/processing-plugins/normalize-schemas.d.ts +3 -0
  95. package/dist/lib/processing-plugins/normalize-schemas.d.ts.map +1 -0
  96. package/dist/lib/processing-plugins/normalize-schemas.js +170 -0
  97. package/dist/lib/processing-plugins/normalize-schemas.js.map +7 -0
  98. package/dist/lib/processing-plugins/normalize-tags.d.ts +3 -0
  99. package/dist/lib/processing-plugins/normalize-tags.d.ts.map +1 -0
  100. package/dist/lib/processing-plugins/normalize-tags.js +18 -0
  101. package/dist/lib/processing-plugins/normalize-tags.js.map +7 -0
  102. package/dist/lib/processing.d.ts +33 -0
  103. package/dist/lib/processing.d.ts.map +1 -0
  104. package/dist/lib/processing.js +41 -0
  105. package/dist/lib/processing.js.map +7 -0
  106. package/dist/lib/reserved-keywords.d.ts.map +1 -1
  107. package/dist/lib/reserved-keywords.js +18 -1
  108. package/dist/lib/reserved-keywords.js.map +2 -2
  109. package/dist/lib/tag.js +2 -2
  110. package/dist/lib/tag.js.map +2 -2
  111. package/dist/lib/types.d.ts +4 -1
  112. package/dist/lib/types.d.ts.map +1 -1
  113. package/dist/lib/walk-schemas.d.ts +8 -0
  114. package/dist/lib/walk-schemas.d.ts.map +1 -0
  115. package/dist/lib/walk-schemas.js +51 -0
  116. package/dist/lib/walk-schemas.js.map +7 -0
  117. package/package.json +2 -2
  118. package/dist/lib/tune-request-body.d.ts +0 -5
  119. package/dist/lib/tune-request-body.d.ts.map +0 -1
  120. package/dist/lib/tune-request-body.js +0 -91
  121. package/dist/lib/tune-request-body.js.map +0 -7
  122. package/dist/lib/tune-response.d.ts +0 -5
  123. package/dist/lib/tune-response.d.ts.map +0 -1
  124. package/dist/lib/tune-response.js.map +0 -7
  125. package/dist/lib/tune.d.ts +0 -11
  126. package/dist/lib/tune.d.ts.map +0 -1
  127. package/dist/lib/tune.js +0 -291
  128. package/dist/lib/tune.js.map +0 -7
@@ -1,7 +1,8 @@
1
1
  import { parse as parseContentType } from "fast-content-type-parse";
2
2
  import { isRef, parseRef, resolveRef } from "@sdk-it/core/ref.js";
3
3
  import { isEmpty, pascalcase } from "@sdk-it/core/utils.js";
4
- import { findUniqueSchemaName } from "./find-unique-schema-name.js";
4
+ import { findUniqueSchemaName } from "../find-unique-schema-name.js";
5
+ import { iterateOperations } from "../for-each-operation.js";
5
6
  import {
6
7
  isBinaryContentType,
7
8
  isSseContentType,
@@ -9,21 +10,16 @@ import {
9
10
  isSuccessStatusCode,
10
11
  isTextContentType,
11
12
  parseJsonContentType
12
- } from "./is.js";
13
- import {} from "./options.js";
14
- function resolveResponses(spec, operationId, operation, responsesConfig) {
13
+ } from "../is.js";
14
+ function normalizeOperationResponses(spec, operationId, operation, responsesConfig) {
15
15
  const responses = operation.responses ?? {};
16
16
  operation.responses ??= {};
17
17
  let foundSuccessResponse = false;
18
18
  for (const status in responses) {
19
- if (status === "default") {
20
- delete responses[status];
21
- continue;
22
- }
23
19
  operation.responses[status] = structuredClone(
24
20
  resolveRef(spec, responses[status])
25
21
  );
26
- if (isSuccessStatusCode(status)) {
22
+ if (status !== "default" && isSuccessStatusCode(status)) {
27
23
  foundSuccessResponse = true;
28
24
  }
29
25
  }
@@ -40,22 +36,15 @@ function resolveResponses(spec, operationId, operation, responsesConfig) {
40
36
  for (const status in operation.responses) {
41
37
  const response = operation.responses[status];
42
38
  const statusCode = +status;
43
- const outputName = statusCode !== 200 ? pascalcase(operationId) + status : findUniqueSchemaName(spec, operationId, [
44
- "output",
45
- "payload",
46
- "result"
47
- ]);
48
- if (!responsesConfig?.flattenErrorResponses) {
49
- if (!isSuccessStatusCode(status)) {
50
- continue;
51
- }
39
+ if (!responsesConfig?.flattenErrorResponses && !isSuccessStatusCode(status)) {
40
+ continue;
52
41
  }
53
42
  if (isEmpty(response.content)) {
54
43
  response.content = {
55
44
  "application/octet-stream": {}
56
45
  };
57
46
  }
58
- response["x-response-name"] = outputName;
47
+ let responseName;
59
48
  for (const [contentType, mediaType] of Object.entries(
60
49
  response.content
61
50
  )) {
@@ -63,13 +52,20 @@ function resolveResponses(spec, operationId, operation, responsesConfig) {
63
52
  const { model } = parseRef(mediaType.schema.$ref);
64
53
  Object.assign(spec.components.schemas[model], {
65
54
  "x-responsebody": true
66
- // do not assign response ref to a group
67
- // because they are supposed to be in a separate file only inlined
68
- // schemas are grouped by operationId
69
55
  });
70
- response["x-response-name"] = model;
56
+ responseName ??= model;
71
57
  continue;
72
58
  }
59
+ const outputName = statusCode !== 200 ? findUniqueSchemaName(spec, `${pascalcase(operationId)}${status}`, [
60
+ "output",
61
+ "payload",
62
+ "result"
63
+ ]) : findUniqueSchemaName(spec, operationId, [
64
+ "output",
65
+ "payload",
66
+ "result"
67
+ ]);
68
+ responseName ??= outputName;
73
69
  const isSse = isSseContentType(contentType);
74
70
  const normalizedContentType = normalizeContentType(contentType);
75
71
  const hasContentDisposition = hasHeader(
@@ -108,6 +104,9 @@ function resolveResponses(spec, operationId, operation, responsesConfig) {
108
104
  $ref: `#/components/schemas/${outputName}`
109
105
  };
110
106
  }
107
+ if (responseName) {
108
+ response["x-response-name"] = responseName;
109
+ }
111
110
  }
112
111
  return operation.responses;
113
112
  }
@@ -125,7 +124,38 @@ function hasHeader(headers, name) {
125
124
  const target = name.toLowerCase();
126
125
  return Object.keys(headers).some((key) => key.toLowerCase() === target);
127
126
  }
127
+ function normalizeResponses() {
128
+ return {
129
+ name: "normalize-responses",
130
+ process({ spec, options, report }) {
131
+ for (const { entry, operation } of iterateOperations(spec)) {
132
+ if (!operation.operationId) {
133
+ throw new Error(
134
+ `Cannot normalize responses before assigning an operation ID for ${entry.method.toUpperCase()} ${entry.path}`
135
+ );
136
+ }
137
+ const hadSuccessResponse = Object.keys(operation.responses ?? {}).some(
138
+ isSuccessStatusCode
139
+ );
140
+ operation.responses = normalizeOperationResponses(
141
+ spec,
142
+ operation.operationId,
143
+ operation,
144
+ options.responses
145
+ );
146
+ if (!hadSuccessResponse) {
147
+ report({
148
+ severity: "warning",
149
+ code: "success-response-added",
150
+ message: "Added a default 200 success response",
151
+ path: `${entry.method.toUpperCase()} ${entry.path}`
152
+ });
153
+ }
154
+ }
155
+ }
156
+ };
157
+ }
128
158
  export {
129
- resolveResponses
159
+ normalizeResponses
130
160
  };
131
- //# sourceMappingURL=tune-response.js.map
161
+ //# sourceMappingURL=normalize-responses.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/processing-plugins/normalize-responses.ts"],
4
+ "sourcesContent": ["import { parse as parseContentType } from 'fast-content-type-parse';\nimport type {\n MediaTypeObject,\n OperationObject,\n ResponseObject,\n} from 'openapi3-ts/oas31';\n\nimport { isRef, parseRef, resolveRef } from '@sdk-it/core/ref.js';\nimport { isEmpty, pascalcase } from '@sdk-it/core/utils.js';\n\nimport { findUniqueSchemaName } from '../find-unique-schema-name.js';\nimport { iterateOperations } from '../for-each-operation.js';\nimport {\n isBinaryContentType,\n isSseContentType,\n isStreamingContentType,\n isSuccessStatusCode,\n isTextContentType,\n parseJsonContentType,\n} from '../is.js';\nimport type { ResponsesConfig } from '../options.js';\nimport type { ProcessingPlugin } from '../processing.js';\nimport type { IR, TunedOperationObject } from '../types.js';\n\nfunction normalizeOperationResponses(\n spec: IR,\n operationId: string,\n operation: OperationObject,\n responsesConfig?: ResponsesConfig,\n) {\n const responses = operation.responses ?? {};\n operation.responses ??= {};\n let foundSuccessResponse = false;\n for (const status in responses) {\n operation.responses[status] = structuredClone(\n resolveRef<ResponseObject>(spec, responses[status]),\n );\n\n if (status !== 'default' && isSuccessStatusCode(status)) {\n foundSuccessResponse = true;\n }\n }\n\n if (!foundSuccessResponse) {\n operation.responses['200'] = {\n description: 'OK',\n content: {\n 'application/json': {\n schema: {},\n },\n },\n };\n }\n\n for (const status in operation.responses) {\n const response = operation.responses[status] as ResponseObject;\n const statusCode = +status;\n\n if (\n !responsesConfig?.flattenErrorResponses &&\n !isSuccessStatusCode(status)\n ) {\n continue;\n }\n\n if (isEmpty(response.content)) {\n response.content = {\n 'application/octet-stream': {},\n };\n }\n\n let responseName: string | undefined;\n for (const [contentType, mediaType] of Object.entries(\n response.content as Record<string, MediaTypeObject>,\n )) {\n if (isRef(mediaType.schema)) {\n const { model } = parseRef(mediaType.schema.$ref);\n Object.assign(spec.components.schemas[model], {\n 'x-responsebody': true,\n });\n responseName ??= model;\n continue;\n }\n const outputName =\n statusCode !== 200\n ? findUniqueSchemaName(spec, `${pascalcase(operationId)}${status}`, [\n 'output',\n 'payload',\n 'result',\n ])\n : findUniqueSchemaName(spec, operationId, [\n 'output',\n 'payload',\n 'result',\n ]);\n responseName ??= outputName;\n const isSse = isSseContentType(contentType);\n const normalizedContentType = normalizeContentType(contentType);\n const hasContentDisposition = hasHeader(\n response.headers,\n 'Content-Disposition',\n );\n const isBinary =\n isBinaryContentType(contentType) ||\n (isStreamingContentType(normalizedContentType) &&\n hasContentDisposition);\n const isText = isTextContentType(contentType);\n\n if (parseJsonContentType(contentType)) {\n if (isEmpty(mediaType.schema)) {\n spec.components.schemas[outputName] = {\n type: 'object',\n additionalProperties: true,\n };\n }\n } else {\n if (isEmpty(mediaType.schema) && (isText || isBinary)) {\n mediaType.schema = {\n type: 'string',\n ...(isBinary ? { format: 'binary' } : {}),\n };\n }\n spec.components.schemas[outputName] = {\n ...spec.components.schemas[outputName],\n 'x-stream': isSse || (!isText && !isBinary),\n ...(isSse ? { 'x-sse': true } : {}),\n };\n }\n\n spec.components.schemas[outputName] = {\n ...spec.components.schemas[outputName],\n ...mediaType.schema,\n 'x-responsebody': true,\n 'x-response-group': operationId,\n };\n operation.responses[status].content[contentType].schema = {\n $ref: `#/components/schemas/${outputName}`,\n };\n }\n if (responseName) {\n response['x-response-name'] = responseName;\n }\n }\n\n return operation.responses;\n}\n\nfunction normalizeContentType(contentType: string) {\n try {\n return parseContentType(contentType)?.type?.toLowerCase();\n } catch {\n return contentType.split(';')[0]?.trim().toLowerCase();\n }\n}\n\nfunction hasHeader(headers: ResponseObject['headers'], name: string) {\n if (!headers) {\n return false;\n }\n const target = name.toLowerCase();\n return Object.keys(headers).some((key) => key.toLowerCase() === target);\n}\n\nexport function normalizeResponses(): ProcessingPlugin {\n return {\n name: 'normalize-responses',\n process({ spec, options, report }) {\n for (const { entry, operation } of iterateOperations(spec)) {\n if (!operation.operationId) {\n throw new Error(\n `Cannot normalize responses before assigning an operation ID for ${entry.method.toUpperCase()} ${entry.path}`,\n );\n }\n const hadSuccessResponse = Object.keys(operation.responses ?? {}).some(\n isSuccessStatusCode,\n );\n (operation as TunedOperationObject).responses =\n normalizeOperationResponses(\n spec,\n operation.operationId,\n operation,\n options.responses,\n );\n if (!hadSuccessResponse) {\n report({\n severity: 'warning',\n code: 'success-response-added',\n message: 'Added a default 200 success response',\n path: `${entry.method.toUpperCase()} ${entry.path}`,\n });\n }\n }\n },\n };\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,3 @@
1
+ import type { ProcessingPlugin } from '../processing.js';
2
+ export declare function normalizeSchemas(): ProcessingPlugin;
3
+ //# sourceMappingURL=normalize-schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize-schemas.d.ts","sourceRoot":"","sources":["../../../src/lib/processing-plugins/normalize-schemas.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAmLzD,wBAAgB,gBAAgB,IAAI,gBAAgB,CAOnD"}
@@ -0,0 +1,170 @@
1
+ import { merge, uniq } from "lodash-es";
2
+ import assert from "node:assert";
3
+ import { isEmpty, isRef, notRef, resolveRef, snakecase } from "@sdk-it/core";
4
+ import { findVarients } from "../find-polymorphic-varients.js";
5
+ import { formatName } from "../format-name.js";
6
+ import { isPrimitiveSchema } from "../is-primitive-schema.js";
7
+ function normalizeSchemaObjects(spec, schemas, visited = /* @__PURE__ */ new Set()) {
8
+ for (const schema of schemas) {
9
+ if (isRef(schema)) continue;
10
+ if (!isEmpty(schema.properties)) {
11
+ schema.type = "object";
12
+ delete schema.oneOf;
13
+ delete schema.anyOf;
14
+ normalizeSchemaObjects(spec, Object.values(schema.properties), visited);
15
+ for (const [key, value] of Object.entries(schema.properties)) {
16
+ if (notRef(value) && isPrimitiveSchema(value)) {
17
+ value.default ??= schema.default?.[key];
18
+ delete schema.default?.[key];
19
+ }
20
+ }
21
+ delete schema.default;
22
+ }
23
+ if (!isEmpty(schema["x-properties"])) {
24
+ normalizeSchemaObjects(
25
+ spec,
26
+ Object.values(schema["x-properties"]),
27
+ visited
28
+ );
29
+ }
30
+ if (!isEmpty(schema.items)) {
31
+ delete schema.oneOf;
32
+ delete schema.anyOf;
33
+ schema.type = "array";
34
+ normalizeSchemaObjects(spec, [schema.items], visited);
35
+ const items = resolveRef(spec, schema.items);
36
+ if (Array.isArray(items.default)) {
37
+ schema.default ??= structuredClone(items.default);
38
+ }
39
+ delete items.default;
40
+ }
41
+ if (!isEmpty(schema.anyOf) && !isEmpty(schema.oneOf)) {
42
+ delete schema.anyOf;
43
+ }
44
+ if (isEmpty(schema.enum)) {
45
+ delete schema.enum;
46
+ }
47
+ if (!isEmpty(schema.enum)) {
48
+ if (schema.enum.length === 1) {
49
+ schema.const = schema.enum[0];
50
+ delete schema.enum;
51
+ } else {
52
+ const valuesSet = /* @__PURE__ */ new Set();
53
+ const valuesList = [];
54
+ for (const value of schema.enum) {
55
+ const formattedValue = formatName(snakecase(formatName(value)));
56
+ if (!valuesSet.has(formattedValue)) {
57
+ valuesSet.add(formattedValue);
58
+ valuesList.push(value);
59
+ }
60
+ }
61
+ schema.enum = valuesList;
62
+ }
63
+ delete schema.allOf;
64
+ }
65
+ if (schema.const !== void 0) {
66
+ schema.default = schema.const;
67
+ }
68
+ if (!isEmpty(schema.allOf)) {
69
+ const schemas2 = schema.allOf;
70
+ const resolved = schemas2.map(
71
+ (item) => resolveRef(spec, item)
72
+ );
73
+ const hasObjects = resolved.some((item) => item.type === "object");
74
+ const hasOtherTypes = resolved.some(
75
+ (item) => item.type && item.type !== "object"
76
+ );
77
+ if (hasObjects && hasOtherTypes) {
78
+ assert(false, `allOf must be an object`);
79
+ }
80
+ merge(
81
+ schema,
82
+ ...resolved.map((resolvedSchema, index) => {
83
+ const sourceSchema = schemas2[index];
84
+ if (isRef(sourceSchema)) {
85
+ if (visited.has(sourceSchema.$ref)) {
86
+ throw new Error(
87
+ `Circular allOf reference detected: ${[
88
+ ...visited,
89
+ sourceSchema.$ref
90
+ ].join(" -> ")}`
91
+ );
92
+ }
93
+ normalizeSchemaObjects(
94
+ spec,
95
+ [resolvedSchema],
96
+ new Set(visited).add(sourceSchema.$ref)
97
+ );
98
+ } else {
99
+ normalizeSchemaObjects(spec, [resolvedSchema], visited);
100
+ }
101
+ return resolvedSchema;
102
+ })
103
+ );
104
+ delete schema.allOf;
105
+ } else {
106
+ delete schema.allOf;
107
+ }
108
+ if (schema.type === "object" && isEmpty(schema.properties) && typeof schema.additionalProperties === "object" && !isEmpty(schema.additionalProperties) && notRef(schema.additionalProperties) && !isEmpty(schema.additionalProperties.properties)) {
109
+ normalizeSchemaObjects(
110
+ spec,
111
+ Object.values(schema.additionalProperties.properties),
112
+ visited
113
+ );
114
+ }
115
+ for (const kind of ["oneOf", "anyOf"]) {
116
+ if (!isEmpty(schema[kind])) {
117
+ delete schema.type;
118
+ normalizeSchemaObjects(spec, schema[kind], visited);
119
+ if (isEmpty(schema[kind])) {
120
+ continue;
121
+ }
122
+ let enumSchemaIndex = -1;
123
+ const enumValues = [];
124
+ for (let index = 0; index < schema[kind].length; index++) {
125
+ const item = schema[kind][index];
126
+ if (notRef(item) && item.type === "string") {
127
+ if (item.enum && item.enum.length > 1) {
128
+ enumValues.push(...item.enum);
129
+ if (enumSchemaIndex === -1) {
130
+ enumSchemaIndex = index;
131
+ }
132
+ }
133
+ }
134
+ }
135
+ if (enumSchemaIndex !== -1) {
136
+ const enumSchema = schema[kind][enumSchemaIndex];
137
+ if (notRef(enumSchema)) {
138
+ enumSchema.enum = uniq(enumValues);
139
+ }
140
+ schema[kind] = schema[kind].filter(
141
+ (item, index) => index === enumSchemaIndex || isRef(item)
142
+ );
143
+ }
144
+ const otherTypes = schema[kind].filter(
145
+ (item) => resolveRef(spec, item).type !== "null"
146
+ );
147
+ if (otherTypes.length === 1) {
148
+ Object.assign(schema, otherTypes[0]);
149
+ delete schema[kind];
150
+ continue;
151
+ }
152
+ schema["x-varients"] = findVarients(spec, schema[kind]);
153
+ } else {
154
+ delete schema[kind];
155
+ }
156
+ }
157
+ }
158
+ }
159
+ function normalizeSchemas() {
160
+ return {
161
+ name: "normalize-schemas",
162
+ process({ spec }) {
163
+ normalizeSchemaObjects(spec, Object.values(spec.components.schemas));
164
+ }
165
+ };
166
+ }
167
+ export {
168
+ normalizeSchemas
169
+ };
170
+ //# sourceMappingURL=normalize-schemas.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/processing-plugins/normalize-schemas.ts"],
4
+ "sourcesContent": ["import { merge, uniq } from 'lodash-es';\nimport assert from 'node:assert';\nimport type { ReferenceObject, SchemaObject } from 'openapi3-ts/oas31';\n\nimport { isEmpty, isRef, notRef, resolveRef, snakecase } from '@sdk-it/core';\n\nimport { findVarients } from '../find-polymorphic-varients.js';\nimport { formatName } from '../format-name.js';\nimport { isPrimitiveSchema } from '../is-primitive-schema.js';\nimport type { ProcessingPlugin } from '../processing.js';\nimport type { IR } from '../types.js';\n\nfunction normalizeSchemaObjects(\n spec: IR,\n schemas: (SchemaObject | ReferenceObject)[],\n visited = new Set<string>(),\n) {\n for (const schema of schemas) {\n if (isRef(schema)) continue;\n\n if (!isEmpty(schema.properties)) {\n schema.type = 'object';\n delete schema.oneOf;\n delete schema.anyOf;\n normalizeSchemaObjects(spec, Object.values(schema.properties), visited);\n for (const [key, value] of Object.entries(schema.properties)) {\n if (notRef(value) && isPrimitiveSchema(value)) {\n value.default ??= schema.default?.[key];\n delete schema.default?.[key];\n }\n }\n delete schema.default;\n }\n\n if (!isEmpty(schema['x-properties'])) {\n normalizeSchemaObjects(\n spec,\n Object.values(schema['x-properties']),\n visited,\n );\n }\n\n if (!isEmpty(schema.items)) {\n delete schema.oneOf;\n delete schema.anyOf;\n schema.type = 'array';\n normalizeSchemaObjects(spec, [schema.items], visited);\n const items = resolveRef<SchemaObject>(spec, schema.items);\n if (Array.isArray(items.default)) {\n schema.default ??= structuredClone(items.default);\n }\n delete items.default;\n }\n\n if (!isEmpty(schema.anyOf) && !isEmpty(schema.oneOf)) {\n delete schema.anyOf;\n }\n\n if (isEmpty(schema.enum)) {\n delete schema.enum;\n }\n\n if (!isEmpty(schema.enum)) {\n if (schema.enum.length === 1) {\n schema.const = schema.enum[0];\n delete schema.enum;\n } else {\n const valuesSet = new Set<string>();\n const valuesList = [];\n for (const value of schema.enum) {\n const formattedValue = formatName(snakecase(formatName(value)));\n if (!valuesSet.has(formattedValue)) {\n valuesSet.add(formattedValue);\n valuesList.push(value);\n }\n }\n schema.enum = valuesList;\n }\n delete schema.allOf;\n }\n\n if (schema.const !== undefined) {\n schema.default = schema.const;\n }\n\n if (!isEmpty(schema.allOf)) {\n const schemas = schema.allOf;\n const resolved = schemas.map((item) =>\n resolveRef<SchemaObject>(spec, item),\n );\n const hasObjects = resolved.some((item) => item.type === 'object');\n const hasOtherTypes = resolved.some(\n (item) => item.type && item.type !== 'object',\n );\n if (hasObjects && hasOtherTypes) {\n assert(false, `allOf must be an object`);\n }\n merge(\n schema,\n ...resolved.map((resolvedSchema, index) => {\n const sourceSchema = schemas[index];\n if (isRef(sourceSchema)) {\n if (visited.has(sourceSchema.$ref)) {\n throw new Error(\n `Circular allOf reference detected: ${[\n ...visited,\n sourceSchema.$ref,\n ].join(' -> ')}`,\n );\n }\n normalizeSchemaObjects(\n spec,\n [resolvedSchema],\n new Set(visited).add(sourceSchema.$ref),\n );\n } else {\n normalizeSchemaObjects(spec, [resolvedSchema], visited);\n }\n return resolvedSchema;\n }),\n );\n delete schema.allOf;\n } else {\n delete schema.allOf;\n }\n\n if (\n schema.type === 'object' &&\n isEmpty(schema.properties) &&\n typeof schema.additionalProperties === 'object' &&\n !isEmpty(schema.additionalProperties) &&\n notRef(schema.additionalProperties) &&\n !isEmpty(schema.additionalProperties.properties)\n ) {\n normalizeSchemaObjects(\n spec,\n Object.values(schema.additionalProperties.properties),\n visited,\n );\n }\n\n for (const kind of ['oneOf', 'anyOf'] as const) {\n if (!isEmpty(schema[kind])) {\n delete schema.type;\n normalizeSchemaObjects(spec, schema[kind], visited);\n if (isEmpty(schema[kind])) {\n continue;\n }\n\n let enumSchemaIndex = -1;\n const enumValues: string[] = [];\n for (let index = 0; index < schema[kind].length; index++) {\n const item = schema[kind][index];\n if (notRef(item) && item.type === 'string') {\n if (item.enum && item.enum.length > 1) {\n enumValues.push(...item.enum);\n if (enumSchemaIndex === -1) {\n enumSchemaIndex = index;\n }\n }\n }\n }\n if (enumSchemaIndex !== -1) {\n const enumSchema = schema[kind][enumSchemaIndex];\n if (notRef(enumSchema)) {\n enumSchema.enum = uniq(enumValues);\n }\n schema[kind] = schema[kind].filter(\n (item, index) => index === enumSchemaIndex || isRef(item),\n );\n }\n const otherTypes = schema[kind].filter(\n (item) => resolveRef<SchemaObject>(spec, item).type !== 'null',\n );\n if (otherTypes.length === 1) {\n Object.assign(schema, otherTypes[0]);\n delete schema[kind];\n continue;\n }\n\n schema['x-varients'] = findVarients(spec, schema[kind]);\n } else {\n delete schema[kind];\n }\n }\n }\n}\n\nexport function normalizeSchemas(): ProcessingPlugin {\n return {\n name: 'normalize-schemas',\n process({ spec }) {\n normalizeSchemaObjects(spec, Object.values(spec.components.schemas));\n },\n };\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["schemas"]
7
+ }
@@ -0,0 +1,3 @@
1
+ import type { ProcessingPlugin } from '../processing.js';
2
+ export declare function normalizeTags(): ProcessingPlugin;
3
+ //# sourceMappingURL=normalize-tags.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize-tags.d.ts","sourceRoot":"","sources":["../../../src/lib/processing-plugins/normalize-tags.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,wBAAgB,aAAa,IAAI,gBAAgB,CAWhD"}
@@ -0,0 +1,18 @@
1
+ import { snakecase } from "@sdk-it/core/utils.js";
2
+ import { iterateOperations } from "../for-each-operation.js";
3
+ function normalizeTags() {
4
+ return {
5
+ name: "normalize-tags",
6
+ process({ spec, options }) {
7
+ for (const { entry, operation } of iterateOperations(spec)) {
8
+ const tag = options.tag(operation, entry.path);
9
+ operation["x-fn-group"] = tag;
10
+ operation.tags = [snakecase(tag)];
11
+ }
12
+ }
13
+ };
14
+ }
15
+ export {
16
+ normalizeTags
17
+ };
18
+ //# sourceMappingURL=normalize-tags.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/lib/processing-plugins/normalize-tags.ts"],
4
+ "sourcesContent": ["import { snakecase } from '@sdk-it/core/utils.js';\n\nimport { iterateOperations } from '../for-each-operation.js';\nimport type { ProcessingPlugin } from '../processing.js';\n\nexport function normalizeTags(): ProcessingPlugin {\n return {\n name: 'normalize-tags',\n process({ spec, options }) {\n for (const { entry, operation } of iterateOperations(spec)) {\n const tag = options.tag(operation, entry.path);\n operation['x-fn-group'] = tag;\n operation.tags = [snakecase(tag)];\n }\n },\n };\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB;AAE1B,SAAS,yBAAyB;AAG3B,SAAS,gBAAkC;AAChD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,QAAQ,EAAE,MAAM,QAAQ,GAAG;AACzB,iBAAW,EAAE,OAAO,UAAU,KAAK,kBAAkB,IAAI,GAAG;AAC1D,cAAM,MAAM,QAAQ,IAAI,WAAW,MAAM,IAAI;AAC7C,kBAAU,YAAY,IAAI;AAC1B,kBAAU,OAAO,CAAC,UAAU,GAAG,CAAC;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,33 @@
1
+ import { type GenerateSdkConfig, coeraceConfig as coerceConfig } from './options.js';
2
+ import type { IR } from './types.js';
3
+ export type ProcessingDiagnosticSeverity = 'info' | 'warning' | 'error';
4
+ export interface ProcessingDiagnostic {
5
+ plugin: string;
6
+ severity: ProcessingDiagnosticSeverity;
7
+ code: string;
8
+ message: string;
9
+ path?: string;
10
+ }
11
+ export type ProcessingOptions = Omit<ReturnType<typeof coerceConfig>, 'spec'>;
12
+ export interface ProcessingContext {
13
+ spec: IR;
14
+ options: ProcessingOptions;
15
+ diagnostics: ProcessingDiagnostic[];
16
+ signal?: AbortSignal;
17
+ report(diagnostic: Omit<ProcessingDiagnostic, 'plugin'>): ProcessingDiagnostic;
18
+ }
19
+ export interface ProcessingPlugin {
20
+ name: string;
21
+ process(context: ProcessingContext): void | Promise<void>;
22
+ }
23
+ export interface ProcessSpecConfig extends GenerateSdkConfig {
24
+ plugins: readonly ProcessingPlugin[];
25
+ signal?: AbortSignal;
26
+ onDiagnostic?: (diagnostic: ProcessingDiagnostic) => void;
27
+ }
28
+ export interface ProcessingResult {
29
+ spec: IR;
30
+ diagnostics: ProcessingDiagnostic[];
31
+ }
32
+ export declare function processSpec(config: ProcessSpecConfig): Promise<ProcessingResult>;
33
+ //# sourceMappingURL=processing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"processing.d.ts","sourceRoot":"","sources":["../../src/lib/processing.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,iBAAiB,EACtB,aAAa,IAAI,YAAY,EAC9B,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAErC,MAAM,MAAM,4BAA4B,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAExE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,4BAA4B,CAAC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,YAAY,CAAC,EAAE,MAAM,CAAC,CAAC;AAE9E,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,EAAE,CAAC;IACT,OAAO,EAAE,iBAAiB,CAAC;IAC3B,WAAW,EAAE,oBAAoB,EAAE,CAAC;IACpC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,MAAM,CACJ,UAAU,EAAE,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAC,GAC/C,oBAAoB,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3D;AAED,MAAM,WAAW,iBAAkB,SAAQ,iBAAiB;IAC1D,OAAO,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACrC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,oBAAoB,KAAK,IAAI,CAAC;CAC3D;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,EAAE,CAAC;IACT,WAAW,EAAE,oBAAoB,EAAE,CAAC;CACrC;AAED,wBAAsB,WAAW,CAC/B,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAAC,gBAAgB,CAAC,CAoC3B"}
@@ -0,0 +1,41 @@
1
+ import {
2
+ coeraceConfig as coerceConfig
3
+ } from "./options.js";
4
+ async function processSpec(config) {
5
+ const { plugins, signal, onDiagnostic, ...generateConfig } = config;
6
+ signal?.throwIfAborted();
7
+ const coerced = coerceConfig({
8
+ ...generateConfig,
9
+ spec: structuredClone(generateConfig.spec)
10
+ });
11
+ const { spec, ...options } = coerced;
12
+ const diagnostics = [];
13
+ const pluginNames = plugins.map((plugin) => plugin.name);
14
+ const configuration = JSON.stringify({
15
+ pagination: options.pagination,
16
+ responses: options.responses
17
+ });
18
+ for (const plugin of plugins) {
19
+ signal?.throwIfAborted();
20
+ const context = {
21
+ spec,
22
+ options,
23
+ diagnostics,
24
+ signal,
25
+ report(diagnostic) {
26
+ const reported = { ...diagnostic, plugin: plugin.name };
27
+ diagnostics.push(reported);
28
+ onDiagnostic?.(reported);
29
+ return reported;
30
+ }
31
+ };
32
+ await plugin.process(context);
33
+ signal?.throwIfAborted();
34
+ }
35
+ spec["x-sdk-processing"] = { plugins: pluginNames, configuration };
36
+ return { spec, diagnostics };
37
+ }
38
+ export {
39
+ processSpec
40
+ };
41
+ //# sourceMappingURL=processing.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/lib/processing.ts"],
4
+ "sourcesContent": ["import type { OpenAPIObject } from 'openapi3-ts/oas31';\n\nimport {\n type GenerateSdkConfig,\n coeraceConfig as coerceConfig,\n} from './options.js';\nimport type { IR } from './types.js';\n\nexport type ProcessingDiagnosticSeverity = 'info' | 'warning' | 'error';\n\nexport interface ProcessingDiagnostic {\n plugin: string;\n severity: ProcessingDiagnosticSeverity;\n code: string;\n message: string;\n path?: string;\n}\n\nexport type ProcessingOptions = Omit<ReturnType<typeof coerceConfig>, 'spec'>;\n\nexport interface ProcessingContext {\n spec: IR;\n options: ProcessingOptions;\n diagnostics: ProcessingDiagnostic[];\n signal?: AbortSignal;\n report(\n diagnostic: Omit<ProcessingDiagnostic, 'plugin'>,\n ): ProcessingDiagnostic;\n}\n\nexport interface ProcessingPlugin {\n name: string;\n process(context: ProcessingContext): void | Promise<void>;\n}\n\nexport interface ProcessSpecConfig extends GenerateSdkConfig {\n plugins: readonly ProcessingPlugin[];\n signal?: AbortSignal;\n onDiagnostic?: (diagnostic: ProcessingDiagnostic) => void;\n}\n\nexport interface ProcessingResult {\n spec: IR;\n diagnostics: ProcessingDiagnostic[];\n}\n\nexport async function processSpec(\n config: ProcessSpecConfig,\n): Promise<ProcessingResult> {\n const { plugins, signal, onDiagnostic, ...generateConfig } = config;\n signal?.throwIfAborted();\n const coerced = coerceConfig({\n ...generateConfig,\n spec: structuredClone(generateConfig.spec) as OpenAPIObject,\n });\n const { spec, ...options } = coerced;\n const diagnostics: ProcessingDiagnostic[] = [];\n const pluginNames = plugins.map((plugin) => plugin.name);\n const configuration = JSON.stringify({\n pagination: options.pagination,\n responses: options.responses,\n });\n\n for (const plugin of plugins) {\n signal?.throwIfAborted();\n const context: ProcessingContext = {\n spec,\n options,\n diagnostics,\n signal,\n report(diagnostic) {\n const reported = { ...diagnostic, plugin: plugin.name };\n diagnostics.push(reported);\n onDiagnostic?.(reported);\n return reported;\n },\n };\n await plugin.process(context);\n signal?.throwIfAborted();\n }\n\n spec['x-sdk-processing'] = { plugins: pluginNames, configuration };\n\n return { spec, diagnostics };\n}\n"],
5
+ "mappings": "AAEA;AAAA,EAEE,iBAAiB;AAAA,OACZ;AAyCP,eAAsB,YACpB,QAC2B;AAC3B,QAAM,EAAE,SAAS,QAAQ,cAAc,GAAG,eAAe,IAAI;AAC7D,UAAQ,eAAe;AACvB,QAAM,UAAU,aAAa;AAAA,IAC3B,GAAG;AAAA,IACH,MAAM,gBAAgB,eAAe,IAAI;AAAA,EAC3C,CAAC;AACD,QAAM,EAAE,MAAM,GAAG,QAAQ,IAAI;AAC7B,QAAM,cAAsC,CAAC;AAC7C,QAAM,cAAc,QAAQ,IAAI,CAAC,WAAW,OAAO,IAAI;AACvD,QAAM,gBAAgB,KAAK,UAAU;AAAA,IACnC,YAAY,QAAQ;AAAA,IACpB,WAAW,QAAQ;AAAA,EACrB,CAAC;AAED,aAAW,UAAU,SAAS;AAC5B,YAAQ,eAAe;AACvB,UAAM,UAA6B;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,YAAY;AACjB,cAAM,WAAW,EAAE,GAAG,YAAY,QAAQ,OAAO,KAAK;AACtD,oBAAY,KAAK,QAAQ;AACzB,uBAAe,QAAQ;AACvB,eAAO;AAAA,MACT;AAAA,IACF;AACA,UAAM,OAAO,QAAQ,OAAO;AAC5B,YAAQ,eAAe;AAAA,EACzB;AAEA,OAAK,kBAAkB,IAAI,EAAE,SAAS,aAAa,cAAc;AAEjE,SAAO,EAAE,MAAM,YAAY;AAC7B;",
6
+ "names": []
7
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"reserved-keywords.d.ts","sourceRoot":"","sources":["../../src/lib/reserved-keywords.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,gBAAgB,aAkD3B,CAAC;AAEH,eAAO,MAAM,mBAAmB,aAI9B,CAAC"}
1
+ {"version":3,"file":"reserved-keywords.d.ts","sourceRoot":"","sources":["../../src/lib/reserved-keywords.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,gBAAgB,aAmE3B,CAAC;AAEH,eAAO,MAAM,mBAAmB,aAI9B,CAAC"}
@@ -57,7 +57,24 @@ const reservedKeywords = /* @__PURE__ */ new Set([
57
57
  // Strict mode / Generator functions
58
58
  // 'arguments' is not technically a reserved word, but it's a special identifier within functions
59
59
  // and assigning to it or declaring it can cause issues or unexpected behavior.
60
- "arguments"
60
+ "arguments",
61
+ // Common operation verbs are ambiguous group identifiers in generated SDKs.
62
+ "get",
63
+ "list",
64
+ "create",
65
+ "update",
66
+ "post",
67
+ "put",
68
+ "patch",
69
+ "do",
70
+ "send",
71
+ "add",
72
+ "remove",
73
+ "set",
74
+ "find",
75
+ "search",
76
+ "check",
77
+ "make"
61
78
  ]);
62
79
  const reservedSdkKeywords = /* @__PURE__ */ new Set([
63
80
  "ClientError",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/reserved-keywords.ts"],
4
- "sourcesContent": ["/**\n * Set of reserved TypeScript keywords and common verbs potentially used as tags.\n */\nexport const reservedKeywords = new Set([\n 'await', // Reserved in async functions\n 'break',\n 'case',\n 'catch',\n 'class',\n 'const',\n 'continue',\n 'debugger',\n 'default',\n 'delete',\n 'do',\n 'else',\n 'enum',\n 'export',\n 'extends',\n 'false',\n 'finally',\n 'for',\n 'function',\n 'if',\n 'implements', // Strict mode\n 'import',\n 'in',\n 'instanceof',\n 'interface', // Strict mode\n 'let', // Strict mode\n 'new',\n 'null',\n 'package', // Strict mode\n 'private', // Strict mode\n 'protected', // Strict mode\n 'public', // Strict mode\n 'return',\n 'static', // Strict mode\n 'super',\n 'switch',\n 'this',\n 'throw',\n 'true',\n 'try',\n 'typeof',\n 'var',\n 'void',\n 'while',\n 'with',\n 'yield', // Strict mode / Generator functions\n // 'arguments' is not technically a reserved word, but it's a special identifier within functions\n // and assigning to it or declaring it can cause issues or unexpected behavior.\n 'arguments',\n]);\n\nexport const reservedSdkKeywords = new Set([\n 'ClientError',\n 'Error',\n 'ConflictError',\n]);\n"],
5
- "mappings": "AAGO,MAAM,mBAAmB,oBAAI,IAAI;AAAA,EACtC;AAAA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA,EAGA;AACF,CAAC;AAEM,MAAM,sBAAsB,oBAAI,IAAI;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AACF,CAAC;",
4
+ "sourcesContent": ["/**\n * Set of reserved TypeScript keywords and common verbs potentially used as tags.\n */\nexport const reservedKeywords = new Set([\n 'await', // Reserved in async functions\n 'break',\n 'case',\n 'catch',\n 'class',\n 'const',\n 'continue',\n 'debugger',\n 'default',\n 'delete',\n 'do',\n 'else',\n 'enum',\n 'export',\n 'extends',\n 'false',\n 'finally',\n 'for',\n 'function',\n 'if',\n 'implements', // Strict mode\n 'import',\n 'in',\n 'instanceof',\n 'interface', // Strict mode\n 'let', // Strict mode\n 'new',\n 'null',\n 'package', // Strict mode\n 'private', // Strict mode\n 'protected', // Strict mode\n 'public', // Strict mode\n 'return',\n 'static', // Strict mode\n 'super',\n 'switch',\n 'this',\n 'throw',\n 'true',\n 'try',\n 'typeof',\n 'var',\n 'void',\n 'while',\n 'with',\n 'yield', // Strict mode / Generator functions\n // 'arguments' is not technically a reserved word, but it's a special identifier within functions\n // and assigning to it or declaring it can cause issues or unexpected behavior.\n 'arguments',\n // Common operation verbs are ambiguous group identifiers in generated SDKs.\n 'get',\n 'list',\n 'create',\n 'update',\n 'post',\n 'put',\n 'patch',\n 'do',\n 'send',\n 'add',\n 'remove',\n 'set',\n 'find',\n 'search',\n 'check',\n 'make',\n]);\n\nexport const reservedSdkKeywords = new Set([\n 'ClientError',\n 'Error',\n 'ConflictError',\n]);\n"],
5
+ "mappings": "AAGO,MAAM,mBAAmB,oBAAI,IAAI;AAAA,EACtC;AAAA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,MAAM,sBAAsB,oBAAI,IAAI;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AACF,CAAC;",
6
6
  "names": []
7
7
  }
package/dist/lib/tag.js CHANGED
@@ -6,7 +6,7 @@ function sanitizeTag(tag) {
6
6
  }
7
7
  tag = tag.replace(/[^A-Za-z0-9_-]/g, "").replace(/-+/g, "-");
8
8
  if (reservedKeywords.has(tag) || reservedSdkKeywords.has(tag)) {
9
- return `$${tag}`;
9
+ return `${tag}_`;
10
10
  }
11
11
  return tag;
12
12
  }
@@ -16,7 +16,7 @@ function sanitizeImportName(tag) {
16
16
  }
17
17
  tag = tag.replace(/[^A-Za-z0-9_-]/g, "");
18
18
  if (reservedKeywords.has(tag) || reservedSdkKeywords.has(tag)) {
19
- return `$${tag}`;
19
+ return `${tag}_`;
20
20
  }
21
21
  return tag;
22
22
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/tag.ts"],
4
- "sourcesContent": ["import type { OperationObject } from 'openapi3-ts/oas31';\n\nimport { camelcase } from '@sdk-it/core';\n\nimport { reservedKeywords, reservedSdkKeywords } from './reserved-keywords.js';\n\nexport function sanitizeTag(tag: string): string {\n // Prepend underscore if starts with a number\n if (/^\\d/.test(tag)) {\n return `_${tag}`;\n }\n\n tag = tag\n // Remove any non-alphanumeric characters except underscores and dashes\n .replace(/[^A-Za-z0-9_-]/g, '')\n // Normalize multiple dashes to a single dash\n .replace(/-+/g, '-');\n\n // Append underscore if it's a reserved keyword\n if (reservedKeywords.has(tag) || reservedSdkKeywords.has(tag)) {\n return `$${tag}`;\n }\n return tag;\n}\nexport function sanitizeImportName(tag: string): string {\n // Prepend underscore if starts with a number\n if (/^\\d/.test(tag)) {\n return `_${tag}`;\n }\n\n tag = tag\n // Remove any non-alphanumeric characters except underscores\n .replace(/[^A-Za-z0-9_-]/g, '');\n\n // Append underscore if it's a reserved keyword\n if (reservedKeywords.has(tag) || reservedSdkKeywords.has(tag)) {\n return `$${tag}`;\n }\n return tag;\n}\n\n/**\n * Attempts to determine a generic tag for an OpenAPI operation based on path and operationId.\n * Rules and fallbacks are documented within the code.\n * @param pathString The path string.\n * @param operation The OpenAPI Operation Object.\n * @returns A sanitized, camelCased tag name string.\n */\nexport function determineGenericTag(\n pathString: string,\n operation: OperationObject,\n): string {\n const operationId = operation.operationId || '';\n const VERSION_REGEX = /^[vV]\\d+$/;\n const commonVerbs = new Set([\n // Verbs to potentially strip from operationId prefix\n 'get',\n 'list',\n 'create',\n 'update',\n 'delete',\n 'post',\n 'put',\n 'patch',\n 'do',\n 'send',\n 'add',\n 'remove',\n 'set',\n 'find',\n 'search',\n 'check',\n 'make',\n ]);\n\n const segments = pathString.split('/').filter(Boolean);\n\n const potentialCandidates = segments.filter(\n (segment) =>\n segment &&\n !segment.startsWith('{') &&\n !segment.endsWith('}') &&\n !VERSION_REGEX.test(segment),\n );\n\n // --- Heuristic 1: Last non-'@' path segment ---\n for (let i = potentialCandidates.length - 1; i >= 0; i--) {\n const segment = potentialCandidates[i];\n if (!segment.startsWith('@')) {\n // Sanitize just before returning\n return sanitizeTag(camelcase(segment));\n }\n }\n\n const canFallbackToPathSegment = potentialCandidates.length > 0;\n\n // --- Heuristic 2: OperationId parsing ---\n if (operationId) {\n const lowerOpId = operationId.toLowerCase();\n const parts = operationId\n .replace(/([a-z])([A-Z])/g, '$1_$2')\n .replace(/([A-Z])([A-Z][a-z])/g, '$1_$2')\n .replace(/([a-zA-Z])(\\d)/g, '$1_$2')\n .replace(/(\\d)([a-zA-Z])/g, '$1_$2')\n .toLowerCase()\n .split(/[_-\\s]+/);\n\n const validParts = parts.filter(Boolean);\n\n // Quick skip: If opId is just a verb and we can use Heuristic 3, prefer that.\n if (\n commonVerbs.has(lowerOpId) &&\n validParts.length === 1 &&\n canFallbackToPathSegment\n ) {\n // Proceed directly to Heuristic 3\n }\n // Only process if there are valid parts and the quick skip didn't happen\n else if (validParts.length > 0) {\n const firstPart = validParts[0];\n const isFirstPartVerb = commonVerbs.has(firstPart);\n\n // Case 2a: Starts with verb, has following parts\n if (isFirstPartVerb && validParts.length > 1) {\n const verbPrefixLength = firstPart.length;\n let nextPartStartIndex = -1;\n if (operationId.length > verbPrefixLength) {\n // Simplified check for next part start\n const charAfterPrefix = operationId[verbPrefixLength];\n if (charAfterPrefix >= 'A' && charAfterPrefix <= 'Z') {\n nextPartStartIndex = verbPrefixLength;\n } else if (charAfterPrefix >= '0' && charAfterPrefix <= '9') {\n nextPartStartIndex = verbPrefixLength;\n } else if (['_', '-'].includes(charAfterPrefix)) {\n nextPartStartIndex = verbPrefixLength + 1;\n } else {\n const match = operationId\n .substring(verbPrefixLength)\n .match(/[A-Z0-9]/);\n if (match && match.index !== undefined) {\n nextPartStartIndex = verbPrefixLength + match.index;\n }\n if (\n nextPartStartIndex === -1 &&\n operationId.length > verbPrefixLength\n ) {\n nextPartStartIndex = verbPrefixLength; // Default guess\n }\n }\n }\n\n if (\n nextPartStartIndex !== -1 &&\n nextPartStartIndex < operationId.length\n ) {\n const remainingOriginalSubstring =\n operationId.substring(nextPartStartIndex);\n const potentialTag = camelcase(remainingOriginalSubstring);\n if (potentialTag) {\n // Sanitize just before returning\n return sanitizeTag(potentialTag);\n }\n }\n\n // Fallback: join remaining lowercased parts\n const potentialTagJoined = camelcase(validParts.slice(1).join('_'));\n if (potentialTagJoined) {\n // Sanitize just before returning\n return sanitizeTag(potentialTagJoined);\n }\n }\n\n // Case 2b: Doesn't start with verb, or only one part (might be verb)\n const potentialTagFull = camelcase(operationId);\n if (potentialTagFull) {\n const isResultSingleVerb = validParts.length === 1 && isFirstPartVerb;\n\n // Avoid returning only a verb if Heuristic 3 is possible\n if (!(isResultSingleVerb && canFallbackToPathSegment)) {\n if (potentialTagFull.length > 0) {\n // Sanitize just before returning\n return sanitizeTag(potentialTagFull);\n }\n }\n }\n\n // Case 2c: Further fallbacks within OpId if above failed/skipped\n const firstPartCamel = camelcase(firstPart);\n if (firstPartCamel) {\n const isFirstPartCamelVerb = commonVerbs.has(firstPartCamel);\n if (\n !isFirstPartCamelVerb ||\n validParts.length === 1 ||\n !canFallbackToPathSegment\n ) {\n // Sanitize just before returning\n return sanitizeTag(firstPartCamel);\n }\n }\n if (\n isFirstPartVerb &&\n validParts.length > 1 &&\n validParts[1] &&\n canFallbackToPathSegment\n ) {\n const secondPartCamel = camelcase(validParts[1]);\n if (secondPartCamel) {\n // Sanitize just before returning\n return sanitizeTag(secondPartCamel);\n }\n }\n } // End if(validParts.length > 0) after quick skip check\n } // End if(operationId)\n\n // --- Heuristic 3: First path segment (stripping '@') ---\n if (potentialCandidates.length > 0) {\n let firstCandidate = potentialCandidates[0];\n if (firstCandidate.startsWith('@')) {\n firstCandidate = firstCandidate.substring(1);\n }\n if (firstCandidate) {\n // Sanitize just before returning\n return sanitizeTag(camelcase(firstCandidate));\n }\n }\n\n // --- Heuristic 4: Default ---\n console.warn(\n `Could not determine a suitable tag for path: ${pathString}, operationId: ${operationId}. Using 'unknown'.`,\n );\n return 'unknown'; // 'unknown' is safe\n}\n"],
5
- "mappings": "AAEA,SAAS,iBAAiB;AAE1B,SAAS,kBAAkB,2BAA2B;AAE/C,SAAS,YAAY,KAAqB;AAE/C,MAAI,MAAM,KAAK,GAAG,GAAG;AACnB,WAAO,IAAI,GAAG;AAAA,EAChB;AAEA,QAAM,IAEH,QAAQ,mBAAmB,EAAE,EAE7B,QAAQ,OAAO,GAAG;AAGrB,MAAI,iBAAiB,IAAI,GAAG,KAAK,oBAAoB,IAAI,GAAG,GAAG;AAC7D,WAAO,IAAI,GAAG;AAAA,EAChB;AACA,SAAO;AACT;AACO,SAAS,mBAAmB,KAAqB;AAEtD,MAAI,MAAM,KAAK,GAAG,GAAG;AACnB,WAAO,IAAI,GAAG;AAAA,EAChB;AAEA,QAAM,IAEH,QAAQ,mBAAmB,EAAE;AAGhC,MAAI,iBAAiB,IAAI,GAAG,KAAK,oBAAoB,IAAI,GAAG,GAAG;AAC7D,WAAO,IAAI,GAAG;AAAA,EAChB;AACA,SAAO;AACT;AASO,SAAS,oBACd,YACA,WACQ;AACR,QAAM,cAAc,UAAU,eAAe;AAC7C,QAAM,gBAAgB;AACtB,QAAM,cAAc,oBAAI,IAAI;AAAA;AAAA,IAE1B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,WAAW,WAAW,MAAM,GAAG,EAAE,OAAO,OAAO;AAErD,QAAM,sBAAsB,SAAS;AAAA,IACnC,CAAC,YACC,WACA,CAAC,QAAQ,WAAW,GAAG,KACvB,CAAC,QAAQ,SAAS,GAAG,KACrB,CAAC,cAAc,KAAK,OAAO;AAAA,EAC/B;AAGA,WAAS,IAAI,oBAAoB,SAAS,GAAG,KAAK,GAAG,KAAK;AACxD,UAAM,UAAU,oBAAoB,CAAC;AACrC,QAAI,CAAC,QAAQ,WAAW,GAAG,GAAG;AAE5B,aAAO,YAAY,UAAU,OAAO,CAAC;AAAA,IACvC;AAAA,EACF;AAEA,QAAM,2BAA2B,oBAAoB,SAAS;AAG9D,MAAI,aAAa;AACf,UAAM,YAAY,YAAY,YAAY;AAC1C,UAAM,QAAQ,YACX,QAAQ,mBAAmB,OAAO,EAClC,QAAQ,wBAAwB,OAAO,EACvC,QAAQ,mBAAmB,OAAO,EAClC,QAAQ,mBAAmB,OAAO,EAClC,YAAY,EACZ,MAAM,SAAS;AAElB,UAAM,aAAa,MAAM,OAAO,OAAO;AAGvC,QACE,YAAY,IAAI,SAAS,KACzB,WAAW,WAAW,KACtB,0BACA;AAAA,IAEF,WAES,WAAW,SAAS,GAAG;AAC9B,YAAM,YAAY,WAAW,CAAC;AAC9B,YAAM,kBAAkB,YAAY,IAAI,SAAS;AAGjD,UAAI,mBAAmB,WAAW,SAAS,GAAG;AAC5C,cAAM,mBAAmB,UAAU;AACnC,YAAI,qBAAqB;AACzB,YAAI,YAAY,SAAS,kBAAkB;AAEzC,gBAAM,kBAAkB,YAAY,gBAAgB;AACpD,cAAI,mBAAmB,OAAO,mBAAmB,KAAK;AACpD,iCAAqB;AAAA,UACvB,WAAW,mBAAmB,OAAO,mBAAmB,KAAK;AAC3D,iCAAqB;AAAA,UACvB,WAAW,CAAC,KAAK,GAAG,EAAE,SAAS,eAAe,GAAG;AAC/C,iCAAqB,mBAAmB;AAAA,UAC1C,OAAO;AACL,kBAAM,QAAQ,YACX,UAAU,gBAAgB,EAC1B,MAAM,UAAU;AACnB,gBAAI,SAAS,MAAM,UAAU,QAAW;AACtC,mCAAqB,mBAAmB,MAAM;AAAA,YAChD;AACA,gBACE,uBAAuB,MACvB,YAAY,SAAS,kBACrB;AACA,mCAAqB;AAAA,YACvB;AAAA,UACF;AAAA,QACF;AAEA,YACE,uBAAuB,MACvB,qBAAqB,YAAY,QACjC;AACA,gBAAM,6BACJ,YAAY,UAAU,kBAAkB;AAC1C,gBAAM,eAAe,UAAU,0BAA0B;AACzD,cAAI,cAAc;AAEhB,mBAAO,YAAY,YAAY;AAAA,UACjC;AAAA,QACF;AAGA,cAAM,qBAAqB,UAAU,WAAW,MAAM,CAAC,EAAE,KAAK,GAAG,CAAC;AAClE,YAAI,oBAAoB;AAEtB,iBAAO,YAAY,kBAAkB;AAAA,QACvC;AAAA,MACF;AAGA,YAAM,mBAAmB,UAAU,WAAW;AAC9C,UAAI,kBAAkB;AACpB,cAAM,qBAAqB,WAAW,WAAW,KAAK;AAGtD,YAAI,EAAE,sBAAsB,2BAA2B;AACrD,cAAI,iBAAiB,SAAS,GAAG;AAE/B,mBAAO,YAAY,gBAAgB;AAAA,UACrC;AAAA,QACF;AAAA,MACF;AAGA,YAAM,iBAAiB,UAAU,SAAS;AAC1C,UAAI,gBAAgB;AAClB,cAAM,uBAAuB,YAAY,IAAI,cAAc;AAC3D,YACE,CAAC,wBACD,WAAW,WAAW,KACtB,CAAC,0BACD;AAEA,iBAAO,YAAY,cAAc;AAAA,QACnC;AAAA,MACF;AACA,UACE,mBACA,WAAW,SAAS,KACpB,WAAW,CAAC,KACZ,0BACA;AACA,cAAM,kBAAkB,UAAU,WAAW,CAAC,CAAC;AAC/C,YAAI,iBAAiB;AAEnB,iBAAO,YAAY,eAAe;AAAA,QACpC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,oBAAoB,SAAS,GAAG;AAClC,QAAI,iBAAiB,oBAAoB,CAAC;AAC1C,QAAI,eAAe,WAAW,GAAG,GAAG;AAClC,uBAAiB,eAAe,UAAU,CAAC;AAAA,IAC7C;AACA,QAAI,gBAAgB;AAElB,aAAO,YAAY,UAAU,cAAc,CAAC;AAAA,IAC9C;AAAA,EACF;AAGA,UAAQ;AAAA,IACN,gDAAgD,UAAU,kBAAkB,WAAW;AAAA,EACzF;AACA,SAAO;AACT;",
4
+ "sourcesContent": ["import type { OperationObject } from 'openapi3-ts/oas31';\n\nimport { camelcase } from '@sdk-it/core';\n\nimport { reservedKeywords, reservedSdkKeywords } from './reserved-keywords.js';\n\nexport function sanitizeTag(tag: string): string {\n // Prepend underscore if starts with a number\n if (/^\\d/.test(tag)) {\n return `_${tag}`;\n }\n\n tag = tag\n // Remove any non-alphanumeric characters except underscores and dashes\n .replace(/[^A-Za-z0-9_-]/g, '')\n // Normalize multiple dashes to a single dash\n .replace(/-+/g, '-');\n\n // Append underscore if it's a reserved keyword\n if (reservedKeywords.has(tag) || reservedSdkKeywords.has(tag)) {\n return `${tag}_`;\n }\n return tag;\n}\nexport function sanitizeImportName(tag: string): string {\n // Prepend underscore if starts with a number\n if (/^\\d/.test(tag)) {\n return `_${tag}`;\n }\n\n tag = tag\n // Remove any non-alphanumeric characters except underscores\n .replace(/[^A-Za-z0-9_-]/g, '');\n\n // Append underscore if it's a reserved keyword\n if (reservedKeywords.has(tag) || reservedSdkKeywords.has(tag)) {\n return `${tag}_`;\n }\n return tag;\n}\n\n/**\n * Attempts to determine a generic tag for an OpenAPI operation based on path and operationId.\n * Rules and fallbacks are documented within the code.\n * @param pathString The path string.\n * @param operation The OpenAPI Operation Object.\n * @returns A sanitized, camelCased tag name string.\n */\nexport function determineGenericTag(\n pathString: string,\n operation: OperationObject,\n): string {\n const operationId = operation.operationId || '';\n const VERSION_REGEX = /^[vV]\\d+$/;\n const commonVerbs = new Set([\n // Verbs to potentially strip from operationId prefix\n 'get',\n 'list',\n 'create',\n 'update',\n 'delete',\n 'post',\n 'put',\n 'patch',\n 'do',\n 'send',\n 'add',\n 'remove',\n 'set',\n 'find',\n 'search',\n 'check',\n 'make',\n ]);\n\n const segments = pathString.split('/').filter(Boolean);\n\n const potentialCandidates = segments.filter(\n (segment) =>\n segment &&\n !segment.startsWith('{') &&\n !segment.endsWith('}') &&\n !VERSION_REGEX.test(segment),\n );\n\n // --- Heuristic 1: Last non-'@' path segment ---\n for (let i = potentialCandidates.length - 1; i >= 0; i--) {\n const segment = potentialCandidates[i];\n if (!segment.startsWith('@')) {\n // Sanitize just before returning\n return sanitizeTag(camelcase(segment));\n }\n }\n\n const canFallbackToPathSegment = potentialCandidates.length > 0;\n\n // --- Heuristic 2: OperationId parsing ---\n if (operationId) {\n const lowerOpId = operationId.toLowerCase();\n const parts = operationId\n .replace(/([a-z])([A-Z])/g, '$1_$2')\n .replace(/([A-Z])([A-Z][a-z])/g, '$1_$2')\n .replace(/([a-zA-Z])(\\d)/g, '$1_$2')\n .replace(/(\\d)([a-zA-Z])/g, '$1_$2')\n .toLowerCase()\n .split(/[_-\\s]+/);\n\n const validParts = parts.filter(Boolean);\n\n // Quick skip: If opId is just a verb and we can use Heuristic 3, prefer that.\n if (\n commonVerbs.has(lowerOpId) &&\n validParts.length === 1 &&\n canFallbackToPathSegment\n ) {\n // Proceed directly to Heuristic 3\n }\n // Only process if there are valid parts and the quick skip didn't happen\n else if (validParts.length > 0) {\n const firstPart = validParts[0];\n const isFirstPartVerb = commonVerbs.has(firstPart);\n\n // Case 2a: Starts with verb, has following parts\n if (isFirstPartVerb && validParts.length > 1) {\n const verbPrefixLength = firstPart.length;\n let nextPartStartIndex = -1;\n if (operationId.length > verbPrefixLength) {\n // Simplified check for next part start\n const charAfterPrefix = operationId[verbPrefixLength];\n if (charAfterPrefix >= 'A' && charAfterPrefix <= 'Z') {\n nextPartStartIndex = verbPrefixLength;\n } else if (charAfterPrefix >= '0' && charAfterPrefix <= '9') {\n nextPartStartIndex = verbPrefixLength;\n } else if (['_', '-'].includes(charAfterPrefix)) {\n nextPartStartIndex = verbPrefixLength + 1;\n } else {\n const match = operationId\n .substring(verbPrefixLength)\n .match(/[A-Z0-9]/);\n if (match && match.index !== undefined) {\n nextPartStartIndex = verbPrefixLength + match.index;\n }\n if (\n nextPartStartIndex === -1 &&\n operationId.length > verbPrefixLength\n ) {\n nextPartStartIndex = verbPrefixLength; // Default guess\n }\n }\n }\n\n if (\n nextPartStartIndex !== -1 &&\n nextPartStartIndex < operationId.length\n ) {\n const remainingOriginalSubstring =\n operationId.substring(nextPartStartIndex);\n const potentialTag = camelcase(remainingOriginalSubstring);\n if (potentialTag) {\n // Sanitize just before returning\n return sanitizeTag(potentialTag);\n }\n }\n\n // Fallback: join remaining lowercased parts\n const potentialTagJoined = camelcase(validParts.slice(1).join('_'));\n if (potentialTagJoined) {\n // Sanitize just before returning\n return sanitizeTag(potentialTagJoined);\n }\n }\n\n // Case 2b: Doesn't start with verb, or only one part (might be verb)\n const potentialTagFull = camelcase(operationId);\n if (potentialTagFull) {\n const isResultSingleVerb = validParts.length === 1 && isFirstPartVerb;\n\n // Avoid returning only a verb if Heuristic 3 is possible\n if (!(isResultSingleVerb && canFallbackToPathSegment)) {\n if (potentialTagFull.length > 0) {\n // Sanitize just before returning\n return sanitizeTag(potentialTagFull);\n }\n }\n }\n\n // Case 2c: Further fallbacks within OpId if above failed/skipped\n const firstPartCamel = camelcase(firstPart);\n if (firstPartCamel) {\n const isFirstPartCamelVerb = commonVerbs.has(firstPartCamel);\n if (\n !isFirstPartCamelVerb ||\n validParts.length === 1 ||\n !canFallbackToPathSegment\n ) {\n // Sanitize just before returning\n return sanitizeTag(firstPartCamel);\n }\n }\n if (\n isFirstPartVerb &&\n validParts.length > 1 &&\n validParts[1] &&\n canFallbackToPathSegment\n ) {\n const secondPartCamel = camelcase(validParts[1]);\n if (secondPartCamel) {\n // Sanitize just before returning\n return sanitizeTag(secondPartCamel);\n }\n }\n } // End if(validParts.length > 0) after quick skip check\n } // End if(operationId)\n\n // --- Heuristic 3: First path segment (stripping '@') ---\n if (potentialCandidates.length > 0) {\n let firstCandidate = potentialCandidates[0];\n if (firstCandidate.startsWith('@')) {\n firstCandidate = firstCandidate.substring(1);\n }\n if (firstCandidate) {\n // Sanitize just before returning\n return sanitizeTag(camelcase(firstCandidate));\n }\n }\n\n // --- Heuristic 4: Default ---\n console.warn(\n `Could not determine a suitable tag for path: ${pathString}, operationId: ${operationId}. Using 'unknown'.`,\n );\n return 'unknown'; // 'unknown' is safe\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }