@buildvision/nest-sdk-generator 2.0.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/.eslintrc.js +63 -0
  2. package/README.md +2 -2
  3. package/build/analyzer/classdeps.js +1 -1
  4. package/build/analyzer/controller.d.ts +4 -4
  5. package/build/analyzer/controller.js +3 -3
  6. package/build/analyzer/controllers.d.ts +1 -1
  7. package/build/analyzer/controllers.js +4 -4
  8. package/build/analyzer/decorator.d.ts +2 -2
  9. package/build/analyzer/decorator.js +19 -19
  10. package/build/analyzer/extractor.d.ts +4 -4
  11. package/build/analyzer/extractor.js +2 -2
  12. package/build/analyzer/index.d.ts +1 -1
  13. package/build/analyzer/index.js +2 -2
  14. package/build/analyzer/methods.d.ts +7 -7
  15. package/build/analyzer/methods.js +5 -6
  16. package/build/analyzer/module.js +2 -2
  17. package/build/analyzer/params.d.ts +12 -12
  18. package/build/analyzer/params.js +31 -15
  19. package/build/analyzer/route.d.ts +1 -1
  20. package/build/analyzer/route.js +6 -4
  21. package/build/analyzer/typedeps.d.ts +6 -6
  22. package/build/analyzer/typedeps.js +3 -3
  23. package/build/bin.js +9 -13
  24. package/build/config.d.ts +33 -19
  25. package/build/config.js +2 -2
  26. package/build/generator/genmodules.d.ts +29 -5
  27. package/build/generator/genmodules.js +58 -31
  28. package/build/generator/gentypes.js +1 -1
  29. package/build/generator/index.d.ts +1 -1
  30. package/build/generator/index.js +23 -17
  31. package/build/generator/prettier.d.ts +1 -1
  32. package/build/generator/prettier.js +2 -2
  33. package/build/generator/sdk-interface.d.ts +1 -1
  34. package/build/generator/sdk-interface.js +5 -5
  35. package/build/logging.js +1 -1
  36. package/build/rtk-query-generator/genmodules.d.ts +69 -0
  37. package/build/rtk-query-generator/genmodules.js +295 -0
  38. package/build/rtk-query-generator/gentypes.d.ts +10 -0
  39. package/build/rtk-query-generator/gentypes.js +62 -0
  40. package/build/rtk-query-generator/index.d.ts +6 -0
  41. package/build/rtk-query-generator/index.js +84 -0
  42. package/build/rtk-query-generator/prettier.d.ts +16 -0
  43. package/build/rtk-query-generator/prettier.js +43 -0
  44. package/build/rtk-query-generator/sdk-interface.d.ts +1 -0
  45. package/build/rtk-query-generator/sdk-interface.js +36 -0
  46. package/build/tsconfig.tsbuildinfo +1 -1
  47. package/build/utils.js +1 -1
  48. package/bun.lockb +0 -0
  49. package/package.json +15 -5
  50. package/src/analyzer/classdeps.ts +3 -0
  51. package/src/analyzer/controller.ts +12 -6
  52. package/src/analyzer/controllers.ts +7 -4
  53. package/src/analyzer/extractor.ts +9 -6
  54. package/src/analyzer/index.ts +5 -2
  55. package/src/analyzer/methods.ts +13 -12
  56. package/src/analyzer/module.ts +4 -10
  57. package/src/analyzer/params.ts +78 -64
  58. package/src/analyzer/route.ts +5 -3
  59. package/src/analyzer/typedeps.ts +13 -11
  60. package/src/bin.ts +11 -13
  61. package/src/config.ts +39 -24
  62. package/src/generator/genmodules.ts +90 -37
  63. package/src/generator/gentypes.ts +1 -0
  64. package/src/generator/index.ts +23 -19
  65. package/src/generator/prettier.ts +4 -2
  66. package/src/logging.ts +2 -1
  67. package/src/rtk-query-generator/genmodules.ts +407 -0
  68. package/src/rtk-query-generator/gentypes.ts +74 -0
  69. package/src/rtk-query-generator/index.ts +92 -0
  70. package/src/rtk-query-generator/prettier.ts +48 -0
  71. package/src/rtk-query-generator/sdk-interface.ts +32 -0
  72. package/src/utils.ts +2 -2
  73. package/tsconfig.tsbuildinfo +1 -1
@@ -2,20 +2,58 @@
2
2
  * @file Generate SDK modules
3
3
  */
4
4
 
5
+ import path = require('path')
6
+
5
7
  import { SdkController } from '../analyzer/controller'
