@kubb/plugin-ts 5.0.0-beta.22 → 5.0.0-beta.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -171,6 +171,129 @@ function stringify(value) {
171
171
  return JSON.stringify(trimQuotes(value.toString()));
172
172
  }
173
173
  //#endregion
174
+ //#region ../../internals/utils/src/reserved.ts
175
+ /**
176
+ * JavaScript and Java reserved words.
177
+ * @link https://github.com/jonschlinkert/reserved/blob/master/index.js
178
+ */
179
+ const reservedWords = new Set([
180
+ "abstract",
181
+ "arguments",
182
+ "boolean",
183
+ "break",
184
+ "byte",
185
+ "case",
186
+ "catch",
187
+ "char",
188
+ "class",
189
+ "const",
190
+ "continue",
191
+ "debugger",
192
+ "default",
193
+ "delete",
194
+ "do",
195
+ "double",
196
+ "else",
197
+ "enum",
198
+ "eval",
199
+ "export",
200
+ "extends",
201
+ "false",
202
+ "final",
203
+ "finally",
204
+ "float",
205
+ "for",
206
+ "function",
207
+ "goto",
208
+ "if",
209
+ "implements",
210
+ "import",
211
+ "in",
212
+ "instanceof",
213
+ "int",
214
+ "interface",
215
+ "let",
216
+ "long",
217
+ "native",
218
+ "new",
219
+ "null",
220
+ "package",
221
+ "private",
222
+ "protected",
223
+ "public",
224
+ "return",
225
+ "short",
226
+ "static",
227
+ "super",
228
+ "switch",
229
+ "synchronized",
230
+ "this",
231
+ "throw",
232
+ "throws",
233
+ "transient",
234
+ "true",
235
+ "try",
236
+ "typeof",
237
+ "var",
238
+ "void",
239
+ "volatile",
240
+ "while",
241
+ "with",
242
+ "yield",
243
+ "Array",
244
+ "Date",
245
+ "hasOwnProperty",
246
+ "Infinity",
247
+ "isFinite",
248
+ "isNaN",
249
+ "isPrototypeOf",
250
+ "length",
251
+ "Math",
252
+ "name",
253
+ "NaN",
254
+ "Number",
255
+ "Object",
256
+ "prototype",
257
+ "String",
258
+ "toString",
259
+ "undefined",
260
+ "valueOf"
261
+ ]);
262
+ /**
263
+ * Returns `true` when `name` is a syntactically valid JavaScript variable name.
264
+ *
265
+ * @example
266
+ * ```ts
267
+ * isValidVarName('status') // true
268
+ * isValidVarName('class') // false (reserved word)
269
+ * isValidVarName('42foo') // false (starts with digit)
270
+ * ```
271
+ */
272
+ function isValidVarName(name) {
273
+ if (!name || reservedWords.has(name)) return false;
274
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
275
+ }
276
+ /**
277
+ * Returns `name` when it's a syntactically valid JavaScript variable name,
278
+ * otherwise prefixes it with `_` so the result is a valid identifier.
279
+ *
280
+ * Useful for sanitizing OpenAPI schema names or operation IDs that start with
281
+ * a digit (e.g. `409`, `504AccountCancel`) before using them as exported
282
+ * variable, type, or function names.
283
+ *
284
+ * @example
285
+ * ```ts
286
+ * ensureValidVarName('409') // '_409'
287
+ * ensureValidVarName('504AccountCancel') // '_504AccountCancel'
288
+ * ensureValidVarName('Pet') // 'Pet'
289
+ * ensureValidVarName('class') // '_class'
290
+ * ```
291
+ */
292
+ function ensureValidVarName(name) {
293
+ if (!name || isValidVarName(name)) return name;
294
+ return `_${name}`;
295
+ }
296
+ //#endregion
174
297
  //#region src/constants.ts
