@kubb/plugin-client 5.0.0-beta.4 → 5.0.0-beta.56

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 (56) hide show
  1. package/README.md +39 -24
  2. package/dist/clients/axios.cjs +26 -4
  3. package/dist/clients/axios.cjs.map +1 -1
  4. package/dist/clients/axios.d.ts +11 -5
  5. package/dist/clients/axios.js +26 -4
  6. package/dist/clients/axios.js.map +1 -1
  7. package/dist/clients/fetch.cjs +77 -9
  8. package/dist/clients/fetch.cjs.map +1 -1
  9. package/dist/clients/fetch.d.ts +10 -3
  10. package/dist/clients/fetch.js +77 -9
  11. package/dist/clients/fetch.js.map +1 -1
  12. package/dist/index.cjs +836 -514
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.ts +206 -105
  15. package/dist/index.js +833 -515
  16. package/dist/index.js.map +1 -1
  17. package/dist/templates/clients/axios.source.cjs +1 -1
  18. package/dist/templates/clients/axios.source.cjs.map +1 -1
  19. package/dist/templates/clients/axios.source.d.ts +1 -1
  20. package/dist/templates/clients/axios.source.js +1 -1
  21. package/dist/templates/clients/axios.source.js.map +1 -1
  22. package/dist/templates/clients/fetch.source.cjs +1 -1
  23. package/dist/templates/clients/fetch.source.cjs.map +1 -1
  24. package/dist/templates/clients/fetch.source.d.ts +1 -1
  25. package/dist/templates/clients/fetch.source.js +1 -1
  26. package/dist/templates/clients/fetch.source.js.map +1 -1
  27. package/dist/templates/config.source.cjs.map +1 -1
  28. package/dist/templates/config.source.d.ts +1 -1
  29. package/dist/templates/config.source.js.map +1 -1
  30. package/package.json +14 -26
  31. package/src/clients/axios.ts +41 -7
  32. package/src/clients/fetch.ts +106 -6
  33. package/src/components/ClassClient.tsx +47 -24
  34. package/src/components/Client.tsx +100 -71
  35. package/src/components/StaticClassClient.tsx +47 -24
  36. package/src/components/Url.tsx +10 -12
  37. package/src/components/WrapperClient.tsx +9 -5
  38. package/src/functionParams.ts +8 -8
  39. package/src/generators/classClientGenerator.tsx +63 -51
  40. package/src/generators/clientGenerator.tsx +45 -48
  41. package/src/generators/groupedClientGenerator.tsx +12 -6
  42. package/src/generators/operationsGenerator.ts +47 -0
  43. package/src/generators/staticClassClientGenerator.tsx +57 -45
  44. package/src/index.ts +2 -1
  45. package/src/plugin.ts +30 -28
  46. package/src/resolvers/resolverClient.ts +32 -8
  47. package/src/types.ts +111 -65
  48. package/src/utils.ts +142 -63
  49. package/extension.yaml +0 -776
  50. package/src/components/Operations.tsx +0 -28
  51. package/src/generators/operationsGenerator.tsx +0 -28
  52. package/templates/clients/axios.ts +0 -73
  53. package/templates/clients/fetch.ts +0 -96
  54. package/templates/config.ts +0 -43
  55. /package/dist/{chunk-ByKO4r7w.cjs → chunk-Bx3C2hgW.cjs} +0 -0
  56. /package/dist/{chunk--u3MIqq1.js → chunk-C0LytTxp.js} +0 -0
@@ -1,7 +1,7 @@
1
1
  import path from 'node:path'
2
- import { camelCase, pascalCase } from '@internals/utils'
3
- import type { ast } from '@kubb/core'
4
- import { defineGenerator } from '@kubb/core'
2
+ import { getOperationParameters, operationFileEntry, resolveOperationTypeNames } from '@internals/shared'
3
+ import { camelCase } from '@internals/utils'
4
+ import { ast, defineGenerator } from '@kubb/core'
5
5
  import type { ResolverTs } from '@kubb/plugin-ts'
6
6
  import { pluginTsName } from '@kubb/plugin-ts'
7
7
  import type { ResolverZod } from '@kubb/plugin-zod'
