@alevnyacow/nzmt 0.1.14 → 0.2.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.
- package/bin/cli.js +192 -34
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -4,11 +4,30 @@ import path from "path";
|
|
|
4
4
|
|
|
5
5
|
var args = process.argv.slice(2);
|
|
6
6
|
|
|
7
|
-
var [command, entityName, options
|
|
7
|
+
var [command, entityName, ...options] = args;
|
|
8
8
|
|
|
9
|
-
function
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
function insertAfterLineInFile(filePath, targetLine, newLine) {
|
|
10
|
+
let content = fs.readFileSync(filePath, 'utf8');
|
|
11
|
+
|
|
12
|
+
const lines = content.split('\n');
|
|
13
|
+
const index = lines.findIndex(line => line.includes(targetLine));
|
|
14
|
+
|
|
15
|
+
if (index !== -1) {
|
|
16
|
+
lines.splice(index + 1, 0, newLine);
|
|
17
|
+
fs.writeFileSync(filePath, lines.join('\n'), 'utf8');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function insertBeforeLineInFile(filePath, targetLine, newLine) {
|
|
22
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
23
|
+
const lines = content.split('\n');
|
|
24
|
+
|
|
25
|
+
const index = lines.findIndex(line => line.includes(targetLine));
|
|
26
|
+
|
|
27
|
+
if (index !== -1) {
|
|
28
|
+
lines.splice(index, 0, newLine);
|
|
29
|
+
fs.writeFileSync(filePath, lines.join('\n'), 'utf8');
|
|
30
|
+
}
|
|
12
31
|
}
|
|
13
32
|
|
|
14
33
|
function camelizeVariants(str) {
|
|
@@ -74,24 +93,19 @@ function createDefaultConfig() {
|
|
|
74
93
|
|
|
75
94
|
fs.writeFileSync(path.resolve(projectRoot, 'nzmt.config.json'), JSON.stringify({
|
|
76
95
|
paths: {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
96
|
+
di: './src/server/di',
|
|
97
|
+
stores: './src/server/stores',
|
|
98
|
+
services: './src/server/services',
|
|
99
|
+
providers: './src/server/providers',
|
|
100
|
+
controllers: './src/server/controllers',
|
|
81
101
|
entities: './src/shared/entities',
|
|
82
|
-
queries: './src/client/shared/queries'
|
|
83
|
-
di: './src/backend/dependency-injection'
|
|
84
|
-
},
|
|
85
|
-
dependencyInjection: {
|
|
86
|
-
inversifyjs: {
|
|
87
|
-
storeTokensImport: "import { DIStores } from '@/backend/di'"
|
|
88
|
-
}
|
|
102
|
+
queries: './src/client/shared/queries'
|
|
89
103
|
},
|
|
90
104
|
store: {
|
|
91
105
|
prisma: {
|
|
92
106
|
import: [
|
|
93
|
-
"import { prisma } from '@/
|
|
94
|
-
"import type { Prisma } from '@/
|
|
107
|
+
"import { prisma } from '@/server/infrastructure/prisma'",
|
|
108
|
+
"import type { Prisma } from '@/server/generated-prisma/client'",
|
|
95
109
|
]
|
|
96
110
|
},
|
|
97
111
|
}
|
|
@@ -100,8 +114,136 @@ function createDefaultConfig() {
|
|
|
100
114
|
|
|
101
115
|
}
|
|
102
116
|
|
|
117
|
+
function initDI() {
|
|
118
|
+
const config = loadConfig()
|
|
119
|
+
const diPath = config?.paths?.di
|
|
120
|
+
|
|
121
|
+
const folder = path.resolve(process.cwd(), diPath)
|
|
122
|
+
fs.mkdirSync(folder, { recursive: true })
|
|
123
|
+
|
|
124
|
+
// Entries
|
|
125
|
+
fs.writeFileSync(path.resolve(folder, `entries.di.ts`), [
|
|
126
|
+
"import type { BindInWhenOnFluentSyntax } from 'inversify'",
|
|
127
|
+
"",
|
|
128
|
+
"type DIEntries = Record<",
|
|
129
|
+
"\tstring,",
|
|
130
|
+
"\t| (new (...args: any[]) => any)",
|
|
131
|
+
"\t| Record<'test' | 'dev' | 'prod',",
|
|
132
|
+
"\t\t| [new (...args: any[]) => any, (x: BindInWhenOnFluentSyntax<unknown>) => any]",
|
|
133
|
+
"\t\t| (new (...args: any[]) => any)",
|
|
134
|
+
"\t>",
|
|
135
|
+
">",
|
|
136
|
+
"",
|
|
137
|
+
"export const diEntries = {",
|
|
138
|
+
"\t// Stores",
|
|
139
|
+
"\t// Providers",
|
|
140
|
+
"\t// Services",
|
|
141
|
+
"\t// Controllers",
|
|
142
|
+
"\t// Other",
|
|
143
|
+
"} satisfies DIEntries",
|
|
144
|
+
"",
|
|
145
|
+
"export type DITokens = keyof typeof diEntries",
|
|
146
|
+
].join('\n'))
|
|
147
|
+
|
|
148
|
+
// Containers
|
|
149
|
+
fs.writeFileSync(path.resolve(folder, `container.dev.di.ts`), [
|
|
150
|
+
"import { Container } from 'inversify'",
|
|
151
|
+
"import { diEntries } from './entries.di'",
|
|
152
|
+
"",
|
|
153
|
+
"const container = new Container()",
|
|
154
|
+
"",
|
|
155
|
+
"for (const rule in diEntries) {",
|
|
156
|
+
"\tconst ruleContentRaw = diEntries[rule as keyof typeof diEntries]",
|
|
157
|
+
"\tconst ruleContent =",
|
|
158
|
+
"\t\ttypeof ruleContentRaw === 'object'",
|
|
159
|
+
"\t\t\t? ruleContentRaw.dev",
|
|
160
|
+
"\t\t\t: ruleContentRaw",
|
|
161
|
+
"\tif (Array.isArray(ruleContent)) {",
|
|
162
|
+
"\t\tconst [Entry, builder] = ruleContent",
|
|
163
|
+
"\t\tbuilder(container.bind(rule).to(Entry))",
|
|
164
|
+
"\t\tcontinue",
|
|
165
|
+
"\t}",
|
|
166
|
+
"\tcontainer.bind(rule).to(ruleContent)",
|
|
167
|
+
"}",
|
|
168
|
+
"",
|
|
169
|
+
"export { container as devContainer }"
|
|
170
|
+
].join('\n'))
|
|
171
|
+
|
|
172
|
+
fs.writeFileSync(path.resolve(folder, `container.test.di.ts`), [
|
|
173
|
+
"import { Container } from 'inversify'",
|
|
174
|
+
"import { diEntries } from './entries.di'",
|
|
175
|
+
"",
|
|
176
|
+
"const container = new Container()",
|
|
177
|
+
"",
|
|
178
|
+
"for (const rule in diEntries) {",
|
|
179
|
+
"\tconst ruleContentRaw = diEntries[rule as keyof typeof diEntries]",
|
|
180
|
+
"\tconst ruleContent =",
|
|
181
|
+
"\t\ttypeof ruleContentRaw === 'object'",
|
|
182
|
+
"\t\t\t? ruleContentRaw.test",
|
|
183
|
+
"\t\t\t: ruleContentRaw",
|
|
184
|
+
"\tif (Array.isArray(ruleContent)) {",
|
|
185
|
+
"\t\tconst [Entry, builder] = ruleContent",
|
|
186
|
+
"\t\tbuilder(container.bind(rule).to(Entry))",
|
|
187
|
+
"\t\tcontinue",
|
|
188
|
+
"\t}",
|
|
189
|
+
"\tcontainer.bind(rule).to(ruleContent)",
|
|
190
|
+
"}",
|
|
191
|
+
"",
|
|
192
|
+
"export { container as testContainer }"
|
|
193
|
+
].join('\n'))
|
|
194
|
+
|
|
195
|
+
fs.writeFileSync(path.resolve(folder, `container.prod.di.ts`), [
|
|
196
|
+
"import { Container } from 'inversify'",
|
|
197
|
+
"import { diEntries } from './entries.di'",
|
|
198
|
+
"",
|
|
199
|
+
"const container = new Container()",
|
|
200
|
+
"",
|
|
201
|
+
"for (const rule in diEntries) {",
|
|
202
|
+
"\tconst ruleContentRaw = diEntries[rule as keyof typeof diEntries]",
|
|
203
|
+
"\tconst ruleContent =",
|
|
204
|
+
"\t\ttypeof ruleContentRaw === 'object'",
|
|
205
|
+
"\t\t\t? ruleContentRaw.prod",
|
|
206
|
+
"\t\t\t: ruleContentRaw",
|
|
207
|
+
"\tif (Array.isArray(ruleContent)) {",
|
|
208
|
+
"\t\tconst [Entry, builder] = ruleContent",
|
|
209
|
+
"\t\tbuilder(container.bind(rule).to(Entry))",
|
|
210
|
+
"\t\tcontinue",
|
|
211
|
+
"\t}",
|
|
212
|
+
"\tcontainer.bind(rule).to(ruleContent)",
|
|
213
|
+
"}",
|
|
214
|
+
"",
|
|
215
|
+
"export { container as prodContainer }"
|
|
216
|
+
].join('\n'))
|
|
217
|
+
|
|
218
|
+
// Index
|
|
219
|
+
fs.writeFileSync(path.resolve(folder, `index.ts`), [
|
|
220
|
+
"import 'reflect-metadata'",
|
|
221
|
+
"import { devContainer } from './container.dev.di'",
|
|
222
|
+
"import { prodContainer } from './container.prod.di'",
|
|
223
|
+
"import { testContainer } from './container.test.di'",
|
|
224
|
+
"import type { DITokens } from './entries.di'",
|
|
225
|
+
"",
|
|
226
|
+
"const getActiveContainer = () => {",
|
|
227
|
+
"\tconst environment = process.env.NODE_ENV",
|
|
228
|
+
"\tif (environment === 'test') {",
|
|
229
|
+
"\t\treturn testContainer",
|
|
230
|
+
"\t}",
|
|
231
|
+
"\tif (environment === 'development') {",
|
|
232
|
+
"\t\treturn devContainer",
|
|
233
|
+
"\t}",
|
|
234
|
+
"\treturn prodContainer",
|
|
235
|
+
"}",
|
|
236
|
+
"",
|
|
237
|
+
"export const fromDI = <Result>(key: DITokens) => {",
|
|
238
|
+
"\tconst container = getActiveContainer()",
|
|
239
|
+
"\treturn container.get<Result>(key)",
|
|
240
|
+
"}"
|
|
241
|
+
].join('\n'))
|
|
242
|
+
};
|
|
243
|
+
|
|
103
244
|
if (command === 'init') {
|
|
104
245
|
createDefaultConfig()
|
|
246
|
+
initDI()
|
|
105
247
|
process.exit(0)
|
|
106
248
|
}
|
|
107
249
|
|
|
@@ -141,13 +283,13 @@ function generateStores(lowerCase, upperCase) {
|
|
|
141
283
|
// RAM
|
|
142
284
|
|
|
143
285
|
fs.writeFileSync(path.resolve(folder, `${entityName}.store.ram.ts`), [
|
|
144
|
-
|
|
286
|
+
"import { injectable } from 'inversify'",
|
|
145
287
|
"import { Store } from '@alevnyacow/nzmt'",
|
|
146
288
|
`import { type ${upperCase}Store, ${lowerCase}StoreMetadata } from './${entityName}.store'`,
|
|
147
289
|
"",
|
|
148
290
|
`const CRUDInRAM = Store.InRAM(${lowerCase}StoreMetadata)`,
|
|
149
291
|
"",
|
|
150
|
-
|
|
292
|
+
"@injectable()",
|
|
151
293
|
`export class ${upperCase}RAMStore extends CRUDInRAM implements ${upperCase}Store {`,
|
|
152
294
|
"\t",
|
|
153
295
|
"}"
|
|
@@ -157,7 +299,7 @@ function generateStores(lowerCase, upperCase) {
|
|
|
157
299
|
|
|
158
300
|
fs.writeFileSync(path.resolve(folder, `${entityName}.store.prisma.ts`), [
|
|
159
301
|
...config?.store?.prisma?.import ?? [],
|
|
160
|
-
|
|
302
|
+
"import { injectable } from 'inversify'",
|
|
161
303
|
"import { Store } from '@alevnyacow/nzmt'",
|
|
162
304
|
`import { type ${upperCase}Store, ${lowerCase}StoreMetadata } from './${entityName}.store'`,
|
|
163
305
|
"",
|
|
@@ -196,7 +338,7 @@ function generateStores(lowerCase, upperCase) {
|
|
|
196
338
|
"\t}",
|
|
197
339
|
"}",
|
|
198
340
|
"",
|
|
199
|
-
|
|
341
|
+
"@injectable()",
|
|
200
342
|
`export class ${upperCase}PrismaStore implements ${upperCase}Store {`,
|
|
201
343
|
`\tprivate method = Store.methods(${lowerCase}StoreMetadata);`,
|
|
202
344
|
"",
|
|
@@ -383,7 +525,7 @@ function generateService(lowerCase, upperCase, withCrud) {
|
|
|
383
525
|
"\tschemas: {}",
|
|
384
526
|
"} satisfies Module.Metadata",
|
|
385
527
|
"",
|
|
386
|
-
`export type ${upperCase}ServiceDTOs = Module.DTOs<typeof ${lowerCase}ServiceMetadata
|
|
528
|
+
`export type ${upperCase}ServiceDTOs = Module.DTOs<typeof ${lowerCase}ServiceMetadata>`
|
|
387
529
|
].filter(x => typeof x === 'string').join('\n'))
|
|
388
530
|
}
|
|
389
531
|
|
|
@@ -391,50 +533,50 @@ function generateService(lowerCase, upperCase, withCrud) {
|
|
|
391
533
|
|
|
392
534
|
if (withCrud) {
|
|
393
535
|
fs.writeFileSync(path.resolve(folder, `${entityName}.service.ts`), [
|
|
394
|
-
|
|
395
|
-
config?.
|
|
536
|
+
"import { injectable, inject } from 'inversify'",
|
|
537
|
+
`import { DITokens } from '${config?.paths?.di?.replace('./src', '@')}'`,
|
|
396
538
|
`import type { ${upperCase}Store } from '${config?.paths?.stores?.replace('./src', '@')}/${entityName}'`,
|
|
397
539
|
`import { ${lowerCase}ServiceMetadata } from './${entityName}.service.metadata'`,
|
|
398
540
|
"import { Module } from '@alevnyacow/nzmt'",
|
|
399
|
-
|
|
541
|
+
"@injectable()",
|
|
400
542
|
`export class ${upperCase}Service {`,
|
|
401
543
|
`\tconstructor(`,
|
|
402
|
-
|
|
403
|
-
`\t\tprivate readonly ${lowerCase}
|
|
544
|
+
`\t\t@inject('${upperCase}Store' satisfies DITokens)`,
|
|
545
|
+
`\t\tprivate readonly ${lowerCase}Store: ${upperCase}Store`,
|
|
404
546
|
'\t) { }',
|
|
405
547
|
'\t',
|
|
406
548
|
`\tprivate method = Module.methods(${lowerCase}ServiceMetadata)`,
|
|
407
549
|
'\t',
|
|
408
|
-
`\tcreate = this.method('create', this.${lowerCase}
|
|
550
|
+
`\tcreate = this.method('create', this.${lowerCase}Store.create);`,
|
|
409
551
|
'\t',
|
|
410
552
|
`\tgetSpecific = this.method('getSpecific', async (x) => {`,
|
|
411
|
-
`\t\tconst item = await
|
|
553
|
+
`\t\tconst item = await ${lowerCase}Store.details(x);`,
|
|
412
554
|
`\t\treturn { item };`,
|
|
413
555
|
`\t})`,
|
|
414
556
|
`\t`,
|
|
415
557
|
`\tgetList = this.method('getList', async (x) => {`,
|
|
416
|
-
`\t\tconst items = await
|
|
558
|
+
`\t\tconst items = await ${lowerCase}Store.list(x);`,
|
|
417
559
|
`\t\treturn { items };`,
|
|
418
560
|
`\t})`,
|
|
419
561
|
`\t`,
|
|
420
562
|
`\tupdateOne = this.method('updateOne', async (x) => {`,
|
|
421
|
-
`\t\tawait
|
|
563
|
+
`\t\tawait ${lowerCase}Store.updateOne(x);`,
|
|
422
564
|
`\t\treturn {};`,
|
|
423
565
|
`\t})`,
|
|
424
566
|
`\t`,
|
|
425
567
|
`\tdeleteOne = this.method('deleteOne', async (x) => {`,
|
|
426
|
-
`\t\tawait
|
|
568
|
+
`\t\tawait ${lowerCase}Store.deleteOne(x);`,
|
|
427
569
|
`\t\treturn {};`,
|
|
428
570
|
`\t})`,
|
|
429
571
|
"}"
|
|
430
572
|
].filter(x => typeof x === 'string').join('\n'))
|
|
431
573
|
} else {
|
|
432
574
|
fs.writeFileSync(path.resolve(folder, `${entityName}.service.ts`), [
|
|
433
|
-
|
|
575
|
+
"import { injectable } from 'inversify'",
|
|
434
576
|
`import { ${lowerCase}ServiceMetadata } from './${entityName}.service.metadata'`,
|
|
435
577
|
"import { Module } from '@alevnyacow/nzmt'",
|
|
436
578
|
"",
|
|
437
|
-
|
|
579
|
+
"@injectable()",
|
|
438
580
|
`export class ${upperCase}Service {`,
|
|
439
581
|
`\tprivate methods = Module.methods(${lowerCase}ServiceMetadata)`,
|
|
440
582
|
"}"
|
|
@@ -447,6 +589,22 @@ function generateService(lowerCase, upperCase, withCrud) {
|
|
|
447
589
|
`export * from './${entityName}.service.metadata'`,
|
|
448
590
|
`export * from './${entityName}.service'`
|
|
449
591
|
].join('\n'))
|
|
592
|
+
|
|
593
|
+
// Update DI
|
|
594
|
+
|
|
595
|
+
const diEntriesPath = path.resolve(process.cwd(), config?.paths?.di, 'entries.di.ts')
|
|
596
|
+
|
|
597
|
+
insertBeforeLineInFile(
|
|
598
|
+
diEntriesPath,
|
|
599
|
+
'type DIEntries =',
|
|
600
|
+
`import { ${upperCase}Service } from '${config?.paths?.services.replace('./src', '@')}/${entityName}}'\n`
|
|
601
|
+
)
|
|
602
|
+
|
|
603
|
+
insertAfterLineInFile(
|
|
604
|
+
diEntriesPath,
|
|
605
|
+
'// Services',
|
|
606
|
+
`\t${upperCase}Service,`,
|
|
607
|
+
)
|
|
450
608
|
}
|
|
451
609
|
|
|
452
610
|
if (command === 'service') {
|