domain-driver 0.0.1
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/.idea/copilot.data.migration.ask2agent.xml +6 -0
- package/.idea/domain-driver.iml +8 -0
- package/.idea/inspectionProfiles/Project_Default.xml +5 -0
- package/.idea/jsLibraryMappings.xml +6 -0
- package/.idea/material_theme_project_new.xml +10 -0
- package/.idea/modules.xml +8 -0
- package/.idea/swift-toolchain.xml +6 -0
- package/.idea/vcs.xml +6 -0
- package/README.md +116 -0
- package/dist/commands/feature.js +71 -0
- package/dist/index.js +16 -0
- package/package.json +23 -0
- package/src/commands/feature.ts +42 -0
- package/src/index.ts +16 -0
- package/tsconfig.json +13 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<module type="WEB_MODULE" version="4">
|
|
3
|
+
<component name="NewModuleRootManager">
|
|
4
|
+
<content url="file://$MODULE_DIR$" />
|
|
5
|
+
<orderEntry type="inheritedJdk" />
|
|
6
|
+
<orderEntry type="sourceFolder" forTests="false" />
|
|
7
|
+
</component>
|
|
8
|
+
</module>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="MaterialThemeProjectNewConfig">
|
|
4
|
+
<option name="metadata">
|
|
5
|
+
<MTProjectMetadataState>
|
|
6
|
+
<option name="userId" value="3f40c18c:19cdf0955d0:-7e51" />
|
|
7
|
+
</MTProjectMetadataState>
|
|
8
|
+
</option>
|
|
9
|
+
</component>
|
|
10
|
+
</project>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="ProjectModuleManager">
|
|
4
|
+
<modules>
|
|
5
|
+
<module fileurl="file://$PROJECT_DIR$/.idea/domain-driver.iml" filepath="$PROJECT_DIR$/.idea/domain-driver.iml" />
|
|
6
|
+
</modules>
|
|
7
|
+
</component>
|
|
8
|
+
</project>
|
package/.idea/vcs.xml
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# domain-driver 🚀
|
|
2
|
+
|
|
3
|
+
A CLI scaffolding tool for domain-driven development in Next.js. Generate feature folder structures instantly — like Laravel's `php artisan make` but for Next.js.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g domain-driver
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or use without installing:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx domain-driver make:feature <name>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
domain-driver make:feature <feature-name>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Examples
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
domain-driver make:feature api-key
|
|
31
|
+
domain-driver make:feature user-profile
|
|
32
|
+
domain-driver make:feature payment
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## What it generates
|
|
38
|
+
|
|
39
|
+
Running `domain-driver make:feature api-key` creates the following structure inside your Next.js `app/` directory:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
app/
|
|
43
|
+
└── api-key/
|
|
44
|
+
├── components/
|
|
45
|
+
│ ├── server/ # React Server Components
|
|
46
|
+
│ └── client/ # Client components ('use client')
|
|
47
|
+
├── containers/ # Smart components — wire hooks → UI
|
|
48
|
+
├── hooks/ # Feature-specific hooks (useApiKey, etc.)
|
|
49
|
+
├── services/ # Business logic and transformations
|
|
50
|
+
├── repositories/ # Data access layer (fetch/axios calls)
|
|
51
|
+
├── schemas/ # Zod schemas for forms and API validation
|
|
52
|
+
└── page.tsx # Next.js page entry point
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Each folder includes a `.gitkeep` file so empty directories are tracked in Git.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Philosophy
|
|
60
|
+
|
|
61
|
+
This tool follows a strict **domain-driven** folder structure where everything related to a feature lives together. No more hunting across `/components`, `/hooks`, and `/services` top-level folders.
|
|
62
|
+
|
|
63
|
+
The layer responsibilities are:
|
|
64
|
+
|
|
65
|
+
- **repositories** — data fetching only, no business logic
|
|
66
|
+
- **services** — business logic, calls repositories
|
|
67
|
+
- **hooks** — React state and side effects, calls services
|
|
68
|
+
- **containers** — wire hooks into UI, no direct data fetching
|
|
69
|
+
- **components** — pure presentational UI, no data dependencies
|
|
70
|
+
- **schemas** — Zod validation for both forms and API responses
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Requirements
|
|
75
|
+
|
|
76
|
+
- Node.js 18+
|
|
77
|
+
- A Next.js project with an `app/` directory (App Router)
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Local Development
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# Clone the repo
|
|
85
|
+
git clone https://github.com/yourname/domain-driver
|
|
86
|
+
cd domain-driver
|
|
87
|
+
|
|
88
|
+
# Install dependencies
|
|
89
|
+
npm install
|
|
90
|
+
|
|
91
|
+
# Build
|
|
92
|
+
npm run build
|
|
93
|
+
|
|
94
|
+
# Link globally for local testing
|
|
95
|
+
npm link
|
|
96
|
+
|
|
97
|
+
# Test it
|
|
98
|
+
domain-driver make:feature test-feature
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Roadmap
|
|
104
|
+
|
|
105
|
+
- [ ] `make:component` — scaffold a single component
|
|
106
|
+
- [ ] `make:hook` — scaffold a custom hook
|
|
107
|
+
- [ ] `make:service` — scaffold a service
|
|
108
|
+
- [ ] Framework detection — auto-adapt structure for Laravel, Go, etc.
|
|
109
|
+
- [ ] Interactive mode — prompt for feature name if not provided
|
|
110
|
+
- [ ] Config file — customize folder structure per project
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## License
|
|
115
|
+
|
|
116
|
+
MIT
|
|
@@ -0,0 +1,71 @@
|
|
|
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.makeFeature = makeFeature;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const FEATURE_DIRS = [
|
|
40
|
+
'components/server',
|
|
41
|
+
'components/client',
|
|
42
|
+
'containers',
|
|
43
|
+
'hooks',
|
|
44
|
+
'services',
|
|
45
|
+
'repositories',
|
|
46
|
+
'schemas',
|
|
47
|
+
];
|
|
48
|
+
function renderTemplate(name) {
|
|
49
|
+
const componentName = name
|
|
50
|
+
.split('-')
|
|
51
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
52
|
+
.join('');
|
|
53
|
+
return `export default function ${componentName}Page() {
|
|
54
|
+
return (
|
|
55
|
+
<div>
|
|
56
|
+
<h1>${componentName}</h1>
|
|
57
|
+
</div>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
`;
|
|
61
|
+
}
|
|
62
|
+
async function makeFeature(name) {
|
|
63
|
+
const base = path.join(process.cwd(), 'app', name);
|
|
64
|
+
for (const dir of FEATURE_DIRS) {
|
|
65
|
+
fs.mkdirSync(path.join(base, dir), { recursive: true });
|
|
66
|
+
fs.writeFileSync(path.join(base, dir, '.gitkeep'), '');
|
|
67
|
+
}
|
|
68
|
+
const page = renderTemplate(name);
|
|
69
|
+
fs.writeFileSync(path.join(base, 'page.tsx'), page);
|
|
70
|
+
console.log(`✅ Feature "${name}" scaffolded at ${base}`);
|
|
71
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const feature_1 = require("./commands/feature");
|
|
5
|
+
const [, , command, name] = process.argv;
|
|
6
|
+
if (!command || !name) {
|
|
7
|
+
console.error('Usage: domain-driver make:feature <name>');
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
if (command === 'make:feature') {
|
|
11
|
+
(0, feature_1.makeFeature)(name);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
console.error(`Unknown command: ${command}`);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "domain-driver",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"domain-driver": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "npx tsc",
|
|
11
|
+
"dev": "ts-node src/index.ts",
|
|
12
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [],
|
|
15
|
+
"author": "",
|
|
16
|
+
"license": "ISC",
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/node": "^25.4.0"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"typescript": "^5.9.3"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
|
|
4
|
+
const FEATURE_DIRS = [
|
|
5
|
+
'components/server',
|
|
6
|
+
'components/client',
|
|
7
|
+
'containers',
|
|
8
|
+
'hooks',
|
|
9
|
+
'services',
|
|
10
|
+
'repositories',
|
|
11
|
+
'schemas',
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
function renderTemplate(name: string): string {
|
|
15
|
+
const componentName = name
|
|
16
|
+
.split('-')
|
|
17
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
18
|
+
.join('');
|
|
19
|
+
|
|
20
|
+
return `export default function ${componentName}Page() {
|
|
21
|
+
return (
|
|
22
|
+
<div>
|
|
23
|
+
<h1>${componentName}</h1>
|
|
24
|
+
</div>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function makeFeature(name: string) {
|
|
31
|
+
const base = path.join(process.cwd(), 'app', name);
|
|
32
|
+
|
|
33
|
+
for (const dir of FEATURE_DIRS) {
|
|
34
|
+
fs.mkdirSync(path.join(base, dir), { recursive: true });
|
|
35
|
+
fs.writeFileSync(path.join(base, dir, '.gitkeep'), '');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const page = renderTemplate(name);
|
|
39
|
+
fs.writeFileSync(path.join(base, 'page.tsx'), page);
|
|
40
|
+
|
|
41
|
+
console.log(`✅ Feature "${name}" scaffolded at ${base}`);
|
|
42
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { makeFeature } from './commands/feature';
|
|
3
|
+
|
|
4
|
+
const [,, command, name] = process.argv;
|
|
5
|
+
|
|
6
|
+
if (!command || !name) {
|
|
7
|
+
console.error('Usage: domain-driver make:feature <name>');
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (command === 'make:feature') {
|
|
12
|
+
makeFeature(name);
|
|
13
|
+
} else {
|
|
14
|
+
console.error(`Unknown command: ${command}`);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"outDir": "./dist",
|
|
6
|
+
"rootDir": "./src",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"types": ["node"]
|
|
10
|
+
},
|
|
11
|
+
"include": ["src/**/*"],
|
|
12
|
+
"exclude": ["node_modules", "dist"]
|
|
13
|
+
}
|