domain-driver 0.1.0 → 0.3.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/README.md +159 -145
- package/dist/cli.js +208 -0
- package/dist/commands/action.js +118 -0
- package/dist/commands/component.js +18 -19
- package/dist/commands/container.js +10 -31
- package/dist/commands/controller.js +85 -0
- package/dist/commands/feature.js +59 -51
- package/dist/commands/hints.js +28 -0
- package/dist/commands/hook.js +10 -111
- package/dist/commands/repository.js +17 -115
- package/dist/commands/resolve.js +61 -0
- package/dist/commands/schema.js +22 -69
- package/dist/commands/service.js +15 -113
- package/dist/commands/sides.js +34 -0
- package/dist/commands/target.js +32 -0
- package/dist/commands/types.js +9 -17
- package/dist/commands/update.js +148 -0
- package/dist/commands/write.js +66 -0
- package/dist/index.js +8 -122
- package/dist/init/content.js +73 -0
- package/dist/init/init.js +66 -0
- package/dist/init/markers.js +21 -0
- package/dist/postinstall.js +80 -0
- package/dist/stack/detect.js +125 -0
- package/dist/stack/profiles/nest.js +18 -0
- package/dist/stack/profiles/next-frontend.js +28 -0
- package/dist/stack/profiles/next-fullstack.js +44 -0
- package/dist/stack/profiles/node.js +17 -0
- package/dist/stack/profiles/react.js +19 -0
- package/dist/stack/registry.js +63 -0
- package/dist/stack/types.js +24 -0
- package/dist/templates/actions.js +68 -0
- package/dist/templates/backend/server-repository.js +22 -0
- package/dist/templates/context.js +52 -0
- package/dist/templates/controllers/express.js +60 -0
- package/dist/templates/controllers/fastify.js +54 -0
- package/dist/templates/controllers/generic.js +30 -0
- package/dist/templates/controllers/hono.js +52 -0
- package/dist/templates/controllers/nest.js +63 -0
- package/dist/templates/controllers/next-action-route.js +40 -0
- package/dist/templates/controllers/next-route.js +62 -0
- package/dist/templates/controllers/node.js +46 -0
- package/dist/templates/controllers/shape.js +28 -0
- package/dist/templates/frontend/client-repository.js +38 -0
- package/dist/templates/frontend/component.js +18 -0
- package/dist/templates/frontend/container.js +28 -0
- package/{src/commands/hook.ts → dist/templates/frontend/hook.js} +28 -41
- package/dist/templates/frontend/page.js +26 -0
- package/dist/templates/nest/dto.js +12 -0
- package/dist/templates/nest/injectable.js +4 -0
- package/dist/templates/nest/module.js +41 -0
- package/dist/templates/service.js +40 -0
- package/dist/templates/shared/schema.js +13 -0
- package/dist/templates/shared/types.js +12 -0
- package/dist/templates/signatures.js +15 -0
- package/dist/update/cache.js +80 -0
- package/dist/update/check.js +47 -0
- package/dist/update/install-mode.js +96 -0
- package/dist/update/package-manager.js +99 -0
- package/dist/update/registry.js +77 -0
- package/dist/update/version.js +70 -0
- package/dist/utils/alias.js +80 -0
- package/dist/utils/fs.js +70 -0
- package/dist/utils/imports.js +61 -0
- package/dist/utils/naming.js +31 -0
- package/dist/utils/paths.js +44 -0
- package/package.json +27 -6
- package/scripts/postinstall.js +7 -0
- package/.github/workflows/publish.yml +0 -28
- package/dist/utils.js +0 -132
- package/src/__tests__/utils.test.ts +0 -128
- package/src/commands/__tests__/feature.test.ts +0 -85
- package/src/commands/__tests__/imports.test.ts +0 -115
- package/src/commands/__tests__/individual.test.ts +0 -137
- package/src/commands/component.ts +0 -33
- package/src/commands/container.ts +0 -42
- package/src/commands/feature.ts +0 -74
- package/src/commands/repository.ts +0 -95
- package/src/commands/schema.ts +0 -47
- package/src/commands/service.ts +0 -93
- package/src/commands/types.ts +0 -25
- package/src/index.ts +0 -126
- package/src/utils.ts +0 -115
- package/tsconfig.json +0 -13
- package/vitest.config.ts +0 -7
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.parseReturns = parseReturns;
|
|
37
|
+
exports.makeAction = makeAction;
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const registry_1 = require("../stack/registry");
|
|
40
|
+
const actions_1 = require("../templates/actions");
|
|
41
|
+
const server_repository_1 = require("../templates/backend/server-repository");
|
|
42
|
+
const nest_1 = require("../templates/controllers/nest");
|
|
43
|
+
const next_action_route_1 = require("../templates/controllers/next-action-route");
|
|
44
|
+
const node_1 = require("../templates/controllers/node");
|
|
45
|
+
const client_repository_1 = require("../templates/frontend/client-repository");
|
|
46
|
+
const dto_1 = require("../templates/nest/dto");
|
|
47
|
+
const service_1 = require("../templates/service");
|
|
48
|
+
const schema_1 = require("../templates/shared/schema");
|
|
49
|
+
const fs_1 = require("../utils/fs");
|
|
50
|
+
const naming_1 = require("../utils/naming");
|
|
51
|
+
const paths_1 = require("../utils/paths");
|
|
52
|
+
const hints_1 = require("./hints");
|
|
53
|
+
const resolve_1 = require("./resolve");
|
|
54
|
+
const write_1 = require("./write");
|
|
55
|
+
function parseReturns(value) {
|
|
56
|
+
if (actions_1.RETURN_KINDS.includes(value))
|
|
57
|
+
return value;
|
|
58
|
+
throw new Error(`Invalid --returns "${value}". Use list, one, or void.`);
|
|
59
|
+
}
|
|
60
|
+
function makeAction(feature, entity, actionName, options) {
|
|
61
|
+
const ctx = (0, resolve_1.requireFeature)(feature);
|
|
62
|
+
const spec = (0, actions_1.customAction)(entity, actionName, options);
|
|
63
|
+
hintMissingTypes(ctx, entity);
|
|
64
|
+
let wroteAny = false;
|
|
65
|
+
if (spec.schema !== null)
|
|
66
|
+
wroteAny = writeInput(ctx, spec) || wroteAny;
|
|
67
|
+
if ((0, registry_1.hasLayer)(ctx.profile, 'serverRepository'))
|
|
68
|
+
wroteAny = writeSide(ctx, spec, entity, 'server') || wroteAny;
|
|
69
|
+
if ((0, registry_1.hasLayer)(ctx.profile, 'controller'))
|
|
70
|
+
wroteAny = writeController(ctx, spec, entity) || wroteAny;
|
|
71
|
+
if ((0, registry_1.hasLayer)(ctx.profile, 'clientRepository'))
|
|
72
|
+
wroteAny = writeSide(ctx, spec, entity, 'client') || wroteAny;
|
|
73
|
+
if (wroteAny)
|
|
74
|
+
console.log(`✅ Action "${spec.name}" scaffolded in "${feature}"`);
|
|
75
|
+
return wroteAny;
|
|
76
|
+
}
|
|
77
|
+
function hintMissingTypes(ctx, entity) {
|
|
78
|
+
const typesFile = path.join(ctx.featureDir, (0, registry_1.layerDir)(ctx.profile, 'types'), `${entity}.types.ts`);
|
|
79
|
+
if ((0, fs_1.fileExists)(typesFile))
|
|
80
|
+
return;
|
|
81
|
+
console.log(`ℹ️ types/${entity}.types.ts not found. Run: domain-driver make:types ${ctx.feature}/${entity}`);
|
|
82
|
+
}
|
|
83
|
+
function writeInput(ctx, spec) {
|
|
84
|
+
const schemaFile = path.join((0, resolve_1.ensureLayerDir)(ctx, 'schema'), `${spec.name}.schema.ts`);
|
|
85
|
+
const wroteSchema = (0, write_1.writeIfAbsent)(schemaFile, () => (0, schema_1.renderSchema)(spec.name, (0, naming_1.lowerFirst)(spec.name)));
|
|
86
|
+
if (!(0, registry_1.hasLayer)(ctx.profile, 'dto'))
|
|
87
|
+
return wroteSchema;
|
|
88
|
+
const dtoFile = path.join((0, resolve_1.ensureLayerDir)(ctx, 'dto'), `${spec.name}.dto.ts`);
|
|
89
|
+
const wroteDto = (0, write_1.writeIfAbsent)(dtoFile, () => (0, dto_1.renderDto)(ctx, spec.name, dtoFile));
|
|
90
|
+
(0, hints_1.hintNestjsZod)(ctx.stack);
|
|
91
|
+
return wroteSchema || wroteDto;
|
|
92
|
+
}
|
|
93
|
+
function writeSide(ctx, spec, entity, side) {
|
|
94
|
+
const repositoryLayer = side === 'client' ? 'clientRepository' : 'serverRepository';
|
|
95
|
+
const serviceLayer = side === 'client' ? 'clientService' : 'serverService';
|
|
96
|
+
const renderRepository = side === 'client' ? client_repository_1.renderClientRepository : server_repository_1.renderServerRepository;
|
|
97
|
+
const repositoryFile = path.join((0, resolve_1.ensureLayerDir)(ctx, repositoryLayer), `${spec.name}.repository.ts`);
|
|
98
|
+
const wroteRepository = (0, write_1.writeIfAbsent)(repositoryFile, () => renderRepository(ctx, spec, entity, repositoryFile));
|
|
99
|
+
const serviceFile = path.join((0, resolve_1.ensureLayerDir)(ctx, serviceLayer), `${spec.name}.service.ts`);
|
|
100
|
+
const wroteService = (0, write_1.writeIfAbsent)(serviceFile, () => (0, service_1.renderService)(ctx, spec, entity, serviceFile, side));
|
|
101
|
+
return wroteRepository || wroteService;
|
|
102
|
+
}
|
|
103
|
+
function writeController(ctx, spec, entity) {
|
|
104
|
+
if (ctx.profile.name === 'next-fullstack') {
|
|
105
|
+
const routeDir = path.join((0, paths_1.apiRouteDir)(ctx.stack, ctx.feature), spec.path.slice(1));
|
|
106
|
+
(0, fs_1.mkdirSafe)(routeDir);
|
|
107
|
+
const routeFile = path.join(routeDir, 'route.ts');
|
|
108
|
+
return (0, write_1.writeIfAbsent)(routeFile, () => (0, next_action_route_1.renderActionRoute)(ctx, spec, routeFile));
|
|
109
|
+
}
|
|
110
|
+
const controllerFile = path.join((0, resolve_1.ensureLayerDir)(ctx, 'controller'), `${spec.name}.controller.ts`);
|
|
111
|
+
const render = ctx.profile.name === 'nest' ? nest_1.renderNestController : node_1.renderNodeController;
|
|
112
|
+
const wroteController = (0, write_1.writeIfAbsent)(controllerFile, () => render(ctx, spec, entity, controllerFile));
|
|
113
|
+
const line = ctx.profile.name === 'node' ? (0, node_1.renderNodeRouteLine)(ctx, spec, entity) : null;
|
|
114
|
+
if (wroteController && line !== null) {
|
|
115
|
+
console.log(`ℹ️ Add to ${ctx.feature}.routes.ts above the '/:id' routes: ${line}`);
|
|
116
|
+
}
|
|
117
|
+
return wroteController;
|
|
118
|
+
}
|
|
@@ -33,30 +33,29 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.parseComponentType = parseComponentType;
|
|
36
37
|
exports.makeComponent = makeComponent;
|
|
37
38
|
const path = __importStar(require("path"));
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
export default function ${name}({ id }: ${name}Props) {
|
|
46
|
-
return (
|
|
47
|
-
<div>
|
|
48
|
-
<h1>${name}</h1>
|
|
49
|
-
</div>
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
`;
|
|
39
|
+
const registry_1 = require("../stack/registry");
|
|
40
|
+
const component_1 = require("../templates/frontend/component");
|
|
41
|
+
const fs_1 = require("../utils/fs");
|
|
42
|
+
const resolve_1 = require("./resolve");
|
|
43
|
+
function parseComponentType(value) {
|
|
44
|
+
return value === 'server' ? 'server' : 'client';
|
|
53
45
|
}
|
|
54
46
|
function makeComponent(feature, name, type = 'client') {
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
if (
|
|
47
|
+
const ctx = (0, resolve_1.requireFeature)(feature);
|
|
48
|
+
(0, registry_1.assertLayer)(ctx.profile, 'component', 'make:component');
|
|
49
|
+
if (type === 'server' && !ctx.profile.serverComponents) {
|
|
50
|
+
throw new Error(`The ${ctx.profile.name} stack has no server components.`);
|
|
51
|
+
}
|
|
52
|
+
const dir = path.join(ctx.featureDir, (0, registry_1.componentDir)(ctx.profile, type));
|
|
53
|
+
(0, fs_1.mkdirSafe)(dir);
|
|
54
|
+
const filePath = path.join(dir, `${name}.tsx`);
|
|
55
|
+
if ((0, fs_1.fileExists)(filePath)) {
|
|
58
56
|
throw new Error(`Component "${name}" already exists at ${filePath}`);
|
|
59
57
|
}
|
|
60
|
-
|
|
58
|
+
const directive = type === 'client' && ctx.profile.clientDirective;
|
|
59
|
+
(0, fs_1.writeFileSafe)(filePath, (0, component_1.renderComponent)(name, directive));
|
|
61
60
|
console.log(`✅ Component "${name}" created at ${filePath}`);
|
|
62
61
|
}
|
|
@@ -35,39 +35,18 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.makeContainer = makeContainer;
|
|
37
37
|
const path = __importStar(require("path"));
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const componentPath = (0, utils_1.resolveImport)(feature, `components/client/${name}`);
|
|
43
|
-
return `'use client';
|
|
44
|
-
|
|
45
|
-
import { ${hookName} } from '${hookPath}';
|
|
46
|
-
import ${name} from '${componentPath}';
|
|
47
|
-
|
|
48
|
-
export default function ${containerName}() {
|
|
49
|
-
const { items, loading, error } = ${hookName}();
|
|
50
|
-
|
|
51
|
-
if (loading) return <div>Loading...</div>;
|
|
52
|
-
if (error) return <div>Error: {error}</div>;
|
|
53
|
-
|
|
54
|
-
return (
|
|
55
|
-
<div>
|
|
56
|
-
{items.map((item) => (
|
|
57
|
-
<${name} key={item.id} {...item} />
|
|
58
|
-
))}
|
|
59
|
-
</div>
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
`;
|
|
63
|
-
}
|
|
38
|
+
const registry_1 = require("../stack/registry");
|
|
39
|
+
const container_1 = require("../templates/frontend/container");
|
|
40
|
+
const fs_1 = require("../utils/fs");
|
|
41
|
+
const resolve_1 = require("./resolve");
|
|
64
42
|
function makeContainer(feature, name, pascalName) {
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
43
|
+
const ctx = (0, resolve_1.requireFeature)(feature);
|
|
44
|
+
(0, registry_1.assertLayer)(ctx.profile, 'container', 'make:container');
|
|
45
|
+
const filePath = path.join((0, resolve_1.ensureLayerDir)(ctx, 'container'), `${name}.tsx`);
|
|
46
|
+
if ((0, fs_1.fileExists)(filePath)) {
|
|
68
47
|
throw new Error(`Container "${name}" already exists at ${filePath}`);
|
|
69
48
|
}
|
|
70
|
-
const
|
|
71
|
-
(0,
|
|
49
|
+
const entity = pascalName ?? name.replace(/Container$/, '');
|
|
50
|
+
(0, fs_1.writeFileSafe)(filePath, (0, container_1.renderContainer)(ctx, name, entity, filePath));
|
|
72
51
|
console.log(`✅ Container "${name}" created at ${filePath}`);
|
|
73
52
|
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.makeController = makeController;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const registry_1 = require("../stack/registry");
|
|
39
|
+
const actions_1 = require("../templates/actions");
|
|
40
|
+
const nest_1 = require("../templates/controllers/nest");
|
|
41
|
+
const next_route_1 = require("../templates/controllers/next-route");
|
|
42
|
+
const node_1 = require("../templates/controllers/node");
|
|
43
|
+
const fs_1 = require("../utils/fs");
|
|
44
|
+
const paths_1 = require("../utils/paths");
|
|
45
|
+
const resolve_1 = require("./resolve");
|
|
46
|
+
const write_1 = require("./write");
|
|
47
|
+
function makeController(feature, name) {
|
|
48
|
+
const ctx = (0, resolve_1.requireFeature)(feature);
|
|
49
|
+
(0, registry_1.assertLayer)(ctx.profile, 'controller', 'make:controller');
|
|
50
|
+
if (ctx.profile.name === 'next-fullstack') {
|
|
51
|
+
return writeNextRoutes(ctx, name);
|
|
52
|
+
}
|
|
53
|
+
const dir = (0, resolve_1.ensureLayerDir)(ctx, 'controller');
|
|
54
|
+
const render = ctx.profile.name === 'nest' ? nest_1.renderNestController : node_1.renderNodeController;
|
|
55
|
+
const written = (0, write_1.writeSpecFiles)(dir, (0, actions_1.standardActions)(name), 'controller', (spec, filePath) => render(ctx, spec, name, filePath));
|
|
56
|
+
if (written > 0)
|
|
57
|
+
console.log(`✅ Controllers for "${name}" created at ${dir}`);
|
|
58
|
+
const wroteRoutes = ctx.profile.name === 'node' ? writeNodeRoutes(ctx, name) : false;
|
|
59
|
+
return written > 0 || wroteRoutes;
|
|
60
|
+
}
|
|
61
|
+
function writeNodeRoutes(ctx, name) {
|
|
62
|
+
const filePath = path.join(ctx.featureDir, `${ctx.feature}.routes.ts`);
|
|
63
|
+
const content = (0, node_1.renderNodeRoutes)(ctx, name, filePath);
|
|
64
|
+
if (content === null) {
|
|
65
|
+
console.log('ℹ️ No HTTP framework detected, generating framework-agnostic controllers.');
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
const wrote = (0, write_1.writeIfAbsent)(filePath, () => content);
|
|
69
|
+
if (wrote)
|
|
70
|
+
console.log(`✅ Routes for "${name}" created at ${filePath}`);
|
|
71
|
+
return wrote;
|
|
72
|
+
}
|
|
73
|
+
function writeNextRoutes(ctx, name) {
|
|
74
|
+
const collectionDir = (0, paths_1.apiRouteDir)(ctx.stack, ctx.feature);
|
|
75
|
+
const itemDir = path.join(collectionDir, '[id]');
|
|
76
|
+
(0, fs_1.mkdirSafe)(itemDir);
|
|
77
|
+
const collectionFile = path.join(collectionDir, 'route.ts');
|
|
78
|
+
const itemFile = path.join(itemDir, 'route.ts');
|
|
79
|
+
const wroteCollection = (0, write_1.writeIfAbsent)(collectionFile, () => (0, next_route_1.renderCollectionRoute)(ctx, name, collectionFile));
|
|
80
|
+
const wroteItem = (0, write_1.writeIfAbsent)(itemFile, () => (0, next_route_1.renderItemRoute)(ctx, name, itemFile));
|
|
81
|
+
const wroteAny = wroteCollection || wroteItem;
|
|
82
|
+
if (wroteAny)
|
|
83
|
+
console.log(`✅ Route handlers for "${name}" created at ${collectionDir}`);
|
|
84
|
+
return wroteAny;
|
|
85
|
+
}
|
package/dist/commands/feature.js
CHANGED
|
@@ -35,64 +35,72 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.makeFeature = makeFeature;
|
|
37
37
|
const path = __importStar(require("path"));
|
|
38
|
-
const
|
|
38
|
+
const registry_1 = require("../stack/registry");
|
|
39
|
+
const page_1 = require("../templates/frontend/page");
|
|
40
|
+
const module_1 = require("../templates/nest/module");
|
|
41
|
+
const fs_1 = require("../utils/fs");
|
|
42
|
+
const naming_1 = require("../utils/naming");
|
|
39
43
|
const component_1 = require("./component");
|
|
44
|
+
const container_1 = require("./container");
|
|
45
|
+
const controller_1 = require("./controller");
|
|
40
46
|
const hook_1 = require("./hook");
|
|
41
|
-
const service_1 = require("./service");
|
|
42
47
|
const repository_1 = require("./repository");
|
|
48
|
+
const resolve_1 = require("./resolve");
|
|
43
49
|
const schema_1 = require("./schema");
|
|
44
|
-
const
|
|
50
|
+
const service_1 = require("./service");
|
|
45
51
|
const types_1 = require("./types");
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
'hooks',
|
|
51
|
-
'services',
|
|
52
|
-
'repositories',
|
|
53
|
-
'schemas',
|
|
54
|
-
'types',
|
|
55
|
-
];
|
|
56
|
-
function renderPage(name, pascalName) {
|
|
57
|
-
const containerPath = (0, utils_1.resolveImport)(name, `containers/${pascalName}Container`, true);
|
|
58
|
-
return `import ${pascalName}Container from '${containerPath}';
|
|
59
|
-
|
|
60
|
-
export default function ${pascalName}Page() {
|
|
61
|
-
return (
|
|
62
|
-
<div>
|
|
63
|
-
<${pascalName}Container />
|
|
64
|
-
</div>
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
`;
|
|
68
|
-
}
|
|
69
|
-
async function makeFeature(name, all = false) {
|
|
70
|
-
const base = (0, utils_1.featureBasePath)(name);
|
|
71
|
-
const pascalName = (0, utils_1.toPascalCase)(name);
|
|
72
|
-
if ((0, utils_1.fileExists)(base)) {
|
|
73
|
-
throw new Error(`Feature "${name}" already exists at ${base}`);
|
|
52
|
+
async function makeFeature(name, all = false, entityName) {
|
|
53
|
+
const ctx = (0, resolve_1.resolveFeature)(name);
|
|
54
|
+
if ((0, fs_1.fileExists)(ctx.featureDir)) {
|
|
55
|
+
throw new Error(`Feature "${name}" already exists at ${ctx.featureDir}`);
|
|
74
56
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (all)
|
|
82
|
-
|
|
57
|
+
const entity = entityName ?? (0, naming_1.toPascalCase)(name);
|
|
58
|
+
createFolders(ctx, all);
|
|
59
|
+
console.log(`✅ Feature "${name}" scaffolded at ${ctx.featureDir}`);
|
|
60
|
+
if (all)
|
|
61
|
+
scaffoldLayers(ctx, entity);
|
|
62
|
+
writeEntryFile(ctx, entity, all);
|
|
63
|
+
if (all)
|
|
64
|
+
console.log(`✅ All files scaffolded for "${name}"`);
|
|
65
|
+
}
|
|
66
|
+
function createFolders(ctx, all) {
|
|
67
|
+
for (const folder of ctx.profile.folders) {
|
|
68
|
+
const dir = path.join(ctx.featureDir, folder);
|
|
69
|
+
(0, fs_1.mkdirSafe)(dir);
|
|
70
|
+
if (!all)
|
|
71
|
+
(0, fs_1.writeFileSafe)(path.join(dir, '.gitkeep'), '');
|
|
83
72
|
}
|
|
84
|
-
|
|
85
|
-
|
|
73
|
+
}
|
|
74
|
+
function scaffoldLayers(ctx, entity) {
|
|
75
|
+
const { feature, profile } = ctx;
|
|
76
|
+
if ((0, registry_1.hasLayer)(profile, 'types'))
|
|
77
|
+
(0, types_1.makeTypes)(feature, entity);
|
|
78
|
+
if ((0, registry_1.hasLayer)(profile, 'schema'))
|
|
79
|
+
(0, schema_1.makeSchema)(feature, entity);
|
|
80
|
+
if ((0, registry_1.hasLayer)(profile, 'serverRepository'))
|
|
81
|
+
(0, repository_1.makeRepository)(feature, entity, 'server');
|
|
82
|
+
if ((0, registry_1.hasLayer)(profile, 'serverService'))
|
|
83
|
+
(0, service_1.makeService)(feature, entity, 'server');
|
|
84
|
+
if ((0, registry_1.hasLayer)(profile, 'controller'))
|
|
85
|
+
(0, controller_1.makeController)(feature, entity);
|
|
86
|
+
if ((0, registry_1.hasLayer)(profile, 'clientRepository'))
|
|
87
|
+
(0, repository_1.makeRepository)(feature, entity, 'client');
|
|
88
|
+
if ((0, registry_1.hasLayer)(profile, 'clientService'))
|
|
89
|
+
(0, service_1.makeService)(feature, entity, 'client');
|
|
90
|
+
if ((0, registry_1.hasLayer)(profile, 'hook'))
|
|
91
|
+
(0, hook_1.makeHook)(feature, `use${entity}`, entity);
|
|
92
|
+
if ((0, registry_1.hasLayer)(profile, 'component'))
|
|
93
|
+
(0, component_1.makeComponent)(feature, entity, 'client');
|
|
94
|
+
if ((0, registry_1.hasLayer)(profile, 'container'))
|
|
95
|
+
(0, container_1.makeContainer)(feature, `${entity}Container`, entity);
|
|
96
|
+
}
|
|
97
|
+
function writeEntryFile(ctx, entity, all) {
|
|
98
|
+
if ((0, registry_1.hasLayer)(ctx.profile, 'page')) {
|
|
99
|
+
const filePath = path.join(ctx.featureDir, 'page.tsx');
|
|
100
|
+
(0, fs_1.writeFileSafe)(filePath, (0, page_1.renderPage)(ctx, entity, filePath, all));
|
|
86
101
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
(0,
|
|
90
|
-
(0, schema_1.makeSchema)(name, pascalName);
|
|
91
|
-
(0, repository_1.makeRepository)(name, pascalName);
|
|
92
|
-
(0, service_1.makeService)(name, pascalName);
|
|
93
|
-
(0, hook_1.makeHook)(name, `use${pascalName}`, pascalName);
|
|
94
|
-
(0, component_1.makeComponent)(name, pascalName, 'client');
|
|
95
|
-
(0, container_1.makeContainer)(name, `${pascalName}Container`, pascalName);
|
|
96
|
-
console.log(`✅ All files scaffolded for "${name}"`);
|
|
102
|
+
if ((0, registry_1.hasLayer)(ctx.profile, 'module')) {
|
|
103
|
+
const filePath = path.join(ctx.featureDir, `${ctx.feature}.module.ts`);
|
|
104
|
+
(0, fs_1.writeFileSafe)(filePath, (0, module_1.renderModule)(ctx, entity, filePath, all));
|
|
97
105
|
}
|
|
98
106
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resetHints = resetHints;
|
|
4
|
+
exports.hintNestjsZod = hintNestjsZod;
|
|
5
|
+
exports.standardClassNames = standardClassNames;
|
|
6
|
+
exports.hintRegisterInModule = hintRegisterInModule;
|
|
7
|
+
const detect_1 = require("../stack/detect");
|
|
8
|
+
const actions_1 = require("../templates/actions");
|
|
9
|
+
let nestjsZodHinted = false;
|
|
10
|
+
function resetHints() {
|
|
11
|
+
nestjsZodHinted = false;
|
|
12
|
+
}
|
|
13
|
+
function hintNestjsZod(stack) {
|
|
14
|
+
if (stack.stack !== 'nest' || stack.hasNestjsZod || nestjsZodHinted)
|
|
15
|
+
return;
|
|
16
|
+
nestjsZodHinted = true;
|
|
17
|
+
console.log('ℹ️ nestjs-zod is not installed. Run: npm install nestjs-zod');
|
|
18
|
+
console.log(' Then register the pipe in AppModule: { provide: APP_PIPE, useClass: ZodValidationPipe }');
|
|
19
|
+
}
|
|
20
|
+
function standardClassNames(name, suffix) {
|
|
21
|
+
return actions_1.ACTIONS.map((action) => `${action}${name}${suffix}`);
|
|
22
|
+
}
|
|
23
|
+
function hintRegisterInModule(feature, classNames, note) {
|
|
24
|
+
if ((0, detect_1.detectStack)().stack !== 'nest')
|
|
25
|
+
return;
|
|
26
|
+
const suffix = note !== undefined ? ` (${note})` : '';
|
|
27
|
+
console.log(`ℹ️ Register ${classNames.join(', ')} in ${feature}.module.ts${suffix}`);
|
|
28
|
+
}
|
package/dist/commands/hook.js
CHANGED
|
@@ -35,119 +35,18 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.makeHook = makeHook;
|
|
37
37
|
const path = __importStar(require("path"));
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const schemaPath = (op) => (0, utils_1.resolveImport)(feature, `schemas/${op}${name}.schema`);
|
|
43
|
-
return `'use client';
|
|
44
|
-
|
|
45
|
-
import { useState, useEffect, useCallback } from 'react';
|
|
46
|
-
import { ${name} } from '${typePath}';
|
|
47
|
-
import { List${name}Service } from '${svcPath('List')}';
|
|
48
|
-
import { Show${name}Service } from '${svcPath('Show')}';
|
|
49
|
-
import { Create${name}Service } from '${svcPath('Create')}';
|
|
50
|
-
import { Update${name}Service } from '${svcPath('Update')}';
|
|
51
|
-
import { Delete${name}Service } from '${svcPath('Delete')}';
|
|
52
|
-
import { Create${name} } from '${schemaPath('Create')}';
|
|
53
|
-
import { Update${name} } from '${schemaPath('Update')}';
|
|
54
|
-
|
|
55
|
-
const listService = new List${name}Service();
|
|
56
|
-
const showService = new Show${name}Service();
|
|
57
|
-
const createService = new Create${name}Service();
|
|
58
|
-
const updateService = new Update${name}Service();
|
|
59
|
-
const deleteService = new Delete${name}Service();
|
|
60
|
-
|
|
61
|
-
export function ${hookName}() {
|
|
62
|
-
const [items, setItems] = useState<${name}[]>([]);
|
|
63
|
-
const [selected, setSelected] = useState<${name} | null>(null);
|
|
64
|
-
const [loading, setLoading] = useState(false);
|
|
65
|
-
const [error, setError] = useState<string | null>(null);
|
|
66
|
-
|
|
67
|
-
const fetchAll = useCallback(async () => {
|
|
68
|
-
setLoading(true);
|
|
69
|
-
setError(null);
|
|
70
|
-
try {
|
|
71
|
-
const data = await listService.handle();
|
|
72
|
-
setItems(data);
|
|
73
|
-
} catch (err: unknown) {
|
|
74
|
-
setError(err instanceof Error ? err.message : 'Failed to fetch');
|
|
75
|
-
} finally {
|
|
76
|
-
setLoading(false);
|
|
77
|
-
}
|
|
78
|
-
}, []);
|
|
79
|
-
|
|
80
|
-
const fetchOne = useCallback(async (id: string) => {
|
|
81
|
-
setLoading(true);
|
|
82
|
-
setError(null);
|
|
83
|
-
try {
|
|
84
|
-
const data = await showService.handle(id);
|
|
85
|
-
setSelected(data);
|
|
86
|
-
} catch (err: unknown) {
|
|
87
|
-
setError(err instanceof Error ? err.message : 'Failed to fetch');
|
|
88
|
-
} finally {
|
|
89
|
-
setLoading(false);
|
|
90
|
-
}
|
|
91
|
-
}, []);
|
|
92
|
-
|
|
93
|
-
const create = useCallback(async (data: Create${name}) => {
|
|
94
|
-
setLoading(true);
|
|
95
|
-
setError(null);
|
|
96
|
-
try {
|
|
97
|
-
const created = await createService.handle(data);
|
|
98
|
-
setItems((prev) => [...prev, created]);
|
|
99
|
-
return created;
|
|
100
|
-
} catch (err: unknown) {
|
|
101
|
-
setError(err instanceof Error ? err.message : 'Failed to create');
|
|
102
|
-
return null;
|
|
103
|
-
} finally {
|
|
104
|
-
setLoading(false);
|
|
105
|
-
}
|
|
106
|
-
}, []);
|
|
107
|
-
|
|
108
|
-
const update = useCallback(async (id: string, data: Update${name}) => {
|
|
109
|
-
setLoading(true);
|
|
110
|
-
setError(null);
|
|
111
|
-
try {
|
|
112
|
-
const updated = await updateService.handle(id, data);
|
|
113
|
-
setItems((prev) => prev.map((item) => (item.id === id ? updated : item)));
|
|
114
|
-
return updated;
|
|
115
|
-
} catch (err: unknown) {
|
|
116
|
-
setError(err instanceof Error ? err.message : 'Failed to update');
|
|
117
|
-
return null;
|
|
118
|
-
} finally {
|
|
119
|
-
setLoading(false);
|
|
120
|
-
}
|
|
121
|
-
}, []);
|
|
122
|
-
|
|
123
|
-
const remove = useCallback(async (id: string) => {
|
|
124
|
-
setLoading(true);
|
|
125
|
-
setError(null);
|
|
126
|
-
try {
|
|
127
|
-
await deleteService.handle(id);
|
|
128
|
-
setItems((prev) => prev.filter((item) => item.id !== id));
|
|
129
|
-
} catch (err: unknown) {
|
|
130
|
-
setError(err instanceof Error ? err.message : 'Failed to delete');
|
|
131
|
-
} finally {
|
|
132
|
-
setLoading(false);
|
|
133
|
-
}
|
|
134
|
-
}, []);
|
|
135
|
-
|
|
136
|
-
useEffect(() => {
|
|
137
|
-
fetchAll();
|
|
138
|
-
}, [fetchAll]);
|
|
139
|
-
|
|
140
|
-
return { items, selected, loading, error, fetchAll, fetchOne, create, update, remove };
|
|
141
|
-
}
|
|
142
|
-
`;
|
|
143
|
-
}
|
|
38
|
+
const registry_1 = require("../stack/registry");
|
|
39
|
+
const hook_1 = require("../templates/frontend/hook");
|
|
40
|
+
const fs_1 = require("../utils/fs");
|
|
41
|
+
const resolve_1 = require("./resolve");
|
|
144
42
|
function makeHook(feature, name, pascalName) {
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
43
|
+
const ctx = (0, resolve_1.requireFeature)(feature);
|
|
44
|
+
(0, registry_1.assertLayer)(ctx.profile, 'hook', 'make:hook');
|
|
45
|
+
const filePath = path.join((0, resolve_1.ensureLayerDir)(ctx, 'hook'), `${name}.ts`);
|
|
46
|
+
if ((0, fs_1.fileExists)(filePath)) {
|
|
148
47
|
throw new Error(`Hook "${name}" already exists at ${filePath}`);
|
|
149
48
|
}
|
|
150
|
-
const
|
|
151
|
-
(0,
|
|
49
|
+
const entity = pascalName ?? name.replace(/^use/, '');
|
|
50
|
+
(0, fs_1.writeFileSafe)(filePath, (0, hook_1.renderHook)(ctx, name, entity, filePath));
|
|
152
51
|
console.log(`✅ Hook "${name}" created at ${filePath}`);
|
|
153
52
|
}
|