domain-driver 0.1.0 → 0.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/README.md +138 -146
- 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/write.js +66 -0
- package/dist/index.js +109 -94
- package/dist/init/content.js +73 -0
- package/dist/init/init.js +60 -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/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,60 @@
|
|
|
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.runInit = runInit;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const fs_1 = require("../utils/fs");
|
|
39
|
+
const content_1 = require("./content");
|
|
40
|
+
const markers_1 = require("./markers");
|
|
41
|
+
const SKILL_FILE = '.claude/skills/domain-driver/SKILL.md';
|
|
42
|
+
function runInit(root) {
|
|
43
|
+
return [writeSection(root, 'AGENTS.md'), writeSection(root, 'CLAUDE.md'), writeSkill(root)];
|
|
44
|
+
}
|
|
45
|
+
function writeSection(root, file) {
|
|
46
|
+
const filePath = path.join(root, file);
|
|
47
|
+
const result = (0, markers_1.applySection)((0, fs_1.readTextFile)(filePath), content_1.AGENTS_SECTION);
|
|
48
|
+
if (result.status !== 'unchanged')
|
|
49
|
+
(0, fs_1.writeFileSafe)(filePath, result.content);
|
|
50
|
+
return Object.freeze({ file, status: result.status });
|
|
51
|
+
}
|
|
52
|
+
function writeSkill(root) {
|
|
53
|
+
const filePath = path.join(root, SKILL_FILE);
|
|
54
|
+
const existing = (0, fs_1.readTextFile)(filePath);
|
|
55
|
+
if (existing === content_1.SKILL_CONTENT)
|
|
56
|
+
return Object.freeze({ file: SKILL_FILE, status: 'unchanged' });
|
|
57
|
+
(0, fs_1.mkdirSafe)(path.dirname(filePath));
|
|
58
|
+
(0, fs_1.writeFileSafe)(filePath, content_1.SKILL_CONTENT);
|
|
59
|
+
return Object.freeze({ file: SKILL_FILE, status: existing === null ? 'created' : 'updated' });
|
|
60
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.END = exports.START = void 0;
|
|
4
|
+
exports.applySection = applySection;
|
|
5
|
+
exports.START = '<!-- domain-driver:start -->';
|
|
6
|
+
exports.END = '<!-- domain-driver:end -->';
|
|
7
|
+
function applySection(existing, section) {
|
|
8
|
+
if (existing === null) {
|
|
9
|
+
return { content: `${section}\n`, status: 'created' };
|
|
10
|
+
}
|
|
11
|
+
const start = existing.indexOf(exports.START);
|
|
12
|
+
const end = existing.indexOf(exports.END);
|
|
13
|
+
if (start !== -1 && end !== -1 && end > start) {
|
|
14
|
+
const before = existing.slice(0, start);
|
|
15
|
+
const after = existing.slice(end + exports.END.length);
|
|
16
|
+
const content = `${before}${section}${after}`;
|
|
17
|
+
return { content, status: content === existing ? 'unchanged' : 'updated' };
|
|
18
|
+
}
|
|
19
|
+
const separator = existing.endsWith('\n') ? '\n' : '\n\n';
|
|
20
|
+
return { content: `${existing}${separator}${section}\n`, status: 'updated' };
|
|
21
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
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.shouldRunPostinstall = shouldRunPostinstall;
|
|
37
|
+
exports.readPackageName = readPackageName;
|
|
38
|
+
exports.run = run;
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const init_1 = require("./init/init");
|
|
42
|
+
const NOT_CI = new Set(['', '0', 'false']);
|
|
43
|
+
function shouldRunPostinstall(env, readName) {
|
|
44
|
+
if (env.CI !== undefined && !NOT_CI.has(env.CI))
|
|
45
|
+
return { run: false, reason: 'ci' };
|
|
46
|
+
if (env.npm_config_global === 'true')
|
|
47
|
+
return { run: false, reason: 'global' };
|
|
48
|
+
const root = env.INIT_CWD;
|
|
49
|
+
if (!root)
|
|
50
|
+
return { run: false, reason: 'no-init-cwd' };
|
|
51
|
+
const name = readName(root);
|
|
52
|
+
if (name === null)
|
|
53
|
+
return { run: false, reason: 'no-consumer-package' };
|
|
54
|
+
if (name === 'domain-driver')
|
|
55
|
+
return { run: false, reason: 'self-install' };
|
|
56
|
+
return { run: true, root };
|
|
57
|
+
}
|
|
58
|
+
function readPackageName(root) {
|
|
59
|
+
try {
|
|
60
|
+
const parsed = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf-8'));
|
|
61
|
+
const name = parsed.name;
|
|
62
|
+
return typeof name === 'string' ? name : '';
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function run(init = init_1.runInit, env = process.env, readName = readPackageName) {
|
|
69
|
+
try {
|
|
70
|
+
const decision = shouldRunPostinstall(env, readName);
|
|
71
|
+
if (!decision.run)
|
|
72
|
+
return;
|
|
73
|
+
for (const result of init(decision.root)) {
|
|
74
|
+
console.log(`domain-driver: ${result.file} ${result.status}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// A postinstall must never fail an install.
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
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.resetStackCache = resetStackCache;
|
|
37
|
+
exports.detectStack = detectStack;
|
|
38
|
+
exports.describeStack = describeStack;
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const fs_1 = require("../utils/fs");
|
|
42
|
+
const types_1 = require("./types");
|
|
43
|
+
const API_DIRS = ['app/api', 'src/app/api', 'pages/api', 'src/pages/api'];
|
|
44
|
+
let cached;
|
|
45
|
+
function resetStackCache() {
|
|
46
|
+
cached = undefined;
|
|
47
|
+
}
|
|
48
|
+
function detectStack(override) {
|
|
49
|
+
if (cached)
|
|
50
|
+
return cached;
|
|
51
|
+
const cwd = process.cwd();
|
|
52
|
+
const overridden = override !== undefined;
|
|
53
|
+
const deps = readDependencies(cwd, overridden);
|
|
54
|
+
const stack = overridden ? parseOverride(override) : inferStack(cwd, deps);
|
|
55
|
+
const result = Object.freeze({
|
|
56
|
+
stack,
|
|
57
|
+
source: overridden ? 'override' : 'detected',
|
|
58
|
+
httpFramework: stack === 'node' ? detectHttpFramework(deps) : null,
|
|
59
|
+
featureRoot: resolveFeatureRoot(cwd, stack),
|
|
60
|
+
hasNestjsZod: deps.has('nestjs-zod'),
|
|
61
|
+
});
|
|
62
|
+
cached = result;
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
function describeStack(stack) {
|
|
66
|
+
const base = `Stack: ${stack.stack} (${stack.source})`;
|
|
67
|
+
if (stack.stack !== 'node')
|
|
68
|
+
return base;
|
|
69
|
+
return `${base}, http: ${stack.httpFramework ?? 'none'}`;
|
|
70
|
+
}
|
|
71
|
+
function readDependencies(cwd, optional) {
|
|
72
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
73
|
+
if (!fs.existsSync(pkgPath)) {
|
|
74
|
+
if (optional)
|
|
75
|
+
return new Set();
|
|
76
|
+
throw new Error(`No package.json found in ${cwd}. Run domain-driver from your project root, or pass --stack <name>.`);
|
|
77
|
+
}
|
|
78
|
+
const pkg = parsePackageJson(pkgPath);
|
|
79
|
+
return new Set([
|
|
80
|
+
...Object.keys(pkg.dependencies ?? {}),
|
|
81
|
+
...Object.keys(pkg.devDependencies ?? {}),
|
|
82
|
+
]);
|
|
83
|
+
}
|
|
84
|
+
function parsePackageJson(pkgPath) {
|
|
85
|
+
try {
|
|
86
|
+
const parsed = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
87
|
+
return (parsed ?? {});
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
91
|
+
throw new Error(`Could not parse package.json: ${message}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function parseOverride(value) {
|
|
95
|
+
if ((0, types_1.isStackName)(value))
|
|
96
|
+
return value;
|
|
97
|
+
throw new Error(`Unknown stack "${value}". Valid stacks: ${types_1.STACK_NAMES.join(', ')}.`);
|
|
98
|
+
}
|
|
99
|
+
function inferStack(cwd, deps) {
|
|
100
|
+
if (deps.has('@nestjs/core'))
|
|
101
|
+
return 'nest';
|
|
102
|
+
if (deps.has('next'))
|
|
103
|
+
return hasApiDir(cwd) ? 'next-fullstack' : 'next-frontend';
|
|
104
|
+
if (deps.has('react'))
|
|
105
|
+
return 'react';
|
|
106
|
+
return 'node';
|
|
107
|
+
}
|
|
108
|
+
function hasApiDir(cwd) {
|
|
109
|
+
return API_DIRS.some((dir) => (0, fs_1.isDirectory)(path.join(cwd, dir)));
|
|
110
|
+
}
|
|
111
|
+
function detectHttpFramework(deps) {
|
|
112
|
+
return types_1.HTTP_FRAMEWORKS.find((name) => deps.has(name)) ?? null;
|
|
113
|
+
}
|
|
114
|
+
function resolveFeatureRoot(cwd, stack) {
|
|
115
|
+
switch (stack) {
|
|
116
|
+
case 'next-fullstack':
|
|
117
|
+
case 'next-frontend':
|
|
118
|
+
return (0, fs_1.isDirectory)(path.join(cwd, 'src', 'app')) ? 'src/app' : 'app';
|
|
119
|
+
case 'react':
|
|
120
|
+
case 'node':
|
|
121
|
+
return (0, fs_1.isDirectory)(path.join(cwd, 'src')) ? 'src/features' : 'features';
|
|
122
|
+
case 'nest':
|
|
123
|
+
return 'src';
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.nest = void 0;
|
|
4
|
+
exports.nest = Object.freeze({
|
|
5
|
+
name: 'nest',
|
|
6
|
+
folders: ['controllers', 'services', 'repositories', 'schemas', 'dto', 'types'],
|
|
7
|
+
layers: ['serverService', 'serverRepository', 'controller', 'module', 'dto', 'schema', 'types'],
|
|
8
|
+
layerDirs: {
|
|
9
|
+
serverService: 'services',
|
|
10
|
+
serverRepository: 'repositories',
|
|
11
|
+
controller: 'controllers',
|
|
12
|
+
dto: 'dto',
|
|
13
|
+
schema: 'schemas',
|
|
14
|
+
types: 'types',
|
|
15
|
+
},
|
|
16
|
+
clientDirective: false,
|
|
17
|
+
serverComponents: false,
|
|
18
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.nextFrontend = void 0;
|
|
4
|
+
exports.nextFrontend = Object.freeze({
|
|
5
|
+
name: 'next-frontend',
|
|
6
|
+
folders: [
|
|
7
|
+
'components/client',
|
|
8
|
+
'components/server',
|
|
9
|
+
'containers',
|
|
10
|
+
'hooks',
|
|
11
|
+
'services',
|
|
12
|
+
'repositories',
|
|
13
|
+
'schemas',
|
|
14
|
+
'types',
|
|
15
|
+
],
|
|
16
|
+
layers: ['page', 'component', 'container', 'hook', 'clientService', 'clientRepository', 'schema', 'types'],
|
|
17
|
+
layerDirs: {
|
|
18
|
+
component: 'components',
|
|
19
|
+
container: 'containers',
|
|
20
|
+
hook: 'hooks',
|
|
21
|
+
clientService: 'services',
|
|
22
|
+
clientRepository: 'repositories',
|
|
23
|
+
schema: 'schemas',
|
|
24
|
+
types: 'types',
|
|
25
|
+
},
|
|
26
|
+
clientDirective: true,
|
|
27
|
+
serverComponents: true,
|
|
28
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.nextFullstack = void 0;
|
|
4
|
+
exports.nextFullstack = Object.freeze({
|
|
5
|
+
name: 'next-fullstack',
|
|
6
|
+
folders: [
|
|
7
|
+
'components/client',
|
|
8
|
+
'components/server',
|
|
9
|
+
'containers',
|
|
10
|
+
'hooks',
|
|
11
|
+
'client/services',
|
|
12
|
+
'client/repositories',
|
|
13
|
+
'server/services',
|
|
14
|
+
'server/repositories',
|
|
15
|
+
'schemas',
|
|
16
|
+
'types',
|
|
17
|
+
],
|
|
18
|
+
layers: [
|
|
19
|
+
'page',
|
|
20
|
+
'component',
|
|
21
|
+
'container',
|
|
22
|
+
'hook',
|
|
23
|
+
'clientService',
|
|
24
|
+
'clientRepository',
|
|
25
|
+
'serverService',
|
|
26
|
+
'serverRepository',
|
|
27
|
+
'controller',
|
|
28
|
+
'schema',
|
|
29
|
+
'types',
|
|
30
|
+
],
|
|
31
|
+
layerDirs: {
|
|
32
|
+
component: 'components',
|
|
33
|
+
container: 'containers',
|
|
34
|
+
hook: 'hooks',
|
|
35
|
+
clientService: 'client/services',
|
|
36
|
+
clientRepository: 'client/repositories',
|
|
37
|
+
serverService: 'server/services',
|
|
38
|
+
serverRepository: 'server/repositories',
|
|
39
|
+
schema: 'schemas',
|
|
40
|
+
types: 'types',
|
|
41
|
+
},
|
|
42
|
+
clientDirective: true,
|
|
43
|
+
serverComponents: true,
|
|
44
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.node = void 0;
|
|
4
|
+
exports.node = Object.freeze({
|
|
5
|
+
name: 'node',
|
|
6
|
+
folders: ['controllers', 'services', 'repositories', 'schemas', 'types'],
|
|
7
|
+
layers: ['serverService', 'serverRepository', 'controller', 'schema', 'types'],
|
|
8
|
+
layerDirs: {
|
|
9
|
+
serverService: 'services',
|
|
10
|
+
serverRepository: 'repositories',
|
|
11
|
+
controller: 'controllers',
|
|
12
|
+
schema: 'schemas',
|
|
13
|
+
types: 'types',
|
|
14
|
+
},
|
|
15
|
+
clientDirective: false,
|
|
16
|
+
serverComponents: false,
|
|
17
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.react = void 0;
|
|
4
|
+
exports.react = Object.freeze({
|
|
5
|
+
name: 'react',
|
|
6
|
+
folders: ['components', 'containers', 'hooks', 'services', 'repositories', 'schemas', 'types'],
|
|
7
|
+
layers: ['component', 'container', 'hook', 'clientService', 'clientRepository', 'schema', 'types'],
|
|
8
|
+
layerDirs: {
|
|
9
|
+
component: 'components',
|
|
10
|
+
container: 'containers',
|
|
11
|
+
hook: 'hooks',
|
|
12
|
+
clientService: 'services',
|
|
13
|
+
clientRepository: 'repositories',
|
|
14
|
+
schema: 'schemas',
|
|
15
|
+
types: 'types',
|
|
16
|
+
},
|
|
17
|
+
clientDirective: false,
|
|
18
|
+
serverComponents: false,
|
|
19
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getProfile = getProfile;
|
|
4
|
+
exports.hasLayer = hasLayer;
|
|
5
|
+
exports.layerDir = layerDir;
|
|
6
|
+
exports.componentDir = componentDir;
|
|
7
|
+
exports.availableCommands = availableCommands;
|
|
8
|
+
exports.assertLayer = assertLayer;
|
|
9
|
+
const next_fullstack_1 = require("./profiles/next-fullstack");
|
|
10
|
+
const next_frontend_1 = require("./profiles/next-frontend");
|
|
11
|
+
const react_1 = require("./profiles/react");
|
|
12
|
+
const node_1 = require("./profiles/node");
|
|
13
|
+
const nest_1 = require("./profiles/nest");
|
|
14
|
+
const PROFILES = Object.freeze({
|
|
15
|
+
'next-fullstack': next_fullstack_1.nextFullstack,
|
|
16
|
+
'next-frontend': next_frontend_1.nextFrontend,
|
|
17
|
+
react: react_1.react,
|
|
18
|
+
node: node_1.node,
|
|
19
|
+
nest: nest_1.nest,
|
|
20
|
+
});
|
|
21
|
+
const LAYER_COMMANDS = Object.freeze({
|
|
22
|
+
component: 'make:component',
|
|
23
|
+
container: 'make:container',
|
|
24
|
+
hook: 'make:hook',
|
|
25
|
+
clientService: 'make:service',
|
|
26
|
+
serverService: 'make:service',
|
|
27
|
+
clientRepository: 'make:repository',
|
|
28
|
+
serverRepository: 'make:repository',
|
|
29
|
+
controller: 'make:controller',
|
|
30
|
+
schema: 'make:schema',
|
|
31
|
+
dto: 'make:schema',
|
|
32
|
+
types: 'make:types',
|
|
33
|
+
});
|
|
34
|
+
function getProfile(stack) {
|
|
35
|
+
return PROFILES[stack];
|
|
36
|
+
}
|
|
37
|
+
function hasLayer(profile, layer) {
|
|
38
|
+
return profile.layers.includes(layer);
|
|
39
|
+
}
|
|
40
|
+
function layerDir(profile, layer) {
|
|
41
|
+
const dir = profile.layerDirs[layer];
|
|
42
|
+
if (dir === undefined) {
|
|
43
|
+
throw new Error(`Layer "${layer}" has no directory in the ${profile.name} profile.`);
|
|
44
|
+
}
|
|
45
|
+
return dir;
|
|
46
|
+
}
|
|
47
|
+
function componentDir(profile, type) {
|
|
48
|
+
return profile.serverComponents ? `components/${type}` : 'components';
|
|
49
|
+
}
|
|
50
|
+
function availableCommands(profile) {
|
|
51
|
+
const commands = profile.layers
|
|
52
|
+
.map((layer) => LAYER_COMMANDS[layer])
|
|
53
|
+
.filter((command) => command !== undefined);
|
|
54
|
+
return [...new Set(commands)];
|
|
55
|
+
}
|
|
56
|
+
function assertLayer(profile, layer, command) {
|
|
57
|
+
if (hasLayer(profile, layer))
|
|
58
|
+
return;
|
|
59
|
+
const escapeHatch = profile.name === 'next-frontend' && layer === 'controller'
|
|
60
|
+
? ' Create an app/api directory or pass --stack next-fullstack to enable route handlers.'
|
|
61
|
+
: '';
|
|
62
|
+
throw new Error(`${command} is not available for the ${profile.name} stack. Available: ${availableCommands(profile).join(', ')}.${escapeHatch}`);
|
|
63
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LAYERS = exports.HTTP_FRAMEWORKS = exports.STACK_NAMES = void 0;
|
|
4
|
+
exports.isStackName = isStackName;
|
|
5
|
+
exports.STACK_NAMES = ['next-fullstack', 'next-frontend', 'react', 'node', 'nest'];
|
|
6
|
+
exports.HTTP_FRAMEWORKS = ['express', 'fastify', 'hono'];
|
|
7
|
+
exports.LAYERS = [
|
|
8
|
+
'page',
|
|
9
|
+
'component',
|
|
10
|
+
'container',
|
|
11
|
+
'hook',
|
|
12
|
+
'clientService',
|
|
13
|
+
'clientRepository',
|
|
14
|
+
'serverService',
|
|
15
|
+
'serverRepository',
|
|
16
|
+
'controller',
|
|
17
|
+
'module',
|
|
18
|
+
'dto',
|
|
19
|
+
'schema',
|
|
20
|
+
'types',
|
|
21
|
+
];
|
|
22
|
+
function isStackName(value) {
|
|
23
|
+
return exports.STACK_NAMES.includes(value);
|
|
24
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RETURN_KINDS = exports.WRITE_ACTIONS = exports.ACTIONS = void 0;
|
|
4
|
+
exports.actionCase = actionCase;
|
|
5
|
+
exports.standardAction = standardAction;
|
|
6
|
+
exports.standardActions = standardActions;
|
|
7
|
+
exports.customAction = customAction;
|
|
8
|
+
const naming_1 = require("../utils/naming");
|
|
9
|
+
exports.ACTIONS = ['List', 'Show', 'Create', 'Update', 'Delete'];
|
|
10
|
+
exports.WRITE_ACTIONS = ['Create', 'Update'];
|
|
11
|
+
exports.RETURN_KINDS = ['list', 'one', 'void'];
|
|
12
|
+
const ACTION_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9]*$/;
|
|
13
|
+
function actionCase(name) {
|
|
14
|
+
if (!ACTION_NAME_PATTERN.test(name)) {
|
|
15
|
+
throw new Error(`Action name "${name}" must be camelCase or PascalCase, for example findActiveUsers.`);
|
|
16
|
+
}
|
|
17
|
+
const pascal = (0, naming_1.upperFirst)(name);
|
|
18
|
+
return Object.freeze({ pascal, camel: (0, naming_1.lowerFirst)(pascal), slug: (0, naming_1.toKebabCase)(pascal) });
|
|
19
|
+
}
|
|
20
|
+
function freeze(spec) {
|
|
21
|
+
return Object.freeze(spec);
|
|
22
|
+
}
|
|
23
|
+
function returnType(kind, entity) {
|
|
24
|
+
switch (kind) {
|
|
25
|
+
case 'list':
|
|
26
|
+
return `Promise<${entity}[]>`;
|
|
27
|
+
case 'one':
|
|
28
|
+
return `Promise<${entity}>`;
|
|
29
|
+
case 'void':
|
|
30
|
+
return 'Promise<void>';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function standardAction(action, entity) {
|
|
34
|
+
const name = `${action}${entity}`;
|
|
35
|
+
const handler = `${(0, naming_1.lowerFirst)(action)}${entity}Controller`;
|
|
36
|
+
switch (action) {
|
|
37
|
+
case 'List':
|
|
38
|
+
return freeze({ name, handler, params: '', args: '', returns: `Promise<${entity}[]>`, usesEntityType: true, schema: null, usesId: false, status: 200, method: 'get', path: '/', failure: `Failed to fetch ${entity} list` });
|
|
39
|
+
case 'Show':
|
|
40
|
+
return freeze({ name, handler, params: 'id: string', args: 'id', returns: `Promise<${entity}>`, usesEntityType: true, schema: null, usesId: true, status: 200, method: 'get', path: '/:id', failure: `Failed to fetch ${entity}` });
|
|
41
|
+
case 'Create':
|
|
42
|
+
return freeze({ name, handler, params: `data: ${name}`, args: 'data', returns: `Promise<${entity}>`, usesEntityType: true, schema: name, usesId: false, status: 201, method: 'post', path: '/', failure: `Failed to create ${entity}` });
|
|
43
|
+
case 'Update':
|
|
44
|
+
return freeze({ name, handler, params: `id: string, data: ${name}`, args: 'id, data', returns: `Promise<${entity}>`, usesEntityType: true, schema: name, usesId: true, status: 200, method: 'put', path: '/:id', failure: `Failed to update ${entity}` });
|
|
45
|
+
case 'Delete':
|
|
46
|
+
return freeze({ name, handler, params: 'id: string', args: 'id', returns: 'Promise<void>', usesEntityType: false, schema: null, usesId: true, status: 204, method: 'delete', path: '/:id', failure: `Failed to delete ${entity}` });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function standardActions(entity) {
|
|
50
|
+
return exports.ACTIONS.map((action) => standardAction(action, entity));
|
|
51
|
+
}
|
|
52
|
+
function customAction(entity, actionName, options) {
|
|
53
|
+
const { pascal, camel, slug } = actionCase(actionName);
|
|
54
|
+
return freeze({
|
|
55
|
+
name: pascal,
|
|
56
|
+
handler: `${camel}Controller`,
|
|
57
|
+
params: options.withInput ? `data: ${pascal}` : '',
|
|
58
|
+
args: options.withInput ? 'data' : '',
|
|
59
|
+
returns: returnType(options.returns, entity),
|
|
60
|
+
usesEntityType: options.returns !== 'void',
|
|
61
|
+
schema: options.withInput ? pascal : null,
|
|
62
|
+
usesId: false,
|
|
63
|
+
status: options.returns === 'void' ? 204 : 200,
|
|
64
|
+
method: options.withInput ? 'post' : 'get',
|
|
65
|
+
path: `/${slug}`,
|
|
66
|
+
failure: `Failed to ${camel} ${entity}`,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.renderServerRepository = renderServerRepository;
|
|
4
|
+
const injectable_1 = require("../nest/injectable");
|
|
5
|
+
const signatures_1 = require("../signatures");
|
|
6
|
+
function renderServerRepository(ctx, spec, entity, fromFile) {
|
|
7
|
+
const cls = `${spec.name}Repository`;
|
|
8
|
+
const injectable = ctx.profile.name === 'nest';
|
|
9
|
+
const imports = [
|
|
10
|
+
...(injectable ? [injectable_1.INJECTABLE_IMPORT] : []),
|
|
11
|
+
...(0, signatures_1.domainImports)(ctx, fromFile, spec, entity),
|
|
12
|
+
].join('\n');
|
|
13
|
+
const header = imports ? `${imports}\n\n` : '';
|
|
14
|
+
const decorator = injectable ? '@Injectable()\n' : '';
|
|
15
|
+
return `${header}${decorator}export class ${cls} {
|
|
16
|
+
async handle(${spec.params}): ${spec.returns} {
|
|
17
|
+
// TODO: implement with your ORM (Prisma, Drizzle, TypeORM, ...)
|
|
18
|
+
throw new Error('${cls}.handle is not implemented');
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
`;
|
|
22
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
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.createContext = createContext;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const registry_1 = require("../stack/registry");
|
|
39
|
+
const imports_1 = require("../utils/imports");
|
|
40
|
+
const paths_1 = require("../utils/paths");
|
|
41
|
+
function createContext(feature, stack, profile) {
|
|
42
|
+
const dir = (0, paths_1.featureDir)(stack, feature);
|
|
43
|
+
const importFrom = (fromFile, relative) => (0, imports_1.resolveImport)(fromFile, path.join(dir, relative));
|
|
44
|
+
return Object.freeze({
|
|
45
|
+
feature,
|
|
46
|
+
stack,
|
|
47
|
+
profile,
|
|
48
|
+
featureDir: dir,
|
|
49
|
+
importFrom,
|
|
50
|
+
importLayer: (fromFile, layer, fileName) => importFrom(fromFile, `${(0, registry_1.layerDir)(profile, layer)}/${fileName}`),
|
|
51
|
+
});
|
|
52
|
+
}
|