@domain-first/project-structure 1.1.3 → 2.0.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.
package/dist/index.cjs CHANGED
@@ -124,7 +124,8 @@ const configSchema = external_zod_default().object({
124
124
  '@domain-first/wire',
125
125
  '@domain-first/handlers-rest'
126
126
  ])),
127
- defaultPersistenceLayerImplementation: external_zod_default().string()
127
+ defaultPersistenceLayerImplementation: external_zod_default().string(),
128
+ useReact: external_zod_default().boolean()
128
129
  });
129
130
  class ConfigFile {
130
131
  data;
@@ -166,10 +167,14 @@ const initializeUseCase = async ()=>{
166
167
  const defaultPersistenceLayerImplementation = await (0, prompts_namespaceObject.input)({
167
168
  message: 'Default persistence layer implementation:'
168
169
  });
170
+ const useReact = await (0, prompts_namespaceObject.confirm)({
171
+ message: 'Use React'
172
+ });
169
173
  ConfigFile.write({
170
174
  rootFolder: rootFolderName,
171
175
  domainFirstPackages,
172
- defaultPersistenceLayerImplementation
176
+ defaultPersistenceLayerImplementation,
177
+ useReact
173
178
  });
174
179
  const { path } = new ProjectRoot();
175
180
  const rootFolder = new Folder(path);
@@ -277,41 +282,26 @@ export class ${naming.ClassName}${aggregateNaming.ClassName}Repository implement
277
282
  }
278
283
 
279
284
  `.trim());
280
- if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/wire')) {
281
- const wiringFolder = boundedContextFolder.subitem([
282
- 'wiring',
283
- 'infrastructure',
284
- 'repositories',
285
- naming.fileName
286
- ]);
287
- wiringFolder.createFile(`wire-${naming.fileName}-${aggregateNaming.fileName}-repository.ts`, `
288
- import { wireClass } from '@domain-first/wire'
289
- import { ${naming.ClassName}${aggregateNaming.ClassName}Repository } from '../../../../infrastructure/repositories/${naming.fileName}/${naming.fileName}-${aggregateNaming.fileName}-repository'
290
-
291
- export const wire${naming.ClassName}${aggregateNaming.ClassName}Repository = wireClass(
292
- ${naming.ClassName}${aggregateNaming.ClassName}Repository,
293
- []
294
- )
295
- `.trim());
296
- }
297
285
  }
298
286
  if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/wire')) {
299
287
  const implementationNaming = new UnknownFormatNaming(infrastructureImplementationType);
300
288
  const testImplementationNaming = new UnknownFormatNaming(testImplementationType);
301
289
  boundedContextFolder.subitem([
302
290
  'wiring',
303
- 'domain',
304
291
  'repositories'
305
292
  ]).createFile(`wire-${aggregateNaming.fileName}-repository.ts`, `
306
- import { envBranchedWire } from '../../../../../shared/wiring/env-branched-wire'
307
- ${implementationTypes.map((x)=>new UnknownFormatNaming(x)).map(({ ClassName, fileName })=>`import { wire${ClassName}${aggregateNaming.ClassName}Repository } from '../../infrastructure/repositories/${fileName}/wire-${fileName}-${aggregateNaming.fileName}-repository'`).join('\n')}
293
+ import { wireClass } from '@domain-first/wire'
294
+ import { envBranchedWire } from '../../../../shared/wiring/env-branched-wire'
295
+ ${implementationTypes.map((x)=>new UnknownFormatNaming(x)).map(({ ClassName, fileName })=>`import { ${ClassName}${aggregateNaming.ClassName}Repository } from '../../infrastructure/repositories/${fileName}/${fileName}-${aggregateNaming.fileName}-repository'`).join('\n')}
296
+
297
+ ${implementationTypes.map((x)=>new UnknownFormatNaming(x)).map(({ ClassName })=>`const wire${ClassName}Implementation = wireClass(${ClassName}${aggregateNaming.ClassName}Repository, [])`).join('\n\n')}
308
298
 
309
299
  export const wire${aggregateNaming.ClassName}Repository = envBranchedWire({
310
- test: wire${addTestImplementation ? testImplementationNaming.ClassName : implementationNaming.ClassName}${aggregateNaming.ClassName}Repository,
311
- development: wire${implementationNaming.ClassName}${aggregateNaming.ClassName}Repository,
312
- production: wire${implementationNaming.ClassName}${aggregateNaming.ClassName}Repository
300
+ test: wire${addTestImplementation ? testImplementationNaming.ClassName : implementationNaming.ClassName}Implementation,
301
+ development: wire${implementationNaming.ClassName}Implementation,
302
+ production: wire${implementationNaming.ClassName}Implementation
313
303
  })
314
- `.trim());
304
+ `.trim());
315
305
  }
316
306
  }
317
307
  };
