@kubb/plugin-msw 5.0.0-beta.84 → 5.0.0-beta.86

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
@@ -35,31 +35,6 @@ function camelCase(text, { prefix = "", suffix = "" } = {}) {
35
35
  return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false);
36
36
  }
37
37
  //#endregion
38
- //#region ../../internals/utils/src/fs.ts
39
- /**
40
- * Builds a nested file path from a dotted name. Splits on dots that precede a letter
41
- * (so version numbers embedded in operationIds like `v2025.0` stay intact), camelCases
42
- * every earlier segment, applies `caseLast` to the final segment, and joins with `/`.
43
- *
44
- * Empty segments are dropped before joining. They arise when the name starts with a dot
45
- * followed by a letter (e.g. `..Schema` splits into `['..', 'Schema']` and `'..'` cases to
46
- * an empty string). Without this a leading `/` would form, which `path.resolve` reads as an
47
- * absolute path, letting generated files escape the configured output directory.
48
- *
49
- * @example Nested path from a dotted name
50
- * `toFilePath('pet.petId') // 'pet/petId'`
51
- *
52
- * @example PascalCase the final segment
53
- * `toFilePath('pet.Pet', pascalCase) // 'pet/Pet'`
54
- *
55
- * @example Suffix applied to the final segment only
56
- * `toFilePath('tag.tag', (part) => camelCase(part, { suffix: 'schema' })) // 'tag/tagSchema'`
57
- */
58
- function toFilePath(name, caseLast = camelCase) {
59
- const parts = name.split(/\.(?=[a-zA-Z])/);
60
- return parts.map((part, i) => i === parts.length - 1 ? caseLast(part) : camelCase(part)).filter(Boolean).join("/");
61
- }
62
- //#endregion
63
38
  //#region ../../internals/utils/src/reserved.ts