@@ -9,14 +9,15 @@ import { pluginZodName } from '@kubb/plugin-zod'
9
9
  import { File, jsxRenderer } from '@kubb/renderer-jsx'
10
10
  import { StaticClassClient } from '../components/StaticClassClient'
11
11
  import type { PluginClient } from '../types'
12
+ import { isParserEnabled, resolveQueryParamsParser, resolveRequestParser, resolveResponseParser } from '../utils.ts'
12
13
 
13
14
  type OperationData = {
14
15
  node: ast.OperationNode
15
16
  name: string
16
17
  tsResolver: ResolverTs
17
- zodResolver: ResolverZod | undefined
18
+ zodResolver: ResolverZod | null
18
19
  typeFile: ast.FileNode
19
- zodFile: ast.FileNode | undefined
20
+ zodFile: ast.FileNode | null
20
21
  }
21
22
 
22
23
  type Controller = {
@@ -26,53 +27,55 @@ type Controller = {
26
27
  }
27
28
 
28
29
  function resolveTypeImportNames(node: ast.OperationNode, tsResolver: ResolverTs): Array<string> {
29
- const names: Array<string | undefined> = [
30
- node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : undefined,
31
- tsResolver.resolveResponseName(node),
32
- ...node.parameters.filter((p) => p.in === 'path').map((p) => tsResolver.resolvePathParamsName(node, p)),
33
- ...node.parameters.filter((p) => p.in === 'query').map((p) => tsResolver.resolveQueryParamsName(node, p)),
34
- ...node.parameters.filter((p) => p.in === 'header').map((p) => tsResolver.resolveHeaderParamsName(node, p)),
35
- ...node.responses.map((res) => tsResolver.resolveResponseStatusName(node, res.statusCode)),
36
- ]
37
- return names.filter((n): n is string => Boolean(n))
30
+ return resolveOperationTypeNames(node, tsResolver, { order: 'body-response-first' })
38
31
  }
39
32
 
40
- function resolveZodImportNames(node: ast.OperationNode, zodResolver: ResolverZod): Array<string> {
41
- const names: Array<string | undefined> = [
42
- zodResolver.resolveResponseName?.(node),
43
- node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : undefined,
33
+ function resolveZodImportNames(node: ast.OperationNode, zodResolver: ResolverZod, parser: PluginClient['resolvedOptions']['parser']): Array<string> {
34
+ const { query: queryParams } = getOperationParameters(node)
35
+ const names: Array<string | null | undefined> = [
36
+ resolveResponseParser(parser) === 'zod' ? zodResolver.resolveResponseName?.(node) : null,
37
+ resolveRequestParser(parser) === 'zod' && node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName?.(node) : null,
38
+ resolveQueryParamsParser(parser) === 'zod' && queryParams.length > 0 ? zodResolver.resolveQueryParamsName?.(node, queryParams[0]!) : null,
44
39
  ]
45
40
  return names.filter((n): n is string => Boolean(n))
46
41
  }
47
42
 
43
+ /**
44
+ * Built-in `operations` generator for `@kubb/plugin-client` when
45
+ * `clientType: 'staticClass'`. Emits one class per tag, with a static method
46
+ * per operation so callers can use `Pet.getPetById(...)` without
47
+ * instantiating the class.
48
+ */
48
49
  export const staticClassClientGenerator = defineGenerator<PluginClient>({
49
50
  name: 'staticClassClient',
50
51
  renderer: jsxRenderer,
51
52
  operations(nodes, ctx) {
52
- const { adapter, config, driver, resolver, root } = ctx
53
+ const { config, driver, resolver, root } = ctx
53
54
  const { output, group, dataReturnType, paramsCasing, paramsType, pathParamsType, parser, importPath } = ctx.options
54
- const baseURL = ctx.options.baseURL ?? adapter.inputNode?.meta?.baseURL
55
+ const baseURL = ctx.options.baseURL ?? ctx.meta.baseURL
55
56
 
56
57
  const pluginTs = driver.getPlugin(pluginTsName)
57
58
  if (!pluginTs) return null
58
59
 
59
60
  const tsResolver = driver.getResolver(pluginTsName)
60
61
  const tsPluginOptions = pluginTs.options
61
- const pluginZod = parser === 'zod' ? driver.getPlugin(pluginZodName) : undefined
62
- const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : undefined
62
+ const pluginZod = isParserEnabled(parser) ? driver.getPlugin(pluginZodName) : null
63
+ const zodResolver = pluginZod ? driver.getResolver(pluginZodName) : null
63
64
 
64
65
  function buildOperationData(node: ast.OperationNode): OperationData {
65
- const typeFile = tsResolver.resolveFile(
66
- { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
67
- { root, output: tsPluginOptions?.output ?? output, group: tsPluginOptions?.group },
68
- )
66
+ const typeFile = tsResolver.resolveFile(operationFileEntry(node, node.operationId), {
67
+ root,
68
+ output: tsPluginOptions?.output ?? output,
69
+ group: tsPluginOptions?.group,
70
+ })
69
71
  const zodFile =
70
72
  zodResolver && pluginZod?.options
71
- ? zodResolver.resolveFile(
72
- { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
73
- { root, output: pluginZod.options?.output ?? output, group: pluginZod.options?.group },
74
- )
75
- : undefined
73
+ ? zodResolver.resolveFile(operationFileEntry(node, node.operationId), {
74
+ root,
75
+ output: pluginZod.options?.output ?? output,
76
+ group: pluginZod.options?.group ?? undefined,
77
+ })
78
+ : null
76
79
 
77
80
  return {
78
81
  node: node,
@@ -85,12 +88,13 @@ export const staticClassClientGenerator = defineGenerator<PluginClient>({
85
88
  }
86
89
 
87
90
  const controllers = nodes.reduce((acc, operationNode) => {
91
+ if (!ast.isHttpOperationNode(operationNode)) return acc
88
92
  const tag = operationNode.tags[0]
89
- const groupName = tag ? (group?.name?.({ group: camelCase(tag) }) ?? pascalCase(tag)) : 'Client'
93
+ const groupName = tag ? (group?.name?.({ group: camelCase(tag) }) ?? resolver.resolveGroupName(tag)) : resolver.resolveClassName('Client')
90
94
 
91
95
  if (!tag && !group) {
92
- const name = 'ApiClient'
93
- const file = resolver.resolveFile({ name, extname: '.ts' }, { root, output, group })
96
+ const name = resolver.resolveClassName('ApiClient')
97
+ const file = resolver.resolveFile({ name, extname: '.ts' }, { root, output, group: group ?? undefined })
94
98
  const operationData = buildOperationData(operationNode)
95
99
  const previous = acc.find((item) => item.file.path === file.path)
96
100
 
@@ -99,9 +103,12 @@ export const staticClassClientGenerator = defineGenerator<PluginClient>({
99
103
  } else {
100
104
  acc.push({ name, file, operations: [operationData] })
101
105
  }
102
- } else if (tag) {
106
+ return acc
107
+ }
108
+
109
+ if (tag) {
103
110
  const name = groupName
104
- const file = resolver.resolveFile({ name, extname: '.ts', tag }, { root, output, group })
111
+ const file = resolver.resolveFile({ name, extname: '.ts', tag }, { root, output, group: group ?? undefined })
105
112
  const operationData = buildOperationData(operationNode)
106
113
  const previous = acc.find((item) => item.file.path === file.path)
107
114
 
@@ -140,7 +147,7 @@ export const staticClassClientGenerator = defineGenerator<PluginClient>({
140
147
 
141
148
  ops.forEach((op) => {
142
149
  if (!op.zodFile || !zodResolver) return
143
- const names = resolveZodImportNames(op.node, zodResolver)
150
+ const names = resolveZodImportNames(op.node, zodResolver, parser)
144
151
  if (!zodImportsByFile.has(op.zodFile.path)) {
145
152
  zodImportsByFile.set(op.zodFile.path, new Set())
146
153
  }
@@ -158,9 +165,10 @@ export const staticClassClientGenerator = defineGenerator<PluginClient>({
158
165
  <>
159
166
  {controllers.map(({ name, file, operations: ops }) => {
160
167
  const { typeImportsByFile, typeFilesByPath } = collectTypeImports(ops)
161
- const { zodImportsByFile, zodFilesByPath } =
162
- parser === 'zod' ? collectZodImports(ops) : { zodImportsByFile: new Map<string, Set<string>>(), zodFilesByPath: new Map<string, ast.FileNode>() }
163
- const hasFormData = ops.some((op) => op.node.requestBody?.content?.[0]?.contentType === 'multipart/form-data')
168
+ const { zodImportsByFile, zodFilesByPath } = isParserEnabled(parser)
169
+ ? collectZodImports(ops)
170
+ : { zodImportsByFile: new Map<string, Set<string>>(), zodFilesByPath: new Map<string, ast.FileNode>() }
171
+ const hasFormData = ops.some((op) => op.node.requestBody?.content?.some((e) => e.contentType === 'multipart/form-data') ?? false)
164
172
 
165
173
  return (
166
174
  <File
@@ -168,18 +176,18 @@ export const staticClassClientGenerator = defineGenerator<PluginClient>({
168
176
  baseName={file.baseName}
169
177
  path={file.path}
170
178
  meta={file.meta}
171
- banner={resolver.resolveBanner(adapter.inputNode, { output, config })}
172
- footer={resolver.resolveFooter(adapter.inputNode, { output, config })}
179
+ banner={resolver.resolveBanner(ctx.meta, { output, config, file: { path: file.path, baseName: file.baseName } })}
180
+ footer={resolver.resolveFooter(ctx.meta, { output, config, file: { path: file.path, baseName: file.baseName } })}
173
181
  >
174
182
  {importPath ? (
175
183
  <>
176
- <File.Import name={'fetch'} path={importPath} />
184
+ <File.Import name={'client'} path={importPath} />
177
185
  <File.Import name={['mergeConfig']} path={importPath} />
178
186
  <File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} path={importPath} isTypeOnly />
179
187
  </>
180
188
  ) : (
181
189
  <>
182
- <File.Import name={['fetch']} root={file.path} path={path.resolve(root, '.kubb/client.ts')} />
190
+ <File.Import name={['client']} root={file.path} path={path.resolve(root, '.kubb/client.ts')} />
183
191
  <File.Import name={['mergeConfig']} root={file.path} path={path.resolve(root, '.kubb/client.ts')} />
184
192
  <File.Import
185
193
  name={['Client', 'RequestConfig', 'ResponseErrorConfig']}
@@ -192,6 +200,10 @@ export const staticClassClientGenerator = defineGenerator<PluginClient>({
192
200
 
193
201
  {hasFormData && <File.Import name={['buildFormData']} root={file.path} path={path.resolve(root, '.kubb/config.ts')} />}
194
202
 
203
+ {parser === 'zod' && zodResolver && ops.some((op) => op.node.requestBody?.content?.[0]?.schema != null) && (
204
+ <File.Import name={['z']} path="zod" isTypeOnly />
205
+ )}
206
+
195
207
  {Array.from(typeImportsByFile.entries()).map(([filePath, importSet]) => {
196
208
  const typeFile = typeFilesByPath.get(filePath)
197
209
  if (!typeFile) return null
@@ -200,7 +212,7 @@ export const staticClassClientGenerator = defineGenerator<PluginClient>({
200
212
  return <File.Import key={filePath} name={importNames} root={file.path} path={typeFile.path} isTypeOnly />
201
213
  })}
202
214
 
203
- {parser === 'zod' &&
215
+ {isParserEnabled(parser) &&
204
216
  Array.from(zodImportsByFile.entries()).map(([filePath, importSet]) => {
205
217
  const zodFile = zodFilesByPath.get(filePath)
206
218
  if (!zodFile) return null
package/src/index.ts CHANGED
@@ -2,8 +2,9 @@ export { Client } from './components/Client.tsx'
2
2
  export { classClientGenerator } from './generators/classClientGenerator.tsx'
3
3
  export { clientGenerator } from './generators/clientGenerator.tsx'
4
4
  export { groupedClientGenerator } from './generators/groupedClientGenerator.tsx'
5
- export { operationsGenerator } from './generators/operationsGenerator.tsx'
5
+ export { operationsGenerator } from './generators/operationsGenerator.ts'
6
6
  export { staticClassClientGenerator } from './generators/staticClassClientGenerator.tsx'
7
7
  export { default, pluginClient, pluginClientName } from './plugin.ts'
8
8
  export { resolverClient } from './resolvers/resolverClient.ts'
9
+ export { isParserEnabled, resolveQueryParamsParser, resolveRequestParser, resolveResponseParser } from './utils.ts'
9
10
  export type { ClientImportPath, PluginClient, ResolverClient } from './types.ts'
package/src/plugin.ts CHANGED
@@ -1,41 +1,55 @@
1
1
  import path from 'node:path'
2
- import { camelCase } from '@internals/utils'
2
+ import { createGroupConfig } from '@internals/shared'
3
3
 
4
- import { ast, definePlugin, type Group } from '@kubb/core'
4
+ import { ast, definePlugin } from '@kubb/core'
5
5
  import { pluginTsName } from '@kubb/plugin-ts'
6
6
  import { pluginZodName } from '@kubb/plugin-zod'
7
7
  import { classClientGenerator } from './generators/classClientGenerator.tsx'
8
8
  import { clientGenerator } from './generators/clientGenerator.tsx'
9
9
  import { groupedClientGenerator } from './generators/groupedClientGenerator.tsx'
10
- import { operationsGenerator } from './generators/operationsGenerator.tsx'
10
+ import { operationsGenerator } from './generators/operationsGenerator.ts'
11
11
  import { staticClassClientGenerator } from './generators/staticClassClientGenerator.tsx'
12
12
  import { resolverClient } from './resolvers/resolverClient.ts'
13
13
  import { source as axiosClientSource } from './templates/clients/axios.source.ts'
14
14
  import { source as fetchClientSource } from './templates/clients/fetch.source.ts'
15
15
  import { source as configSource } from './templates/config.source.ts'
16
16
  import type { PluginClient } from './types.ts'
17
+ import { isParserEnabled } from './utils.ts'
17
18
 
18
19
  /**
19
- * Canonical plugin name for `@kubb/plugin-client`, used in driver lookups and warnings.
20
+ * Canonical plugin name for `@kubb/plugin-client`. Used for driver lookups and
21
+ * cross-plugin dependency references.
20
22
  */
21
23
  export const pluginClientName = 'plugin-client' satisfies PluginClient['name']
22
24
 
23
25
  /**
24
- * Generates type-safe HTTP client functions or classes from an OpenAPI specification.
25
- * Creates client APIs by walking operations and delegating to generators.
26
- * Writes barrel files based on the configured `barrelType`.
26
+ * Generates one HTTP client function per OpenAPI operation. Each function has
27
+ * typed path params, query params, body, and response, so callers use the API
28
+ * like any other typed function. Ships with `axios` and `fetch` runtimes; bring
29
+ * your own by setting `importPath`.
27
30
  *
28
- * @example Client generator
31
+ * @example
29
32
  * ```ts
30
- * import pluginClient from '@kubb/plugin-client'
33
+ * import { defineConfig } from 'kubb'
34
+ * import { pluginTs } from '@kubb/plugin-ts'
35
+ * import { pluginClient } from '@kubb/plugin-client'
36
+ *
31
37
  * export default defineConfig({
32
- * plugins: [pluginClient({ output: { path: 'clients' } })]
38
+ * input: { path: './petStore.yaml' },
39
+ * output: { path: './src/gen' },
40
+ * plugins: [
41
+ * pluginTs(),
42
+ * pluginClient({
43
+ * output: { path: './clients' },
44
+ * client: 'fetch',
45
+ * }),
46
+ * ],
33
47
  * })
34
48
  * ```
35
49
  */
36
50
  export const pluginClient = definePlugin<PluginClient>((options) => {
37
51
  const {
38
- output = { path: 'clients', barrelType: 'named' },
52
+ output = { path: 'clients', barrel: { type: 'named' } },
39
53
  group,
40
54
  exclude = [],
41
55
  include,
@@ -47,7 +61,7 @@ export const pluginClient = definePlugin<PluginClient>((options) => {
47
61
  operations = false,
48
62
  paramsCasing,
49
63
  clientType = options.sdk ? 'class' : 'function',
50
- parser = 'client',
64
+ parser = false,
51
65
  client = 'axios',
52
66
  importPath,
53
67
  bundle = false,
@@ -63,28 +77,16 @@ export const pluginClient = definePlugin<PluginClient>((options) => {
63
77
  options.generators ??
64
78
  [
65
79
  clientType === 'staticClass' ? staticClassClientGenerator : clientType === 'class' ? classClientGenerator : clientGenerator,
66
- group && clientType === 'function' ? groupedClientGenerator : undefined,
67
- operations ? operationsGenerator : undefined,
80
+ group && clientType === 'function' ? groupedClientGenerator : null,
81
+ operations ? operationsGenerator : null,
68
82
  ].filter((x): x is NonNullable<typeof x> => Boolean(x))
69
83
 
70
- const groupConfig = group
71
- ? ({
72
- ...group,
73
- name: group.name
74
- ? group.name
75
- : (ctx: { group: string }) => {
76
- if (group.type === 'path') {
77
- return `${ctx.group.split('/')[1]}`
78
- }
79
- return `${camelCase(ctx.group)}Controller`
80
- },
81
- } satisfies Group)
82
- : undefined
84
+ const groupConfig = createGroupConfig(group)
83
85
 
84
86
  return {
85
87
  name: pluginClientName,
86
88
  options,
87
- dependencies: [pluginTsName, parser === 'zod' ? pluginZodName : undefined].filter(Boolean),
89
+ dependencies: [pluginTsName, isParserEnabled(parser) ? pluginZodName : null].filter((dependency): dependency is string => Boolean(dependency)),
88
90
  hooks: {
89
91
  'kubb:plugin:setup'(ctx) {
90
92
  const resolver = userResolver ? { ...resolverClient, ...userResolver } : resolverClient
@@ -1,22 +1,46 @@
1
- import { camelCase } from '@internals/utils'
1
+ import { camelCase, ensureValidVarName, pascalCase, toFilePath } from '@internals/utils'
2
2
  import { defineResolver } from '@kubb/core'
3
3
  import type { PluginClient } from '../types.ts'
4
4
 
5
5
  /**
6
- * Naming convention resolver for client plugin.
6
+ * Default resolver used by `@kubb/plugin-client`. Decides the names and file
7
+ * paths for every generated client function or class. Functions and files use
8
+ * camelCase; classes and tag groups use PascalCase.
7
9
  *
8
- * Provides default naming helpers using camelCase for functions and file paths.
10
+ * @example Resolve client function and class names
11
+ * ```ts
12
+ * import { resolverClient } from '@kubb/plugin-client'
9
13
  *
10
- * @example
11
- * `resolverClient.default('list pets', 'function') // 'listPets'`
14
+ * resolverClient.default('list pets', 'function') // 'listPets'
15
+ * resolverClient.resolveClassName('pet') // 'Pet'
16
+ * resolverClient.resolveGroupName('pet') // 'PetClient'
17
+ * resolverClient.resolveUrlName(operationNode) // 'getShowPetByIdUrl'
18
+ * ```
12
19
  */
13
- export const resolverClient = defineResolver<PluginClient>((ctx) => ({
20
+ export const resolverClient = defineResolver<PluginClient>(() => ({
14
21
  name: 'default',
15
22
  pluginName: 'plugin-client',
16
23
  default(name, type) {
17
- return camelCase(name, { isFile: type === 'file' })
24
+ if (type === 'file') return toFilePath(name)
25
+ return ensureValidVarName(camelCase(name))
18
26
  },
19
27
  resolveName(name) {
20
- return ctx.default(name, 'function')
28
+ return this.default(name, 'function')
29
+ },
30
+ resolvePathName(name, type) {
31
+ return this.default(name, type)
32
+ },
33
+ resolveClassName(name) {
34
+ return ensureValidVarName(pascalCase(name))
35
+ },
36
+ resolveGroupName(name) {
37
+ return ensureValidVarName(pascalCase(`${name} Client`))
38
+ },
39
+ resolveClientPropertyName(name) {
40
+ return ensureValidVarName(camelCase(name))
41
+ },
42
+ resolveUrlName(node) {
43
+ const name = this.resolveName(node.operationId)
44
+ return `get${name.charAt(0).toUpperCase()}${name.slice(1)}Url`
21
45
  },
22
46
  }))