@@ -322,14 +312,8 @@ const scaffoldNewApplicationPort = async (boundedContextFolder)=>{
322
312
  const naming = new UnknownFormatNaming(name);
323
313
  const wiringFolder = boundedContextFolder.subitem([
324
314
  'wiring',
325
- 'application',
326
315
  'ports'
327
316
  ]);
328
- const infraFolder = boundedContextFolder.subitem([
329
- 'wiring',
330
- 'infrastructure',
331
- 'application-ports'
332
- ]);
333
317
  const applicationPortsFolder = boundedContextFolder.subitem([
334
318
  'application',
335
319
  'ports'
@@ -369,29 +353,24 @@ export class ${currentNaming.ClassName} extends ${naming.ClassName} {
369
353
 
370
354
  }
371
355
  `);
372
- if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/wire')) infraFolder.subitem([
373
- implementation
374
- ]).createFile(`wire-${currentNaming.fileName}.ts`, `
375
- import { wireClass } from '@domain-first/wire'
376
- import { ${currentNaming.ClassName} } from '../../../../infrastructure/application-adapters/${implementation}/${currentNaming.fileName}'
377
-
378
- export const wire${currentNaming.ClassName} = wireClass(
379
- ${currentNaming.ClassName},
380
- []
381
- )
382
- `.trim());
383
356
  }
384
357
  if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/wire')) wiringFolder.createFile(`wire-${naming.fileName}.ts`, `
385
- import { envBranchedWire } from '../../../../${'shared' === boundedContextFolder.name ? '' : '../'}shared/wiring/env-branched-wire'
358
+ import { wireClass } from '@domain-first/wire'
359
+ import { envBranchedWire } from '../../../${'shared' === boundedContextFolder.name ? '' : '../'}shared/wiring/env-branched-wire'
360
+ ${implementationTypes.map((x)=>({
361
+ naming: new UnknownFormatNaming(`${x}-${naming.fileName}`),
362
+ implementation: x
363
+ })).map(({ naming: { ClassName, fileName }, implementation })=>`import { ${ClassName} } from '../../infrastructure/application-adapters/${implementation}/${fileName}'`).join('\n')}
364
+
386
365
  ${implementationTypes.map((x)=>({
387
366
  naming: new UnknownFormatNaming(`${x}-${naming.fileName}`),
388
367
  implementation: x
389
- })).map(({ naming: { ClassName, fileName }, implementation })=>`import { wire${ClassName} } from '../../infrastructure/application-ports/${implementation}/wire-${fileName}'`).join('\n')}
368
+ })).map(({ naming: { ClassName }, implementation })=>`const wire${new UnknownFormatNaming(implementation).ClassName}Implementation = wireClass(${ClassName}, [])`).join('\n\n')}
390
369
 
391
370
  export const wire${naming.ClassName} = envBranchedWire({
392
- test: wire${new UnknownFormatNaming(`${implementationTypes.at(-1)}-${naming.fileName}`).ClassName},
393
- development: wire${new UnknownFormatNaming(`${implementationTypes.at(0)}-${naming.fileName}`).ClassName},
394
- production: wire${new UnknownFormatNaming(`${implementationTypes.at(0)}-${naming.fileName}`).ClassName}
371
+ test: wire${new UnknownFormatNaming(`${implementationTypes.at(-1)}-implementation`).ClassName},
372
+ development: wire${new UnknownFormatNaming(`${implementationTypes.at(0)}-implementation`).ClassName},
373
+ production: wire${new UnknownFormatNaming(`${implementationTypes.at(0)}-implementation`).ClassName}
395
374
  })
396
375
 
397
376
  `.trim());
@@ -431,9 +410,14 @@ const scaffoldNewCommand = async (boundedContextFolder)=>{
431
410
  message: 'Name: '
432
411
  });
433
412
  const naming = new UnknownFormatNaming(commandName);
434
- const isOrchestrator = await (0, prompts_namespaceObject.confirm)({
435
- message: 'Is an orchestrator command (no infrastructure implementations)?'
413
+ const commandType = await (0, prompts_namespaceObject.select)({
414
+ choices: [
415
+ 'Execution (with infrastructure implementation)',
416
+ 'Orchestrator (no infrastructure implementation)'
417
+ ],
418
+ message: 'Command type'
436
419
  });
420
+ const isOrchestrator = 'Orchestrator (no infrastructure implementation)' === commandType;
437
421
  if (!isOrchestrator) {
438
422
  const implementationType = await (0, prompts_namespaceObject.input)({
439
423
  message: 'Command infrastructure implementation type:',
@@ -457,81 +441,73 @@ const scaffoldNewCommand = async (boundedContextFolder)=>{
457
441
  infrastructureFolder.subitem([
458
442
  formatNaming.fileName
459
443
  ]).createFile(`${formatNaming.fileName}-${naming.fileName}-command.ts`, ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/handlers') ? `