64
39
  /**
65
40
  * JavaScript and Java reserved words.
@@ -160,6 +135,22 @@ const reservedWords = /* @__PURE__ */ new Set([
160
135
  */
161
136
  function isValidVarName(name) {
162
137
  if (!name || reservedWords.has(name)) return false;
138
+ return isIdentifier(name);
139
+ }
140
+ /**
141
+ * Returns `true` when `name` is syntactically a valid identifier, ignoring reserved words.
142
+ *
143
+ * Reserved words and globals (`class`, `name`, `Date`, …) are valid as bare object-literal keys
144
+ * even though they are not valid variable names, so use this (not {@link isValidVarName}) when
145
+ * deciding whether an object key needs quoting.
146
+ *
147
+ * @example
148
+ * ```ts
149
+ * isIdentifier('name') // true
150
+ * isIdentifier('x-total')// false
151
+ * ```
152
+ */
153
+ function isIdentifier(name) {
163
154
  return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
164
155
  }
165
156
  //#endregion
@@ -296,12 +287,12 @@ function resolveResponseTypes(node, resolver) {
296
287
  const types = [];
297
288
  for (const response of node.responses) {
298
289
  if (response.statusCode === "default") {
299
- types.push(["default", resolver.resolveResponseName(node)]);
290
+ types.push(["default", resolver.response.response(node)]);
300
291
  continue;
301
292
  }
302
293
  const code = getStatusCodeNumber(response.statusCode);
303
294
  if (code === null) continue;
304
- types.push([code, isSuccessStatusCode(code) ? resolver.resolveResponseName(node) : resolver.resolveResponseStatusName(node, response.statusCode)]);
295
+ types.push([code, isSuccessStatusCode(code) ? resolver.response.response(node) : resolver.response.status(node, response.statusCode)]);
305
296
  }
306
297
  return types;
307
298
  }
@@ -349,23 +340,21 @@ const handlersGenerator = (0, kubb_kit.defineGenerator)({
349
340
  operations(nodes, ctx) {
350
341
  const { resolver, config, root } = ctx;
351
342
  const { output, group } = ctx.options;
352
- const handlersName = resolver.resolveHandlersName();
353
- const file = resolver.resolveFile({
354
- name: resolver.resolvePathName(handlersName, "file"),
355
- extname: ".ts"
356
- }, {
343
+ const handlersName = resolver.handler.listName();
344
+ const file = resolver.file({
345
+ name: handlersName,
346
+ extname: ".ts",
357
347
  root,
358
348
  output,
359
349
  group: group ?? void 0
360
350
  });
361
351
  const imports = nodes.map((node) => {
362
- const operationName = resolver.resolveHandlerName(node);
363
- const operationFile = resolver.resolveFile({
364
- name: resolver.resolveName(node.operationId),
352
+ const operationName = resolver.handler.name(node);
353
+ const operationFile = resolver.file({
354
+ name: resolver.name(node.operationId),
365
355
  extname: ".ts",
366
356
  tag: node.tags[0] ?? "default",
367
- path: node.path
368
- }, {
357
+ path: node.path,
369
358
  root,
370
359
  output,
371
360
  group: group ?? void 0
@@ -376,12 +365,12 @@ const handlersGenerator = (0, kubb_kit.defineGenerator)({
376
365
  path: operationFile.path
377
366
  });
378
367
  });
379
- const handlers = nodes.map((node) => `${resolver.resolveHandlerName(node)}()`);
368
+ const handlers = nodes.map((node) => `${resolver.handler.name(node)}()`);
380
369
  return [kubb_kit.ast.factory.createFile({
381
370
  baseName: file.baseName,
382
371
  path: file.path,
383
372
  meta: file.meta,
384
- banner: resolver.resolveBanner(ctx.meta, {
373
+ banner: resolver.default.banner(ctx.meta, {
385
374
  output,
386
375
  config,
387
376
  file: {
@@ -389,7 +378,7 @@ const handlersGenerator = (0, kubb_kit.defineGenerator)({
389
378
  baseName: file.baseName
390
379
  }
391
380
  }),
392
- footer: resolver.resolveFooter(ctx.meta, {
381
+ footer: resolver.default.footer(ctx.meta, {
393
382
  output,
394
383
  config,
395
384
  file: {
@@ -454,13 +443,12 @@ function resolveFakerMeta(node, options) {
454
443
  const { root, fakerResolver, fakerOutput, fakerGroup } = options;
455
444
  const tag = node.tags[0] ?? "default";
456
445
  return {
457
- name: fakerResolver.resolveResponseName(node),
458
- file: fakerResolver.resolveFile({
446
+ name: fakerResolver.response.response(node),
447
+ file: fakerResolver.file({
459
448
  name: node.operationId,
460
449
  extname: ".ts",
461
450
  tag,
462
- path: node.path
463
- }, {
451
+ path: node.path,
464
452
  root,
465
453
  output: fakerOutput,
466
454
  group: fakerGroup ?? void 0
@@ -469,60 +457,26 @@ function resolveFakerMeta(node, options) {
469
457
  }
470
458
  //#endregion
471
459
  //#region src/components/Mock.tsx
472
- const declarationPrinter$2 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
473
- function Mock({ baseURL = "", name, typeName, requestTypeName, node }) {
474
- const method = getMswMethod(node);
475
- const successResponse = getPrimarySuccessResponse(node);
476
- const statusCode = successResponse ? Number(successResponse.statusCode) : 200;
477
- const contentType = getContentType(successResponse);
478
- const url = Url.toPath(getMswUrl(node));
479
- const headers = [contentType ? `'Content-Type': '${contentType}'` : null].filter(Boolean);
480
- const dataType = hasResponseSchema(successResponse) ? typeName : "string | number | boolean | null | object";
481
- const callbackType = requestTypeName ? `HttpResponseResolver<Record<string, string>, ${requestTypeName}>` : `((info: Parameters<Parameters<typeof http.${method}>[1]>[0]) => Response | Promise<Response>)`;
482
- const params = declarationPrinter$2.print((0, _kubb_plugin_ts.createFunctionParameters)({ params: [(0, _kubb_plugin_ts.createFunctionParameter)({
483
- name: "data",
484
- type: `${dataType} | ${callbackType}`,
485
- optional: true
486
- })] }));
487
- const httpCall = requestTypeName ? `http.${method}<Record<string, string>, ${requestTypeName}>` : `http.${method}`;
488
- return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Source, {
489
- name,
490
- isIndexable: true,
491
- isExportable: true,
492
- children: /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.Function, {
493
- name,
494
- export: true,
495
- params: params ?? "",
496
- children: `return ${httpCall}(\`${baseURL}${url.replace(/([^/]):/g, "$1\\\\:")}\`, function handler(info) {
497
- if(typeof data === 'function') return data(info)
498
-
499
- return new Response(JSON.stringify(data), {
500
- status: ${statusCode},
501
- ${headers.length ? ` headers: {
502
- ${headers.join(", \n")}
503
- },` : ""}
504
- })
505
- })`
506
- })
507
- });
508
- }
509
- //#endregion
510
- //#region src/components/MockWithFaker.tsx
511
460
  const declarationPrinter$1 = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
512
- function MockWithFaker({ baseURL = "", name, fakerName, typeName, requestTypeName, node }) {
461
+ function Mock({ baseURL = "", name, fakerName, typeName, requestTypeName, node }) {
513
462
  const method = getMswMethod(node);
514
463
  const successResponse = getPrimarySuccessResponse(node);
515
464
  const statusCode = successResponse ? Number(successResponse.statusCode) : 200;
516
465
  const contentType = getContentType(successResponse);
517
466
  const url = Url.toPath(getMswUrl(node));
518
467
  const headers = [contentType ? `'Content-Type': '${contentType}'` : null].filter(Boolean);
468
+ const dataType = hasResponseSchema(successResponse) ? typeName : "string | number | boolean | null | object";
469
+ const paramType = fakerName ? typeName : dataType;
519
470
  const callbackType = requestTypeName ? `HttpResponseResolver<Record<string, string>, ${requestTypeName}>` : `((info: Parameters<Parameters<typeof http.${method}>[1]>[0]) => Response | Promise<Response>)`;
520
471
  const params = declarationPrinter$1.print((0, _kubb_plugin_ts.createFunctionParameters)({ params: [(0, _kubb_plugin_ts.createFunctionParameter)({
521
472
  name: "data",
522
- type: `${typeName} | ${callbackType}`,
473
+ type: `${paramType} | ${callbackType}`,
523
474
  optional: true
524
475
  })] }));
525
476
  const httpCall = requestTypeName ? `http.${method}<Record<string, string>, ${requestTypeName}>` : `http.${method}`;
477
+ const requestUrl = `${baseURL}${url.replace(/([^/]):/g, "$1\\\\:")}`;
478
+ const urlLiteral = fakerName ? `'${requestUrl}'` : `\`${requestUrl}\``;
479
+ const responseBody = fakerName ? `JSON.stringify(data || ${fakerName}(data))` : "JSON.stringify(data)";
526
480
  return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(kubb_jsx.File.Source, {
527
481
  name,
528
482
  isIndexable: true,
@@ -531,10 +485,10 @@ function MockWithFaker({ baseURL = "", name, fakerName, typeName, requestTypeNam
531
485
  name,
532
486
  export: true,
533
487
  params: params ?? "",
534
- children: `return ${httpCall}('${baseURL}${url.replace(/([^/]):/g, "$1\\\\:")}', function handler(info) {
488
+ children: `return ${httpCall}(${urlLiteral}, function handler(info) {
535
489
  if(typeof data === 'function') return data(info)
536
490
 
537
- return new Response(JSON.stringify(data || ${fakerName}(data)), {
491
+ return new Response(${responseBody}, {
538
492
  status: ${statusCode},
539
493
  ${headers.length ? ` headers: {
540
494
  ${headers.join(", \n")}
@@ -590,15 +544,14 @@ const mswGenerator = (0, kubb_kit.defineGenerator)({
590
544
  if (!kubb_kit.ast.isHttpOperationNode(node)) return null;
591
545
  const { driver, resolver, config, root } = ctx;
592
546
  const { output, parser, baseURL, group } = ctx.options;
593
- const fileName = resolver.resolveName(node.operationId);
547
+ const fileName = resolver.name(node.operationId);
594
548
  const mock = {
595
- name: resolver.resolveHandlerName(node),
596
- file: resolver.resolveFile({
549
+ name: resolver.handler.name(node),
550
+ file: resolver.file({
597
551
  name: fileName,
598
552
  extname: ".ts",
599
553
  tag: node.tags[0] ?? "default",
600
- path: node.path
601
- }, {
554
+ path: node.path,
602
555
  root,
603
556
  output,
604
557
  group: group ?? void 0
@@ -615,26 +568,25 @@ const mswGenerator = (0, kubb_kit.defineGenerator)({
615
568
  if (!pluginTs) return null;
616
569
  const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
617
570
  const type = {
618
- file: tsResolver.resolveFile({
571
+ file: tsResolver.file({
619
572
  name: node.operationId,
620
573
  extname: ".ts",
621
574
  tag: node.tags[0] ?? "default",
622
- path: node.path
623
- }, {
575
+ path: node.path,
624
576
  root,
625
577
  output: pluginTs.options?.output ?? output,
626
578
  group: pluginTs.options?.group ?? void 0
627
579
  }),
628
- responseName: tsResolver.resolveResponseName(node)
580
+ responseName: tsResolver.response.response(node)
629
581
  };
630
582
  const types = resolveResponseTypes(node, tsResolver);
631
583
  const hasSuccessSchema = getOperationSuccessResponses(node).some((response) => !!response.content?.[0]?.schema);
632
- const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : null;
584
+ const requestName = node.requestBody?.content?.[0]?.schema ? tsResolver.response.body(node) : null;
633
585
  return /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsxs)(kubb_jsx.File, {
634
586
  baseName: mock.file.baseName,
635
587
  path: mock.file.path,
636
588
  meta: mock.file.meta,
637
- banner: resolver.resolveBanner(ctx.meta, {
589
+ banner: resolver.default.banner(ctx.meta, {
638
590
  output,
639
591
  config,
640
592
  file: {
@@ -642,7 +594,7 @@ const mswGenerator = (0, kubb_kit.defineGenerator)({
642
594
  baseName: mock.file.baseName
643
595
  }
644
596
  }),
645
- footer: resolver.resolveFooter(ctx.meta, {
597
+ footer: resolver.default.footer(ctx.meta, {
646
598
  output,
647
599
  config,
648
600
  file: {
@@ -684,7 +636,7 @@ const mswGenerator = (0, kubb_kit.defineGenerator)({
684
636
  name: mock.name
685
637
  }, typeName);
686
638
  }),
687
- parser === "faker" && faker && hasSuccessSchema ? /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(MockWithFaker, {
639
+ parser === "faker" && faker && hasSuccessSchema ? /* @__PURE__ */ (0, kubb_jsx_jsx_runtime.jsx)(Mock, {
688
640
  name: mock.name,
689
641
  typeName: type.responseName,
690
642
  requestTypeName: requestName,
@@ -709,32 +661,30 @@ const mswGenerator = (0, kubb_kit.defineGenerator)({
709
661
  * paths for every generated MSW handler. Function names get a `Handler`
710
662
  * suffix; the aggregate export is always `handlers`.
711
663
  *
664
+ * The top-level `name` applies the `handler` suffix, and `file` falls back to the built-in
665
+ * `toFilePath` casing. Operation-specific naming is grouped under the `handler` namespace.
666
+ *
712
667
  * @example Resolve a handler name
713
668
  * ```ts
714
669
  * import { resolverMsw } from '@kubb/plugin-msw'
715
670
  *
716
- * resolverMsw.resolveName('addPet') // 'addPetHandler'
671
+ * resolverMsw.name('addPet') // 'addPetHandler'
717
672
  * ```
718
673
  */
719
- const resolverMsw = (0, kubb_kit.defineResolver)(() => ({
720
- name: "default",
674
+ const resolverMsw = (0, kubb_kit.createResolver)({
721
675
  pluginName: "plugin-msw",
722
- default(name, type) {
723
- return type === "file" ? toFilePath(name) : camelCase(name);
724
- },
725
- resolveName(name) {
676
+ name(name) {
726
677
  return camelCase(name, { suffix: "handler" });
727
678
  },
728
- resolvePathName(name, type) {
729
- return this.default(name, type);
730
- },
731
- resolveHandlerName(node) {
732
- return this.resolveName(node.operationId);
733
- },
734
- resolveHandlersName() {
735
- return "handlers";
679
+ handler: {
680
+ name(node) {
681
+ return this.name(node.operationId);
682
+ },
683
+ listName() {
684
+ return "handlers";
685
+ }
736
686
  }
737
- }));
687
+ });
738
688
  //#endregion
739
689
  //#region src/plugin.ts
740
690
  /**
@@ -779,10 +729,7 @@ const pluginMsw = (0, kubb_kit.definePlugin)((options) => {
779
729
  options,
780
730
  dependencies: [_kubb_plugin_ts.pluginTsName, parser === "faker" ? _kubb_plugin_faker.pluginFakerName : null].filter((dependency) => Boolean(dependency)),
781
731
  hooks: { "kubb:plugin:setup"(ctx) {
782
- const resolver = userResolver ? {
783
- ...resolverMsw,
784
- ...userResolver
785
- } : resolverMsw;
732
+ const resolver = userResolver ? kubb_kit.Resolver.merge(resolverMsw, userResolver) : resolverMsw;
786
733
  ctx.setOptions({
787
734
  output,
788
735
  parser,