6
8
  import { SdkModules } from '../analyzer/controllers'
7
9
  import { SdkHttpMethod, SdkMethod } from '../analyzer/methods'
8
10
  import { SdkMethodParam, getParamResolvedTypes, isParamResolvedType } from '../analyzer/params'
9
11
  import { paramsFromRoute, resolveRouteWith, unparseRoute } from '../analyzer/route'
10
12
  import { ResolvedTypeDeps, normalizeExternalFilePath } from '../analyzer/typedeps'
13
+ import { config } from '../config'
11
14
  import { panic } from '../logging'
12
15
 
16
+ export function replaceSuffix(value: string, { addSuffix = '', removeSuffix = '' }: { addSuffix?: string; removeSuffix?: string }) {
17
+ return value.replace(new RegExp(removeSuffix + '$'), '') + addSuffix
18
+ }
19
+
20
+ export function controllerExportName(controller: SdkController): string {
21
+ const suffixReplacement = config.controllerOutput?.exportName ?? {}
22
+ return replaceSuffix(controller.className, suffixReplacement)
23
+ }
24
+
25
+ export function controllerFileName(controller: SdkController): { ext: string; name: string } {
26
+ const { ext, name } = path.parse(controller.path)
27
+ const suffixReplacement = config.controllerOutput?.fileName ?? {}
28
+ const fileName = replaceSuffix(name, suffixReplacement)
29
+ return {
30
+ name: fileName,
31
+ ext: ext || '.ts',
32
+ }
33
+ }
34
+
35
+ export function controllerRelativePath({
36
+ controller,
37
+ inputRelativePath,
38
+ }: {
39
+ controller: SdkController
40
+ inputRelativePath: string
41
+ }): string {
42
+ return path.join(inputRelativePath, controller.path)
43
+ }
44
+
13
45
  /**
14
46
  * Generate the SDK's module and controllers files
15
47
  * @param modules
16
48
  * @returns
17
49
  */
