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 ADDED
@@ -0,0 +1,2 @@
1
+ ```shell
2
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-epinoetics-app",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Scaffold a new project from your boilerplate repos",
5
5
  "type": "module",
6
6
  "bin": {
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
- await pruneSchema({ dest, toRemove });
68
+ pruneSchema({ dest, toRemove });
69
69
 
70
- // 4. Strip .git
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
- async function pruneSchema({ dest, toRemove }) {
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
- // Matches lines like:
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, selected, backendId, frontendId }) {
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 repoLines = selected
26
- .map(r => `| \`code/${r.id}\` | ${r.label} | ${r.url} |`)
27
- .join('\n');
25
+ const nestSection = backendId === 'api-nest' ? `
26
+ ## NestJS backend
28
27
 
29
- const hasFrontend = !!frontendId;
28
+ - **Database**: ${database.label}
29
+ - **Features**: ${features.length ? features.map(f => f.label).join(', ') : 'none'}
30
30
 
31
- const readme = `# ${projectName}
31
+ \`\`\`bash
32
+ cd code/api-nest
33
+ # follow README inside
34
+ \`\`\`
35
+ ` : '';
32
36
 
33
- > Scaffolded with \`create-myapp\`
37
+ const repoLines = plainRepos.map(r =>
38
+ `| \`code/${r.id}\` | ${r.label} | ${r.url} |`
39
+ ).join('\n');
34
40
 
35
- ## Structure
36
-
37
- \`\`\`
38
- ${projectName}/
39
- └── code/
40
- ${selected.map(r => ` ├── ${r.id}/`).join('\n')}
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
- ## Getting started
56
+ const readme = `# ${projectName}
50
57
 
51
- Each piece is self-contained. Navigate into a folder and follow its own README:
58
+ > Scaffolded with \`create-epinoetics-app\`
52
59
 
53
- \`\`\`bash
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
+ }