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.
Files changed (85) hide show
  1. package/README.md +159 -145
  2. package/dist/cli.js +208 -0
  3. package/dist/commands/action.js +118 -0
  4. package/dist/commands/component.js +18 -19
  5. package/dist/commands/container.js +10 -31
  6. package/dist/commands/controller.js +85 -0
  7. package/dist/commands/feature.js +59 -51
  8. package/dist/commands/hints.js +28 -0
  9. package/dist/commands/hook.js +10 -111
  10. package/dist/commands/repository.js +17 -115
  11. package/dist/commands/resolve.js +61 -0
  12. package/dist/commands/schema.js +22 -69
  13. package/dist/commands/service.js +15 -113
  14. package/dist/commands/sides.js +34 -0
  15. package/dist/commands/target.js +32 -0
  16. package/dist/commands/types.js +9 -17
  17. package/dist/commands/update.js +148 -0
  18. package/dist/commands/write.js +66 -0
  19. package/dist/index.js +8 -122
  20. package/dist/init/content.js +73 -0
  21. package/dist/init/init.js +66 -0
  22. package/dist/init/markers.js +21 -0
  23. package/dist/postinstall.js +80 -0
  24. package/dist/stack/detect.js +125 -0
  25. package/dist/stack/profiles/nest.js +18 -0
  26. package/dist/stack/profiles/next-frontend.js +28 -0
  27. package/dist/stack/profiles/next-fullstack.js +44 -0
  28. package/dist/stack/profiles/node.js +17 -0
  29. package/dist/stack/profiles/react.js +19 -0
  30. package/dist/stack/registry.js +63 -0
  31. package/dist/stack/types.js +24 -0
  32. package/dist/templates/actions.js +68 -0
  33. package/dist/templates/backend/server-repository.js +22 -0
  34. package/dist/templates/context.js +52 -0
  35. package/dist/templates/controllers/express.js +60 -0
  36. package/dist/templates/controllers/fastify.js +54 -0
  37. package/dist/templates/controllers/generic.js +30 -0
  38. package/dist/templates/controllers/hono.js +52 -0
  39. package/dist/templates/controllers/nest.js +63 -0
  40. package/dist/templates/controllers/next-action-route.js +40 -0
  41. package/dist/templates/controllers/next-route.js +62 -0
  42. package/dist/templates/controllers/node.js +46 -0
  43. package/dist/templates/controllers/shape.js +28 -0
  44. package/dist/templates/frontend/client-repository.js +38 -0
  45. package/dist/templates/frontend/component.js +18 -0
  46. package/dist/templates/frontend/container.js +28 -0
  47. package/{src/commands/hook.ts → dist/templates/frontend/hook.js} +28 -41
  48. package/dist/templates/frontend/page.js +26 -0
  49. package/dist/templates/nest/dto.js +12 -0
  50. package/dist/templates/nest/injectable.js +4 -0
  51. package/dist/templates/nest/module.js +41 -0
  52. package/dist/templates/service.js +40 -0
  53. package/dist/templates/shared/schema.js +13 -0
  54. package/dist/templates/shared/types.js +12 -0
  55. package/dist/templates/signatures.js +15 -0
  56. package/dist/update/cache.js +80 -0
  57. package/dist/update/check.js +47 -0
  58. package/dist/update/install-mode.js +96 -0
  59. package/dist/update/package-manager.js +99 -0
  60. package/dist/update/registry.js +77 -0
  61. package/dist/update/version.js +70 -0
  62. package/dist/utils/alias.js +80 -0
  63. package/dist/utils/fs.js +70 -0
  64. package/dist/utils/imports.js +61 -0
  65. package/dist/utils/naming.js +31 -0
  66. package/dist/utils/paths.js +44 -0
  67. package/package.json +27 -6
  68. package/scripts/postinstall.js +7 -0
  69. package/.github/workflows/publish.yml +0 -28
  70. package/dist/utils.js +0 -132
  71. package/src/__tests__/utils.test.ts +0 -128
  72. package/src/commands/__tests__/feature.test.ts +0 -85
  73. package/src/commands/__tests__/imports.test.ts +0 -115
  74. package/src/commands/__tests__/individual.test.ts +0 -137
  75. package/src/commands/component.ts +0 -33
  76. package/src/commands/container.ts +0 -42
  77. package/src/commands/feature.ts +0 -74
  78. package/src/commands/repository.ts +0 -95
  79. package/src/commands/schema.ts +0 -47
  80. package/src/commands/service.ts +0 -93
  81. package/src/commands/types.ts +0 -25
  82. package/src/index.ts +0 -126
  83. package/src/utils.ts +0 -115
  84. package/tsconfig.json +0 -13
  85. package/vitest.config.ts +0 -7