175
298
  /**
176
299
  * `optionalType` values that cause a property's type to include `| undefined`.
@@ -664,13 +787,13 @@ function Enum({ node, enumType, enumTypeSuffix, enumKeyCasing, resolver }) {
664
787
  isExportable: true,
665
788
  isIndexable: true,
666
789
  isTypeOnly: false,
667
- children: (0, _kubb_parser_ts.safePrint)(nameNode)
790
+ children: _kubb_parser_ts.parserTs.print(nameNode)
668
791
  }), /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Source, {
669
792
  name: typeName,
670
793
  isIndexable: true,
671
794
  isExportable: ENUM_TYPES_WITH_RUNTIME_VALUE.has(enumType),
672
795
  isTypeOnly: ENUM_TYPES_WITH_TYPE_ONLY.has(enumType),
673
- children: (0, _kubb_parser_ts.safePrint)(typeNode)
796
+ children: _kubb_parser_ts.parserTs.print(typeNode)
674
797
  })] });
675
798
  }
676
799
  //#endregion
@@ -733,14 +856,14 @@ function buildPropertyJSDocComments(schema) {
733
856
  const meta = _kubb_core.ast.syncSchemaRef(schema);
734
857
  const isArray = meta?.primitive === "array";
735
858
  return [
736
- meta && "description" in meta && meta.description ? `@description ${jsStringEscape(meta.description)}` : void 0,
737
- meta && "deprecated" in meta && meta.deprecated ? "@deprecated" : void 0,
738
- !isArray && meta && "min" in meta && meta.min !== void 0 ? `@minLength ${meta.min}` : void 0,
739
- !isArray && meta && "max" in meta && meta.max !== void 0 ? `@maxLength ${meta.max}` : void 0,
740
- meta && "pattern" in meta && meta.pattern ? `@pattern ${meta.pattern}` : void 0,
741
- meta && "default" in meta && meta.default !== void 0 ? `@default ${"primitive" in meta && meta.primitive === "string" ? stringify(meta.default) : meta.default}` : void 0,
742
- meta && "example" in meta && meta.example !== void 0 ? `@example ${meta.example}` : void 0,
743
- meta && "primitive" in meta && meta.primitive ? [`@type ${meta.primitive}`, "optional" in schema && schema.optional ? " | undefined" : void 0].filter(Boolean).join("") : void 0
859
+ meta && "description" in meta && meta.description ? `@description ${jsStringEscape(meta.description)}` : null,
860
+ meta && "deprecated" in meta && meta.deprecated ? "@deprecated" : null,
861
+ !isArray && meta && "min" in meta && meta.min !== void 0 ? `@minLength ${meta.min}` : null,
862
+ !isArray && meta && "max" in meta && meta.max !== void 0 ? `@maxLength ${meta.max}` : null,
863
+ meta && "pattern" in meta && meta.pattern ? `@pattern ${meta.pattern}` : null,
864
+ meta && "default" in meta && meta.default !== void 0 ? `@default ${"primitive" in meta && meta.primitive === "string" ? stringify(meta.default) : meta.default}` : null,
865
+ meta && "example" in meta && meta.example !== void 0 ? `@example ${meta.example}` : null,
866
+ meta && "primitive" in meta && meta.primitive ? [`@type ${meta.primitive}`, "optional" in schema && schema.optional ? " | undefined" : null].filter(Boolean).join("") : null
744
867
  ].filter(Boolean);
745
868
  }
746
869
  function buildParams(node, { params, resolver }) {
@@ -984,7 +1107,8 @@ const printerTs = _kubb_core.ast.definePrinter((options) => {
984
1107
  const meta = _kubb_core.ast.syncSchemaRef(node);
985
1108
  if (!name) {
986
1109
  const withNullable = meta.nullable ? createUnionDeclaration({ nodes: [transformed, keywordTypeNodes.null] }) : transformed;
987
- return (0, _kubb_parser_ts.safePrint)((meta.nullish || meta.optional) && addsUndefined ? createUnionDeclaration({ nodes: [withNullable, keywordTypeNodes.undefined] }) : withNullable);
1110
+ const result = (meta.nullish || meta.optional) && addsUndefined ? createUnionDeclaration({ nodes: [withNullable, keywordTypeNodes.undefined] }) : withNullable;
1111
+ return _kubb_parser_ts.parserTs.print(result);
988
1112
  }
989
1113
  const inner = (() => {
990
1114
  const omitted = keysToOmit?.length ? createOmitDeclaration({
@@ -995,17 +1119,17 @@ const printerTs = _kubb_core.ast.definePrinter((options) => {
995
1119
  const withNullable = meta.nullable ? createUnionDeclaration({ nodes: [omitted, keywordTypeNodes.null] }) : omitted;
996
1120
  return meta.nullish || meta.optional ? createUnionDeclaration({ nodes: [withNullable, keywordTypeNodes.undefined] }) : withNullable;
997
1121
  })();
998
- const useTypeGeneration = syntaxType === "type" || inner.kind === syntaxKind.union || !!keysToOmit?.length;
999
- return (0, _kubb_parser_ts.safePrint)(createTypeDeclaration({
1122
+ const typeNode = createTypeDeclaration({
1000
1123
  name,
1001
1124
  isExportable: true,
1002
1125
  type: inner,
1003
- syntax: useTypeGeneration ? "type" : "interface",
1126
+ syntax: syntaxType === "type" || inner.kind === syntaxKind.union || !!keysToOmit?.length ? "type" : "interface",
1004
1127
  comments: buildPropertyJSDocComments({
1005
1128
  ...meta,
1006
1129
  description
1007
1130
  })
1008
- }));
1131
+ });
1132
+ return _kubb_parser_ts.parserTs.print(typeNode);
1009
1133
  }
1010
1134
  };
1011
1135
  });
@@ -1024,6 +1148,12 @@ function getPerContentTypeName(dataName, suffix) {
1024
1148
  if (dataName.endsWith("Data")) return suffix.endsWith("Data") ? dataName.slice(0, -4) + suffix : `${dataName.slice(0, -4)}${suffix}Data`;
1025
1149
  return dataName + suffix;
1026
1150
  }
1151
+ /**
1152
+ * Built-in generator for `@kubb/plugin-ts`. Emits one TypeScript file per
1153
+ * schema in the spec plus per-operation request, response, and parameter
1154
+ * types. Drop-replace with a custom `Generator<PluginTs>` to change how
1155
+ * TypeScript output is produced.
1156
+ */
1027
1157
  const typeGenerator = (0, _kubb_core.defineGenerator)({
1028
1158
  name: "typescript",
1029
1159
  renderer: _kubb_renderer_jsx.jsxRendererSync,
@@ -1045,7 +1175,7 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
1045
1175
  }, {
1046
1176
  root,
1047
1177
  output,
1048
- group
1178
+ group: group ?? void 0
1049
1179
  }).path
