@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.
Files changed (2) hide show
  1. package/bin/cli.js +192 -34
  2. 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 = ''] = args;
7
+ var [command, entityName, ...options] = args;
8
8
 
9
- function getImportName(str) {
10
- const match = str.match(/import\s*{\s*([^}]+)\s*}/);
11
- return match ? match[1].trim() : null;
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
- stores: './src/backend/stores',
78
- services: './src/backend/services',
79
- providers: './src/backend/providers',
80
- controllers: './src/backend/controllers',
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 '@/backend/infrastructure/prisma'",
94
- "import type { Prisma } from '@/backend/generated-prisma/client'",
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
- config?.dependencyInjection?.inversifyjs ? "import { injectable } from 'inversify'" : undefined,
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
- config?.dependencyInjection?.inversifyjs ? "@injectable()" : undefined,
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
- config?.dependencyInjection?.inversifyjs ? "import { injectable } from 'inversify'" : undefined,
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
- config?.dependencyInjection?.inversifyjs ? "@injectable()" : undefined,
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
- config?.dependencyInjection?.inversifyjs ? "import { injectable, inject } from 'inversify'" : undefined,
395
- config?.dependencyInjection?.inversifyjs?.storeTokensImport ?? undefined,
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
- config?.dependencyInjection?.inversifyjs ? "@injectable()" : undefined,
541
+ "@injectable()",
400
542
  `export class ${upperCase}Service {`,
401
543
  `\tconstructor(`,
402
- config?.dependencyInjection?.inversifyjs?.storeTokensImport ? `\t\t@inject(${getImportName(config?.dependencyInjection?.inversifyjs?.storeTokensImport)}.${lowerCase}s)` : undefined,
403
- `\t\tprivate readonly ${lowerCase}s: ${upperCase}Store`,
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}s.create);`,
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 this.${lowerCase}s.details(x);`,
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 this.${lowerCase}s.list(x);`,
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 this.${lowerCase}s.updateOne(x);`,
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 this.${lowerCase}s.deleteOne(x);`,
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
- config?.dependencyInjection?.inversifyjs ? "import { injectable } from 'inversify'" : undefined,
575
+ "import { injectable } from 'inversify'",
434
576
  `import { ${lowerCase}ServiceMetadata } from './${entityName}.service.metadata'`,
435
577
  "import { Module } from '@alevnyacow/nzmt'",
436
578
  "",
437
- config?.dependencyInjection === 'inversifyjs' ? "@injectable()" : undefined,
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') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alevnyacow/nzmt",
3
- "version": "0.1.14",
3
+ "version": "0.2.1",
4
4
  "description": "Next Zod Modules Toolkit",
5
5
  "repository": {
6
6
  "type": "git",