460
- import { defineHandler } from '@domain-first/handlers'
461
- import { ${naming.ClassName}Command } from '../../../application/commands/${naming.fileName}-command'
462
-
463
- export class ${formatNaming.ClassName}${naming.ClassName}Command implements ${naming.ClassName}Command {
464
- constructor() {}
444
+ import { defineHandler } from '@domain-first/handlers'
445
+ import { ${naming.ClassName}Command } from '../../../application/commands/execution/${naming.fileName}-command'
465
446
 
466
- handle = defineHandler({
467
- inputSchema: ${naming.ClassName}Command.inputSchema,
468
- outputSchema: ${naming.ClassName}Command.outputSchema,
469
- handler: async (input) => {
470
- return {}
471
- }
472
- })
447
+ export class ${formatNaming.ClassName}${naming.ClassName}Command extends ${naming.ClassName}Command {
448
+ constructor() {
449
+ super()
473
450
  }
474
- `.trim() : `
475
- import { ${naming.ClassName}Command } from '../../../domain/commands/${naming.fileName}-command'
476
451
 
477
- export class ${formatNaming.ClassName}${naming.ClassName}Command implements ${naming.ClassName}Command {
452
+ handle = defineHandler({
453
+ inputSchema: ${naming.ClassName}Command.inputSchema,
454
+ outputSchema: ${naming.ClassName}Command.outputSchema,
455
+ handler: async (input) => {
456
+ return {}
457
+ }
458
+ })
459
+ }
460
+ `.trim() : `
461
+ import { ${naming.ClassName}Command } from '../../../domain/commands/${naming.fileName}-command'
478
462
 
463
+ export class ${formatNaming.ClassName}${naming.ClassName}Command extends ${naming.ClassName}Command {
464
+ constructor() {
465
+ super()
479
466
  }
467
+ }
480
468
  `.trim());
481
- if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/wire')) {
482
- const wiringFolder = boundedContextFolder.subitem([
483
- 'wiring',
484
- 'infrastructure',
485
- 'commands',
486
- formatNaming.fileName
487
- ]);
488
- wiringFolder.createFile(`wire-${formatNaming.fileName}-${naming.fileName}-command.ts`, `
489
- import { wireClass } from '@domain-first/wire'
490
- import { ${formatNaming.ClassName}${naming.ClassName}Command } from '../../../../infrastructure/commands/${formatNaming.fileName}/${formatNaming.fileName}-${naming.fileName}-command'
491
-
492
- export const wire${formatNaming.ClassName}${naming.ClassName}Command = wireClass(
493
- ${formatNaming.ClassName}${naming.ClassName}Command,
494
- []
495
- )
496
-
497
- `.trim());
498
- }
499
469
  }
500
- if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/handlers')) commandsFolder.createFile(`${naming.fileName}-command.ts`, `
501
- import type { Handler } from '@domain-first/handlers'
470
+ if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/handlers')) commandsFolder.subitem([
471
+ 'execution'
472
+ ]).createFile(`${naming.fileName}-command.ts`, `
473
+ import type { Handler } from '@domain-first/handlers'
502
474
 
503
- export abstract class ${naming.ClassName}Command {
504
- static inputSchema = {}
505
- static outputSchema = {}
475
+ export abstract class ${naming.ClassName}Command {
476
+ static inputSchema = {}
477
+ static outputSchema = {}
506
478
 
507
- abstract handle: Handler<typeof ${naming.ClassName}Command.inputSchema, typeof ${naming.ClassName}Command.outputSchema>
508
- }
479
+ abstract handle: Handler<typeof ${naming.ClassName}Command.inputSchema, typeof ${naming.ClassName}Command.outputSchema>
480
+ }
509
481
  `.trim());
510
482
  else commandsFolder.createFile(`${naming.fileName}-command.ts`, `
511
- export abstract class ${naming.ClassName}Command {
483
+ export abstract class ${naming.ClassName}Command {
512
484
 
513
- }`.trim());
485
+ }`.trim());
514
486
  if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/wire')) {
515
487
  const implementationNaming = new UnknownFormatNaming(implementationType);
516
488
  const testImplementationNaming = new UnknownFormatNaming(testImplementationType);
517
489
  boundedContextFolder.subitem([
518
490
  'wiring',
519
- 'application',
520
491
  'commands'
521
492
  ]).createFile(`wire-${naming.fileName}-command.ts`, `
522
- import { envBranchedWire } from '../../../../../shared/wiring/env-branched-wire'
523
- ${implementationTypes.map((x)=>new UnknownFormatNaming(x)).map(({ ClassName, fileName })=>`import { wire${ClassName}${naming.ClassName}Command } from '../../infrastructure/commands/${fileName}/wire-${fileName}-${naming.fileName}-command'`).join('\n')}
493
+ import { wireClass } from '@domain-first/wire'
494
+ import { envBranchedWire } from '../../../../shared/wiring/env-branched-wire'
495
+ ${implementationTypes.map((x)=>new UnknownFormatNaming(x)).map(({ ClassName, fileName })=>`import { ${ClassName}${naming.ClassName}Command } from '../../infrastructure/commands/${fileName}/${fileName}-${naming.fileName}-command'`).join('\n')}
524
496
 
