@solid-stack/mason 1.0.11

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 (111) hide show
  1. package/LICENSE +18 -0
  2. package/README.md +238 -0
  3. package/dist/bin.cjs +3480 -0
  4. package/dist/bin.cjs.map +1 -0
  5. package/dist/bin.d.ts +3 -0
  6. package/dist/bin.d.ts.map +1 -0
  7. package/dist/bin.js +3451 -0
  8. package/dist/bin.js.map +1 -0
  9. package/dist/cli.d.ts +3 -0
  10. package/dist/cli.d.ts.map +1 -0
  11. package/dist/commands/create.d.ts +2 -0
  12. package/dist/commands/create.d.ts.map +1 -0
  13. package/dist/commands/domain.d.ts +2 -0
  14. package/dist/commands/domain.d.ts.map +1 -0
  15. package/dist/commands/feature.d.ts +2 -0
  16. package/dist/commands/feature.d.ts.map +1 -0
  17. package/dist/commands/httpHandler.d.ts +2 -0
  18. package/dist/commands/httpHandler.d.ts.map +1 -0
  19. package/dist/commands/import.d.ts +10 -0
  20. package/dist/commands/import.d.ts.map +1 -0
  21. package/dist/commands/infrastructure.d.ts +2 -0
  22. package/dist/commands/infrastructure.d.ts.map +1 -0
  23. package/dist/commands/injectable.d.ts +2 -0
  24. package/dist/commands/injectable.d.ts.map +1 -0
  25. package/dist/commands/interface.d.ts +2 -0
  26. package/dist/commands/interface.d.ts.map +1 -0
  27. package/dist/commands/menu.d.ts +2 -0
  28. package/dist/commands/menu.d.ts.map +1 -0
  29. package/dist/commands/usecase.d.ts +2 -0
  30. package/dist/commands/usecase.d.ts.map +1 -0
  31. package/dist/core/domainGenerator.d.ts +4 -0
  32. package/dist/core/domainGenerator.d.ts.map +1 -0
  33. package/dist/core/featureGenerator.d.ts +3 -0
  34. package/dist/core/featureGenerator.d.ts.map +1 -0
  35. package/dist/core/httpHandlerGenerator.d.ts +8 -0
  36. package/dist/core/httpHandlerGenerator.d.ts.map +1 -0
  37. package/dist/core/infraGenerator.d.ts +60 -0
  38. package/dist/core/infraGenerator.d.ts.map +1 -0
  39. package/dist/core/injectableGenerator.d.ts +4 -0
  40. package/dist/core/injectableGenerator.d.ts.map +1 -0
  41. package/dist/core/interfaceGenerator.d.ts +4 -0
  42. package/dist/core/interfaceGenerator.d.ts.map +1 -0
  43. package/dist/core/providerManager.d.ts +16 -0
  44. package/dist/core/providerManager.d.ts.map +1 -0
  45. package/dist/core/useCaseGenerator.d.ts +5 -0
  46. package/dist/core/useCaseGenerator.d.ts.map +1 -0
  47. package/dist/index.cjs +3545 -0
  48. package/dist/index.cjs.map +1 -0
  49. package/dist/index.d.ts +19 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +3444 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/templates/domain/class.hbs +17 -0
  54. package/dist/templates/domain/interface.hbs +5 -0
  55. package/dist/templates/domain/valueObject.hbs +15 -0
  56. package/dist/templates/domain.template.d.ts +4 -0
  57. package/dist/templates/domain.template.d.ts.map +1 -0
  58. package/dist/templates/engine.d.ts +20 -0
  59. package/dist/templates/engine.d.ts.map +1 -0
  60. package/dist/templates/express/index.hbs +1 -0
  61. package/dist/templates/expressIndex.template.d.ts +2 -0
  62. package/dist/templates/expressIndex.template.d.ts.map +1 -0
  63. package/dist/templates/httpHandler/handler.hbs +71 -0
  64. package/dist/templates/httpHandler.template.d.ts +2 -0
  65. package/dist/templates/httpHandler.template.d.ts.map +1 -0
  66. package/dist/templates/index.d.ts +10 -0
  67. package/dist/templates/index.d.ts.map +1 -0
  68. package/dist/templates/infra/concrete.hbs +29 -0
  69. package/dist/templates/infra/stub.hbs +103 -0
  70. package/dist/templates/infra.template.d.ts +3 -0
  71. package/dist/templates/infra.template.d.ts.map +1 -0
  72. package/dist/templates/injectable/injectable.hbs +32 -0
  73. package/dist/templates/injectable/interface.hbs +3 -0
  74. package/dist/templates/injectable.template.d.ts +3 -0
  75. package/dist/templates/injectable.template.d.ts.map +1 -0
  76. package/dist/templates/interface/interface.hbs +19 -0
  77. package/dist/templates/interface.template.d.ts +2 -0
  78. package/dist/templates/interface.template.d.ts.map +1 -0
  79. package/dist/templates/provider/provider.hbs +13 -0
  80. package/dist/templates/provider.template.d.ts +2 -0
  81. package/dist/templates/provider.template.d.ts.map +1 -0
  82. package/dist/templates/useCase/useCase.hbs +57 -0
  83. package/dist/templates/useCase/useCaseTest.hbs +24 -0
  84. package/dist/templates/useCase.template.d.ts +3 -0
  85. package/dist/templates/useCase.template.d.ts.map +1 -0
  86. package/dist/types/index.d.ts +129 -0
  87. package/dist/types/index.d.ts.map +1 -0
  88. package/dist/utils/fileOperations.d.ts +8 -0
  89. package/dist/utils/fileOperations.d.ts.map +1 -0
  90. package/dist/utils/formatting.d.ts +43 -0
  91. package/dist/utils/formatting.d.ts.map +1 -0
  92. package/dist/utils/project.d.ts +37 -0
  93. package/dist/utils/project.d.ts.map +1 -0
  94. package/dist/utils/prompts.d.ts +14 -0
  95. package/dist/utils/prompts.d.ts.map +1 -0
  96. package/dist/utils/registry.d.ts +61 -0
  97. package/dist/utils/registry.d.ts.map +1 -0
  98. package/package.json +84 -0
  99. package/templates/domain/class.hbs +17 -0
  100. package/templates/domain/interface.hbs +5 -0
  101. package/templates/domain/valueObject.hbs +15 -0
  102. package/templates/express/index.hbs +1 -0
  103. package/templates/httpHandler/handler.hbs +71 -0
  104. package/templates/infra/concrete.hbs +29 -0
  105. package/templates/infra/stub.hbs +103 -0
  106. package/templates/injectable/injectable.hbs +32 -0
  107. package/templates/injectable/interface.hbs +3 -0
  108. package/templates/interface/interface.hbs +19 -0
  109. package/templates/provider/provider.hbs +13 -0
  110. package/templates/useCase/useCase.hbs +57 -0
  111. package/templates/useCase/useCaseTest.hbs +24 -0
