@domain-first/project-structure 1.1.2 → 1.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.
- package/dist/config-file.d.ts +1 -0
- package/dist/index.cjs +136 -5
- package/dist/index.js +136 -5
- package/dist/use-cases/index.d.ts +1 -0
- package/dist/use-cases/scaffold-react-widget.d.ts +2 -0
- package/package.json +1 -1
package/dist/config-file.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ declare const configSchema: z.ZodObject<{
|
|
|
9
9
|
"@domain-first/handlers-rest": "@domain-first/handlers-rest";
|
|
10
10
|
}>>;
|
|
11
11
|
defaultPersistenceLayerImplementation: z.ZodString;
|
|
12
|
+
useReact: z.ZodBoolean;
|
|
12
13
|
}, z.core.$strip>;
|
|
13
14
|
export declare class ConfigFile {
|
|
14
15
|
readonly data: z.infer<typeof configSchema>;
|
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);
|
|
@@ -532,7 +537,7 @@ const scaffoldNewCommand = async (boundedContextFolder)=>{
|
|
|
532
537
|
return;
|
|
533
538
|
}
|
|
534
539
|
if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/handlers')) commandsFolder.createFile(`${naming.fileName}-command.ts`, `
|
|
535
|
-
import { defineHandler
|
|
540
|
+
import { defineHandler } from '@domain-first/handlers'
|
|
536
541
|
|
|
537
542
|
export class ${naming.ClassName}Command {
|
|
538
543
|
static inputSchema = {}
|
|
@@ -826,7 +831,7 @@ const scaffoldNewQuery = async (boundedContextFolder)=>{
|
|
|
826
831
|
return;
|
|
827
832
|
}
|
|
828
833
|
if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/handlers')) queriesFolder.createFile(`${naming.fileName}-query.ts`, `
|
|
829
|
-
import { defineHandler
|
|
834
|
+
import { defineHandler } from '@domain-first/handlers'
|
|
830
835
|
|
|
831
836
|
export class ${naming.ClassName}Query {
|
|
832
837
|
static inputSchema = {}
|
|
@@ -902,6 +907,109 @@ export const wire${naming.ClassName}UseCase = wireClass(
|
|
|
902
907
|
|
|
903
908
|
`.trim());
|
|
904
909
|
};
|
|
910
|
+
const scaffoldReactWidget = async (presentationReactFolder)=>{
|
|
911
|
+
const widgetName = await (0, prompts_namespaceObject.input)({
|
|
912
|
+
message: 'Name: '
|
|
913
|
+
});
|
|
914
|
+
const widgetType = await (0, prompts_namespaceObject.select)({
|
|
915
|
+
choices: [
|
|
916
|
+
'monolithic',
|
|
917
|
+
'with separated ui',
|
|
918
|
+
'headless'
|
|
919
|
+
],
|
|
920
|
+
message: 'Type: '
|
|
921
|
+
});
|
|
922
|
+
const { ClassName, fileName } = new UnknownFormatNaming(widgetName);
|
|
923
|
+
const folder = presentationReactFolder.subitem([
|
|
924
|
+
'widgets',
|
|
925
|
+
fileName
|
|
926
|
+
]);
|
|
927
|
+
switch(widgetType){
|
|
928
|
+
case 'monolithic':
|
|
929
|
+
folder.createFile('index.tsx', `
|
|
930
|
+
import { type FC } from 'react'
|
|
931
|
+
|
|
932
|
+
export type ${ClassName}WidgetProps = {}
|
|
933
|
+
|
|
934
|
+
export const ${ClassName}Widget: FC<${ClassName}WidgetProps> = (props) => {
|
|
935
|
+
return <></>
|
|
936
|
+
}
|
|
937
|
+
`.trim());
|
|
938
|
+
break;
|
|
939
|
+
case 'with separated ui':
|
|
940
|
+
folder.createFile('types.ts', `
|
|
941
|
+
export type ${ClassName}WidgetProps = { }
|
|
942
|
+
|
|
943
|
+
export type ${ClassName}WidgetUIProps = { }
|
|
944
|
+
`.trim());
|
|
945
|
+
folder.createFile('index.tsx', `
|
|
946
|
+
import { type FC } from 'react'
|
|
947
|
+
import type { ${ClassName}WidgetProps } from './types'
|
|
948
|
+
import { ${ClassName}WidgetUI } from './ui'
|
|
949
|
+
import { useUIModel } from './hooks/use-ui-model'
|
|
950
|
+
|
|
951
|
+
export const ${ClassName}Widget: FC<${ClassName}WidgetProps> = (props) => {
|
|
952
|
+
const uiModel = useUIModel(props)
|
|
953
|
+
return <${ClassName}WidgetUI {...uiModel} />
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
export type { ${ClassName}WidgetProps }
|
|
957
|
+
`.trim());
|
|
958
|
+
folder.subitem([
|
|
959
|
+
'ui'
|
|
960
|
+
]).createFile('index.tsx', `
|
|
961
|
+
import { FC } from 'react'
|
|
962
|
+
import type { ${ClassName}WidgetUIProps } from '../types'
|
|
963
|
+
|
|
964
|
+
export const ${ClassName}WidgetUI: FC<${ClassName}WidgetUIProps> = (props) => {
|
|
965
|
+
return <></>
|
|
966
|
+
}
|
|
967
|
+
`.trim());
|
|
968
|
+
folder.subitem([
|
|
969
|
+
'hooks'
|
|
970
|
+
]).createFile('use-ui-model.ts', `
|
|
971
|
+
import type { ${ClassName}WidgetProps, ${ClassName}WidgetUIProps } from '../types'
|
|
972
|
+
|
|
973
|
+
export const useUIModel = (widgetProps: ${ClassName}WidgetProps): ${ClassName}WidgetUIProps => {
|
|
974
|
+
return {}
|
|
975
|
+
}
|
|
976
|
+
`.trim());
|
|
977
|
+
break;
|
|
978
|
+
case 'headless':
|
|
979
|
+
folder.createFile('types.ts', `
|
|
980
|
+
import { type FC } from 'react'
|
|
981
|
+
|
|
982
|
+
export type ${ClassName}WidgetUIProps = { }
|
|
983
|
+
|
|
984
|
+
export type ${ClassName}WidgetProps = {
|
|
985
|
+
UI: FC<${ClassName}WidgetUIProps>
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
`.trim());
|
|
989
|
+
folder.createFile('index.tsx', `
|
|
990
|
+
import { type FC } from 'react'
|
|
991
|
+
import type { ${ClassName}WidgetProps } from './types'
|
|
992
|
+
import { useUIModel } from './hooks/use-ui-model'
|
|
993
|
+
|
|
994
|
+
export const ${ClassName}Widget: FC<${ClassName}WidgetProps> = (props) => {
|
|
995
|
+
const uiModel = useUIModel(props)
|
|
996
|
+
return <props.UI {...uiModel} />
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
export type { ${ClassName}WidgetProps }
|
|
1000
|
+
`.trim());
|
|
1001
|
+
folder.subitem([
|
|
1002
|
+
'hooks'
|
|
1003
|
+
]).createFile('use-ui-model.ts', `
|
|
1004
|
+
import type { ${ClassName}WidgetProps, ${ClassName}WidgetUIProps } from '../types'
|
|
1005
|
+
|
|
1006
|
+
export const useUIModel = (widgetProps: Omit<${ClassName}WidgetProps, 'UI'>): ${ClassName}WidgetUIProps => {
|
|
1007
|
+
return {}
|
|
1008
|
+
}
|
|
1009
|
+
`.trim());
|
|
1010
|
+
break;
|
|
1011
|
+
}
|
|
1012
|
+
};
|
|
905
1013
|
const main = async ()=>{
|
|
906
1014
|
if (!ConfigFile.exists) return void await initializeUseCase();
|
|
907
1015
|
const rootPath = new ProjectRoot().path;
|
|
@@ -918,18 +1026,41 @@ const main = async ()=>{
|
|
|
918
1026
|
};
|
|
919
1027
|
const options = [
|
|
920
1028
|
...currentBoundedContextOptions,
|
|
1029
|
+
ConfigFile.Instance.data.useReact ? {
|
|
1030
|
+
name: 'Scaffold React module',
|
|
1031
|
+
action: 'Scaffold React module'
|
|
1032
|
+
} : void 0,
|
|
921
1033
|
{
|
|
922
1034
|
name: 'Shared Layer',
|
|
923
1035
|
action: 'Scaffold in bounded context'
|
|
924
1036
|
},
|
|
925
1037
|
scaffoldNewBoundedContext
|
|
926
|
-
];
|
|
1038
|
+
].filter((x)=>!!x);
|
|
927
1039
|
const result = await (0, prompts_namespaceObject.select)({
|
|
928
1040
|
message: '@domain-first/project-structure',
|
|
929
1041
|
choices: options.map((x)=>x.name)
|
|
930
1042
|
});
|
|
931
1043
|
const { action, name } = options.find((x)=>x.name === result);
|
|
932
1044
|
switch(action){
|
|
1045
|
+
case 'Scaffold React module':
|
|
1046
|
+
{
|
|
1047
|
+
const action = await (0, prompts_namespaceObject.select)({
|
|
1048
|
+
message: 'Module: ',
|
|
1049
|
+
choices: [
|
|
1050
|
+
'New widget'
|
|
1051
|
+
]
|
|
1052
|
+
});
|
|
1053
|
+
switch(action){
|
|
1054
|
+
case 'New widget':
|
|
1055
|
+
return void await scaffoldReactWidget(new Folder(rootPath).subitem([
|
|
1056
|
+
ConfigFile.Instance.data.rootFolder,
|
|
1057
|
+
'presentation',
|
|
1058
|
+
'react'
|
|
1059
|
+
]));
|
|
1060
|
+
default:
|
|
1061
|
+
return;
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
933
1064
|
case 'Scaffold new bounded context':
|
|
934
1065
|
return void await scaffoldNewBoundedContextUseCase();
|
|
935
1066
|
case 'Scaffold in bounded context':
|
package/dist/index.js
CHANGED
|
@@ -94,7 +94,8 @@ const configSchema = zod.object({
|
|
|
94
94
|
'@domain-first/wire',
|
|
95
95
|
'@domain-first/handlers-rest'
|
|
96
96
|
])),
|
|
97
|
-
defaultPersistenceLayerImplementation: zod.string()
|
|
97
|
+
defaultPersistenceLayerImplementation: zod.string(),
|
|
98
|
+
useReact: zod.boolean()
|
|
98
99
|
});
|
|
99
100
|
class ConfigFile {
|
|
100
101
|
data;
|
|
@@ -136,10 +137,14 @@ const initializeUseCase = async ()=>{
|
|
|
136
137
|
const defaultPersistenceLayerImplementation = await input({
|
|
137
138
|
message: 'Default persistence layer implementation:'
|
|
138
139
|
});
|
|
140
|
+
const useReact = await prompts_confirm({
|
|
141
|
+
message: 'Use React'
|
|
142
|
+
});
|
|
139
143
|
ConfigFile.write({
|
|
140
144
|
rootFolder: rootFolderName,
|
|
141
145
|
domainFirstPackages,
|
|
142
|
-
defaultPersistenceLayerImplementation
|
|
146
|
+
defaultPersistenceLayerImplementation,
|
|
147
|
+
useReact
|
|
143
148
|
});
|
|
144
149
|
const { path } = new ProjectRoot();
|
|
145
150
|
const rootFolder = new Folder(path);
|
|
@@ -502,7 +507,7 @@ const scaffoldNewCommand = async (boundedContextFolder)=>{
|
|
|
502
507
|
return;
|
|
503
508
|
}
|
|
504
509
|
if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/handlers')) commandsFolder.createFile(`${naming.fileName}-command.ts`, `
|
|
505
|
-
import { defineHandler
|
|
510
|
+
import { defineHandler } from '@domain-first/handlers'
|
|
506
511
|
|
|
507
512
|
export class ${naming.ClassName}Command {
|
|
508
513
|
static inputSchema = {}
|
|
@@ -796,7 +801,7 @@ const scaffoldNewQuery = async (boundedContextFolder)=>{
|
|
|
796
801
|
return;
|
|
797
802
|
}
|
|
798
803
|
if (ConfigFile.Instance.data.domainFirstPackages.includes('@domain-first/handlers')) queriesFolder.createFile(`${naming.fileName}-query.ts`, `
|
|
799
|
-
import { defineHandler
|
|
804
|
+
import { defineHandler } from '@domain-first/handlers'
|
|
800
805
|
|
|
801
806
|
export class ${naming.ClassName}Query {
|
|
802
807
|
static inputSchema = {}
|
|
@@ -872,6 +877,109 @@ export const wire${naming.ClassName}UseCase = wireClass(
|
|
|
872
877
|
|
|
873
878
|
`.trim());
|
|
874
879
|
};
|
|
880
|
+
const scaffoldReactWidget = async (presentationReactFolder)=>{
|
|
881
|
+
const widgetName = await input({
|
|
882
|
+
message: 'Name: '
|
|
883
|
+
});
|
|
884
|
+
const widgetType = await prompts_select({
|
|
885
|
+
choices: [
|
|
886
|
+
'monolithic',
|
|
887
|
+
'with separated ui',
|
|
888
|
+
'headless'
|
|
889
|
+
],
|
|
890
|
+
message: 'Type: '
|
|
891
|
+
});
|
|
892
|
+
const { ClassName, fileName } = new UnknownFormatNaming(widgetName);
|
|
893
|
+
const folder = presentationReactFolder.subitem([
|
|
894
|
+
'widgets',
|
|
895
|
+
fileName
|
|
896
|
+
]);
|
|
897
|
+
switch(widgetType){
|
|
898
|
+
case 'monolithic':
|
|
899
|
+
folder.createFile('index.tsx', `
|
|
900
|
+
import { type FC } from 'react'
|
|
901
|
+
|
|
902
|
+
export type ${ClassName}WidgetProps = {}
|
|
903
|
+
|
|
904
|
+
export const ${ClassName}Widget: FC<${ClassName}WidgetProps> = (props) => {
|
|
905
|
+
return <></>
|
|
906
|
+
}
|
|
907
|
+
`.trim());
|
|
908
|
+
break;
|
|
909
|
+
case 'with separated ui':
|
|
910
|
+
folder.createFile('types.ts', `
|
|
911
|
+
export type ${ClassName}WidgetProps = { }
|
|
912
|
+
|
|
913
|
+
export type ${ClassName}WidgetUIProps = { }
|
|
914
|
+
`.trim());
|
|
915
|
+
folder.createFile('index.tsx', `
|
|
916
|
+
import { type FC } from 'react'
|
|
917
|
+
import type { ${ClassName}WidgetProps } from './types'
|
|
918
|
+
import { ${ClassName}WidgetUI } from './ui'
|
|
919
|
+
import { useUIModel } from './hooks/use-ui-model'
|
|
920
|
+
|
|
921
|
+
export const ${ClassName}Widget: FC<${ClassName}WidgetProps> = (props) => {
|
|
922
|
+
const uiModel = useUIModel(props)
|
|
923
|
+
return <${ClassName}WidgetUI {...uiModel} />
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
export type { ${ClassName}WidgetProps }
|
|
927
|
+
`.trim());
|
|
928
|
+
folder.subitem([
|
|
929
|
+
'ui'
|
|
930
|
+
]).createFile('index.tsx', `
|
|
931
|
+
import { FC } from 'react'
|
|
932
|
+
import type { ${ClassName}WidgetUIProps } from '../types'
|
|
933
|
+
|
|
934
|
+
export const ${ClassName}WidgetUI: FC<${ClassName}WidgetUIProps> = (props) => {
|
|
935
|
+
return <></>
|
|
936
|
+
}
|
|
937
|
+
`.trim());
|
|
938
|
+
folder.subitem([
|
|
939
|
+
'hooks'
|
|
940
|
+
]).createFile('use-ui-model.ts', `
|
|
941
|
+
import type { ${ClassName}WidgetProps, ${ClassName}WidgetUIProps } from '../types'
|
|
942
|
+
|
|
943
|
+
export const useUIModel = (widgetProps: ${ClassName}WidgetProps): ${ClassName}WidgetUIProps => {
|
|
944
|
+
return {}
|
|
945
|
+
}
|
|
946
|
+
`.trim());
|
|
947
|
+
break;
|
|
948
|
+
case 'headless':
|
|
949
|
+
folder.createFile('types.ts', `
|
|
950
|
+
import { type FC } from 'react'
|
|
951
|
+
|
|
952
|
+
export type ${ClassName}WidgetUIProps = { }
|
|
953
|
+
|
|
954
|
+
export type ${ClassName}WidgetProps = {
|
|
955
|
+
UI: FC<${ClassName}WidgetUIProps>
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
`.trim());
|
|
959
|
+
folder.createFile('index.tsx', `
|
|
960
|
+
import { type FC } from 'react'
|
|
961
|
+
import type { ${ClassName}WidgetProps } from './types'
|
|
962
|
+
import { useUIModel } from './hooks/use-ui-model'
|
|
963
|
+
|
|
964
|
+
export const ${ClassName}Widget: FC<${ClassName}WidgetProps> = (props) => {
|
|
965
|
+
const uiModel = useUIModel(props)
|
|
966
|
+
return <props.UI {...uiModel} />
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
export type { ${ClassName}WidgetProps }
|
|
970
|
+
`.trim());
|
|
971
|
+
folder.subitem([
|
|
972
|
+
'hooks'
|
|
973
|
+
]).createFile('use-ui-model.ts', `
|
|
974
|
+
import type { ${ClassName}WidgetProps, ${ClassName}WidgetUIProps } from '../types'
|
|
975
|
+
|
|
976
|
+
export const useUIModel = (widgetProps: Omit<${ClassName}WidgetProps, 'UI'>): ${ClassName}WidgetUIProps => {
|
|
977
|
+
return {}
|
|
978
|
+
}
|
|
979
|
+
`.trim());
|
|
980
|
+
break;
|
|
981
|
+
}
|
|
982
|
+
};
|
|
875
983
|
const main = async ()=>{
|
|
876
984
|
if (!ConfigFile.exists) return void await initializeUseCase();
|
|
877
985
|
const rootPath = new ProjectRoot().path;
|
|
@@ -888,18 +996,41 @@ const main = async ()=>{
|
|
|
888
996
|
};
|
|
889
997
|
const options = [
|
|
890
998
|
...currentBoundedContextOptions,
|
|
999
|
+
ConfigFile.Instance.data.useReact ? {
|
|
1000
|
+
name: 'Scaffold React module',
|
|
1001
|
+
action: 'Scaffold React module'
|
|
1002
|
+
} : void 0,
|
|
891
1003
|
{
|
|
892
1004
|
name: 'Shared Layer',
|
|
893
1005
|
action: 'Scaffold in bounded context'
|
|
894
1006
|
},
|
|
895
1007
|
scaffoldNewBoundedContext
|
|
896
|
-
];
|
|
1008
|
+
].filter((x)=>!!x);
|
|
897
1009
|
const result = await prompts_select({
|
|
898
1010
|
message: '@domain-first/project-structure',
|
|
899
1011
|
choices: options.map((x)=>x.name)
|
|
900
1012
|
});
|
|
901
1013
|
const { action, name } = options.find((x)=>x.name === result);
|
|
902
1014
|
switch(action){
|
|
1015
|
+
case 'Scaffold React module':
|
|
1016
|
+
{
|
|
1017
|
+
const action = await prompts_select({
|
|
1018
|
+
message: 'Module: ',
|
|
1019
|
+
choices: [
|
|
1020
|
+
'New widget'
|
|
1021
|
+
]
|
|
1022
|
+
});
|
|
1023
|
+
switch(action){
|
|
1024
|
+
case 'New widget':
|
|
1025
|
+
return void await scaffoldReactWidget(new Folder(rootPath).subitem([
|
|
1026
|
+
ConfigFile.Instance.data.rootFolder,
|
|
1027
|
+
'presentation',
|
|
1028
|
+
'react'
|
|
1029
|
+
]));
|
|
1030
|
+
default:
|
|
1031
|
+
return;
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
903
1034
|
case 'Scaffold new bounded context':
|
|
904
1035
|
return void await scaffoldNewBoundedContextUseCase();
|
|
905
1036
|
case 'Scaffold in bounded context':
|