525
- export const wire${naming.ClassName}Command = envBranchedWire({
526
- test: wire${addTestImplementation ? testImplementationNaming.ClassName : implementationNaming.ClassName}${naming.ClassName}Command,
527
- development: wire${implementationNaming.ClassName}${naming.ClassName}Command,
528
- production: wire${implementationNaming.ClassName}${naming.ClassName}Command
529
- })
497
+ ${implementationTypes.map((x)=>new UnknownFormatNaming(x)).map(({ ClassName })=>`const wire${ClassName}Implementation = wireClass(${ClassName}${naming.ClassName}Command, [])`).join('\n\n')}
498
+
499
+ export const wire${naming.ClassName}Command = envBranchedWire({
500
+ test: wire${addTestImplementation ? testImplementationNaming.ClassName : implementationNaming.ClassName}Implementation,
501
+ development: wire${implementationNaming.ClassName}Implementation,
502
+ production: wire${implementationNaming.ClassName}Implementation
503
+ })
530
504
  `.trim());
531
505
  }
532
506
  return;
533
507
  }
534
- if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/handlers')) commandsFolder.createFile(`${naming.fileName}-command.ts`, `
508
+ if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/handlers')) commandsFolder.subitem([
509
+ 'orchestration'
510
+ ]).createFile(`${naming.fileName}-command.ts`, `
535
511
  import { defineHandler } from '@domain-first/handlers'
536
512
 
537
513
  export class ${naming.ClassName}Command {
@@ -547,7 +523,9 @@ export class ${naming.ClassName}Command {
547
523
  })
548
524
  }
549
525
  `.trim());