@@ -0,0 +1,8 @@
1
+ import type { GeneratedFile } from "../types/index.js";
2
+ export declare function writeFileSafely(absolutePath: string, content: string, options?: {
3
+ projectRoot?: string | undefined;
4
+ overwrite?: boolean | undefined;
5
+ dryRun?: boolean | undefined;
6
+ }): GeneratedFile;
7
+ export declare function printGeneratedFiles(files: GeneratedFile[], isDryRun?: boolean): void;
8
+ //# sourceMappingURL=fileOperations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileOperations.d.ts","sourceRoot":"","sources":["../../src/utils/fileOperations.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,wBAAgB,eAAe,CAC7B,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;IACP,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACzB,GACL,aAAa,CAuCf;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,QAAQ,GAAE,OAAe,GAAG,IAAI,CAiB3F"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Convert string to PascalCase
3
+ * e.g. "users" -> "Users", "user-profile" -> "UserProfile", "user_service" -> "UserService"
4
+ */
5
+ export declare function toPascalCase(str: string): string;
6
+ /**
7
+ * Convert string to camelCase
8
+ * e.g. "UserProfile" -> "userProfile", "IUserRepository" -> "userRepository"
9
+ */
10
+ export declare function toCamelCase(str: string): string;
11
+ /**
12
+ * Convert string to kebab-case
13
+ * e.g. "UserProfile" -> "user-profile", "user_profile" -> "user-profile"
14
+ */
15
+ export declare function toKebabCase(str: string): string;
16
+ /**
17
+ * Naive singularization for common developer nouns
18
+ */
19
+ export declare function toSingular(str: string): string;
20
+ /**
21
+ * Naive pluralization for common developer nouns
22
+ */
23
+ export declare function toPlural(str: string): string;
24
+ /**
25
+ * Ensure interface starts with 'I'
26
+ * e.g. "UserRepository" -> "IUserRepository", "IUserRepository" -> "IUserRepository"
27
+ */
28
+ export declare function ensureInterfacePrefix(name: string): string;
29
+ /**
30
+ * Remove interface 'I' prefix
31
+ * e.g. "IUserRepository" -> "UserRepository", "UserRepository" -> "UserRepository"
32
+ */
33
+ export declare function removeInterfacePrefix(name: string): string;
34
+ /**
35
+ * Generate stub class name for an interface
36
+ * e.g. "IUserRepository" -> "StubUserRepository", "UserRepository" -> "StubUserRepository"
37
+ */
38
+ export declare function toStubName(ifaceName: string): string;
39
+ /**
40
+ * Validate non-empty valid JS identifier
41
+ */
42
+ export declare function isValidIdentifier(str: string): boolean;
43
+ //# sourceMappingURL=formatting.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatting.d.ts","sourceRoot":"","sources":["../../src/utils/formatting.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMhD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAS/C;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAM/C;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAa9C;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAU5C;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK1D;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAMpD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEtD"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Locate project root by finding the nearest package.json
3
+ */
4
+ export declare function findProjectRoot(startDir?: string): string;
5
+ /**
6
+ * Resolve features directory
7
+ */
8
+ export declare function resolveFeaturesDir(projectRoot: string): string;
9
+ /**
10
+ * List existing feature names in project
11
+ */
12
+ export declare function listExistingFeatures(projectRoot: string): string[];
13
+ /**
14
+ * List domain interfaces in a feature (or all features)
15
+ */
16
+ export declare function listDomainInterfaces(projectRoot: string, featureName?: string): Array<{
17
+ name: string;
18
+ fullPath: string;
19
+ feature: string;
20
+ }>;
21
+ /**
22
+ * List domain entities in a feature (or all features)
23
+ */
24
+ export declare function listDomainEntities(projectRoot: string, featureName?: string): Array<{
25
+ name: string;
26
+ fullPath: string;
27
+ feature: string;
28
+ }>;
29
+ /**
30
+ * List use cases in a feature (or all features)
31
+ */
32
+ export declare function listUseCases(projectRoot: string, featureName?: string): Array<{
33
+ name: string;
34
+ fullPath: string;
35
+ feature: string;
36
+ }>;
37
+ //# sourceMappingURL=project.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/utils/project.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,CAYxE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAalE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,MAAM,GACnB,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CA0C5D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,MAAM,GACnB,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CA4B5D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,MAAM,GACnB,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CA0B5D"}
@@ -0,0 +1,14 @@
1
+ import type { PropertyDef } from "../types/index.js";
2
+ export declare class PromptCancelledError extends Error {
3
+ constructor(message?: string);
4
+ }
5
+ export declare function handleCancel<T>(result: T): Exclude<T, symbol>;
6
+ export declare function printBanner(): void;
7
+ /**
8
+ * Interactive prompt to collect properties (name & type)
9
+ */
10
+ export declare function promptProperties(options?: {
11
+ message?: string | undefined;
12
+ defaults?: PropertyDef[] | undefined;
13
+ }): Promise<PropertyDef[]>;
14
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/utils/prompts.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,OAAO,SAAyB,EAG3C;CACF;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,CAM7D;AAED,wBAAgB,WAAW,IAAI,IAAI,CAGlC;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,GAAE;IACP,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,QAAQ,CAAC,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;CACjC,GACL,OAAO,CAAC,WAAW,EAAE,CAAC,CA8ExB"}
@@ -0,0 +1,61 @@
1
+ export interface RegistryIndexEntry {
2
+ name: string;
3
+ description: string;
4
+ version?: string;
5
+ [key: string]: any;
6
+ }
7
+ export interface RegistryIndex {
8
+ shared: RegistryIndexEntry[];
9
+ features: RegistryIndexEntry[];
10
+ }
11
+ export interface ModuleManifest {
12
+ name: string;
13
+ type: "shared" | "feature";
14
+ description: string;
15
+ version: string;
16
+ dependencies: {
17
+ npm?: string[];
18
+ shared?: string[];
19
+ features?: string[];
20
+ };
21
+ files: string[];
22
+ [key: string]: any;
23
+ }
24
+ export declare const DEFAULT_REGISTRY_BASE = "https://raw.githubusercontent.com/solid-stack-digital/mason-registry/main";
25
+ /**
26
+ * Resolves the active registry base URL or local directory path.
27
+ */
28
+ export declare function getRegistryBase(projectRoot?: string, override?: string): string;
29
+ /**
30
+ * Fetch raw file contents from a remote URL or local file directory.
31
+ */
32
+ export declare function fetchRegistryFile(registryBase: string, relPath: string): Promise<string>;
33
+ /**
34
+ * Fetches and parses master index.json from the registry.
35
+ */
36
+ export declare function fetchRegistryIndex(registryBase: string): Promise<RegistryIndex>;
37
+ /**
38
+ * Fetches the registry.json manifest for a given shared or feature module.
39
+ */
40
+ export declare function fetchModuleManifest(registryBase: string, type: "shared" | "feature", name: string): Promise<ModuleManifest>;
41
+ /**
42
+ * Computes Levenshtein distance between two strings.
43
+ */
44
+ export declare function levenshteinDistance(a: string, b: string): number;
45
+ /**
46
+ * Finds closest matching candidate string for typo correction suggestions.
47
+ */
48
+ export declare function findClosestMatch(target: string, candidates: string[]): string | null;
49
+ /**
50
+ * Detects the package manager used in the target project.
51
+ */
52
+ export declare function detectPackageManager(projectRoot: string): "pnpm" | "yarn" | "bun" | "npm";
53
+ /**
54
+ * Checks which npm packages from the requested list are missing in package.json.
55
+ */
56
+ export declare function getMissingNpmPackages(projectRoot: string, requiredPackages: string[]): string[];
57
+ /**
58
+ * Installs missing npm packages using the detected package manager.
59
+ */
60
+ export declare function installNpmPackages(projectRoot: string, packages: string[], pm?: "pnpm" | "yarn" | "bun" | "npm"): void;
61
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/utils/registry.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7B,QAAQ,EAAE,kBAAkB,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE;QACZ,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;IACF,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,eAAO,MAAM,qBAAqB,8EAC2C,CAAC;AAE9E;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAiC/E;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAwB9F;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAGrF;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,QAAQ,GAAG,SAAS,EAC1B,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,cAAc,CAAC,CAKzB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CA2BhE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CA2BpF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,CAKzF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CA0B/F;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAAE,EAClB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GACnC,IAAI,CA0BN"}
package/package.json ADDED
@@ -0,0 +1,84 @@
1
+ {
2
+ "name": "@solid-stack/mason",
3
+ "version": "1.0.11",
4
+ "description": "An interactive, type-safe CLI generator for scaffolding Solid Stack Clean Architecture features, usecases, domain entities, infrastructure, interfaces, httpHandlers, and injectables.",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "bin": {
10
+ "mason": "./dist/bin.js",
11
+ "solid-mason": "./dist/bin.js"
12
+ },
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.js",
17
+ "require": "./dist/index.cjs",
18
+ "default": "./dist/index.js"
19
+ },
20
+ "./package.json": "./package.json"
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "templates"
25
+ ],
26
+ "keywords": [
27
+ "solid-stack",
28
+ "mason",
29
+ "cli",
30
+ "scaffolder",
31
+ "generator",
32
+ "clean-architecture",
33
+ "agnos",
34
+ "typescript",
35
+ "esm",
36
+ "cjs"
37
+ ],
38
+ "author": "Solid Stack Digital",
39
+ "license": "UNLICENSED",
40
+ "publishConfig": {
41
+ "access": "public"
42
+ },
43
+ "engines": {
44
+ "node": ">=18.0.0"
45
+ },
46
+ "devEngines": {
47
+ "packageManager": {
48
+ "name": "pnpm",
49
+ "version": "11.18.0",
50
+ "onFail": "download"
51
+ }
52
+ },
53
+ "repository": {
54
+ "type": "git",
55
+ "url": "git+https://github.com/solid-stack-digital/mason.git"
56
+ },
57
+ "homepage": "https://github.com/solid-stack-digital/mason#readme",
58
+ "peerDependencies": {
59
+ "@solid-stack/di": ">=1.0.0"
60
+ },
61
+ "dependencies": {
62
+ "@clack/prompts": "^1.7.0",
63
+ "@solid-stack/di": "^1.0.4",
64
+ "cac": "^7.0.0",
65
+ "handlebars": "^4.7.9",
66
+ "picocolors": "^1.1.1"
67
+ },
68
+ "devDependencies": {
69
+ "@types/node": "^26.1.2",
70
+ "tsup": "^8.5.1",
71
+ "tsx": "^4.23.1",
72
+ "typescript": "^7.0.2",
73
+ "vitest": "^4.1.10"
74
+ },
75
+ "scripts": {
76
+ "build": "tsup && tsc --project tsconfig.build.json --emitDeclarationOnly --outDir dist",
77
+ "dev": "tsup --watch",
78
+ "test": "vitest run",
79
+ "test:watch": "vitest",
80
+ "test:coverage": "vitest run --coverage",
81
+ "typecheck": "tsc --noEmit",
82
+ "check": "pnpm typecheck && pnpm test && pnpm build"
83
+ }
84
+ }
@@ -0,0 +1,17 @@
1
+ export interface {{name}}Props {
2
+ {{#each properties}}
3
+ {{name}}{{#if optional}}?{{/if}}: {{type}};
4
+ {{/each}}
5
+ }
6
+
7
+ export class {{name}} {
8
+ {{#each properties}}
9
+ public {{name}}{{#if optional}}?{{/if}}: {{type}};
10
+ {{/each}}
11
+
12
+ constructor(props: {{name}}Props) {
13
+ {{#each properties}}
14
+ this.{{name}} = props.{{name}};
15
+ {{/each}}
16
+ }
17
+ }
@@ -0,0 +1,5 @@
1
+ export interface {{name}} {
2
+ {{#each properties}}
3
+ {{name}}{{#if optional}}?{{/if}}: {{type}};
4
+ {{/each}}
5
+ }
@@ -0,0 +1,15 @@
1
+ export class {{name}} {
2
+ private constructor(public readonly {{valueProp.name}}: {{valueProp.type}}) {}
3
+
4
+ public static create({{valueProp.name}}: {{valueProp.type}}): {{name}} {
5
+ if ({{valueProp.name}} === undefined || {{valueProp.name}} === null) {
6
+ throw new Error("Value is required for {{name}}");
7
+ }
8
+ return new {{name}}({{valueProp.name}});
9
+ }
10
+
11
+ public equals(other?: {{name}}): boolean {
12
+ if (!other) return false;
13
+ return this.{{valueProp.name}} === other.{{valueProp.name}};
14
+ }
15
+ }
@@ -0,0 +1 @@
1
+ export const path = "{{routePath}}";
@@ -0,0 +1,71 @@
1
+ import { ExpressRoute } from "@solid-stack/agnos-express";
2
+ import { MakeInjectable, type DepsType } from "@solid-stack/di";
3
+ import type { Request, Response } from "express";
4
+ {{#if includeValidation}}
5
+ import { z } from "zod";
6
+ {{/if}}
7
+ {{#if ucName}}
8
+ import { {{ucName}} } from "../../useCases/{{ucName}}.js";
9
+ {{/if}}
10
+
11
+ export type HttpResponseStatus = "info" | "success" | "redirect" | "fail" | "error";
12
+
13
+ export interface HttpResponse<T = object> {
14
+ status: HttpResponseStatus;
15
+ message: string;
16
+ data?: T;
17
+ }
18
+
19
+ {{#if includeValidation}}
20
+ const {{schemaName}} = z.object({
21
+ {{#if hasValidationFields}}
22
+ {{#each validationFields}}
23
+ {{name}}: {{{zodType}}},
24
+ {{/each}}
25
+ {{else}}
26
+ // TODO: define schema properties
27
+ example: z.string().optional(),
28
+ {{/if}}
29
+ });
30
+
31
+ {{/if}}
32
+ @MakeInjectable
33
+ export default class {{className}} extends ExpressRoute {
34
+ public static deps = {
35
+ {{#if ucName}}
36
+ {{ucDepKey}}: {{ucName}},
37
+ {{/if}}
38
+ };
39
+
40
+ constructor(public deps: DepsType<typeof {{className}}.deps>) {
41
+ super();
42
+ }
43
+
44
+ public method = "{{method}}" as const;
45
+ public path = "{{routeSubPath}}";
46
+ public handler = async (req: Request, res: Response) => {
47
+ {{#if includeValidation}}
48
+ const parsed = {{schemaName}}.safeParse(req.{{validationSource}});
49
+ if (!parsed.success) {
50
+ return res.status(400).json({
51
+ status: "error",
52
+ message: "Validation failed",
53
+ data: parsed.error.format(),
54
+ });
55
+ }
56
+ {{/if}}
57
+ {{#if ucName}}
58
+ const result = await this.deps.{{ucDepKey}}.execute({{callArg}});
59
+ return res.status({{statusCode}}).json({
60
+ status: "success",
61
+ message: "{{successMessage}}",
62
+ data: result,
63
+ });
64
+ {{else}}
65
+ return res.status(200).json({
66
+ status: "success",
67
+ message: "{{successMessage}}",
68
+ });
69
+ {{/if}}
70
+ };
71
+ }
@@ -0,0 +1,29 @@
1
+ import { MakeInjectable, type DepsType } from "@solid-stack/di";
2
+ {{#if ifaceName}}
3
+ import { {{ifaceName}} } from "{{ifaceImportPath}}";
4
+ {{/if}}
5
+ {{#each domainImports}}
6
+ import {{#if isTypeOnly}}type {{/if}}{ {{names}} } from "{{from}}";
7
+ {{/each}}
8
+
9
+ @MakeInjectable
10
+ export class {{className}}{{#if ifaceName}} implements {{ifaceName}}{{/if}} {
11
+ public static deps = {
12
+ {{#each dependencies}}
13
+ {{key}}: {{name}},
14
+ {{/each}}
15
+ };
16
+
17
+ constructor(public deps: DepsType<typeof {{className}}.deps>) {}
18
+ {{#if hasMethods}}
19
+ {{#each methods}}
20
+
21
+ {{#if isAsync}}async {{/if}}{{name}}{{{typeParams}}}({{{params}}}): {{{returnType}}} {
22
+ throw new Error("not implemented");
23
+ }
24
+ {{/each}}
25
+ {{else}}
26
+
27
+ // Implement your infrastructure methods here
28
+ {{/if}}
29
+ }
@@ -0,0 +1,103 @@
1
+ import { MakeInjectable, type DepsType } from "@solid-stack/di";
2
+ import { {{ifaceName}} } from "{{ifaceImportPath}}";
3
+ {{#if baseEntity}}
4
+ import type { {{baseEntity}} } from "{{entityImportPath}}";
5
+ {{/if}}
6
+ {{#each domainImports}}
7
+ import {{#if isTypeOnly}}type {{/if}}{ {{names}} } from "{{from}}";
8
+ {{/each}}
9
+
10
+ @MakeInjectable
11
+ export class {{stubClassName}} implements {{ifaceName}} {
12
+ public static deps = {};
13
+ {{#if baseEntity}}
14
+
15
+ private {{entitiesVar}}: Map<string, {{baseEntity}}> = new Map();
16
+ private errorToThrow: Error | null = null;
17
+
18
+ constructor(public deps: DepsType<typeof {{stubClassName}}.deps>) {}
19
+
20
+ // --- Test Helpers ---
21
+ public clear(): void {
22
+ this.{{entitiesVar}}.clear();
23
+ this.errorToThrow = null;
24
+ }
25
+
26
+ public add{{baseEntity}}({{entityVar}}: {{baseEntity}}): void {
27
+ this.{{entitiesVar}}.set({{entityVar}}.id, { ...{{entityVar}} });
28
+ }
29
+
30
+ public get{{baseEntity}}s(): {{baseEntity}}[] {
31
+ return Array.from(this.{{entitiesVar}}.values()).map((e) => ({ ...e }));
32
+ }
33
+
34
+ public setError(error: Error | null): void {
35
+ this.errorToThrow = error;
36
+ }
37
+
38
+ // --- {{ifaceName}} Methods ---
39
+ async Get{{baseEntity}}ById(input: { {{idKey}}: string }): Promise<{ {{entityVar}}: {{baseEntity}} }> {
40
+ if (this.errorToThrow) throw this.errorToThrow;
41
+ const found = this.{{entitiesVar}}.get(input.{{idKey}});
42
+ if (!found) throw new Error("{{baseEntity}} with ID " + input.{{idKey}} + " not found");
43
+ return { {{entityVar}}: { ...found } };
44
+ }
45
+
46
+ async List{{baseEntity}}s(input?: { page?: number | undefined; limit?: number | undefined }): Promise<{ {{entitiesVar}}: {{baseEntity}}[]; total?: number | undefined; page?: number | undefined; limit?: number | undefined }> {
47
+ if (this.errorToThrow) throw this.errorToThrow;
48
+ let all = this.get{{baseEntity}}s();
49
+ const total = all.length;
50
+ if (input?.page && input?.limit) {
51
+ const start = (input.page - 1) * input.limit;
52
+ all = all.slice(start, start + input.limit);
53
+ return { {{entitiesVar}}: all, total, page: input.page, limit: input.limit };
54
+ }
55
+ return { {{entitiesVar}}: all, total };
56
+ }
57
+
58
+ async Create{{baseEntity}}(input: { {{entityVar}}: {{baseEntity}} }): Promise<{ {{entityVar}}: {{baseEntity}} }> {
59
+ if (this.errorToThrow) throw this.errorToThrow;
60
+ const entity = { ...input.{{entityVar}} };
61
+ this.{{entitiesVar}}.set(entity.id, entity);
62
+ return { {{entityVar}}: { ...entity } };
63
+ }
64
+
65
+ async Update{{baseEntity}}(input: { {{entityVar}}: {{baseEntity}} }): Promise<{ {{entityVar}}: {{baseEntity}} }> {
66
+ if (this.errorToThrow) throw this.errorToThrow;
67
+ if (!this.{{entitiesVar}}.has(input.{{entityVar}}.id)) {
68
+ throw new Error("{{baseEntity}} with ID " + input.{{entityVar}}.id + " not found");
69
+ }
70
+ const entity = { ...input.{{entityVar}} };
71
+ this.{{entitiesVar}}.set(entity.id, entity);
72
+ return { {{entityVar}}: { ...entity } };
73
+ }
74
+
75
+ async Delete{{baseEntity}}(input: { {{idKey}}: string }): Promise<{ success: boolean }> {
76
+ if (this.errorToThrow) throw this.errorToThrow;
77
+ this.{{entitiesVar}}.delete(input.{{idKey}});
78
+ return { success: true };
79
+ }
80
+ {{#each extraMethods}}
81
+
82
+ {{#if isAsync}}async {{/if}}{{name}}{{{typeParams}}}({{{params}}}): {{{returnType}}} {
83
+ throw new Error("not implemented");
84
+ }
85
+ {{/each}}
86
+ {{else}}
87
+
88
+ constructor(public deps: DepsType<typeof {{stubClassName}}.deps>) {}
89
+ {{#if hasMethods}}
90
+ {{#each methods}}
91
+
92
+ {{#if isAsync}}async {{/if}}{{name}}{{{typeParams}}}({{{params}}}): {{{returnType}}} {
93
+ throw new Error("not implemented");
94
+ }
95
+ {{/each}}
96
+ {{else}}
97
+
98
+ async execute(input?: unknown): Promise<unknown> {
99
+ throw new Error("{{stubClassName}}.execute not implemented");
100
+ }
101
+ {{/if}}
102
+ {{/if}}
103
+ }
@@ -0,0 +1,32 @@
1
+ import { MakeInjectable, type DepsType } from "@solid-stack/di";
2
+ {{#if implementsInterface}}
3
+ import { {{implementsInterface}} } from "./{{implementsInterface}}.js";
4
+ {{/if}}
5
+
6
+ @MakeInjectable
7
+ export class {{className}}{{#if implementsInterface}} implements {{implementsInterface}}{{/if}} {
8
+ public static deps = {
9
+ {{#each dependencies}}
10
+ {{key}}: {{name}},
11
+ {{/each}}
12
+ };
13
+
14
+ {{#if hasDependencies}}
15
+ constructor(public deps: DepsType<typeof {{className}}.deps>) {}
16
+ {{else}}
17
+ constructor() {}
18
+ {{/if}}
19
+
20
+ {{#if hasMethods}}
21
+ {{#each methods}}
22
+ public {{#if isAsync}}async {{/if}}{{name}}({{{params}}}): {{{returnType}}} {
23
+ // TODO: implement method logic
24
+ }
25
+
26
+ {{/each}}
27
+ {{else}}
28
+ public execute(): void {
29
+ // TODO: implement logic
30
+ }
31
+ {{/if}}
32
+ }
@@ -0,0 +1,3 @@
1
+ export abstract class {{ifaceName}} {
2
+ abstract execute(): void;
3
+ }
@@ -0,0 +1,19 @@
1
+ {{#if domainImport}}
2
+ import type { {{domainImport}} } from "./{{domainImport}}.js";
3
+
4
+ {{/if}}
5
+ export {{#if isAbstractClass}}abstract class{{else}}interface{{/if}} {{ifaceName}} {
6
+ {{#if isCrud}}
7
+ {{methodPrefix}}Get{{baseEntity}}ById(input: { {{idKey}}: string }): Promise<{ {{entityKey}}: {{baseEntity}} }>;
8
+ {{methodPrefix}}List{{baseEntity}}s(input?: { page?: number | undefined; limit?: number | undefined }): Promise<{ {{listKey}}: {{baseEntity}}[]; total?: number | undefined; page?: number | undefined; limit?: number | undefined }>;
9
+ {{methodPrefix}}Create{{baseEntity}}(input: { {{entityKey}}: {{baseEntity}} }): Promise<{ {{entityKey}}: {{baseEntity}} }>;
10
+ {{methodPrefix}}Update{{baseEntity}}(input: { {{entityKey}}: {{baseEntity}} }): Promise<{ {{entityKey}}: {{baseEntity}} }>;
11
+ {{methodPrefix}}Delete{{baseEntity}}(input: { {{idKey}}: string }): Promise<{ success: boolean }>;
12
+ {{else if isCustom}}
13
+ {{#each customMethods}}
14
+ {{../methodPrefix}}{{name}}({{#if params}}input: { {{params}} }{{/if}}): {{returnType}};
15
+ {{/each}}
16
+ {{else}}
17
+ {{methodPrefix}}execute(input?: unknown): Promise<unknown>;
18
+ {{/if}}
19
+ }
@@ -0,0 +1,13 @@
1
+ import type { Container, DIModule } from "@solid-stack/di";
2
+ {{#each bindings}}
3
+ import { {{ifaceName}} } from "{{ifaceImportPath}}";
4
+ import { {{implName}} } from "{{implImportPath}}";
5
+ {{/each}}
6
+
7
+ export const {{providerModuleName}}: DIModule = (c: Container) => {
8
+ {{#each bindings}}
9
+ c.provide({{ifaceName}}, {{implName}});
10
+ {{/each}}
11
+ };
12
+
13
+ export default {{providerModuleName}};
@@ -0,0 +1,57 @@
1
+ import { MakeInjectable, type DepsType } from "@solid-stack/di";
2
+ {{#each dependencyImports}}
3
+ import { {{name}} } from "{{from}}";
4
+ {{/each}}
5
+ {{#each domainImports}}
6
+ import type { {{this}} } from "../domain/{{this}}.js";
7
+ {{/each}}
8
+
9
+ {{#if hasInputProps}}
10
+ export type {{inputTypeName}} = {
11
+ {{#each inputProperties}}
12
+ {{name}}{{#if optional}}?{{/if}}: {{type}};
13
+ {{/each}}
14
+ };
15
+ {{else}}
16
+ export type {{inputTypeName}} = Record<string, never>;
17
+ {{/if}}
18
+
19
+ {{#if hasOutputProps}}
20
+ export type {{outputTypeName}} = {
21
+ {{#each outputProperties}}
22
+ {{name}}{{#if optional}}?{{/if}}: {{type}};
23
+ {{/each}}
24
+ };
25
+ {{else}}
26
+ export type {{outputTypeName}} = {
27
+ success: boolean;
28
+ };
29
+ {{/if}}
30
+
31
+ @MakeInjectable
32
+ export class {{ucName}} {
33
+ public static deps = {
34
+ {{#each dependencies}}
35
+ {{key}}: {{name}},
36
+ {{/each}}
37
+ };
38
+
39
+ {{#if hasDependencies}}
40
+ constructor(public deps: DepsType<typeof {{ucName}}.deps>) {}
41
+ {{else}}
42
+ constructor() {}
43
+ {{/if}}
44
+
45
+ async execute({{paramStr}}): Promise<{{outputTypeName}}> {
46
+ {{#if callWired}}
47
+ {{{callWired}}}
48
+ {{else}}
49
+ // TODO: Implement use case business logic
50
+ {{#if hasOutputProps}}
51
+ throw new Error("{{ucName}} not implemented");
52
+ {{else}}
53
+ return { success: true };
54
+ {{/if}}
55
+ {{/if}}
56
+ }
57
+ }