@nikelyh/metamorph 2.0.10 → 2.1.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.
@@ -0,0 +1,1256 @@
1
+ // ../domain/src/entities/catalogs/backendCatalog.ts
2
+ var backendCatalog = [
3
+ {
4
+ source: "nestjs",
5
+ target: "express",
6
+ description: "Migration from NestJS framework to a plain Express application structure.",
7
+ filesToDelete: ["nest-cli.json", "tsconfig.build.json"],
8
+ dependenciesToRemove: ["@nestjs/common", "@nestjs/core", "@nestjs/platform-express", "reflect-metadata", "rxjs"],
9
+ dependenciesToAdd: { "express": "^4.18.2" },
10
+ devDependenciesToRemove: ["@nestjs/cli", "@nestjs/schematics", "@nestjs/testing", "@types/express", "@types/supertest", "source-map-support", "supertest"],
11
+ devDependenciesToAdd: { "@types/express": "^4.17.17" },
12
+ architecturalRules: [
13
+ "Remove all NestJS decorators (@Module, @Controller, @Injectable, @Get, @Post, etc.).",
14
+ 'Remove all NestJS core imports (e.g., from "@nestjs/common" or "@nestjs/core").',
15
+ "Controllers must be converted into Express Router factory functions or classes that return an Express Router.",
16
+ "Modules must be converted to plain dependency composition functions or startup scripts that wire Routers together.",
17
+ "Services/Providers must be converted to plain TypeScript classes or functions, with dependencies passed explicitly via constructors (manual dependency injection) since NestJS DI is gone.",
18
+ "Make sure to export the router or the configured Express application, not a Nest module."
19
+ ],
20
+ examples: [
21
+ {
22
+ description: "Converting a NestJS Controller to an Express Router",
23
+ before: `import { Controller, Get } from '@nestjs/common';
24
+ import { AppService } from './app.service';
25
+
26
+ @Controller()
27
+ export class AppController {
28
+ constructor(private readonly appService: AppService) {}
29
+
30
+ @Get()
31
+ getHello(): string {
32
+ return this.appService.getHello();
33
+ }
34
+ }`,
35
+ after: `import { Router } from 'express';
36
+ import { AppService } from './app.service';
37
+
38
+ export function createAppRouter(appService: AppService): Router {
39
+ const router = Router();
40
+
41
+ router.get('/', (req, res) => {
42
+ const result = appService.getHello();
43
+ res.send(result);
44
+ });
45
+
46
+ return router;
47
+ }`
48
+ }
49
+ ]
50
+ },
51
+ {
52
+ source: "express",
53
+ target: "nestjs",
54
+ description: "Migration from a plain Express application to the NestJS framework.",
55
+ dependenciesToRemove: ["express"],
56
+ dependenciesToAdd: {
57
+ "@nestjs/common": "latest",
58
+ "@nestjs/core": "latest",
59
+ "@nestjs/platform-express": "latest",
60
+ "reflect-metadata": "^0.1.13",
61
+ "rxjs": "^7.8.1"
62
+ },
63
+ devDependenciesToRemove: ["@types/express"],
64
+ devDependenciesToAdd: {
65
+ "@nestjs/cli": "latest",
66
+ "@nestjs/schematics": "latest",
67
+ "@nestjs/testing": "latest",
68
+ "@types/supertest": "^2.0.12",
69
+ "source-map-support": "^0.5.21",
70
+ "supertest": "^6.3.3"
71
+ },
72
+ architecturalRules: [
73
+ "Express routing logic must be encapsulated in classes decorated with @Controller().",
74
+ "Business logic must be encapsulated in classes decorated with @Injectable() (Providers/Services).",
75
+ "All Controllers and Providers must be registered in a class decorated with @Module().",
76
+ "Use NestJS decorators for routing (@Get(), @Post(), @Param(), @Body(), etc.) instead of Express route definitions.",
77
+ "Rely on NestJS dependency injection instead of manual class instantiation or function passing.",
78
+ "The entry point must use NestFactory.create() to bootstrap the application, replacing app.listen().",
79
+ "You are authorized to rename, create, or delete files to adhere strictly to the NestJS directory and file structure conventions (e.g., app.module.ts, app.controller.ts, app.service.ts, main.ts)."
80
+ ],
81
+ examples: [
82
+ {
83
+ description: "Converting an Express Router to a NestJS Controller and Service",
84
+ before: `import { Router } from 'express';
85
+ import { getHelloLogic } from './logic';
86
+
87
+ export function createAppRouter(): Router {
88
+ const router = Router();
89
+ router.get('/', (req, res) => {
90
+ res.send(getHelloLogic());
91
+ });
92
+ return router;
93
+ }`,
94
+ after: `import { Controller, Get, Injectable } from '@nestjs/common';
95
+
96
+ @Injectable()
97
+ export class AppService {
98
+ getHello(): string {
99
+ return 'Hello from logic';
100
+ }
101
+ }
102
+
103
+ @Controller()
104
+ export class AppController {
105
+ constructor(private readonly appService: AppService) {}
106
+
107
+ @Get()
108
+ getHello(): string {
109
+ return this.appService.getHello();
110
+ }
111
+ }`
112
+ }
113
+ ]
114
+ },
115
+ {
116
+ source: "nestjs",
117
+ target: "fastify",
118
+ description: "Migration from NestJS framework to a Fastify application structure.",
119
+ filesToDelete: ["nest-cli.json", "tsconfig.build.json"],
120
+ dependenciesToRemove: ["@nestjs/common", "@nestjs/core", "@nestjs/platform-express", "reflect-metadata", "rxjs"],
121
+ dependenciesToAdd: { "fastify": "latest" },
122
+ devDependenciesToRemove: ["@nestjs/cli", "@nestjs/schematics", "@nestjs/testing", "@types/express", "@types/supertest", "source-map-support", "supertest"],
123
+ devDependenciesToAdd: { "fastify-plugin": "latest" },
124
+ architecturalRules: [
125
+ "Remove all NestJS decorators (@Module, @Controller, @Injectable, @Get, @Post, etc.).",
126
+ "Remove all NestJS core imports.",
127
+ "The entry point (main.ts) must initialize a FastifyInstance (fastify()) instead of NestFactory.",
128
+ "Controllers and routing logic must be converted to Fastify route declarations (fastify.get, fastify.post).",
129
+ "Ideally, encapsulate routes and modules as Fastify plugins.",
130
+ "Remove NestJS dependency injection; use standard JavaScript/TypeScript classes or functions passing dependencies directly.",
131
+ "Ensure standard Fastify schema validation (JSON Schema) is added if types or DTOs are available.",
132
+ "You are authorized to rename, create, or delete files to adhere to a standard fastify plugin-based directory structure."
133
+ ],
134
+ examples: [
135
+ {
136
+ description: "Converting a NestJS Controller to a Fastify Plugin",
137
+ before: `import { Controller, Get } from '@nestjs/common';
138
+ import { AppService } from './app.service';
139
+
140
+ @Controller('users')
141
+ export class UsersController {
142
+ constructor(private readonly appService: AppService) {}
143
+
144
+ @Get()
145
+ getUsers() {
146
+ return this.appService.getUsers();
147
+ }
148
+ }`,
149
+ after: `import { FastifyInstance } from 'fastify';
150
+ import { AppService } from './app.service';
151
+
152
+ export default async function usersPlugin(fastify: FastifyInstance, options: any) {
153
+ const appService = new AppService(); // Or inject via options
154
+
155
+ fastify.get('/users', async (request, reply) => {
156
+ return appService.getUsers();
157
+ });
158
+ }`
159
+ }
160
+ ]
161
+ },
162
+ {
163
+ source: "express",
164
+ target: "fastify",
165
+ description: "Migration from a plain Express application to Fastify.",
166
+ dependenciesToRemove: ["express"],
167
+ dependenciesToAdd: { "fastify": "latest", "fastify-plugin": "latest" },
168
+ devDependenciesToRemove: ["@types/express"],
169
+ devDependenciesToAdd: {},
170
+ architecturalRules: [
171
+ "Replace all Express app instantiations with fastify().",
172
+ "Replace Express middleware signatures (req, res, next) with Fastify hooks (onRequest, preHandler, etc.) or Fastify plugins.",
173
+ "Replace Express routing (app.use(), app.get()) with Fastify routing (fastify.get(), fastify.register()).",
174
+ "Replace Express response methods (res.send(), res.json()) with Fastify reply methods (reply.send()) or simply return the payload from the async handler.",
175
+ "Migrate standard Express middlewares (like cors, helmet) to their Fastify native equivalents (@fastify/cors, @fastify/helmet) if they are present.",
176
+ "You are authorized to rename, create, or delete files to restructure the Express app into modular Fastify plugins."
177
+ ],
178
+ examples: [
179
+ {
180
+ description: "Converting an Express Route to a Fastify Route",
181
+ before: `const express = require('express');
182
+ const app = express();
183
+
184
+ app.get('/api/data', (req, res) => {
185
+ res.json({ message: 'Hello Express' });
186
+ });
187
+
188
+ app.listen(3000);`,
189
+ after: `import Fastify from 'fastify';
190
+
191
+ const fastify = Fastify({ logger: true });
192
+
193
+ fastify.get('/api/data', async (request, reply) => {
194
+ return { message: 'Hello Fastify' };
195
+ });
196
+
197
+ fastify.listen({ port: 3000 }, (err) => {
198
+ if (err) {
199
+ fastify.log.error(err);
200
+ process.exit(1);
201
+ }
202
+ });`
203
+ }
204
+ ]
205
+ },
206
+ {
207
+ source: "fastify",
208
+ target: "express",
209
+ description: "Migration from a Fastify application to Express.",
210
+ dependenciesToRemove: ["fastify", "fastify-plugin"],
211
+ dependenciesToAdd: { "express": "latest" },
212
+ devDependenciesToRemove: [],
213
+ devDependenciesToAdd: { "@types/express": "latest" },
214
+ architecturalRules: [
215
+ "Replace all fastify() app instantiations with express().",
216
+ "Replace Fastify hooks (onRequest, preHandler, etc.) with standard Express middleware signatures (req, res, next).",
217
+ "Replace Fastify routing (fastify.get, fastify.register) with Express routing (app.get, express.Router().use).",
218
+ "Replace Fastify reply methods (reply.send) or implicit returns with Express response methods (res.send, res.json).",
219
+ "CRITICAL: Fastify catches async errors automatically. When migrating to Express, ensure all asynchronous route handlers use try/catch blocks passing the error to next(err), or wrap them in an async wrapper.",
220
+ "You are authorized to rename, create, or delete files to restructure the Fastify plugins into standard Express routers."
221
+ ],
222
+ examples: [
223
+ {
224
+ description: "Converting a Fastify Route to an Express Route",
225
+ before: `import Fastify from 'fastify';
226
+
227
+ const fastify = Fastify();
228
+
229
+ fastify.get('/api/data', async (request, reply) => {
230
+ return { message: 'Hello Fastify' };
231
+ });
232
+
233
+ fastify.listen({ port: 3000 });`,
234
+ after: `const express = require('express');
235
+ const app = express();
236
+
237
+ app.get('/api/data', async (req, res, next) => {
238
+ try {
239
+ res.json({ message: 'Hello Fastify' });
240
+ } catch (err) {
241
+ next(err);
242
+ }
243
+ });
244
+
245
+ app.listen(3000);`
246
+ }
247
+ ]
248
+ },
249
+ {
250
+ source: "fastify",
251
+ target: "nestjs",
252
+ description: "Migration from Fastify framework to NestJS (using platform-express by default).",
253
+ dependenciesToRemove: ["fastify", "fastify-plugin"],
254
+ dependenciesToAdd: {
255
+ "@nestjs/common": "latest",
256
+ "@nestjs/core": "latest",
257
+ "@nestjs/platform-express": "latest",
258
+ "reflect-metadata": "^0.1.13",
259
+ "rxjs": "^7.8.1"
260
+ },
261
+ devDependenciesToRemove: [],
262
+ devDependenciesToAdd: {
263
+ "@nestjs/cli": "latest",
264
+ "@nestjs/schematics": "latest",
265
+ "@nestjs/testing": "latest",
266
+ "@types/supertest": "^2.0.12",
267
+ "source-map-support": "^0.5.21",
268
+ "supertest": "^6.3.3"
269
+ },
270
+ architecturalRules: [
271
+ "Fastify routing logic must be encapsulated in classes decorated with @Controller().",
272
+ "Business logic must be encapsulated in classes decorated with @Injectable() (Providers/Services).",
273
+ "All Controllers and Providers must be registered in a class decorated with @Module().",
274
+ "Use NestJS decorators for routing (@Get(), @Post(), @Param(), @Body(), etc.) instead of fastify route definitions.",
275
+ "Rely on NestJS dependency injection instead of Fastify decorators or options passing.",
276
+ "The entry point must use NestFactory.create() to bootstrap the application, replacing fastify().",
277
+ "You are authorized to rename, create, or delete files to adhere strictly to the NestJS directory and file structure conventions (e.g., app.module.ts, app.controller.ts, app.service.ts, main.ts)."
278
+ ],
279
+ examples: [
280
+ {
281
+ description: "Converting a Fastify Plugin to a NestJS Controller and Service",
282
+ before: `export default async function usersPlugin(fastify, options) {
283
+ fastify.get('/users', async (request, reply) => {
284
+ return { users: [] };
285
+ });
286
+ }`,
287
+ after: `import { Controller, Get, Injectable } from '@nestjs/common';
288
+
289
+ @Injectable()
290
+ export class UsersService {
291
+ getUsers() {
292
+ return { users: [] };
293
+ }
294
+ }
295
+
296
+ @Controller('users')
297
+ export class UsersController {
298
+ constructor(private readonly usersService: UsersService) {}
299
+
300
+ @Get()
301
+ getUsers() {
302
+ return this.usersService.getUsers();
303
+ }
304
+ }`
305
+ }
306
+ ]
307
+ }
308
+ ];
309
+
310
+ // ../domain/src/entities/catalogs/scaffolds.ts
311
+ var VITE_SPA_SCRIPTS = {
312
+ dev: "vite",
313
+ build: "vite build",
314
+ preview: "vite preview",
315
+ start: "vite preview"
316
+ };
317
+ var NEXT_SCRIPTS = {
318
+ dev: "next dev",
319
+ build: "next build",
320
+ start: "next start",
321
+ lint: "next lint"
322
+ };
323
+ var ANGULAR_SCRIPTS = {
324
+ dev: "ng serve",
325
+ build: "ng build",
326
+ start: "ng serve"
327
+ };
328
+ var REACT_VITE_SCAFFOLDS = {
329
+ "index.html": `<!DOCTYPE html>
330
+ <html lang="en">
331
+ <head>
332
+ <meta charset="UTF-8" />
333
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
334
+ <title>App</title>
335
+ </head>
336
+ <body>
337
+ <div id="root"></div>
338
+ <script type="module" src="/src/main.tsx"></script>
339
+ </body>
340
+ </html>
341
+ `,
342
+ "vite.config.ts": `import { defineConfig } from 'vite';
343
+ import react from '@vitejs/plugin-react';
344
+ import path from 'node:path';
345
+
346
+ export default defineConfig({
347
+ plugins: [react()],
348
+ resolve: {
349
+ alias: {
350
+ '@': path.resolve(import.meta.dirname, './src'),
351
+ },
352
+ },
353
+ });
354
+ `
355
+ };
356
+ var VUE_SCAFFOLDS = {
357
+ "index.html": `<!DOCTYPE html>
358
+ <html lang="en">
359
+ <head>
360
+ <meta charset="UTF-8" />
361
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
362
+ <title>App</title>
363
+ </head>
364
+ <body>
365
+ <div id="app"></div>
366
+ <script type="module" src="/src/main.ts"></script>
367
+ </body>
368
+ </html>
369
+ `,
370
+ "vite.config.ts": `import { defineConfig } from 'vite';
371
+ import vue from '@vitejs/plugin-vue';
372
+ import path from 'node:path';
373
+
374
+ export default defineConfig({
375
+ plugins: [vue()],
376
+ resolve: {
377
+ alias: {
378
+ '@': path.resolve(import.meta.dirname, './src'),
379
+ },
380
+ },
381
+ });
382
+ `,
383
+ "src/vite-env.d.ts": `/// <reference types="vite/client" />
384
+ declare module '*.vue' {
385
+ import type { DefineComponent } from 'vue';
386
+ const component: DefineComponent<object, object, unknown>;
387
+ export default component;
388
+ }
389
+ `
390
+ };
391
+ var SVELTE_SCAFFOLDS = {
392
+ "index.html": `<!DOCTYPE html>
393
+ <html lang="en">
394
+ <head>
395
+ <meta charset="UTF-8" />
396
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
397
+ <title>App</title>
398
+ </head>
399
+ <body>
400
+ <div id="app"></div>
401
+ <script type="module" src="/src/main.ts"></script>
402
+ </body>
403
+ </html>
404
+ `,
405
+ "vite.config.ts": `import { defineConfig } from 'vite';
406
+ import { svelte } from '@sveltejs/vite-plugin-svelte';
407
+ import path from 'node:path';
408
+
409
+ export default defineConfig({
410
+ plugins: [svelte()],
411
+ resolve: {
412
+ alias: {
413
+ '@': path.resolve(import.meta.dirname, './src'),
414
+ },
415
+ },
416
+ });
417
+ `,
418
+ "svelte.config.js": `import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
419
+
420
+ export default {
421
+ preprocess: vitePreprocess(),
422
+ };
423
+ `,
424
+ "src/vite-env.d.ts": `/// <reference types="svelte" />
425
+ /// <reference types="vite/client" />
426
+ `
427
+ };
428
+ var ANGULAR_SCAFFOLDS = {
429
+ "angular.json": `{
430
+ "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
431
+ "version": 1,
432
+ "newProjectRoot": "projects",
433
+ "projects": {
434
+ "app": {
435
+ "projectType": "application",
436
+ "root": "",
437
+ "sourceRoot": "src",
438
+ "prefix": "app",
439
+ "architect": {
440
+ "build": {
441
+ "builder": "@angular-devkit/build-angular:application",
442
+ "options": {
443
+ "outputPath": "dist/app",
444
+ "index": "src/index.html",
445
+ "browser": "src/main.ts",
446
+ "tsConfig": "tsconfig.app.json",
447
+ "assets": [{ "glob": "**/*", "input": "public" }],
448
+ "styles": ["src/styles.css"]
449
+ },
450
+ "configurations": {
451
+ "production": { "outputHashing": "all" },
452
+ "development": { "optimization": false, "sourceMap": true }
453
+ },
454
+ "defaultConfiguration": "production"
455
+ },
456
+ "serve": {
457
+ "builder": "@angular-devkit/build-angular:dev-server",
458
+ "configurations": {
459
+ "production": { "buildTarget": "app:build:production" },
460
+ "development": { "buildTarget": "app:build:development" }
461
+ },
462
+ "defaultConfiguration": "development"
463
+ }
464
+ }
465
+ }
466
+ }
467
+ }
468
+ `,
469
+ "tsconfig.app.json": `{
470
+ "extends": "./tsconfig.json",
471
+ "compilerOptions": {
472
+ "outDir": "./out-tsc/app",
473
+ "types": []
474
+ },
475
+ "files": ["src/main.ts"],
476
+ "include": ["src/**/*.d.ts", "src/**/*.ts"]
477
+ }
478
+ `,
479
+ "src/index.html": `<!DOCTYPE html>
480
+ <html lang="en">
481
+ <head>
482
+ <meta charset="utf-8" />
483
+ <title>App</title>
484
+ <base href="/" />
485
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
486
+ </head>
487
+ <body>
488
+ <app-root></app-root>
489
+ </body>
490
+ </html>
491
+ `,
492
+ "src/main.ts": `import { bootstrapApplication } from '@angular/platform-browser';
493
+ import { App } from './app/app';
494
+ import { appConfig } from './app/app.config';
495
+
496
+ bootstrapApplication(App, appConfig).catch((err) => console.error(err));
497
+ `,
498
+ "src/app/app.config.ts": `import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
499
+ import { provideRouter } from '@angular/router';
500
+ import { routes } from './app.routes';
501
+
502
+ export const appConfig: ApplicationConfig = {
503
+ providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes)],
504
+ };
505
+ `,
506
+ "src/app/app.routes.ts": `import { Routes } from '@angular/router';
507
+
508
+ /** Worker: map each source URL to the existing feature component. Do not inline that component's template here. */
509
+ export const routes: Routes = [];
510
+ `,
511
+ "src/app/app.ts": `import { Component } from '@angular/core';
512
+ import { RouterOutlet } from '@angular/router';
513
+
514
+ @Component({
515
+ selector: 'app-root',
516
+ imports: [RouterOutlet],
517
+ template: '<router-outlet />',
518
+ })
519
+ export class App {}
520
+ `,
521
+ "src/styles.css": `/* Global styles \u2014 Worker should import/copy the source global stylesheet here. */
522
+ `
523
+ };
524
+ var NEXT_SCAFFOLDS = {
525
+ "next.config.ts": `import type { NextConfig } from 'next';
526
+
527
+ const nextConfig: NextConfig = {
528
+ reactStrictMode: true,
529
+ };
530
+
531
+ export default nextConfig;
532
+ `,
533
+ "src/app/layout.tsx": `import type { ReactNode } from 'react';
534
+ import '../index.css';
535
+
536
+ export default function RootLayout({ children }: { children: ReactNode }) {
537
+ return (
538
+ <html lang="en">
539
+ <body>{children}</body>
540
+ </html>
541
+ );
542
+ }
543
+ `
544
+ };
545
+ var VITE_FILES_TO_DELETE = ["vite.config.ts", "vite.config.js"];
546
+ var NEXT_FILES_TO_DELETE = ["next.config.js", "next.config.mjs", "next.config.ts", "next-env.d.ts"];
547
+ var ANGULAR_FILES_TO_DELETE = ["angular.json"];
548
+ var VUE_FILES_TO_DELETE = ["vue.config.js"];
549
+ var SVELTE_FILES_TO_DELETE = ["svelte.config.js", "svelte.config.ts"];
550
+
551
+ // ../domain/src/entities/catalogs/frontendCatalog.ts
552
+ var REACT_DEPS = { react: "latest", "react-dom": "latest", "react-router-dom": "latest" };
553
+ var REACT_DEV = { vite: "latest", "@vitejs/plugin-react": "latest" };
554
+ var VUE_DEPS = { vue: "latest", "vue-router": "latest" };
555
+ var VUE_DEV = { vite: "latest", "@vitejs/plugin-vue": "latest" };
556
+ var SVELTE_DEPS = { svelte: "latest" };
557
+ var SVELTE_DEV = { vite: "latest", "@sveltejs/vite-plugin-svelte": "latest" };
558
+ var ANGULAR_DEPS = {
559
+ "@angular/animations": "latest",
560
+ "@angular/common": "latest",
561
+ "@angular/compiler": "latest",
562
+ "@angular/core": "latest",
563
+ "@angular/forms": "latest",
564
+ "@angular/platform-browser": "latest",
565
+ "@angular/router": "latest",
566
+ rxjs: "latest",
567
+ tslib: "latest",
568
+ "zone.js": "latest"
569
+ };
570
+ var ANGULAR_DEV = {
571
+ "@angular-devkit/build-angular": "latest",
572
+ "@angular/cli": "latest",
573
+ "@angular/compiler-cli": "latest",
574
+ typescript: "~5.8.0"
575
+ };
576
+ var REACT_REMOVE = ["react", "react-dom", "react-router-dom"];
577
+ var REACT_DEV_REMOVE = ["@vitejs/plugin-react"];
578
+ var NEXT_REMOVE = ["next"];
579
+ var VUE_REMOVE = ["vue", "vue-router", "pinia", "vuex"];
580
+ var VUE_DEV_REMOVE = ["@vitejs/plugin-vue"];
581
+ var SVELTE_REMOVE = ["svelte", "svelte-spa-router", "@sveltejs/kit"];
582
+ var SVELTE_DEV_REMOVE = ["@sveltejs/vite-plugin-svelte", "@sveltejs/kit"];
583
+ var ANGULAR_REMOVE = [
584
+ "@angular/animations",
585
+ "@angular/common",
586
+ "@angular/compiler",
587
+ "@angular/core",
588
+ "@angular/forms",
589
+ "@angular/platform-browser",
590
+ "@angular/platform-browser-dynamic",
591
+ "@angular/router",
592
+ "zone.js"
593
+ ];
594
+ var ANGULAR_DEV_REMOVE = ["@angular/cli", "@angular/compiler-cli", "@angular-devkit/build-angular"];
595
+ var TO_REACT = {
596
+ dependenciesToAdd: REACT_DEPS,
597
+ devDependenciesToAdd: REACT_DEV,
598
+ scriptsToUpdate: VITE_SPA_SCRIPTS,
599
+ filesToScaffold: REACT_VITE_SCAFFOLDS
600
+ };
601
+ var TO_VUE = {
602
+ dependenciesToAdd: VUE_DEPS,
603
+ devDependenciesToAdd: VUE_DEV,
604
+ scriptsToUpdate: VITE_SPA_SCRIPTS,
605
+ filesToScaffold: VUE_SCAFFOLDS
606
+ };
607
+ var TO_SVELTE = {
608
+ dependenciesToAdd: SVELTE_DEPS,
609
+ devDependenciesToAdd: SVELTE_DEV,
610
+ scriptsToUpdate: VITE_SPA_SCRIPTS,
611
+ filesToScaffold: SVELTE_SCAFFOLDS
612
+ };
613
+ var TO_ANGULAR = {
614
+ dependenciesToAdd: ANGULAR_DEPS,
615
+ devDependenciesToAdd: ANGULAR_DEV,
616
+ scriptsToUpdate: ANGULAR_SCRIPTS,
617
+ scriptsToRemove: ["preview"],
618
+ filesToScaffold: ANGULAR_SCAFFOLDS
619
+ };
620
+ var TO_NEXT = {
621
+ dependenciesToAdd: { next: "latest", react: "latest", "react-dom": "latest" },
622
+ devDependenciesToAdd: {},
623
+ scriptsToUpdate: NEXT_SCRIPTS,
624
+ scriptsToRemove: ["preview"],
625
+ filesToScaffold: NEXT_SCAFFOLDS
626
+ };
627
+ var frontendCatalog = [
628
+ {
629
+ source: "react",
630
+ target: "next",
631
+ description: "Migration from a plain React SPA (Vite or CRA) to Next.js App Router.",
632
+ filesToDelete: [...VITE_FILES_TO_DELETE, "index.html"],
633
+ dependenciesToRemove: ["react-router-dom", "vite", "@vitejs/plugin-react"],
634
+ ...TO_NEXT,
635
+ architecturalRules: [
636
+ 'Map react-router routes to src/app/**/page.tsx. Home ("/") is src/app/page.tsx importing the former home screen.',
637
+ "If SPA UI lived under src/pages, move that tree out (Next reserves src/pages). Import those screens from src/app/**/page.tsx. Do not leave UI under src/pages.",
638
+ "Delete the old SPA entry (main/App) after App Router files render real UI. Never import the old App from page.tsx (cycles / SSR crashes).",
639
+ 'Add "use client" only on files that use browser APIs or hooks.',
640
+ "Replace react-router Link with next/link. Keep the imported screen's public prop names at the page.tsx wrapper."
641
+ ],
642
+ examples: [
643
+ {
644
+ description: "Wrap an existing screen; do not re-implement it",
645
+ before: `// router table
646
+ <Route path="/" element={<HomeScreen />} />`,
647
+ after: `// src/app/page.tsx
648
+ 'use client';
649
+ import HomeScreen from '../screens/HomeScreen';
650
+ export default function Page() {
651
+ return <HomeScreen />;
652
+ }`
653
+ }
654
+ ]
655
+ },
656
+ {
657
+ source: "next",
658
+ target: "react",
659
+ description: "Migration from Next.js to a Vite React SPA.",
660
+ filesToDelete: NEXT_FILES_TO_DELETE,
661
+ dependenciesToRemove: NEXT_REMOVE,
662
+ ...TO_REACT,
663
+ architecturalRules: [
664
+ "Replace App Router / Pages Router with react-router-dom. src/main.tsx wraps BrowserRouter and renders the former home screen.",
665
+ 'Strip "use client" / "use server". Replace next/link with react-router Link (href \u2192 to). Replace next/image with img.',
666
+ "Move layout.tsx global CSS import to src/main.tsx. Delete leftover src/app/page.tsx and layout.tsx after the SPA boots.",
667
+ "Do not use __dirname in vite.config.ts ESM."
668
+ ]
669
+ },
670
+ {
671
+ source: "vue",
672
+ target: "react",
673
+ description: "Vue 3 SFC \u2192 React function components on Vite.",
674
+ filesToDelete: [...VUE_FILES_TO_DELETE],
675
+ dependenciesToRemove: VUE_REMOVE,
676
+ devDependenciesToRemove: VUE_DEV_REMOVE,
677
+ ...TO_REACT,
678
+ architecturalRules: [
679
+ "Convert each .vue SFC to .tsx: <template> \u2192 JSX, <script setup> \u2192 function body, keep <style> as an imported CSS module or colocated css.",
680
+ "defineProps fields stay prop names. Each emit X becomes onX (or the equivalent) with the same X. v-model stays whatever the SFC declared (modelValue / update:modelValue unless the source used another name).",
681
+ "vue-router routes become react-router <Route> entries that import the converted screen. src/main.tsx mounts into #root.",
682
+ "Pinia/Vuex stores become modules/hooks; keep action and getter names. Delete leftover .vue files after the .tsx exists."
683
+ ]
684
+ },
685
+ {
686
+ source: "react",
687
+ target: "vue",
688
+ description: "React function components \u2192 Vue 3 SFCs on Vite.",
689
+ filesToDelete: [...VITE_FILES_TO_DELETE, "index.html"],
690
+ dependenciesToRemove: REACT_REMOVE,
691
+ devDependenciesToRemove: REACT_DEV_REMOVE,
692
+ ...TO_VUE,
693
+ architecturalRules: [
694
+ "Convert each .tsx/.jsx component to a .vue SFC with <script setup>. JSX return \u2192 <template>. useState \u2192 ref/reactive; useMemo \u2192 computed; useEffect \u2192 watch/onMounted.",
695
+ "Function props stay defineProps names. Callback props stay the same names (as props or as defineEmits of the same event). Do not invent new event names.",
696
+ 'react-router becomes vue-router. App.vue has <router-view />. src/main.ts createApp(App).use(router).mount("#app").',
697
+ "index.html must use #app (replace #root). Delete leftover .tsx screens after the SFC exists."
698
+ ]
699
+ },
700
+ {
701
+ source: "svelte",
702
+ target: "react",
703
+ description: "Svelte components \u2192 React function components on Vite.",
704
+ filesToDelete: SVELTE_FILES_TO_DELETE,
705
+ dependenciesToRemove: SVELTE_REMOVE,
706
+ devDependenciesToRemove: SVELTE_DEV_REMOVE,
707
+ ...TO_REACT,
708
+ architecturalRules: [
709
+ "Convert each .svelte file to .tsx. $props()/export let names stay prop names. Dispatcher events foo become onFoo.",
710
+ "$state/$derived/$effect (or let/$: ) map to useState/useMemo/useEffect. Keep the same data flow.",
711
+ "If the source used svelte-spa-router or a manual screen map, rebuild it with react-router importing those screens. Mount into #root.",
712
+ "Delete leftover .svelte files after the React files exist. This is a Vite SPA, not Next."
713
+ ]
714
+ },
715
+ {
716
+ source: "react",
717
+ target: "svelte",
718
+ description: "React function components \u2192 Svelte 5 on Vite.",
719
+ filesToDelete: [...VITE_FILES_TO_DELETE, "index.html"],
720
+ dependenciesToRemove: REACT_REMOVE,
721
+ devDependenciesToRemove: REACT_DEV_REMOVE,
722
+ ...TO_SVELTE,
723
+ architecturalRules: [
724
+ "Convert each .tsx component to .svelte. Props become $props() with the same names. Callbacks stay the same names as emits or callback props \u2014 do not rename.",
725
+ "useState \u2192 $state, useMemo \u2192 $derived, useEffect \u2192 $effect. Keep business logic.",
726
+ "react-router becomes a map in App.svelte (or svelte-spa-router) that renders existing screens. src/main.ts mount(App, { target: #app }).",
727
+ "index.html uses #app. Do not create SvelteKit +page.svelte routes. Delete leftover .tsx after the .svelte exists."
728
+ ]
729
+ },
730
+ {
731
+ source: "angular",
732
+ target: "react",
733
+ description: "Angular standalone/NgModule \u2192 React SPA on Vite.",
734
+ filesToDelete: ANGULAR_FILES_TO_DELETE,
735
+ dependenciesToRemove: ANGULAR_REMOVE,
736
+ devDependenciesToRemove: ANGULAR_DEV_REMOVE,
737
+ ...TO_REACT,
738
+ architecturalRules: [
739
+ "Each @Component becomes a function component. @Input() names stay props. @Output() foo stays onFoo. Do not alias them in a wrapper.",
740
+ "Templates (*ngIf, *ngFor, [ngModel]) become JSX. Keep component CSS (styleUrls) as imported stylesheets.",
741
+ "app.routes.ts paths become react-router routes importing those converted components. src/main.tsx mounts into #root.",
742
+ "Services with HTTP become modules/hooks; keep method names. Delete src/index.html Angular shell after Vite index.html exists. Strip Zone.js."
743
+ ]
744
+ },
745
+ {
746
+ source: "react",
747
+ target: "angular",
748
+ description: "React SPA \u2192 Angular standalone + CLI.",
749
+ filesToDelete: [...VITE_FILES_TO_DELETE, "index.html"],
750
+ dependenciesToRemove: [...REACT_REMOVE, "vite"],
751
+ devDependenciesToRemove: REACT_DEV_REMOVE,
752
+ ...TO_ANGULAR,
753
+ architecturalRules: [
754
+ "Each function component becomes a standalone @Component. Props become @Input() with the same names; onFoo becomes @Output() foo.",
755
+ "app.ts is a shell with <router-outlet />. app.routes.ts lists former react-router paths pointing at those components \u2014 do not paste screen templates into App.",
756
+ "Copy global CSS into src/styles.css (angular.json styles). Delete Vite index.html / vite.config after src/index.html and src/main.ts exist.",
757
+ 'Do not introduce an extra wrapper component that remaps inputs to "Angular style" names.'
758
+ ]
759
+ },
760
+ {
761
+ source: "next",
762
+ target: "vue",
763
+ description: "Next.js App Router \u2192 Vue 3 Vite SPA.",
764
+ filesToDelete: NEXT_FILES_TO_DELETE,
765
+ dependenciesToRemove: [...NEXT_REMOVE, ...REACT_REMOVE],
766
+ devDependenciesToRemove: [],
767
+ ...TO_VUE,
768
+ architecturalRules: [
769
+ "Each App Router page.tsx becomes a vue-router route that imports the converted SFC of that screen \u2014 do not re-implement the page in the router.",
770
+ "Strip next/link, next/image, use client. layout.tsx CSS import moves to src/main.ts. Delete leftover src/app after Vue boots."
771
+ ]
772
+ },
773
+ {
774
+ source: "vue",
775
+ target: "next",
776
+ description: "Vue 3 SPA \u2192 Next.js App Router.",
777
+ filesToDelete: [...VITE_FILES_TO_DELETE, ...VUE_FILES_TO_DELETE, "index.html"],
778
+ dependenciesToRemove: [...VUE_REMOVE, "vite"],
779
+ devDependenciesToRemove: VUE_DEV_REMOVE,
780
+ ...TO_NEXT,
781
+ architecturalRules: [
782
+ "Each vue-router path becomes src/app/<path>/page.tsx that imports the converted React screen (from the SFC). Home is src/app/page.tsx.",
783
+ "If SPA UI lived under src/pages, move it out of that folder first. Keep emit/prop names when wrapping in page.tsx."
784
+ ]
785
+ },
786
+ {
787
+ source: "next",
788
+ target: "svelte",
789
+ description: "Next.js \u2192 Svelte 5 Vite SPA.",
790
+ filesToDelete: NEXT_FILES_TO_DELETE,
791
+ dependenciesToRemove: [...NEXT_REMOVE, ...REACT_REMOVE],
792
+ ...TO_SVELTE,
793
+ architecturalRules: [
794
+ "Each App Router page becomes a .svelte screen imported from App.svelte (SPA map), not SvelteKit +page.svelte.",
795
+ "Move layout CSS to src/main.ts. Delete leftover src/app after mount() works."
796
+ ]
797
+ },
798
+ {
799
+ source: "svelte",
800
+ target: "next",
801
+ description: "Svelte Vite SPA \u2192 Next.js App Router.",
802
+ filesToDelete: [...VITE_FILES_TO_DELETE, ...SVELTE_FILES_TO_DELETE, "index.html"],
803
+ dependenciesToRemove: [...SVELTE_REMOVE, "vite"],
804
+ devDependenciesToRemove: SVELTE_DEV_REMOVE,
805
+ ...TO_NEXT,
806
+ architecturalRules: [
807
+ "Each Svelte screen becomes a React component imported from src/app/**/page.tsx. Do not re-implement the screen in the route file.",
808
+ "Keep $props / dispatcher names as React props. Home is src/app/page.tsx."
809
+ ]
810
+ },
811
+ {
812
+ source: "next",
813
+ target: "angular",
814
+ description: "Next.js \u2192 Angular CLI standalone.",
815
+ filesToDelete: [...NEXT_FILES_TO_DELETE, "index.html"],
816
+ dependenciesToRemove: [...NEXT_REMOVE, ...REACT_REMOVE],
817
+ ...TO_ANGULAR,
818
+ architecturalRules: [
819
+ "Each App Router page becomes an Angular standalone component referenced from app.routes.ts. App is only <router-outlet />.",
820
+ "layout.tsx CSS goes to src/styles.css. Delete leftover src/app Next files after Angular src/app exists \u2014 they are different trees; finish the Angular files first, then remove page.tsx/layout.tsx."
821
+ ]
822
+ },
823
+ {
824
+ source: "angular",
825
+ target: "next",
826
+ description: "Angular \u2192 Next.js App Router.",
827
+ filesToDelete: [...ANGULAR_FILES_TO_DELETE],
828
+ dependenciesToRemove: ANGULAR_REMOVE,
829
+ devDependenciesToRemove: ANGULAR_DEV_REMOVE,
830
+ ...TO_NEXT,
831
+ architecturalRules: [
832
+ "Each Angular route component becomes a React screen imported from src/app/**/page.tsx. Keep @Input/@Output names as props.",
833
+ "Delete src/index.html Angular shell after Next layout.tsx exists. Move global styles into the Next layout import."
834
+ ]
835
+ },
836
+ {
837
+ source: "vue",
838
+ target: "svelte",
839
+ description: "Vue 3 SFC \u2192 Svelte 5 on Vite.",
840
+ filesToDelete: VUE_FILES_TO_DELETE,
841
+ dependenciesToRemove: VUE_REMOVE,
842
+ devDependenciesToRemove: VUE_DEV_REMOVE,
843
+ ...TO_SVELTE,
844
+ architecturalRules: [
845
+ "Each .vue SFC becomes .svelte. defineProps \u2192 $props with the same names. defineEmits names stay the same \u2014 do not invent names.",
846
+ "vue-router table becomes App.svelte screen map (or svelte-spa-router). Keep #app. Delete leftover .vue after conversion."
847
+ ]
848
+ },
849
+ {
850
+ source: "svelte",
851
+ target: "vue",
852
+ description: "Svelte \u2192 Vue 3 SFC on Vite.",
853
+ filesToDelete: SVELTE_FILES_TO_DELETE,
854
+ dependenciesToRemove: SVELTE_REMOVE,
855
+ devDependenciesToRemove: SVELTE_DEV_REMOVE,
856
+ ...TO_VUE,
857
+ architecturalRules: [
858
+ "Each .svelte file becomes .vue <script setup>. $props names stay defineProps. Dispatcher events stay defineEmits names.",
859
+ "SPA map becomes vue-router. Keep #app. Delete leftover .svelte after conversion."
860
+ ]
861
+ },
862
+ {
863
+ source: "vue",
864
+ target: "angular",
865
+ description: "Vue 3 \u2192 Angular standalone + CLI.",
866
+ filesToDelete: [...VITE_FILES_TO_DELETE, ...VUE_FILES_TO_DELETE, "index.html"],
867
+ dependenciesToRemove: [...VUE_REMOVE, "vite"],
868
+ devDependenciesToRemove: VUE_DEV_REMOVE,
869
+ ...TO_ANGULAR,
870
+ architecturalRules: [
871
+ 'Each SFC becomes a standalone @Component. defineProps \u2192 @Input same names; defineEmits("add") \u2192 @Output() add.',
872
+ "vue-router paths become app.routes.ts. App is <router-outlet />. Global CSS \u2192 src/styles.css."
873
+ ]
874
+ },
875
+ {
876
+ source: "angular",
877
+ target: "vue",
878
+ description: "Angular \u2192 Vue 3 Vite SPA.",
879
+ filesToDelete: ANGULAR_FILES_TO_DELETE,
880
+ dependenciesToRemove: ANGULAR_REMOVE,
881
+ devDependenciesToRemove: ANGULAR_DEV_REMOVE,
882
+ ...TO_VUE,
883
+ architecturalRules: [
884
+ 'Each Angular component becomes a .vue SFC. @Input \u2192 defineProps; @Output foo \u2192 defineEmits(["foo"]).',
885
+ "app.routes.ts becomes vue-router. Mount #app. Delete Angular src/index.html after Vite index.html exists."
886
+ ]
887
+ },
888
+ {
889
+ source: "svelte",
890
+ target: "angular",
891
+ description: "Svelte Vite SPA \u2192 Angular CLI.",
892
+ filesToDelete: [...VITE_FILES_TO_DELETE, ...SVELTE_FILES_TO_DELETE, "index.html"],
893
+ dependenciesToRemove: [...SVELTE_REMOVE, "vite"],
894
+ devDependenciesToRemove: SVELTE_DEV_REMOVE,
895
+ ...TO_ANGULAR,
896
+ architecturalRules: [
897
+ "Each .svelte screen becomes a standalone @Component. $props names \u2192 @Input; dispatcher events \u2192 @Output with the same names.",
898
+ "App.svelte map becomes app.routes.ts. App is <router-outlet />."
899
+ ]
900
+ },
901
+ {
902
+ source: "angular",
903
+ target: "svelte",
904
+ description: "Angular \u2192 Svelte 5 Vite SPA.",
905
+ filesToDelete: ANGULAR_FILES_TO_DELETE,
906
+ dependenciesToRemove: ANGULAR_REMOVE,
907
+ devDependenciesToRemove: ANGULAR_DEV_REMOVE,
908
+ ...TO_SVELTE,
909
+ architecturalRules: [
910
+ "Each Angular component becomes .svelte. @Input \u2192 $props; @Output foo \u2192 onFoo / emit foo \u2014 same names.",
911
+ "app.routes.ts becomes App.svelte SPA map, not SvelteKit. Mount #app. Delete Angular src/index.html after Vite index.html exists."
912
+ ]
913
+ }
914
+ ];
915
+
916
+ // ../domain/src/entities/catalogs/frameworks/index.ts
917
+ var FRAMEWORK_PACKS = {
918
+ react: {
919
+ contract: [
920
+ "React SPA bootstrap is index.html + src/main.tsx (or main.jsx) mounting into #root with createRoot.",
921
+ "When React is the target, createRoot(...).render must mount the real application (router + screens), not an empty div or placeholder."
922
+ ],
923
+ components: [
924
+ "UI is function components. Preserve hooks, context, and the existing prop names of each component.",
925
+ "Callback/event prop names declared on a component are its public API. A wrapper that renames them to look idiomatic still compiles and often crashes at runtime."
926
+ ],
927
+ routing: [
928
+ "SPA routing is react-router-dom (BrowserRouter / createBrowserRouter). Routes render existing screen components."
929
+ ],
930
+ styling: [
931
+ 'Global CSS must be imported from the JS/TS entry (e.g. import "./index.css" in src/main.tsx).'
932
+ ],
933
+ antiPatterns: [
934
+ "Do not reassemble leaf components inside main.tsx or a new App.tsx when a route-level screen already exists \u2014 import that screen."
935
+ ]
936
+ },
937
+ next: {
938
+ contract: [
939
+ "App Router lives under src/app (or app/). page.tsx files are routes. layout.tsx is the HTML shell.",
940
+ '"use client" / "use server" and next/link, next/image, next/navigation are Next-specific \u2014 strip them when leaving Next.'
941
+ ],
942
+ components: [
943
+ "page.tsx should import the existing screen and return it. Do not paste that screen's JSX into the route file."
944
+ ],
945
+ routing: [
946
+ "src/pages is the Pages Router. If the SPA kept UI there, move that tree to a folder Next does not treat as routes, then import those screens from src/app.",
947
+ "Replace react-router <Route> / <Link> with file-system routes and next/link when Next is the target."
948
+ ],
949
+ styling: [
950
+ "layout.tsx typically imports global CSS. When leaving Next, that import must move to the new SPA entry."
951
+ ],
952
+ antiPatterns: [
953
+ "Never hollow out an existing screen after creating App Router files. Never leave a stub src/app/page.tsx that returns an empty shell or TODO.",
954
+ "Do not leave Vite preview scripts after moving to Next."
955
+ ]
956
+ },
957
+ vue: {
958
+ contract: [
959
+ 'Vue 3 boots from src/main.ts: createApp(App).use(router).mount("#app"). index.html must have <div id="app"> \u2014 not #root.',
960
+ "vite.config.ts uses @vitejs/plugin-vue. Add env.d.ts so TypeScript accepts *.vue modules."
961
+ ],
962
+ components: [
963
+ "UI is Single File Components (.vue) with <script setup>, <template>, and <style> (keep scoped styles on that component).",
964
+ "defineProps names stay the prop names. defineEmits names stay the event names as declared in the SFC. Map to the target with the same names (React: onX for emit X). Do not invent new names.",
965
+ "ref / reactive / computed / watch / onMounted are the state model. Do not drop them; map them (useState, useMemo, useEffect, or the target equivalent)."
966
+ ],
967
+ routing: [
968
+ "vue-router: createRouter({ history: createWebHistory(), routes }). App.vue has <router-view />. Each route component is an existing SFC \u2014 do not inline screens in the router table."
969
+ ],
970
+ styling: [
971
+ "Keep SFC <style scoped> with the component. Import global CSS from src/main.ts (same file the source loaded)."
972
+ ],
973
+ antiPatterns: [
974
+ "Do not convert an SFC into an empty template with a heading. Do not leave ReactDOM.createRoot or .tsx screens once .vue replacements exist.",
975
+ "Do not change #app to #root (or the reverse) without updating both index.html and mount()."
976
+ ]
977
+ },
978
+ angular: {
979
+ contract: [
980
+ "Standalone Angular (current CLI): src/main.ts calls bootstrapApplication(App, appConfig). app.config.ts uses provideRouter(routes).",
981
+ "angular.json must exist and point browser to src/main.ts and styles to the global CSS file."
982
+ ],
983
+ components: [
984
+ 'Prefer standalone @Component. @Input() / @Output() names are the public API \u2014 a route host must bind the same names, not "cleaner" aliases.',
985
+ "Keep templates in the component templateUrl (or inline template). Do not dump a feature template into App.",
986
+ "Services stay injectable or become plain modules; do not silently drop HTTP calls that lived in a service."
987
+ ],
988
+ routing: [
989
+ "Routes live in app.routes.ts. Each path loads the existing feature component. app.ts is a shell with <router-outlet />, not a reimplementation of home."
990
+ ],
991
+ styling: [
992
+ "Component styles stay in styleUrls. Global CSS is listed in angular.json styles (usually src/styles.css) \u2014 copy the source global stylesheet there."
993
+ ],
994
+ antiPatterns: [
995
+ "Do not leave vite.config / root index.html / #root as the real entry. ng serve will ignore them or conflict.",
996
+ "Do not wrap a component in a new dummy component that remaps inputs (the same class of bug as renaming React callback props)."
997
+ ]
998
+ },
999
+ svelte: {
1000
+ contract: [
1001
+ 'Svelte 5 + Vite: src/main.ts uses mount(App, { target: document.getElementById("app") }). index.html has <div id="app">.',
1002
+ "vite.config.ts uses @sveltejs/vite-plugin-svelte. svelte.config.js uses vitePreprocess."
1003
+ ],
1004
+ components: [
1005
+ "UI is .svelte files. Svelte 5 uses $props(), $state(), $derived, $effect. If the source is Svelte 4, map export let / let to $props / $state \u2014 keep the names.",
1006
+ "createEventDispatcher event names (or callback props in $props) are the public API. In React they become onX with the same X."
1007
+ ],
1008
+ routing: [
1009
+ "This catalog targets a Vite SPA, not SvelteKit file routes. Use svelte-spa-router or a tiny custom map in App.svelte that renders existing screens. Do not invent +page.svelte Kit routes unless the source already was Kit."
1010
+ ],
1011
+ styling: [
1012
+ "Keep <style> in the .svelte file that owned it. Import global CSS from src/main.ts."
1013
+ ],
1014
+ antiPatterns: [
1015
+ 'Do not emit an empty App.svelte that only says "Svelte app". Do not leave React/Vue mount code beside mount().',
1016
+ "Do not migrate a Vite SPA into SvelteKit folders unless the user target is explicitly a Kit app (it is not)."
1017
+ ]
1018
+ },
1019
+ nestjs: {
1020
+ contract: ["NestJS boots with NestFactory.create() and a root @Module."],
1021
+ components: ["@Module, @Controller, @Injectable must stay wired: controllers, providers, and imports together."],
1022
+ routing: ["HTTP routes are controller methods. Preserve method, path, and status when mapping away from Nest."],
1023
+ styling: [],
1024
+ antiPatterns: ["Do not leave an empty AppModule that imports nothing the old module imported."]
1025
+ },
1026
+ express: {
1027
+ contract: ["Express apps compose Router instances and a listen() (or exported app) entry."],
1028
+ components: ["Convert Nest/Fastify plugins into routers or middleware functions; pass dependencies explicitly."],
1029
+ routing: ["Preserve path + method on each route."],
1030
+ styling: [],
1031
+ antiPatterns: []
1032
+ },
1033
+ fastify: {
1034
+ contract: ["Fastify apps register plugins and route options."],
1035
+ components: ["Preserve schema validation when mapping to/from Express or Nest."],
1036
+ routing: ["Preserve path + method on each route."],
1037
+ styling: [],
1038
+ antiPatterns: []
1039
+ }
1040
+ };
1041
+ function rulesForFramework(id) {
1042
+ const pack = FRAMEWORK_PACKS[id.toLowerCase()];
1043
+ if (!pack) return [];
1044
+ return [...pack.contract, ...pack.components, ...pack.routing, ...pack.styling, ...pack.antiPatterns];
1045
+ }
1046
+ function packForFramework(id) {
1047
+ return FRAMEWORK_PACKS[id.toLowerCase()];
1048
+ }
1049
+ var FRAMEWORK_RULES = Object.fromEntries(
1050
+ Object.entries(FRAMEWORK_PACKS).map(([id, pack]) => [id, rulesForFramework(id)])
1051
+ );
1052
+
1053
+ // ../domain/src/entities/catalogs/layers/all.ts
1054
+ var ALL_MIGRATION_RULES = [
1055
+ "Never delete or omit business logic, state, API calls, or user-visible behavior. Adapt APIs to the target runtime instead of dropping them.",
1056
+ "Never leave stub, TODO, empty, or placeholder root screens. The migrated app must show the same primary UI the source showed.",
1057
+ "Do not invent features, routes, or pages that were not in the source project.",
1058
+ "Public names are a contract: exported components, props, inputs, outputs, emits, store actions, and route paths. Wrappers import and pass them through \u2014 they do not rename them to look idiomatic.",
1059
+ "Deduce APIs from files on disk (and their imports). If a screen already exists, import it. Do not re-implement it in a router/bootstrap file.",
1060
+ "Keep existing tests, env examples, and README intent unless the target framework requires a mechanical rename."
1061
+ ];
1062
+
1063
+ // ../domain/src/entities/catalogs/layers/backend.ts
1064
+ var BACKEND_LAYER_RULES = [
1065
+ "Preserve every HTTP route, method, path, and status-code contract unless the target framework requires an equivalent mapping.",
1066
+ "Keep middleware/filter order, validation, auth, and error handling. Do not drop them because decorators or plugins changed.",
1067
+ "Keep env-driven config (ports, secrets, database URLs). Do not hardcode values that lived in environment files.",
1068
+ "Preserve request/response body shapes and exported application/bootstrap entry so the process still listens."
1069
+ ];
1070
+
1071
+ // ../domain/src/entities/catalogs/layers/frontend.ts
1072
+ var FRONTEND_LAYER_RULES = [
1073
+ 'Preserve every stylesheet the source loaded: global CSS, CSS modules, Tailwind/PostCSS entry, fonts, and static assets. An unstyled HTML shell that "builds" is a failed migration.',
1074
+ "The target bootstrap must import the same global CSS the source root imported. Wiring CSS only in a deleted layout/HTML file is not enough.",
1075
+ "Keep public/ (or equivalent) assets and favicon references working in the target bundler.",
1076
+ "Map every user-facing route to an equivalent in the target router. Do not drop screens because the folder convention changed.",
1077
+ "When a new router or bootstrap file wraps an existing screen, import that screen and return/render it. Do not copy its template/JSX into the wrapper.",
1078
+ "Client-only APIs (window, document, localStorage) must still run; wrap or gate them for SSR targets instead of removing them.",
1079
+ "A successful compiler/build is not success if the home route is blank, the old bundler scripts remain, or leftover source-framework folders still register routes."
1080
+ ];
1081
+
1082
+ // ../domain/src/entities/catalogs/layers/runtimes.ts
1083
+ var VITE_SPA_RUNTIME_RULES = [
1084
+ 'Vite SPA: index.html at the repo root loads src/main.ts (or main.tsx) as type="module".',
1085
+ "vite.config.ts must use the plugin for the target (react / vue / svelte). In ESM use import.meta.dirname \u2014 never __dirname.",
1086
+ "package.json scripts must be Vite (dev/build/preview). Delete leftover next / ng serve / vue-cli-service scripts.",
1087
+ "Global CSS is imported from the JS/TS entry (or the root SFC). Vite does not apply CSS that only lived in a deleted framework layout."
1088
+ ];
1089
+ var NEXT_APP_RUNTIME_RULES = [
1090
+ "Next App Router: routes are src/app/**/page.tsx (or app/). layout.tsx is the HTML shell and typically the global CSS import.",
1091
+ "src/pages is the Pages Router. SPA UI that lived under src/pages must move to a non-reserved folder before it can stay on disk, then be imported from src/app.",
1092
+ "package.json scripts must be next (dev/build/start). Delete leftover vite preview scripts."
1093
+ ];
1094
+ var ANGULAR_CLI_RUNTIME_RULES = [
1095
+ "Angular CLI: angular.json is required. ng build / ng serve read architect.builder \u2014 a Vite config left behind will not run this app.",
1096
+ "Browser entry is src/main.ts \u2192 bootstrapApplication. The HTML shell is src/index.html (not a Vite root index.html). Delete the Vite index.html and vite.config.* when Angular is the target.",
1097
+ "package.json scripts must be ng serve / ng build. Delete leftover vite / next scripts.",
1098
+ "Global styles go in the angular.json styles array (often src/styles.css) and must still include the source global CSS."
1099
+ ];
1100
+ function targetRuntimeFor(target) {
1101
+ const id = target.toLowerCase();
1102
+ if (id === "react" || id === "vue" || id === "svelte") return "vite-spa";
1103
+ if (id === "next") return "next-app";
1104
+ if (id === "angular") return "angular-cli";
1105
+ return void 0;
1106
+ }
1107
+ function rulesForTargetRuntime(target) {
1108
+ const runtime = targetRuntimeFor(target);
1109
+ if (runtime === "vite-spa") return VITE_SPA_RUNTIME_RULES;
1110
+ if (runtime === "next-app") return NEXT_APP_RUNTIME_RULES;
1111
+ if (runtime === "angular-cli") return ANGULAR_CLI_RUNTIME_RULES;
1112
+ return [];
1113
+ }
1114
+ function labelForTargetRuntime(target) {
1115
+ const runtime = targetRuntimeFor(target);
1116
+ if (runtime === "vite-spa") return `Target runtime: Vite SPA (${target})`;
1117
+ if (runtime === "next-app") return "Target runtime: Next.js App Router";
1118
+ if (runtime === "angular-cli") return "Target runtime: Angular CLI";
1119
+ return `Target runtime: ${target}`;
1120
+ }
1121
+
1122
+ // ../domain/src/entities/catalogs/compose.ts
1123
+ function findPair(source, target) {
1124
+ const src = source.toLowerCase();
1125
+ const tgt = target.toLowerCase();
1126
+ const match = (entry) => entry.source.toLowerCase() === src && entry.target.toLowerCase() === tgt;
1127
+ const frontend = frontendCatalog.find(match);
1128
+ if (frontend) return { pair: frontend, layer: "frontend" };
1129
+ const backend = backendCatalog.find(match);
1130
+ if (backend) return { pair: backend, layer: "backend" };
1131
+ return void 0;
1132
+ }
1133
+ function unique(rules) {
1134
+ const seen = /* @__PURE__ */ new Set();
1135
+ const out = [];
1136
+ for (const rule of rules) {
1137
+ const key = rule.trim();
1138
+ if (!key || seen.has(key)) continue;
1139
+ seen.add(key);
1140
+ out.push(rule);
1141
+ }
1142
+ return out;
1143
+ }
1144
+ function section(scope, label, kind, rules, groups) {
1145
+ const cleaned = unique(rules);
1146
+ const groupRules = groups?.flatMap((group) => unique(group.rules)) ?? [];
1147
+ if (cleaned.length === 0 && groupRules.length === 0) return void 0;
1148
+ return {
1149
+ scope,
1150
+ label,
1151
+ kind,
1152
+ rules: cleaned.length > 0 ? cleaned : groupRules,
1153
+ groups: groups?.map((group) => ({ heading: group.heading, rules: unique(group.rules) })).filter((group) => group.rules.length > 0)
1154
+ };
1155
+ }
1156
+ function frameworkSections(id, role) {
1157
+ const pack = packForFramework(id);
1158
+ if (!pack) return [];
1159
+ const label = `Framework: ${id} (${role})`;
1160
+ const built = section("framework", label, "contract", [], [
1161
+ { heading: "Contract", rules: pack.contract },
1162
+ { heading: "Components", rules: pack.components },
1163
+ { heading: "Routing", rules: pack.routing },
1164
+ { heading: "Styling", rules: pack.styling },
1165
+ { heading: "Do not", rules: pack.antiPatterns }
1166
+ ]);
1167
+ return built ? [built] : [];
1168
+ }
1169
+ function composeRuleSections(layer, source, target, pairRules) {
1170
+ const layerRules = layer === "frontend" ? FRONTEND_LAYER_RULES : BACKEND_LAYER_RULES;
1171
+ const runtimeRules = layer === "frontend" ? rulesForTargetRuntime(target) : [];
1172
+ const sections = [
1173
+ section("all", "All migrations", "invariant", ALL_MIGRATION_RULES),
1174
+ section(layer, `${layer} migrations`, layer === "frontend" ? "invariant" : "contract", layerRules)
1175
+ ];
1176
+ if (runtimeRules.length > 0) {
1177
+ sections.push(section("runtime", labelForTargetRuntime(target), "contract", runtimeRules));
1178
+ }
1179
+ sections.push(...frameworkSections(source, "source"));
1180
+ if (source.toLowerCase() !== target.toLowerCase()) {
1181
+ sections.push(...frameworkSections(target, "target"));
1182
+ }
1183
+ sections.push(section("pair", `This pair: ${source} \u2192 ${target}`, "mapping", pairRules));
1184
+ return sections.filter((item) => Boolean(item));
1185
+ }
1186
+ function formatCatalogRules(sections) {
1187
+ return sections.map((section2) => {
1188
+ const kind = section2.kind ? ` [${section2.kind}]` : "";
1189
+ const header = `${section2.label}${kind}`;
1190
+ if (section2.groups && section2.groups.length > 0) {
1191
+ const body = section2.groups.map((group) => `${group.heading}:
1192
+ ${group.rules.map((rule) => `- ${rule}`).join("\n")}`).join("\n");
1193
+ return `${header}
1194
+ ${body}`;
1195
+ }
1196
+ return `${header}:
1197
+ ${section2.rules.map((rule) => `- ${rule}`).join("\n")}`;
1198
+ }).join("\n\n");
1199
+ }
1200
+ function resolveMigrationCatalog(source, target) {
1201
+ const found = findPair(source, target);
1202
+ if (!found) return void 0;
1203
+ const ruleSections = composeRuleSections(found.layer, source, target, found.pair.architecturalRules);
1204
+ return {
1205
+ ...found.pair,
1206
+ layer: found.layer,
1207
+ ruleSections,
1208
+ architecturalRules: ruleSections.flatMap((section2) => section2.rules)
1209
+ };
1210
+ }
1211
+
1212
+ // ../domain/src/entities/catalogs/index.ts
1213
+ var MigrationCatalog = [
1214
+ ...backendCatalog,
1215
+ ...frontendCatalog
1216
+ ];
1217
+ function findMigrationCatalogEntry(source, target) {
1218
+ return resolveMigrationCatalog(source, target);
1219
+ }
1220
+
1221
+ // ../domain/src/events/SemanticEvents.ts
1222
+ var SemanticEventName = /* @__PURE__ */ ((SemanticEventName2) => {
1223
+ SemanticEventName2["MIGRATION_STARTED"] = "migration.started";
1224
+ SemanticEventName2["FILE_DISCOVERED"] = "file.discovered";
1225
+ SemanticEventName2["FILE_MIGRATED"] = "file.migrated";
1226
+ SemanticEventName2["FILE_REVIEWED"] = "file.reviewed";
1227
+ SemanticEventName2["FILE_REJECTED"] = "file.rejected";
1228
+ SemanticEventName2["FILE_FATAL_MISMATCH"] = "file.fatal_mismatch";
1229
+ SemanticEventName2["FILE_FAILED"] = "file.failed";
1230
+ SemanticEventName2["PHASE_PACKAGES_READY"] = "phase.packages_ready";
1231
+ SemanticEventName2["PHASE_INTEGRATION_STARTED"] = "phase.integration_started";
1232
+ SemanticEventName2["MIGRATION_COMPLETED"] = "migration.completed";
1233
+ SemanticEventName2["SYSTEM_LOG"] = "system.log";
1234
+ return SemanticEventName2;
1235
+ })(SemanticEventName || {});
1236
+
1237
+ export {
1238
+ FRAMEWORK_PACKS,
1239
+ rulesForFramework,
1240
+ packForFramework,
1241
+ FRAMEWORK_RULES,
1242
+ ALL_MIGRATION_RULES,
1243
+ BACKEND_LAYER_RULES,
1244
+ FRONTEND_LAYER_RULES,
1245
+ VITE_SPA_RUNTIME_RULES,
1246
+ NEXT_APP_RUNTIME_RULES,
1247
+ ANGULAR_CLI_RUNTIME_RULES,
1248
+ targetRuntimeFor,
1249
+ rulesForTargetRuntime,
1250
+ composeRuleSections,
1251
+ formatCatalogRules,
1252
+ resolveMigrationCatalog,
1253
+ MigrationCatalog,
1254
+ findMigrationCatalogEntry,
1255
+ SemanticEventName
1256
+ };