550
- else commandsFolder.createFile(`${naming.fileName}-command.ts`, `
526
+ else commandsFolder.subitem([
527
+ 'orchestration'
528
+ ]).createFile(`${naming.fileName}-command.ts`, `
551
529
  export class ${naming.ClassName}Command {
552
530
 
553
531
  }`.trim());
@@ -557,7 +535,7 @@ export class ${naming.ClassName}Command {
557
535
  'commands'
558
536
  ]).createFile(`wire-${naming.fileName}-command.ts`, `
559
537
  import { wireClass } from '@domain-first/wire'
560
- import { ${naming.ClassName}Command } from '../../../application/commands/${naming.fileName}-command'
538
+ import { ${naming.ClassName}Command } from '../../../application/commands/orchestration/${naming.fileName}-command'
561
539
 
562
540
  export const wire${naming.ClassName}Command = wireClass(${naming.ClassName}Command, [])
563
541
  `.trim());
@@ -609,7 +587,7 @@ const scaffoldNewErrorUseCase = async (boundedContextFolder)=>{
609
587
  message: 'Error name:'
610
588
  });
611
589
  const naming = new UnknownFormatNaming(errorName);
612
- currentErrorFolder.file('index.ts').addLine(`export const ${naming.ClassName}Error = ${new UnknownFormatNaming(boundedContextFolder.name).ClassName}Errors.define('${naming.fileName}')`, '\n\n');
590
+ currentErrorFolder.file('index.ts').addLine(`export const ${naming.ClassName}${new UnknownFormatNaming(boundedContextFolder.name).ClassName}Error = ${new UnknownFormatNaming(boundedContextFolder.name).ClassName}Errors.define('${naming.fileName}')`, '\n\n');
613
591
  return;
614
592
  }
615
593
  if ('New namespace' === selectedVariant) {
@@ -620,17 +598,18 @@ const scaffoldNewErrorUseCase = async (boundedContextFolder)=>{
620
598
  currentErrorFolder.createFile(`${fileName}.ts`, `
621
599
  import { errorNamespace } from '@domain-first/errors'
622
600
 
623
- const ${ClassName}Errors = errorNamespace('${boundedContextFolder.name}').subnamespace('${fileName}')
601
+ export const ${ClassName}${new UnknownFormatNaming(boundedContextFolder.name).ClassName}Errors = errorNamespace('${boundedContextFolder.name}').subnamespace('${fileName}')
624
602
  `);
625
- currentErrorFolder.file('index.ts').addLine(`export * from './${fileName}'`);
603
+ currentErrorFolder.file('index.ts').addLine(`export * from './${fileName}'`, '\n\n');
626
604
  return;
627
605
  }
628
606
  const namespace = selectedVariant.substring(23);
607
+ const namespaceNaming = new UnknownFormatNaming(namespace);
629
608
  const errorName = await (0, prompts_namespaceObject.input)({
630
609
  message: 'Error name:'
631
610
  });
632
611
  const { ClassName, fileName } = new UnknownFormatNaming(errorName);
633
- currentErrorFolder.file(`${namespace}.ts`).addLine(`export const ${ClassName}Error = ${new UnknownFormatNaming(namespace).ClassName}Errors.define('${fileName}')`, '\n\n');
612
+ currentErrorFolder.file(`${namespace}.ts`).addLine(`export const ${ClassName}${namespaceNaming.ClassName}${new UnknownFormatNaming(boundedContextFolder.name).ClassName}Error = ${namespaceNaming.ClassName}${new UnknownFormatNaming(boundedContextFolder.name).ClassName}Errors.define('${fileName}')`, '\n\n');
634
613
  };
635
614
  const scaffoldNewHandlersRestEndpoint = async (boundedContextFolder)=>{
636
615
  const restPresentationFolder = boundedContextFolder.subitem([
@@ -649,11 +628,27 @@ const scaffoldNewHandlersRestEndpoint = async (boundedContextFolder)=>{
649
628
  controller = await (0, prompts_namespaceObject.input)({
650
629
  message: 'Name: '
651
630
  });
652
- if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/wire')) boundedContextFolder.subitem([
653
- 'wiring',
654
- 'presentation',
655
- 'rest'
656
- ]).file('index.ts').addLine(`export * from './${controller}'`);
631
+ if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/wire')) {
632
+ boundedContextFolder.subitem([
633
+ 'wiring',
634
+ 'presentation',
635
+ 'rest'
636
+ ]).file('index.ts').addLine(`export * from './${controller}'`);
637
+ const sharedRestFolder = boundedContextFolder.subitem([
638
+ '..',
639
+ '..',
640
+ 'presentation',
641
+ 'rest'
642
+ ]);
643
+ sharedRestFolder.file('wires.ts').addLine(`export * from '../../bounded-contexts/${boundedContextFolder.name}/wiring/presentation/rest/${controller}'`);
644
+ if (!sharedRestFolder.file('index.ts').exists) sharedRestFolder.createFile('index.ts', `
645
+ import * as wires from './wires'
646
+
647
+ const restWires = Object.values(wires)
648
+
649
+ export const restHandlers = restWires.map(x => x().handle)
650
+ `.trim());
651
+ }
657
652
  }
658
653
  const method = await (0, prompts_namespaceObject.select)({
659
654
  message: 'Method:',
@@ -671,9 +666,10 @@ const scaffoldNewHandlersRestEndpoint = async (boundedContextFolder)=>{
671
666
  const controllerFolder = restPresentationFolder.subitem([
672
667
  controller
673
668
  ]);
669
+ const endpointFolder = controllerFolder.subitem(path);
674
670
  const nameBase = `${controller}-${path.length ? `${path.join('-')}-` : ''}${method}-endpoint`;
675
671
  const endpointNaming = new UnknownFormatNaming(nameBase);
676
- controllerFolder.createFile(`${endpointNaming.fileName}.ts`, `
672
+ endpointFolder.createFile(`${method.toUpperCase()}.ts`, `
677
673
  import { EndpointGenerator } from '@domain-first/handlers-rest'
678
674
 
679
675
  export class ${endpointNaming.ClassName} {
@@ -689,7 +685,6 @@ export class ${endpointNaming.ClassName} {
689
685
  tags: ['${boundedContextFolder.name}: ${controller}'],
690
686
  })
691
687
  }
692
-
693
688
  }
694
689
  `.trim());
695
690
  if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/wire')) {
@@ -703,7 +698,7 @@ export class ${endpointNaming.ClassName} {
703
698
  const wireNaming = new UnknownFormatNaming(wireNameBase);
704
699
  wiringFolder.createFile(`${wireNaming.fileName}.ts`, `
705
700
  import { wireClass } from '@domain-first/wire'
706
- import { ${endpointNaming.ClassName} } from '../../../../presentation/rest/${controller}/${endpointNaming.fileName}'
701
+ import { ${endpointNaming.ClassName} } from '../../../../presentation/rest/${controller}/${path.length ? `${path.join('/')}/` : ''}${method.toUpperCase()}'
707
702
 
708
703
  export const wire${endpointNaming.ClassName} = wireClass(
709
704
  ${endpointNaming.ClassName},
@@ -726,9 +721,14 @@ const scaffoldNewQuery = async (boundedContextFolder)=>{
726
721
  message: 'Name: '
727
722
  });
728
723
  const naming = new UnknownFormatNaming(queryName);
729
- const isOrchestrator = await (0, prompts_namespaceObject.confirm)({
730
- message: 'Is an orchestrator query (no infrastructure implementations)?'
724
+ const queryType = await (0, prompts_namespaceObject.select)({
725
+ choices: [
726
+ 'Execution (with infrastructure implementation)',
727
+ 'Orchestrator (no infrastructure implementation)'
728
+ ],
729
+ message: 'Query type'
731
730
  });
731
+ const isOrchestrator = 'Orchestrator (no infrastructure implementation)' === queryType;
732
732
  if (!isOrchestrator) {
733
733
  const implementationType = await (0, prompts_namespaceObject.input)({
734
734
  message: 'Query infrastructure implementation type:',
@@ -752,80 +752,73 @@ const scaffoldNewQuery = async (boundedContextFolder)=>{
752
752
  infrastructureFolder.subitem([
753
753
  formatNaming.fileName
754
754
  ]).createFile(`${formatNaming.fileName}-${naming.fileName}-query.ts`, ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/handlers') ? `
755
- import { defineHandler } from '@domain-first/handlers'
756
- import { ${naming.ClassName}Query } from '../../../application/queries/${naming.fileName}-query'
757
-
758
- export class ${formatNaming.ClassName}${naming.ClassName}Query implements ${naming.ClassName}Query {
759
- constructor() {}
755
+ import { defineHandler } from '@domain-first/handlers'
756
+ import { ${naming.ClassName}Query } from '../../../application/queries/execution/${naming.fileName}-query'
760
757
 
761
- handle = defineHandler({
762
- inputSchema: ${naming.ClassName}Query.inputSchema,
763
- outputSchema: ${naming.ClassName}Query.outputSchema,
764
- handler: async (input) => {
765
- return {}
766
- }
767
- })
758
+ export class ${formatNaming.ClassName}${naming.ClassName}Query extends ${naming.ClassName}Query {
759
+ constructor() {
760
+ super()
768
761
  }
769
- `.trim() : `
770
- import { ${naming.ClassName}Query } from '../../../domain/queries/${naming.fileName}-query'
771
762
 
772
- export class ${formatNaming.ClassName}${naming.ClassName}Query implements ${naming.ClassName}Query {
763
+ handle = defineHandler({
764
+ inputSchema: ${naming.ClassName}Query.inputSchema,
765
+ outputSchema: ${naming.ClassName}Query.outputSchema,
766
+ handler: async (input) => {
767
+ return {}
768
+ }
769
+ })
770
+ }
771
+ `.trim() : `
772
+ import { ${naming.ClassName}Query } from '../../../domain/queries/${naming.fileName}-query'
773
773
 
774
+ export class ${formatNaming.ClassName}${naming.ClassName}Query extends ${naming.ClassName}Query {
775
+ constructor() {
776
+ super()
774
777
  }
778
+ }
775
779
  `.trim());
776
- if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/wire')) {
777
- const wiringFolder = boundedContextFolder.subitem([
778
- 'wiring',
779
- 'infrastructure',
780
- 'queries',
781
- formatNaming.fileName
782
- ]);
783
- wiringFolder.createFile(`wire-${formatNaming.fileName}-${naming.fileName}-query.ts`, `
784
- import { wireClass } from '@domain-first/wire'
785
- import { ${formatNaming.ClassName}${naming.ClassName}Query } from '../../../../infrastructure/queries/${formatNaming.fileName}/${formatNaming.fileName}-${naming.fileName}-query'
786
-
787
- export const wire${formatNaming.ClassName}${naming.ClassName}Query = wireClass(
788
- ${formatNaming.ClassName}${naming.ClassName}Query,
789
- []
790
- )
791
- `.trim());
792
- }
793
780
  }
794
- if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/handlers')) queriesFolder.createFile(`${naming.fileName}-query.ts`, `
795
- import type { Handler } from '@domain-first/handlers'
781
+ if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/handlers')) queriesFolder.subitem([
782
+ 'execution'
783
+ ]).createFile(`${naming.fileName}-query.ts`, `
784
+ import type { Handler } from '@domain-first/handlers'
796
785
 
797
- export abstract class ${naming.ClassName}Query {
798
- static inputSchema = {}
799
- static outputSchema = {}
786
+ export abstract class ${naming.ClassName}Query {
787
+ static inputSchema = {}
788
+ static outputSchema = {}
800
789
 
801
- abstract handle: Handler<typeof ${naming.ClassName}Query.inputSchema, typeof ${naming.ClassName}Query.outputSchema>
802
- }
790
+ abstract handle: Handler<typeof ${naming.ClassName}Query.inputSchema, typeof ${naming.ClassName}Query.outputSchema>
791
+ }
803
792
  `.trim());
804
793
  else queriesFolder.createFile(`${naming.fileName}-query.ts`, `
805
- export abstract class ${naming.ClassName}Query {
794
+ export abstract class ${naming.ClassName}Query {
806
795
 
807
- }`.trim());
796
+ }`.trim());
808
797
  if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/wire')) {
809
798
  const implementationNaming = new UnknownFormatNaming(implementationType);
810
799
  const testImplementationNaming = new UnknownFormatNaming(testImplementationType);
811
800
  boundedContextFolder.subitem([
812
801
  'wiring',
813
- 'application',
814
802
  'queries'
815
803
  ]).createFile(`wire-${naming.fileName}-query.ts`, `
816
- import { envBranchedWire } from '../../../../../shared/wiring/env-branched-wire'
817
- ${implementationTypes.map((x)=>new UnknownFormatNaming(x)).map(({ ClassName, fileName })=>`import { wire${ClassName}${naming.ClassName}Query } from '../../infrastructure/queries/${fileName}/wire-${fileName}-${naming.fileName}-query'`).join('\n')}
804
+ import { wireClass } from '@domain-first/wire'
805
+ import { envBranchedWire } from '../../../../shared/wiring/env-branched-wire'
806
+ ${implementationTypes.map((x)=>new UnknownFormatNaming(x)).map(({ ClassName, fileName })=>`import { ${ClassName}${naming.ClassName}Query } from '../../infrastructure/queries/${fileName}/${fileName}-${naming.fileName}-query'`).join('\n')}
818
807
 
819
- export const wire${naming.ClassName}Query = envBranchedWire({
820
- test: wire${addTestImplementation ? testImplementationNaming.ClassName : implementationNaming.ClassName}${naming.ClassName}Query,
821
- development: wire${implementationNaming.ClassName}${naming.ClassName}Query,
822
- production: wire${implementationNaming.ClassName}${naming.ClassName}Query
823
- })
808
+ ${implementationTypes.map((x)=>new UnknownFormatNaming(x)).map(({ ClassName })=>`const wire${ClassName}Implementation = wireClass(${ClassName}${naming.ClassName}Query, [])`).join('\n\n')}
809
+
810
+ export const wire${naming.ClassName}Query = envBranchedWire({
811
+ test: wire${addTestImplementation ? testImplementationNaming.ClassName : implementationNaming.ClassName}Implementation,
812
+ development: wire${implementationNaming.ClassName}Implementation,
813
+ production: wire${implementationNaming.ClassName}Implementation
814
+ })
824
815
  `.trim());
825
816
  }
826
817
  return;
827
818
  }
828
- if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/handlers')) queriesFolder.createFile(`${naming.fileName}-query.ts`, `
819
+ if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/handlers')) queriesFolder.subitem([
820
+ 'orchestration'
821
+ ]).createFile(`${naming.fileName}-query.ts`, `
829
822
  import { defineHandler } from '@domain-first/handlers'
830
823
 
831
824
  export class ${naming.ClassName}Query {
@@ -841,7 +834,9 @@ export class ${naming.ClassName}Query {
841
834
  })
842
835
  }
843
836
  `.trim());