1050
1180
  }));
1051
1181
  const isEnumSchema = !!_kubb_core.ast.narrowSchema(node, _kubb_core.ast.schemaTypes.enum);
@@ -1057,7 +1187,7 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
1057
1187
  }, {
1058
1188
  root,
1059
1189
  output,
1060
- group
1190
+ group: group ?? void 0
1061
1191
  })
1062
1192
  };
1063
1193
  const schemaPrinter = printerTs({
@@ -1117,7 +1247,7 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
1117
1247
  }, {
1118
1248
  root,
1119
1249
  output,
1120
- group
1250
+ group: group ?? void 0
1121
1251
  }) };
1122
1252
  const enumSchemaNames = new Set(ctx.meta.enumNames);
1123
1253
  function resolveImportName(schemaName) {
@@ -1134,7 +1264,7 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
1134
1264
  }, {
1135
1265
  root,
1136
1266
  output,
1137
- group
1267
+ group: group ?? void 0
1138
1268
  }).path
1139
1269
  }));
1140
1270
  const schemaPrinter = printerTs({
@@ -1280,20 +1410,21 @@ const typeGenerator = (0, _kubb_core.defineGenerator)({
1280
1410
  //#endregion
1281
1411
  //#region src/resolvers/resolverTs.ts
1282
1412
  /**
1283
- * Resolver for `@kubb/plugin-ts` that provides the default naming and path-resolution
1284
- * helpers used by the plugin. Import this in other plugins to resolve the exact names and
1285
- * paths that `plugin-ts` generates without hardcoding the conventions.
1413
+ * Default resolver used by `@kubb/plugin-ts`. Decides the names and file paths
1414
+ * for every generated TypeScript type. Import this in other plugins that need
1415
+ * to reference the exact names `plugin-ts` produces without duplicating the
1416
+ * casing/file-layout rules.
1286
1417
  *
1287
- * The `default` method is automatically injected by `defineResolver` it uses `camelCase`
1288
- * for identifiers/files and `pascalCase` for type names.
1418
+ * The `default` method is supplied by `defineResolver`. It uses PascalCase for
1419
+ * type names and PascalCase-with-isFile for files.
1289
1420
  *
1290
- * @example
1421
+ * @example Resolve a type and file name
1291
1422
  * ```ts
1292
- * import { resolver } from '@kubb/plugin-ts'
1423
+ * import { resolverTs } from '@kubb/plugin-ts'
1293
1424
  *
1294
- * resolver.default('list pets', 'type') // 'ListPets'
1295
- * resolver.resolveName('list pets status 200') // 'ListPetsStatus200'
1296
- * resolver.resolvePathName('list pets', 'file') // 'listPets'
1425
+ * resolverTs.default('list pets', 'type') // 'ListPets'
1426
+ * resolverTs.resolvePathName('list pets', 'file') // 'ListPets'
1427
+ * resolverTs.resolveResponseStatusName(node, 200) // 'ListPetsStatus200'
1297
1428
  * ```
1298
1429
  */
1299
1430
  const resolverTs = (0, _kubb_core.defineResolver)(() => {
@@ -1301,13 +1432,15 @@ const resolverTs = (0, _kubb_core.defineResolver)(() => {
1301
1432
  name: "default",
1302
1433
  pluginName: "plugin-ts",
1303
1434
  default(name, type) {
1304
- return pascalCase(name, { isFile: type === "file" });
1435
+ const resolved = pascalCase(name, { isFile: type === "file" });
1436
+ return type === "file" ? resolved : ensureValidVarName(resolved);
1305
1437
  },
1306
1438
  resolveTypeName(name) {
1307
- return pascalCase(name);
1439
+ return ensureValidVarName(pascalCase(name));
1308
1440
  },
1309
1441
  resolvePathName(name, type) {
1310
- return pascalCase(name, { isFile: type === "file" });
1442
+ const resolved = pascalCase(name, { isFile: type === "file" });
1443
+ return type === "file" ? resolved : ensureValidVarName(resolved);
1311
1444
  },
1312
1445
  resolveParamName(node, param) {
1313
1446
  return this.resolveTypeName(`${node.operationId} ${param.in} ${param.name}`);
@@ -1344,22 +1477,31 @@ const resolverTs = (0, _kubb_core.defineResolver)(() => {
1344
1477
  //#endregion
1345
1478
  //#region src/plugin.ts
1346
1479
  /**
1347
- * Canonical plugin name for `@kubb/plugin-ts`, used to identify the plugin in driver lookups and warnings.
1480
+ * Canonical plugin name for `@kubb/plugin-ts`. Used for driver lookups and
1481
+ * cross-plugin dependency references.
1348
1482
  */
1349
1483
  const pluginTsName = "plugin-ts";
1350
1484
  /**
1351
- * The `@kubb/plugin-ts` plugin factory.
1352
- *
1353
- * Generates TypeScript type declarations from an OpenAPI/AST `RootNode`.
1354
- * Walks schemas and operations, delegates rendering to the active generators,
1355
- * and writes barrel files based on `output.barrelType`.
1485
+ * Generates TypeScript `type` aliases and `interface` declarations from an
1486
+ * OpenAPI spec. The foundation that every other Kubb plugin builds on:
1487
+ * clients, query hooks, mocks, and validators all reference the names this
1488
+ * plugin produces.
1356
1489
  *
1357
1490
  * @example
1358
1491
  * ```ts
1359
- * import pluginTs from '@kubb/plugin-ts'
1492
+ * import { defineConfig } from 'kubb'
1493
+ * import { pluginTs } from '@kubb/plugin-ts'
1360
1494
  *
1361
1495
  * export default defineConfig({
1362
- * plugins: [pluginTs({ output: { path: 'types' }, enumType: 'asConst' })],
1496
+ * input: { path: './petStore.yaml' },
1497
+ * output: { path: './src/gen' },
1498
+ * plugins: [
1499
+ * pluginTs({
1500
+ * output: { path: './types' },
1501
+ * enumType: 'asConst',
1502
+ * optionalType: 'questionTokenAndUndefined',
1503
+ * }),
1504
+ * ],
1363
1505
  * })
1364
1506
  * ```
1365
1507
  */
@@ -1374,7 +1516,7 @@ const pluginTs = (0, _kubb_core.definePlugin)((options) => {
1374
1516
  if (group.type === "path") return `${ctx.group.split("/")[1]}`;
1375
1517
  return `${camelCase(ctx.group)}Controller`;
1376
1518
  }
1377
- } : void 0;
1519
+ } : null;
1378
1520
  return {
1379
1521
  name: pluginTsName,
1380
1522
  options,