18
- export function generateSdkModules(modules: SdkModules): Map<string, string> {
50
+ export function generateSdkModules({
51
+ inputRelativePath,
52
+ modules,
53
+ }: {
54
+ inputRelativePath: string
55
+ modules: SdkModules
56
+ }): Map<string, string> {
19
57
  /** Generated module files */
20
58
  const genFiles = new Map<string, string>()
21
59
 
@@ -25,10 +63,11 @@ export function generateSdkModules(modules: SdkModules): Map<string, string> {
25
63
  // Iterate over each module
26
64
  for (const [moduleName, controllers] of modules) {
27
65
  // Iterate over each of the module's controllers
28
- for (const [controllerName, controller] of controllers) {
29
- genFiles.set(controller.camelClassName + '.ts', generateController(moduleName, controller))
30
- indexContent.push(`export { default as ${controller.camelClassName} } from "./${controller.camelClassName}";`)
31
- }
66
+ for (const [_, controller] of controllers) {
67
+ const { ext: fileExt, name: fileName } = controllerFileName(controller)
68
+ genFiles.set(fileName + fileExt, generateController({ moduleName, controller, inputRelativePath }))
69
+ indexContent.push(`export { default as ${controllerExportName(controller)} } from "./${fileName}";`)
70
+ }
32
71
  }
33
72
 
34
73
  genFiles.set('index.ts', indexContent.join('\n'))
@@ -36,14 +75,22 @@ export function generateSdkModules(modules: SdkModules): Map<string, string> {
36
75
  return genFiles
37
76
  }
38
77
 
39
- export function generateController(moduleName: string, controller: SdkController): string {
40
- const controllerName = controller.camelClassName
78
+ export function generateController({
79
+ controller,
80
+ inputRelativePath,
81
+ moduleName,
82
+ }: {
83
+ controller: SdkController
84
+ inputRelativePath: string
85
+ moduleName: string
86
+ }): string {
87
+ const controllerName = controller.className
41
88
  /** Generated controller's content */
42
89
  const out: string[] = []
43
90
 
44
- out.push('/// Parent module: ' + moduleName)
45
- out.push(`/// Controller: "${controllerName}" registered as "${controller.registrationName}" (${controller.methods.length} routes)`)
46
- out.push(`/// File Path: ${controller.path}`)
91
+ out.push('/// Module: ' + moduleName)
92
+ out.push(`/// Controller: ${controllerName}`)
93
+ out.push(`/// File Path: file:///./${controllerRelativePath({ controller, inputRelativePath })}`)
47
94
  out.push('')
48
95
  out.push('import { request } from "./central";')
49
96
 
@@ -53,7 +100,7 @@ export function generateController(moduleName: string, controller: SdkController
53
100
 
54
101
  // Iterate over each controller
55
102
  for (const method of controller.methods.values()) {
56
- const { routeParams, queryParams, bodyParams } = method.params
103
+ const { bodyParams, queryParams, routeParams } = method.params
57
104
 
58
105
  depsToImport.push(method.returnType)
59
106
  depsToImport.push(...getParamResolvedTypes(routeParams))
@@ -99,55 +146,62 @@ export function generateController(moduleName: string, controller: SdkController
99
146
  return acc
100
147
  },
101
148
  { mutations: [] as SdkMethod[], queries: [] as SdkMethod[] }
102
- );
149
+ )
103
150
 
104
151
  out.push(` queries: {`)
105
-
152
+
106
153
  for (const method of queries) {
107
- out.push(generateSdkMethod(method, controller))
154
+ out.push(generateSdkMethod({ method, controller, inputRelativePath }))
108
155
  }
109
156
 
110
157
  out.push(' },')
111
158
 
112
159
  out.push(` mutations: {`)
113
-
160
+
114
161
  for (const method of mutations) {
115
- out.push(generateSdkMethod(method, controller))
162
+ out.push(generateSdkMethod({ method, controller, inputRelativePath }))
116
163
  }
117
164
 
118
165
  out.push(' },')
119
166
 
120
167
  out.push('')
121
168
  out.push('};')
122
- return out.join('\n');
169
+ return out.join('\n')
123
170
  }
124
171
 
125
- export function generateSdkMethod(method: SdkMethod, controller: SdkController): string {
126
- const out = [];
127
- const ret = method.returnType.resolvedType
128
- const promised = ret.startsWith('Promise<') ? ret : `Promise<${ret}>`
129
- const paramsType = generateSdkMethodParams(method)
172
+ export function generateSdkMethod({
173
+ controller,
174
+ inputRelativePath,
175
+ method,
176
+ }: {
177
+ controller: SdkController
178
+ inputRelativePath: string
179
+ method: SdkMethod
180
+ }): string {
181
+ const out = []
130
182
 
131
183
  out.push('')
132
- out.push(` // ${controller.camelClassName}.${method.name}`)
133
- out.push(` // ${method.httpMethod} @ ${unparseRoute(method.route)}`)
134
- out.push(` // ${controller.path}`)
184
+ out.push(` /**`)
185
+ out.push(` * ${method.httpMethod} ${unparseRoute(method.route)}`)
186
+ out.push(` * ${controller.className}.${method.name}`)
187
+ out.push(` * file:///./${controllerRelativePath({ controller, inputRelativePath })}`)
188
+ out.push(` */`)
135
189
  out.push(`${generateSdkMethodSignature(method)} {`)
136
190
  out.push(generateSdkMethodBody(method))
137
191
  out.push(' },')
138
192
  return out.join('\n')
139
193
  }
140
194
 
141
- export function generateSdkMethodSignature(method: SdkMethod, prefix = ' '): string {
195
+ export function generateSdkMethodSignature(method: SdkMethod): string {
142
196
  const ret = method.returnType.resolvedType
143
197
  const promised = ret.startsWith('Promise<') ? ret : `Promise<${ret}>`
144
198
  const paramsType = generateSdkMethodParams(method)
145
199
 
146
- return `${prefix}${method.name}(${paramsType}): ${promised}`
200
+ return `${method.name}(${paramsType}): ${promised}`
147
201
  }
148
202
 
149
203
  export function generateSdkMethodParams(method: SdkMethod): string {
150
- const { params, httpMethod, name } = method;
204
+ const { httpMethod, name, params } = method
151
205
 
152
206
  if (httpMethod === SdkHttpMethod.Get && params.bodyParams) {
153
207
  panic(`${httpMethod} ${name} should not have Body params`)
@@ -156,7 +210,7 @@ export function generateSdkMethodParams(method: SdkMethod): string {
156
210
  panic(`${httpMethod} ${name} should not have Query params`)
157
211
  }
158
212
 
159
- const inputTypes = [];
213
+ const inputTypes = []
160
214
 
161
215
  if (params.routeParams) {
162
216
  inputTypes.push(methodParamsToString(params.routeParams))
@@ -180,9 +234,9 @@ export function generateSdkMethodParams(method: SdkMethod): string {
180
234
  * @param method
181
235
  * @returns
182
236
  */
183
- export function generateSdkMethodBody(method: SdkMethod, prefix = ' '): string {
237
+ export function generateSdkMethodBody(method: SdkMethod): string {
184
238
  const output = []
185
- const { route, httpMethod } = method
239
+ const { httpMethod, route } = method
186
240
  const routeParams = paramsFromRoute(route)
187
241
  const resolvedRoute = resolveRouteWith(route, (param) => '${' + param + '}')
188
242
  const hasAnyParams = method.params.routeParams || method.params.queryParams || method.params.bodyParams
@@ -198,10 +252,9 @@ export function generateSdkMethodBody(method: SdkMethod, prefix = ' '): strin
198
252
  }
199
253
 
200
254
  const isGet = httpMethod === SdkHttpMethod.Get
201
- const body = isGet || !hasAnyParams ? "null" : "rest"
202
- const query = isGet && hasAnyParams ? "rest" : "{}"
255
+ const body = isGet || !hasAnyParams ? 'null' : 'rest'
256
+ const query = isGet && hasAnyParams ? 'rest' : '{}'
203
257
 
204
-
205
258
  output.push(`return request('${httpMethod}', \`${resolvedRoute}\`, ${body}, ${query})`)
206
259
  return output.join('\n')
207
260
  }
@@ -215,10 +268,10 @@ export function methodParamsToString(params: SdkMethodParam): string {
215
268
  return params.resolvedType
216
269
  }
217
270
 
218
- const output = ["{"]
271
+ const output = ['{']
219
272
  for (const [name, type] of Object.entries(params)) {
220
273
  output.push(`${name}: ${type.resolvedType},`)
221
274
  }
222
- output.push("}")
223
- return output.join("\n")
275
+ output.push('}')
276
+ return output.join('\n')
224
277
  }
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import * as path from 'path'
6
+
6
7
  import { TypesExtractorContent } from '../analyzer/extractor'
7
8
  import { normalizeExternalFilePath } from '../analyzer/typedeps'
8
9
 
@@ -4,43 +4,47 @@
4
4
 
5
5
  import * as fs from 'fs'
6
6
  import * as path from 'path'
7
+
7
8
  import { SdkContent } from '../analyzer'
8
9
  import { normalizeExternalFilePath } from '../analyzer/typedeps'
9
10
  import { Config } from '../config'
10
11
  import { debug, panic, println } from '../logging'
12
+
11
13
  import { generateSdkModules } from './genmodules'
12
14
  import { generateSdkTypeFiles } from './gentypes'
13
15
  import { findPrettierConfig, prettify } from './prettier'
14
16
  import { defaultSdkInterface } from './sdk-interface'
15
17
 
16
- export default async function generatorCli(config: Config, sdkContent: SdkContent): Promise<void> {
18
+ export default async function generateAPIClient(config: Config, sdkContent: SdkContent): Promise<void> {
17
19
  const prettifyOutput = config.prettify !== false
18
20
 
19
21
  if (!prettifyOutput) {
20
22
  debug('NOTE: files will not be prettified with Prettier')
21
23
  }
22
24
 
23
- const output = path.resolve(process.cwd(), config.sdkOutput)
25
+ const outputPath = path.resolve(process.cwd(), config.sdkOutputPath)
26
+ const inputPath = path.resolve(process.cwd(), config.apiInputPath)
27
+ const inputRelativePath = path.relative(outputPath, inputPath)
24
28
 
25
- if (fs.existsSync(output)) {
29
+ if (fs.existsSync(outputPath)) {
26
30
  if (config.overwriteOldOutputDir === false) {
27
31
  panic("Please provide an output directory that doesn't exist yet")
28
32
  } else {
29
- fs.rmSync(output, { recursive: true })
33
+ fs.rmSync(outputPath, { recursive: true })
30
34
  }
31
35
  }
32
36
 
33
- const outputParentDir = path.dirname(output)
37
+ const outputParentDir = path.dirname(outputPath)
34
38
 
35
39
  if (!fs.existsSync(outputParentDir)) {
36
40
  panic("Output directory's parent {magentaBright} does not exist.", outputParentDir)
37
41
  }
38
42
 
39
- fs.mkdirSync(output)
43
+ fs.mkdirSync(outputPath)
40
44
 
41
45
  const prettierConfig = prettifyOutput ? findPrettierConfig(config) : {}
42
46
 
43
- const writeScriptTo = (parentDir: null | string, file: string, utf8Content: string) => {
47
+ const writeScriptTo = async (parentDir: null | string, file: string, utf8Content: string) => {
44
48
  if (file.endsWith('.ts')) {
45
49
  utf8Content =
46
50
  '/// Auto-generated file (nest-sdk-generator)\n' +
@@ -50,35 +54,35 @@ export default async function generatorCli(config: Config, sdkContent: SdkConten
50
54
  utf8Content
51
55
  }
52
56
 
53
- const fullPath = path.resolve(output, parentDir ?? '', file)
57
+ const fullPath = path.resolve(outputPath, parentDir ?? '', file)
54
58
  fs.mkdirSync(path.dirname(fullPath), { recursive: true })
55
- fs.writeFileSync(
56
- fullPath,
57
- prettifyOutput ? prettify(utf8Content, prettierConfig, file.endsWith('.json') ? 'json' : 'typescript') : utf8Content,
58
- 'utf8'
59
- )
59
+
60
+ const fileContent = prettifyOutput
61
+ ? await prettify(utf8Content, prettierConfig, file.endsWith('.json') ? 'json' : 'typescript')
62
+ : utf8Content
63
+ fs.writeFileSync(fullPath, fileContent, 'utf8')
60
64
  }
61
65
 
62
66
  println('> Generating type files...')
63
67
 
64
68
  for (const [file, content] of generateSdkTypeFiles(sdkContent.types)) {
65
- writeScriptTo('_types', normalizeExternalFilePath(file), content)
69
+ await writeScriptTo('_types', normalizeExternalFilePath(file), content)
66
70
  }
67
71
 
68
72
  println('> Generating modules...')
69
-
70
- for (const [file, content] of generateSdkModules(sdkContent.modules)) {
71
- writeScriptTo(null, file, content)
73
+ const modules = sdkContent.modules
74
+ for (const [file, content] of generateSdkModules({ modules, inputRelativePath })) {
75
+ await writeScriptTo(null, file, content)
72
76
  }
73
77
 
74
78
  const sdkInterfacePath = path.resolve(process.cwd(), config.sdkInterfacePath)
75
79
 
76
80
  const relativeSdkInterfacePath = path
77
- .relative(output, sdkInterfacePath)
81
+ .relative(outputPath, sdkInterfacePath)
78
82
  .replace(/\\/g, '/')
79
83
  .replace(/\.([jt]sx?)$/, '')
80
84
 
81
- writeScriptTo(null, 'central.ts', `export { request } from "${relativeSdkInterfacePath}"`)
85
+ await writeScriptTo(null, 'central.ts', `export { request } from "${relativeSdkInterfacePath}"`)
82
86
 
83
87
  if (!fs.existsSync(sdkInterfacePath) && config.generateDefaultSdkInterface !== false) {
84
88
  println('├─ Generating default SDK interface...')
@@ -3,7 +3,9 @@
3
3
  */
4
4
 
5
5
  import * as fs from 'fs'
6
+
6
7
  import * as prettier from 'prettier'
8
+
7
9
  import { Config } from '../config'
8
10
  import { panic } from '../logging'
9
11
  import { findFileAbove } from '../utils'
@@ -12,7 +14,7 @@ import { findFileAbove } from '../utils'
12
14
  * Find a .prettierrc configuration file in the current directory or above
13
15
  */
14
16
  export function findPrettierConfig(config: Config): object {
15
- let prettierConfigPath = config.prettierConfig ?? findFileAbove('.prettierrc', config.sdkOutput)
17
+ const prettierConfigPath = config.prettierConfig ?? findFileAbove('.prettierrc', config.sdkOutputPath)
16
18
 
17
19
  if (!prettierConfigPath) {
18
20
  return {}
@@ -38,7 +40,7 @@ export function findPrettierConfig(config: Config): object {
38
40
  * @param parser
39
41
  * @returns
40
42
  */
41
- export function prettify(source: string, config: object, parser: 'typescript' | 'json'): string {
43
+ export function prettify(source: string, config: object, parser: 'typescript' | 'json'): Promise<string> {
42
44
  return prettier.format(source, {
43
45
  parser,
44
46
  ...config,
package/src/logging.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as chalk from 'chalk'
2
+
2
3
  import { config } from './config'
3
4
 
4
5
  export function format(message: string, ...params: Array<number | string>): string {
@@ -22,7 +23,7 @@ export function unreachable(message: string, ...params: Array<number | string>):
22
23
 
23
24
  export function warn(message: string, ...params: Array<number | string>) {
24
25
  if (config.verbose) {
25
- console.warn(chalk.yellow(format(message, ...params)))
26
+ console.warn(chalk.yellow(format(message, ...params)))
26
27
  }
27
28
  }
28
29