844
- else queriesFolder.createFile(`${naming.fileName}-query.ts`, `
837
+ else queriesFolder.subitem([
838
+ 'orchestration'
839
+ ]).createFile(`${naming.fileName}-query.ts`, `
845
840
  export class ${naming.ClassName}Query {
846
841
 
847
842
  }`.trim());
@@ -851,7 +846,7 @@ export class ${naming.ClassName}Query {
851
846
  'queries'
852
847
  ]).createFile(`wire-${naming.fileName}-query.ts`, `
853
848
  import { wireClass } from '@domain-first/wire'
854
- import { ${naming.ClassName}Query } from '../../../application/queries/${naming.fileName}-query'
849
+ import { ${naming.ClassName}Query } from '../../../application/queries/orchestration/${naming.fileName}-query'
855
850
 
856
851
  export const wire${naming.ClassName}Query = wireClass(${naming.ClassName}Query, [])
857
852
  `.trim());
@@ -889,11 +884,10 @@ export class ${naming.ClassName}UseCase {
889
884
  `.trim());
890
885
  if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/wire')) boundedContextFolder.subitem([
891
886
  'wiring',
892
- 'application',
893
887
  'use-cases'
894
888
  ]).createFile(`wire-${naming.fileName}-use-case.ts`, `
895
889
  import { wireClass } from '@domain-first/wire'
896
- import { ${naming.ClassName}UseCase } from '../../../application/use-cases/${naming.fileName}-use-case'
890
+ import { ${naming.ClassName}UseCase } from '../../application/use-cases/${naming.fileName}-use-case'
897
891
 
898
892
  export const wire${naming.ClassName}UseCase = wireClass(
899
893
  ${naming.ClassName}UseCase,
@@ -902,6 +896,109 @@ export const wire${naming.ClassName}UseCase = wireClass(
902
896
 
903
897
  `.trim());