@@ -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
+ }
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderExpressController = renderExpressController;
4
+ exports.renderExpressRoutes = renderExpressRoutes;
5
+ const naming_1 = require("../../utils/naming");
6
+ const actions_1 = require("../actions");
7
+ const shape_1 = require("./shape");
8
+ function renderExpressController(ctx, spec, fromFile) {
9
+ const imports = [
10
+ "import { NextFunction, Request, Response } from 'express';",
11
+ ...(spec.schema !== null ? [(0, shape_1.schemaImport)(ctx, fromFile, spec.schema)] : []),
12
+ (0, shape_1.serviceImport)(ctx, fromFile, spec),
13
+ ].join('\n');
14
+ const reqName = spec.schema !== null || spec.usesId ? 'req' : '_req';
15
+ const requestType = spec.usesId ? 'Request<{ id: string }>' : 'Request';
16
+ const validate = spec.schema !== null
17
+ ? ` const parsed = ${spec.schema}Schema.safeParse(req.body);
18
+ if (!parsed.success) {
19
+ res.status(400).json({ errors: parsed.error.flatten() });
20
+ return;
21
+ }
22
+ `
23
+ : '';
24
+ const args = (0, shape_1.callArgs)(spec, 'req.params.id', 'parsed.data');
25
+ const respond = spec.status === 204
26
+ ? ` await service.handle(${args});
27
+ res.status(204).send();`
28
+ : ` res.status(${spec.status}).json(await service.handle(${args}));`;
29
+ return `${imports}
30
+
31
+ const service = new ${spec.name}Service();
32
+
33
+ export async function ${spec.handler}(${reqName}: ${requestType}, res: Response, next: NextFunction): Promise<void> {
34
+ ${validate} try {
35
+ ${respond}
36
+ } catch (error) {
37
+ next(error);
38
+ }
39
+ }
40
+ `;
41
+ }
42
+ function renderExpressRoutes(ctx, entity, fromFile) {
43
+ const name = (0, naming_1.lowerFirst)(entity);
44
+ const handler = (action) => (0, actions_1.standardAction)(action, entity).handler;
45
+ return `import { Router } from 'express';
46
+ ${(0, shape_1.controllerImports)(ctx, fromFile, entity)}
47
+
48
+ const router = Router();
49
+
50
+ router.get('/', ${handler('List')});
51
+ router.get('/:id', ${handler('Show')});
52
+ router.post('/', ${handler('Create')});
53
+ router.put('/:id', ${handler('Update')});
54
+ router.delete('/:id', ${handler('Delete')});
55
+
56
+ export default router;
57
+
58
+ // app.use('/${ctx.feature}', ${name}Routes);
59
+ `;
60
+ }
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderFastifyController = renderFastifyController;
4
+ exports.renderFastifyRoutes = renderFastifyRoutes;
5
+ const naming_1 = require("../../utils/naming");
6
+ const actions_1 = require("../actions");
7
+ const shape_1 = require("./shape");
8
+ function renderFastifyController(ctx, spec, fromFile) {
9
+ const imports = [
10
+ "import { FastifyReply, FastifyRequest } from 'fastify';",
11
+ ...(spec.schema !== null ? [(0, shape_1.schemaImport)(ctx, fromFile, spec.schema)] : []),
12
+ (0, shape_1.serviceImport)(ctx, fromFile, spec),
13
+ ].join('\n');
14
+ const requestType = spec.usesId ? 'FastifyRequest<{ Params: { id: string } }>' : 'FastifyRequest';
15
+ const requestName = spec.schema !== null || spec.usesId ? 'request' : '_request';
16
+ const validate = spec.schema !== null
17
+ ? ` const parsed = ${spec.schema}Schema.safeParse(request.body);
18
+ if (!parsed.success) {
19
+ reply.status(400).send({ errors: parsed.error.flatten() });
20
+ return;
21
+ }
22
+ `
23
+ : '';
24
+ const args = (0, shape_1.callArgs)(spec, 'request.params.id', 'parsed.data');
25
+ const respond = spec.status === 204
26
+ ? ` await service.handle(${args});
27
+ reply.status(204).send();`
28
+ : ` reply.status(${spec.status}).send(await service.handle(${args}));`;
29
+ return `${imports}
30
+
31
+ const service = new ${spec.name}Service();
32
+
33
+ export async function ${spec.handler}(${requestName}: ${requestType}, reply: FastifyReply): Promise<void> {
34
+ ${validate}${respond}
35
+ }
36
+ `;
37
+ }
38
+ function renderFastifyRoutes(ctx, entity, fromFile) {
39
+ const name = (0, naming_1.lowerFirst)(entity);
40
+ const handler = (action) => (0, actions_1.standardAction)(action, entity).handler;
41
+ return `import { FastifyInstance } from 'fastify';
42
+ ${(0, shape_1.controllerImports)(ctx, fromFile, entity)}
43
+
44
+ export async function ${name}Routes(app: FastifyInstance): Promise<void> {
45
+ app.get('/', ${handler('List')});
46
+ app.get('/:id', ${handler('Show')});
47
+ app.post('/', ${handler('Create')});
48
+ app.put('/:id', ${handler('Update')});
49
+ app.delete('/:id', ${handler('Delete')});
50
+ }
51
+
52
+ // app.register(${name}Routes, { prefix: '/${ctx.feature}' });
53
+ `;
54
+ }
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderGenericController = renderGenericController;
4
+ const shape_1 = require("./shape");
5
+ function renderGenericController(ctx, spec, entity, fromFile) {
6
+ const typeImport = spec.usesEntityType
7
+ ? [`import { ${entity} } from '${ctx.importLayer(fromFile, 'types', `${entity}.types`)}';`]
8
+ : [];
9
+ const imports = [
10
+ ...typeImport,
11
+ ...(spec.schema !== null ? [(0, shape_1.schemaImport)(ctx, fromFile, spec.schema)] : []),
12
+ (0, shape_1.serviceImport)(ctx, fromFile, spec),
13
+ ].join('\n');
14
+ const params = [spec.usesId ? 'id: string' : null, spec.schema !== null ? 'input: unknown' : null]
15
+ .filter((param) => param !== null)
16
+ .join(', ');
17
+ const args = [spec.usesId ? 'id' : null, spec.schema !== null ? `${spec.schema}Schema.parse(input)` : null]
18
+ .filter((arg) => arg !== null)
19
+ .join(', ');
20
+ return `${imports}
21
+
22
+ const service = new ${spec.name}Service();
23
+
24
+ export class ${spec.name}Controller {
25
+ async handle(${params}): ${spec.returns} {
26
+ return service.handle(${args});
27
+ }
28
+ }
29
+ `;
30
+ }