@domain-first/project-structure 2.0.1 → 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.
package/dist/config-file.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ declare const configSchema: z.ZodObject<{
|
|
|
10
10
|
}>>;
|
|
11
11
|
defaultPersistenceLayerImplementation: z.ZodString;
|
|
12
12
|
useReact: z.ZodBoolean;
|
|
13
|
+
testingLibrary: z.ZodOptional<z.ZodString>;
|
|
13
14
|
}, z.core.$strip>;
|
|
14
15
|
export declare class ConfigFile {
|
|
15
16
|
readonly data: z.infer<typeof configSchema>;
|
package/dist/index.cjs
CHANGED
|
@@ -125,7 +125,8 @@ const configSchema = external_zod_default().object({
|
|
|
125
125
|
'@domain-first/handlers-rest'
|
|
126
126
|
])),
|
|
127
127
|
defaultPersistenceLayerImplementation: external_zod_default().string(),
|
|
128
|
-
useReact: external_zod_default().boolean()
|
|
128
|
+
useReact: external_zod_default().boolean(),
|
|
129
|
+
testingLibrary: external_zod_default().string().optional()
|
|
129
130
|
});
|
|
130
131
|
class ConfigFile {
|
|
131
132
|
data;
|
|
@@ -170,11 +171,20 @@ const initializeUseCase = async ()=>{
|
|
|
170
171
|
const useReact = await (0, prompts_namespaceObject.confirm)({
|
|
171
172
|
message: 'Use React'
|
|
172
173
|
});
|
|
174
|
+
let testingLibrary;
|
|
175
|
+
const withTests = await (0, prompts_namespaceObject.confirm)({
|
|
176
|
+
message: 'Scaffold unit tests'
|
|
177
|
+
});
|
|
178
|
+
if (withTests) testingLibrary = await (0, prompts_namespaceObject.input)({
|
|
179
|
+
message: 'Unit testing library:',
|
|
180
|
+
default: 'vitest'
|
|
181
|
+
});
|
|
173
182
|
ConfigFile.write({
|
|
174
183
|
rootFolder: rootFolderName,
|
|
175
184
|
domainFirstPackages,
|
|
176
185
|
defaultPersistenceLayerImplementation,
|
|
177
|
-
useReact
|
|
186
|
+
useReact,
|
|
187
|
+
testingLibrary
|
|
178
188
|
});
|
|
179
189
|
const { path } = new ProjectRoot();
|
|
180
190
|
const rootFolder = new Folder(path);
|
|
@@ -225,12 +235,19 @@ class UnknownFormatNaming {
|
|
|
225
235
|
get ClassName() {
|
|
226
236
|
return this.PascalCase;
|
|
227
237
|
}
|
|
238
|
+
get withSpaces() {
|
|
239
|
+
return this.fileName.replaceAll('-', ' ');
|
|
240
|
+
}
|
|
228
241
|
}
|
|
229
242
|
const scaffoldNewAggregateUseCase = async (boundedContextFolder)=>{
|
|
230
243
|
const aggregateName = await (0, prompts_namespaceObject.input)({
|
|
231
244
|
message: 'Aggregate name:'
|
|
232
245
|
});
|
|
233
246
|
const aggregateNaming = new UnknownFormatNaming(aggregateName);
|
|
247
|
+
let scaffoldUnitTests;
|
|
248
|
+
if (ConfigFile.Instance.data.testingLibrary) scaffoldUnitTests = await (0, prompts_namespaceObject.confirm)({
|
|
249
|
+
message: 'Scaffold unit-tests'
|
|
250
|
+
});
|
|
234
251
|
const withRepository = await (0, prompts_namespaceObject.confirm)({
|
|
235
252
|
message: 'With Repository'
|
|
236
253
|
});
|
|
@@ -246,9 +263,42 @@ export class ${aggregateNaming.ClassName} extends domainType() {
|
|
|
246
263
|
|
|
247
264
|
}`.trim() : `export class ${aggregateNaming.ClassName} {}`);
|
|
248
265
|
const barrelFile = aggregatesFolder.createFile("index.ts", `export * from './${aggregateNaming.fileName}.aggregate-root'`);
|
|
266
|
+
if (scaffoldUnitTests) aggregatesFolder.createFile(`${aggregateNaming.fileName}.aggregate-root.spec.ts`, `
|
|
267
|
+
import { describe, test, expect, beforeEach } from '${ConfigFile.Instance.data.testingLibrary}'
|
|
268
|
+
import { ${aggregateNaming.ClassName} } from './${aggregateNaming.fileName}.aggregate-root'
|
|
269
|
+
|
|
270
|
+
let ${aggregateNaming.variableName}: ${aggregateNaming.ClassName}
|
|
271
|
+
|
|
272
|
+
beforeEach(() => {
|
|
273
|
+
${aggregateNaming.variableName} = new ${aggregateNaming.ClassName}()
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
describe('${aggregateNaming.withSpaces}', () => {
|
|
277
|
+
test('can be instantiated via constructor', () => {
|
|
278
|
+
expect(${aggregateNaming.variableName}).toBeDefined()
|
|
279
|
+
})
|
|
280
|
+
})
|
|
281
|
+
`);
|
|
249
282
|
if (withRepository) {
|
|
250
283
|
aggregatesFolder.createFile(`${aggregateNaming.fileName}-repository.ts`, `export abstract class ${aggregateNaming.ClassName}Repository { }`);
|
|
251
284
|
barrelFile.addLine(`export * from './${aggregateNaming.fileName}-repository'`);
|
|
285
|
+
if (scaffoldUnitTests) aggregatesFolder.createFile(`${aggregateNaming.fileName}-repository.spec.ts`, `
|
|
286
|
+
import { describe, test, expect, beforeEach } from '${ConfigFile.Instance.data.testingLibrary}'
|
|
287
|
+
import { wire${aggregateNaming.ClassName}Repository } from '../../../wiring/repositories/wire-${aggregateNaming.fileName}-repository'
|
|
288
|
+
import type { ${aggregateNaming.ClassName}Repository } from './${aggregateNaming.fileName}-repository'
|
|
289
|
+
|
|
290
|
+
let ${aggregateNaming.variableName}Repository: ${aggregateNaming.ClassName}Repository
|
|
291
|
+
|
|
292
|
+
beforeEach(() => {
|
|
293
|
+
${aggregateNaming.variableName}Repository = wire${aggregateNaming.ClassName}Repository()
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
describe('${aggregateNaming.withSpaces} repository', () => {
|
|
297
|
+
test('can be wired', () => {
|
|
298
|
+
expect(${aggregateNaming.variableName}Repository).toBeDefined()
|
|
299
|
+
})
|
|
300
|
+
})
|
|
301
|
+
`.trim());
|
|
252
302
|
const infrastructureImplementationType = await (0, prompts_namespaceObject.input)({
|
|
253
303
|
message: 'Repository infrastructure implementation type:',
|
|
254
304
|
default: 'prisma'
|
|
@@ -895,6 +945,23 @@ export const wire${naming.ClassName}UseCase = wireClass(
|
|
|
895
945
|
|
|
896
946
|
`.trim());
|
|
897
947
|
};
|
|
948
|
+
const scaffoldReactPage = async (presentationReactFolder)=>{
|
|
949
|
+
const name = await (0, prompts_namespaceObject.input)({
|
|
950
|
+
message: 'Provide name:'
|
|
951
|
+
});
|
|
952
|
+
const { ClassName, fileName } = new UnknownFormatNaming(name);
|
|
953
|
+
presentationReactFolder.subitem([
|
|
954
|
+
'pages'
|
|
955
|
+
]).createFile(`${fileName}-page.tsx`, `
|
|
956
|
+
import { type FC } from 'react'
|
|
957
|
+
|
|
958
|
+
export type ${ClassName}PageProps = {}
|
|
959
|
+
|
|
960
|
+
export const ${ClassName}Page: FC<${ClassName}PageProps> = (props) => {
|
|
961
|
+
return <></>
|
|
962
|
+
}
|
|
963
|
+
`.trim());
|
|
964
|
+
};
|
|
898
965
|
const scaffoldReactWidget = async (presentationReactFolder)=>{
|
|
899
966
|
const widgetName = await (0, prompts_namespaceObject.input)({
|
|
900
967
|
message: 'Name: '
|
|
@@ -1032,19 +1099,23 @@ const main = async ()=>{
|
|
|
1032
1099
|
switch(action){
|
|
1033
1100
|
case 'Scaffold React module':
|
|
1034
1101
|
{
|
|
1102
|
+
const reactFolder = new Folder(rootPath).subitem([
|
|
1103
|
+
ConfigFile.Instance.data.rootFolder,
|
|
1104
|
+
'presentation',
|
|
1105
|
+
'react'
|
|
1106
|
+
]);
|
|
1035
1107
|
const action = await (0, prompts_namespaceObject.select)({
|
|
1036
1108
|
message: 'Module: ',
|
|
1037
1109
|
choices: [
|
|
1038
|
-
'New widget'
|
|
1110
|
+
'New widget',
|
|
1111
|
+
'New page'
|
|
1039
1112
|
]
|
|
1040
1113
|
});
|
|
1041
1114
|
switch(action){
|
|
1042
1115
|
case 'New widget':
|
|
1043
|
-
return void await scaffoldReactWidget(
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
'react'
|
|
1047
|
-
]));
|
|
1116
|
+
return void await scaffoldReactWidget(reactFolder);
|
|
1117
|
+
case 'New page':
|
|
1118
|
+
return void await scaffoldReactPage(reactFolder);
|
|
1048
1119
|
default:
|
|
1049
1120
|
return;
|
|
1050
1121
|
}
|
package/dist/index.js
CHANGED
|
@@ -95,7 +95,8 @@ const configSchema = zod.object({
|
|
|
95
95
|
'@domain-first/handlers-rest'
|
|
96
96
|
])),
|
|
97
97
|
defaultPersistenceLayerImplementation: zod.string(),
|
|
98
|
-
useReact: zod.boolean()
|
|
98
|
+
useReact: zod.boolean(),
|
|
99
|
+
testingLibrary: zod.string().optional()
|
|
99
100
|
});
|
|
100
101
|
class ConfigFile {
|
|
101
102
|
data;
|
|
@@ -140,11 +141,20 @@ const initializeUseCase = async ()=>{
|
|
|
140
141
|
const useReact = await prompts_confirm({
|
|
141
142
|
message: 'Use React'
|
|
142
143
|
});
|
|
144
|
+
let testingLibrary;
|
|
145
|
+
const withTests = await prompts_confirm({
|
|
146
|
+
message: 'Scaffold unit tests'
|
|
147
|
+
});
|
|
148
|
+
if (withTests) testingLibrary = await input({
|
|
149
|
+
message: 'Unit testing library:',
|
|
150
|
+
default: 'vitest'
|
|
151
|
+
});
|
|
143
152
|
ConfigFile.write({
|
|
144
153
|
rootFolder: rootFolderName,
|
|
145
154
|
domainFirstPackages,
|
|
146
155
|
defaultPersistenceLayerImplementation,
|
|
147
|
-
useReact
|
|
156
|
+
useReact,
|
|
157
|
+
testingLibrary
|
|
148
158
|
});
|
|
149
159
|
const { path } = new ProjectRoot();
|
|
150
160
|
const rootFolder = new Folder(path);
|
|
@@ -195,12 +205,19 @@ class UnknownFormatNaming {
|
|
|
195
205
|
get ClassName() {
|
|
196
206
|
return this.PascalCase;
|
|
197
207
|
}
|
|
208
|
+
get withSpaces() {
|
|
209
|
+
return this.fileName.replaceAll('-', ' ');
|
|
210
|
+
}
|
|
198
211
|
}
|
|
199
212
|
const scaffoldNewAggregateUseCase = async (boundedContextFolder)=>{
|
|
200
213
|
const aggregateName = await input({
|
|
201
214
|
message: 'Aggregate name:'
|
|
202
215
|
});
|
|
203
216
|
const aggregateNaming = new UnknownFormatNaming(aggregateName);
|
|
217
|
+
let scaffoldUnitTests;
|
|
218
|
+
if (ConfigFile.Instance.data.testingLibrary) scaffoldUnitTests = await prompts_confirm({
|
|
219
|
+
message: 'Scaffold unit-tests'
|
|
220
|
+
});
|
|
204
221
|
const withRepository = await prompts_confirm({
|
|
205
222
|
message: 'With Repository'
|
|
206
223
|
});
|
|
@@ -216,9 +233,42 @@ export class ${aggregateNaming.ClassName} extends domainType() {
|
|
|
216
233
|
|
|
217
234
|
}`.trim() : `export class ${aggregateNaming.ClassName} {}`);
|
|
218
235
|
const barrelFile = aggregatesFolder.createFile("index.ts", `export * from './${aggregateNaming.fileName}.aggregate-root'`);
|
|
236
|
+
if (scaffoldUnitTests) aggregatesFolder.createFile(`${aggregateNaming.fileName}.aggregate-root.spec.ts`, `
|
|
237
|
+
import { describe, test, expect, beforeEach } from '${ConfigFile.Instance.data.testingLibrary}'
|
|
238
|
+
import { ${aggregateNaming.ClassName} } from './${aggregateNaming.fileName}.aggregate-root'
|
|
239
|
+
|
|
240
|
+
let ${aggregateNaming.variableName}: ${aggregateNaming.ClassName}
|
|
241
|
+
|
|
242
|
+
beforeEach(() => {
|
|
243
|
+
${aggregateNaming.variableName} = new ${aggregateNaming.ClassName}()
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
describe('${aggregateNaming.withSpaces}', () => {
|
|
247
|
+
test('can be instantiated via constructor', () => {
|
|
248
|
+
expect(${aggregateNaming.variableName}).toBeDefined()
|
|
249
|
+
})
|
|
250
|
+
})
|
|
251
|
+
`);
|
|
219
252
|
if (withRepository) {
|
|
220
253
|
aggregatesFolder.createFile(`${aggregateNaming.fileName}-repository.ts`, `export abstract class ${aggregateNaming.ClassName}Repository { }`);
|
|
221
254
|
barrelFile.addLine(`export * from './${aggregateNaming.fileName}-repository'`);
|
|
255
|
+
if (scaffoldUnitTests) aggregatesFolder.createFile(`${aggregateNaming.fileName}-repository.spec.ts`, `
|
|
256
|
+
import { describe, test, expect, beforeEach } from '${ConfigFile.Instance.data.testingLibrary}'
|
|
257
|
+
import { wire${aggregateNaming.ClassName}Repository } from '../../../wiring/repositories/wire-${aggregateNaming.fileName}-repository'
|
|
258
|
+
import type { ${aggregateNaming.ClassName}Repository } from './${aggregateNaming.fileName}-repository'
|
|
259
|
+
|
|
260
|
+
let ${aggregateNaming.variableName}Repository: ${aggregateNaming.ClassName}Repository
|
|
261
|
+
|
|
262
|
+
beforeEach(() => {
|
|
263
|
+
${aggregateNaming.variableName}Repository = wire${aggregateNaming.ClassName}Repository()
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
describe('${aggregateNaming.withSpaces} repository', () => {
|
|
267
|
+
test('can be wired', () => {
|
|
268
|
+
expect(${aggregateNaming.variableName}Repository).toBeDefined()
|
|
269
|
+
})
|
|
270
|
+
})
|
|
271
|
+
`.trim());
|
|
222
272
|
const infrastructureImplementationType = await input({
|
|
223
273
|
message: 'Repository infrastructure implementation type:',
|
|
224
274
|
default: 'prisma'
|
|
@@ -865,6 +915,23 @@ export const wire${naming.ClassName}UseCase = wireClass(
|
|
|
865
915
|
|
|
866
916
|
`.trim());
|
|
867
917
|
};
|
|
918
|
+
const scaffoldReactPage = async (presentationReactFolder)=>{
|
|
919
|
+
const name = await input({
|
|
920
|
+
message: 'Provide name:'
|
|
921
|
+
});
|
|
922
|
+
const { ClassName, fileName } = new UnknownFormatNaming(name);
|
|
923
|
+
presentationReactFolder.subitem([
|
|
924
|
+
'pages'
|
|
925
|
+
]).createFile(`${fileName}-page.tsx`, `
|
|
926
|
+
import { type FC } from 'react'
|
|
927
|
+
|
|
928
|
+
export type ${ClassName}PageProps = {}
|
|
929
|
+
|
|
930
|
+
export const ${ClassName}Page: FC<${ClassName}PageProps> = (props) => {
|
|
931
|
+
return <></>
|
|
932
|
+
}
|
|
933
|
+
`.trim());
|
|
934
|
+
};
|
|
868
935
|
const scaffoldReactWidget = async (presentationReactFolder)=>{
|
|
869
936
|
const widgetName = await input({
|
|
870
937
|
message: 'Name: '
|
|
@@ -1002,19 +1069,23 @@ const main = async ()=>{
|
|
|
1002
1069
|
switch(action){
|
|
1003
1070
|
case 'Scaffold React module':
|
|
1004
1071
|
{
|
|
1072
|
+
const reactFolder = new Folder(rootPath).subitem([
|
|
1073
|
+
ConfigFile.Instance.data.rootFolder,
|
|
1074
|
+
'presentation',
|
|
1075
|
+
'react'
|
|
1076
|
+
]);
|
|
1005
1077
|
const action = await prompts_select({
|
|
1006
1078
|
message: 'Module: ',
|
|
1007
1079
|
choices: [
|
|
1008
|
-
'New widget'
|
|
1080
|
+
'New widget',
|
|
1081
|
+
'New page'
|
|
1009
1082
|
]
|
|
1010
1083
|
});
|
|
1011
1084
|
switch(action){
|
|
1012
1085
|
case 'New widget':
|
|
1013
|
-
return void await scaffoldReactWidget(
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
'react'
|
|
1017
|
-
]));
|
|
1086
|
+
return void await scaffoldReactWidget(reactFolder);
|
|
1087
|
+
case 'New page':
|
|
1088
|
+
return void await scaffoldReactPage(reactFolder);
|
|
1018
1089
|
default:
|
|
1019
1090
|
return;
|
|
1020
1091
|
}
|