904
898
  };
899
+ const scaffoldReactWidget = async (presentationReactFolder)=>{
900
+ const widgetName = await (0, prompts_namespaceObject.input)({
901
+ message: 'Name: '
902
+ });
903
+ const widgetType = await (0, prompts_namespaceObject.select)({
904
+ choices: [
905
+ 'monolithic',
906
+ 'with separated ui',
907
+ 'headless'
908
+ ],
909
+ message: 'Type: '
910
+ });
911
+ const { ClassName, fileName } = new UnknownFormatNaming(widgetName);
912
+ const folder = presentationReactFolder.subitem([
913
+ 'widgets',
914
+ fileName
915
+ ]);
916
+ switch(widgetType){
917
+ case 'monolithic':
918
+ folder.createFile('index.tsx', `
919
+ import { type FC } from 'react'
920
+
921
+ export type ${ClassName}WidgetProps = {}
922
+
923
+ export const ${ClassName}Widget: FC<${ClassName}WidgetProps> = (props) => {
924
+ return <></>
925
+ }
926
+ `.trim());
927
+ break;
928
+ case 'with separated ui':
929
+ folder.createFile('types.ts', `
930
+ export type ${ClassName}WidgetProps = { }
931
+
932
+ export type ${ClassName}WidgetUIProps = { }
933
+ `.trim());
934
+ folder.createFile('index.tsx', `
935
+ import { type FC } from 'react'
936
+ import type { ${ClassName}WidgetProps } from './types'
937
+ import { ${ClassName}WidgetUI } from './ui'
938
+ import { useUIModel } from './hooks/use-ui-model'
939
+
940
+ export const ${ClassName}Widget: FC<${ClassName}WidgetProps> = (props) => {
941
+ const uiModel = useUIModel(props)
942
+ return <${ClassName}WidgetUI {...uiModel} />
943
+ }
944
+
945
+ export type { ${ClassName}WidgetProps }
946
+ `.trim());
947
+ folder.subitem([
948
+ 'ui'
949
+ ]).createFile('index.tsx', `
950
+ import { FC } from 'react'
951
+ import type { ${ClassName}WidgetUIProps } from '../types'
952
+
953
+ export const ${ClassName}WidgetUI: FC<${ClassName}WidgetUIProps> = (props) => {
954
+ return <></>
955
+ }
956
+ `.trim());
957
+ folder.subitem([
958
+ 'hooks'
959
+ ]).createFile('use-ui-model.ts', `
960
+ import type { ${ClassName}WidgetProps, ${ClassName}WidgetUIProps } from '../types'
961
+
962
+ export const useUIModel = (widgetProps: ${ClassName}WidgetProps): ${ClassName}WidgetUIProps => {
963
+ return {}
964
+ }
965
+ `.trim());
966
+ break;
967
+ case 'headless':
968
+ folder.createFile('types.ts', `
969
+ import { type FC } from 'react'
970
+
971
+ export type ${ClassName}WidgetUIProps = { }
972
+
973
+ export type ${ClassName}WidgetProps = {
974
+ UI: FC<${ClassName}WidgetUIProps>
975
+ }
976
+
977
+ `.trim());
978
+ folder.createFile('index.tsx', `
979
+ import { type FC } from 'react'
980
+ import type { ${ClassName}WidgetProps } from './types'
981
+ import { useUIModel } from './hooks/use-ui-model'
982
+
983
+ export const ${ClassName}Widget: FC<${ClassName}WidgetProps> = (props) => {
984
+ const uiModel = useUIModel(props)
985
+ return <props.UI {...uiModel} />
986
+ }
987
+
988
+ export type { ${ClassName}WidgetProps }
989
+ `.trim());
990
+ folder.subitem([
991
+ 'hooks'
992
+ ]).createFile('use-ui-model.ts', `
993
+ import type { ${ClassName}WidgetProps, ${ClassName}WidgetUIProps } from '../types'
994
+
995
+ export const useUIModel = (widgetProps: Omit<${ClassName}WidgetProps, 'UI'>): ${ClassName}WidgetUIProps => {
996
+ return {}
997
+ }
998
+ `.trim());
999
+ break;
1000
+ }
1001
+ };
905
1002
  const main = async ()=>{
906
1003
  if (!ConfigFile.exists) return void await initializeUseCase();
907
1004
  const rootPath = new ProjectRoot().path;
@@ -918,18 +1015,41 @@ const main = async ()=>{
918
1015
  };
919
1016
  const options = [
920
1017
  ...currentBoundedContextOptions,
1018
+ ConfigFile.Instance.data.useReact ? {
1019
+ name: 'Scaffold React module',
1020
+ action: 'Scaffold React module'
1021
+ } : void 0,
921
1022
  {
922
1023
  name: 'Shared Layer',
923
1024
  action: 'Scaffold in bounded context'
924
1025
  },
925
1026
  scaffoldNewBoundedContext
926
- ];
1027
+ ].filter((x)=>!!x);
927
1028
  const result = await (0, prompts_namespaceObject.select)({
928
1029
  message: '@domain-first/project-structure',
929
1030
  choices: options.map((x)=>x.name)
930
1031
  });
931
1032
  const { action, name } = options.find((x)=>x.name === result);
932
1033
  switch(action){
1034
+ case 'Scaffold React module':
1035
+ {
1036
+ const action = await (0, prompts_namespaceObject.select)({
1037
+ message: 'Module: ',
1038
+ choices: [
1039
+ 'New widget'
1040
+ ]
1041
+ });
1042
+ switch(action){
1043
+ case 'New widget':
1044
+ return void await scaffoldReactWidget(new Folder(rootPath).subitem([
1045
+ ConfigFile.Instance.data.rootFolder,
1046
+ 'presentation',
1047
+ 'react'
1048
+ ]));
1049
+ default:
1050
+ return;
1051
+ }
1052
+ }
933
1053
  case 'Scaffold new bounded context':
934
1054
  return void await scaffoldNewBoundedContextUseCase();
935
1055
  case 'Scaffold in bounded context':