create-epinoetics-app 1.0.1 → 1.0.3
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 +2 -0
- package/package.json +1 -1
- package/src/cloner.js +49 -7
- package/src/scaffold.js +33 -28
package/README
ADDED
package/package.json
CHANGED
package/src/cloner.js
CHANGED
|
@@ -65,17 +65,19 @@ export async function cloneAndMergeNest({ projectName, database, selectedFeature
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
// 3. Prune schema.ts — remove export lines for deleted features
|
|
68
|
-
|
|
68
|
+
pruneSchema({ dest, toRemove });
|
|
69
69
|
|
|
70
|
-
// 4.
|
|
70
|
+
// 4. Prune app.module.ts — remove imports and module references
|
|
71
|
+
pruneAppModule({ dest, toRemove });
|
|
72
|
+
|
|
73
|
+
// 5. Strip .git
|
|
71
74
|
fs.rmSync(join(dest, '.git'), { recursive: true, force: true });
|
|
72
75
|
}
|
|
73
76
|
|
|
74
77
|
// ── Remove export * lines from schema.ts for deleted features ─────
|
|
75
|
-
|
|
78
|
+
function pruneSchema({ dest, toRemove }) {
|
|
76
79
|
if (toRemove.length === 0) return;
|
|
77
80
|
|
|
78
|
-
// Check common schema.ts locations
|
|
79
81
|
const candidates = [
|
|
80
82
|
join(dest, 'src', 'database', 'schema.ts'),
|
|
81
83
|
join(dest, 'src', 'db', 'schema.ts'),
|
|
@@ -92,9 +94,7 @@ async function pruneSchema({ dest, toRemove }) {
|
|
|
92
94
|
const before = content;
|
|
93
95
|
|
|
94
96
|
for (const feature of toRemove) {
|
|
95
|
-
//
|
|
96
|
-
// export * from '../features/posts/post.schema';
|
|
97
|
-
// export * from "../features/seo/seo.schema";
|
|
97
|
+
// Removes: export * from '../features/posts/post.schema';
|
|
98
98
|
const pattern = new RegExp(
|
|
99
99
|
`^export \\* from ['"].*features\\/${feature.id}\\/.*['"];?\\n?`,
|
|
100
100
|
'gm'
|
|
@@ -106,4 +106,46 @@ async function pruneSchema({ dest, toRemove }) {
|
|
|
106
106
|
fs.writeFileSync(schemaPath, content, 'utf8');
|
|
107
107
|
p.log.step(`Pruned schema.ts ${chalk.dim(`(removed ${toRemove.length} export line(s))`)}`);
|
|
108
108
|
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ── Remove import + Module reference from app.module.ts ───────────
|
|
112
|
+
function pruneAppModule({ dest, toRemove }) {
|
|
113
|
+
if (toRemove.length === 0) return;
|
|
114
|
+
|
|
115
|
+
const appModulePath = join(dest, 'src', 'app.module.ts');
|
|
116
|
+
if (!fs.existsSync(appModulePath)) {
|
|
117
|
+
p.log.warn('Could not find app.module.ts — remove unused imports manually.');
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
let content = fs.readFileSync(appModulePath, 'utf8');
|
|
122
|
+
const before = content;
|
|
123
|
+
|
|
124
|
+
for (const feature of toRemove) {
|
|
125
|
+
// Derive the module class name from the feature id:
|
|
126
|
+
// e.g. posts → PostsModule, seo → SeoModule
|
|
127
|
+
const moduleName = feature.id.charAt(0).toUpperCase() + feature.id.slice(1) + 'Module';
|
|
128
|
+
|
|
129
|
+
// Remove the import line:
|
|
130
|
+
// import { PostsModule } from './features/posts/posts.module';
|
|
131
|
+
const importPattern = new RegExp(
|
|
132
|
+
`^import \\{[^}]*${moduleName}[^}]*\\} from ['"].*features\\/${feature.id}\\/.*['"];?\\n?`,
|
|
133
|
+
'gm'
|
|
134
|
+
);
|
|
135
|
+
content = content.replace(importPattern, '');
|
|
136
|
+
|
|
137
|
+
// Remove the module from the imports array:
|
|
138
|
+
// PostsModule, (with optional trailing comma + whitespace/newline)
|
|
139
|
+
// or ,PostsModule (preceded by comma)
|
|
140
|
+
const refPattern = new RegExp(
|
|
141
|
+
`\\n?\\s*${moduleName},?|,?\\s*${moduleName}`,
|
|
142
|
+
'g'
|
|
143
|
+
);
|
|
144
|
+
content = content.replace(refPattern, '');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (content !== before) {
|
|
148
|
+
fs.writeFileSync(appModulePath, content, 'utf8');
|
|
149
|
+
p.log.step(`Pruned app.module.ts ${chalk.dim(`(removed ${toRemove.length} module(s))`)}`);
|
|
150
|
+
}
|
|
109
151
|
}
|
package/src/scaffold.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { join, resolve } from 'path';
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
|
|
4
|
-
export async function writeRootFiles({ projectName,
|
|
4
|
+
export async function writeRootFiles({ projectName, plainRepos = [], backendId, database, features = [], frontendId }) {
|
|
5
5
|
const projectDir = resolve(process.cwd(), projectName);
|
|
6
6
|
|
|
7
7
|
// ── .gitignore ────────────────────────────────────────────────────
|
|
@@ -22,48 +22,53 @@ export async function writeRootFiles({ projectName, selected, backendId, fronten
|
|
|
22
22
|
fs.writeFileSync(join(projectDir, '.gitignore'), gitignore, 'utf8');
|
|
23
23
|
|
|
24
24
|
// ── README.md ─────────────────────────────────────────────────────
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
.join('\n');
|
|
25
|
+
const nestSection = backendId === 'api-nest' ? `
|
|
26
|
+
## NestJS backend
|
|
28
27
|
|
|
29
|
-
|
|
28
|
+
- **Database**: ${database.label}
|
|
29
|
+
- **Features**: ${features.length ? features.map(f => f.label).join(', ') : 'none'}
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
\`\`\`bash
|
|
32
|
+
cd code/api-nest
|
|
33
|
+
# follow README inside
|
|
34
|
+
\`\`\`
|
|
35
|
+
` : '';
|
|
32
36
|
|
|
33
|
-
|
|
37
|
+
const repoLines = plainRepos.map(r =>
|
|
38
|
+
`| \`code/${r.id}\` | ${r.label} | ${r.url} |`
|
|
39
|
+
).join('\n');
|
|
34
40
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
\`\`\`
|
|
41
|
+
const structureLines = [
|
|
42
|
+
backendId === 'api-nest' ? ' ├── api-nest/ ← NestJS' : null,
|
|
43
|
+
backendId === 'api-dotnet' ? ' ├── api-dotnet/ ← .NET Microservices' : null,
|
|
44
|
+
' ├── dashboard/ ← Angular admin panel',
|
|
45
|
+
frontendId ? ` ├── ${frontendId}/` : null,
|
|
46
|
+
].filter(Boolean).join('\n');
|
|
42
47
|
|
|
48
|
+
const repoTableSection = plainRepos.length > 0 ? `
|
|
43
49
|
## Repos
|
|
44
50
|
|
|
45
51
|
| Folder | Name | Source |
|
|
46
52
|
|--------|------|--------|
|
|
47
53
|
${repoLines}
|
|
54
|
+
` : '';
|
|
48
55
|
|
|
49
|
-
|
|
56
|
+
const readme = `# ${projectName}
|
|
50
57
|
|
|
51
|
-
|
|
58
|
+
> Scaffolded with \`create-epinoetics-app\`
|
|
52
59
|
|
|
53
|
-
|
|
54
|
-
# Backend
|
|
55
|
-
cd code/${backendId}
|
|
56
|
-
# follow README inside
|
|
60
|
+
## Structure
|
|
57
61
|
|
|
58
|
-
# Dashboard
|
|
59
|
-
cd code/dashboard
|
|
60
|
-
# follow README inside
|
|
61
|
-
${hasFrontend ? `
|
|
62
|
-
# Frontend
|
|
63
|
-
cd code/${frontendId}
|
|
64
|
-
# follow README inside` : ''}
|
|
65
62
|
\`\`\`
|
|
63
|
+
${projectName}/
|
|
64
|
+
└── code/
|
|
65
|
+
${structureLines}
|
|
66
|
+
\`\`\`
|
|
67
|
+
${nestSection}${repoTableSection}
|
|
68
|
+
## Getting started
|
|
69
|
+
|
|
70
|
+
Each piece is self-contained — navigate into a folder and follow its own README.
|
|
66
71
|
`;
|
|
67
72
|
|
|
68
73
|
fs.writeFileSync(join(projectDir, 'README.md'), readme, 'utf8');
|
|
69
|
-
}
|
|
74
|
+
}
|