@forgerapi/codegen 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.
Files changed (53) hide show
  1. package/dist/codemod.d.ts +3 -0
  2. package/dist/codemod.js +181 -0
  3. package/dist/generators/action/controller.d.ts +5 -0
  4. package/dist/generators/action/controller.js +51 -0
  5. package/dist/generators/action/dto.d.ts +2 -0
  6. package/dist/generators/action/dto.js +15 -0
  7. package/dist/generators/action/event.d.ts +1 -0
  8. package/dist/generators/action/event.js +10 -0
  9. package/dist/generators/action/impl.d.ts +5 -0
  10. package/dist/generators/action/impl.js +25 -0
  11. package/dist/generators/action/index.d.ts +6 -0
  12. package/dist/generators/action/index.js +15 -0
  13. package/dist/generators/action/module.d.ts +4 -0
  14. package/dist/generators/action/module.js +25 -0
  15. package/dist/generators/action/service.d.ts +2 -0
  16. package/dist/generators/action/service.js +24 -0
  17. package/dist/generators/controller.d.ts +3 -0
  18. package/dist/generators/controller.js +66 -0
  19. package/dist/generators/dto.d.ts +9 -0
  20. package/dist/generators/dto.js +128 -0
  21. package/dist/generators/enum.d.ts +2 -0
  22. package/dist/generators/enum.js +12 -0
  23. package/dist/generators/forger-module/forger-module.d.ts +6 -0
  24. package/dist/generators/forger-module/forger-module.js +49 -0
  25. package/dist/generators/forger-module/index.d.ts +1 -0
  26. package/dist/generators/forger-module/index.js +5 -0
  27. package/dist/generators/forger-modules.d.ts +2 -0
  28. package/dist/generators/forger-modules.js +40 -0
  29. package/dist/generators/guard/guard.d.ts +2 -0
  30. package/dist/generators/guard/guard.js +15 -0
  31. package/dist/generators/guard/index.d.ts +1 -0
  32. package/dist/generators/guard/index.js +5 -0
  33. package/dist/generators/module/index.d.ts +1 -0
  34. package/dist/generators/module/index.js +5 -0
  35. package/dist/generators/module/module-module.d.ts +2 -0
  36. package/dist/generators/module/module-module.js +46 -0
  37. package/dist/generators/module.d.ts +4 -0
  38. package/dist/generators/module.js +25 -0
  39. package/dist/generators/prisma-module.d.ts +1 -0
  40. package/dist/generators/prisma-module.js +15 -0
  41. package/dist/generators/prisma-service.d.ts +1 -0
  42. package/dist/generators/prisma-service.js +22 -0
  43. package/dist/generators/prisma.d.ts +2 -0
  44. package/dist/generators/prisma.js +101 -0
  45. package/dist/generators/service.d.ts +8 -0
  46. package/dist/generators/service.js +71 -0
  47. package/dist/index.d.ts +21 -0
  48. package/dist/index.js +376 -0
  49. package/dist/schema-cache.d.ts +25 -0
  50. package/dist/schema-cache.js +98 -0
  51. package/dist/utils.d.ts +1 -0
  52. package/dist/utils.js +6 -0
  53. package/package.json +29 -0
package/dist/index.js ADDED
@@ -0,0 +1,376 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateUpdateDto = exports.generateResponseDto = exports.generatePrismaService = exports.generatePrismaSchema = exports.generatePrismaModule = exports.generateModule = exports.generateModelImpl = exports.generateForgerModules = exports.generateEnum = exports.generateCreateDto = exports.generateController = exports.generateAbstractService = void 0;
4
+ exports.generate = generate;
5
+ exports.runForger = runForger;
6
+ exports.watchForger = watchForger;
7
+ const node_fs_1 = require("node:fs");
8
+ const promises_1 = require("node:fs/promises");
9
+ const node_path_1 = require("node:path");
10
+ const parser_1 = require("@forgerapi/parser");
11
+ const codemod_1 = require("./codemod");
12
+ const controller_1 = require("./generators/controller");
13
+ Object.defineProperty(exports, "generateController", { enumerable: true, get: function () { return controller_1.generateController; } });
14
+ const dto_1 = require("./generators/dto");
15
+ Object.defineProperty(exports, "generateCreateDto", { enumerable: true, get: function () { return dto_1.generateCreateDto; } });
16
+ Object.defineProperty(exports, "generateResponseDto", { enumerable: true, get: function () { return dto_1.generateResponseDto; } });
17
+ Object.defineProperty(exports, "generateUpdateDto", { enumerable: true, get: function () { return dto_1.generateUpdateDto; } });
18
+ const enum_1 = require("./generators/enum");
19
+ Object.defineProperty(exports, "generateEnum", { enumerable: true, get: function () { return enum_1.generateEnum; } });
20
+ const module_1 = require("./generators/module");
21
+ Object.defineProperty(exports, "generateModule", { enumerable: true, get: function () { return module_1.generateModule; } });
22
+ const prisma_1 = require("./generators/prisma");
23
+ Object.defineProperty(exports, "generatePrismaSchema", { enumerable: true, get: function () { return prisma_1.generatePrismaSchema; } });
24
+ const prisma_module_1 = require("./generators/prisma-module");
25
+ Object.defineProperty(exports, "generatePrismaModule", { enumerable: true, get: function () { return prisma_module_1.generatePrismaModule; } });
26
+ const prisma_service_1 = require("./generators/prisma-service");
27
+ Object.defineProperty(exports, "generatePrismaService", { enumerable: true, get: function () { return prisma_service_1.generatePrismaService; } });
28
+ const service_1 = require("./generators/service");
29
+ Object.defineProperty(exports, "generateAbstractService", { enumerable: true, get: function () { return service_1.generateAbstractService; } });
30
+ Object.defineProperty(exports, "generateModelImpl", { enumerable: true, get: function () { return service_1.generateModelImpl; } });
31
+ const utils_1 = require("./utils");
32
+ const action_1 = require("./generators/action");
33
+ const guard_1 = require("./generators/guard");
34
+ const forger_module_1 = require("./generators/forger-module");
35
+ const forger_modules_1 = require("./generators/forger-modules");
36
+ Object.defineProperty(exports, "generateForgerModules", { enumerable: true, get: function () { return forger_modules_1.generateForgerModules; } });
37
+ const schema_cache_1 = require("./schema-cache");
38
+ async function generate(schema, config) {
39
+ const files = [];
40
+ const swaggerConfig = { enabled: config.swagger ?? true };
41
+ files.push(...(await generatePrisma(schema, config)));
42
+ files.push(...(await generatePrismaServiceFile(config)));
43
+ files.push(...(await generateModels(schema, config, swaggerConfig)));
44
+ files.push(...(await generateActions(schema, config)));
45
+ files.push(...(await generateModules(schema, config, swaggerConfig)));
46
+ files.push(...(await generateGuards(schema, config)));
47
+ files.push(...(await generateEnums(schema, config)));
48
+ files.push(...(await generateForgerModulesFile(schema, config)));
49
+ files.push(...(await deleteOrphans(schema, config)));
50
+ return files;
51
+ }
52
+ async function ensureDir(dir) {
53
+ if (!(0, node_fs_1.existsSync)(dir)) {
54
+ await (0, promises_1.mkdir)(dir, { recursive: true });
55
+ }
56
+ }
57
+ async function generatePrisma(schema, config) {
58
+ const prismaDir = (0, node_path_1.dirname)(config.prismaSchema);
59
+ await ensureDir(prismaDir);
60
+ const content = (0, prisma_1.generatePrismaSchema)(schema);
61
+ await (0, promises_1.writeFile)(config.prismaSchema, content, "utf-8");
62
+ return [config.prismaSchema];
63
+ }
64
+ async function generateModels(schema, config, swagger) {
65
+ const files = [];
66
+ for (const model of schema.models) {
67
+ const kebab = (0, utils_1.toKebab)(model.name);
68
+ const modelDir = (0, node_path_1.resolve)(config.outDir, kebab);
69
+ const implDir = (0, node_path_1.resolve)(modelDir, "impl");
70
+ await ensureDir((0, node_path_1.resolve)(modelDir, "dto"));
71
+ await ensureDir(implDir);
72
+ const dtoPaths = [
73
+ (0, node_path_1.resolve)(modelDir, `dto/create-${kebab}.dto.ts`),
74
+ (0, node_path_1.resolve)(modelDir, `dto/update-${kebab}.dto.ts`),
75
+ (0, node_path_1.resolve)(modelDir, `dto/${kebab}-response.dto.ts`),
76
+ ];
77
+ const dtoContents = [
78
+ (0, dto_1.generateCreateDto)(model, schema, swagger, {
79
+ enumBase: "../../common/enums",
80
+ }),
81
+ (0, dto_1.generateUpdateDto)(model),
82
+ (0, dto_1.generateResponseDto)(model),
83
+ ];
84
+ for (let i = 0; i < dtoPaths.length; i++) {
85
+ await (0, promises_1.writeFile)(dtoPaths[i], dtoContents[i]);
86
+ }
87
+ files.push(...dtoPaths);
88
+ const servicePath = (0, node_path_1.resolve)(modelDir, `${kebab}.service.ts`);
89
+ await (0, promises_1.writeFile)(servicePath, (0, service_1.generateAbstractService)(model));
90
+ files.push(servicePath);
91
+ const controllerPath = (0, node_path_1.resolve)(modelDir, `${kebab}.controller.ts`);
92
+ await (0, promises_1.writeFile)(controllerPath, (0, controller_1.generateController)(model, swagger));
93
+ files.push(controllerPath);
94
+ const modulePath = (0, node_path_1.resolve)(modelDir, `${kebab}.module.ts`);
95
+ await (0, promises_1.writeFile)(modulePath, (0, module_1.generateModule)(model, {
96
+ implRelative: `./impl/${kebab}.impl`,
97
+ }));
98
+ files.push(modulePath);
99
+ const implPath = (0, node_path_1.resolve)(implDir, `${kebab}.impl.ts`);
100
+ if (!(0, node_fs_1.existsSync)(implPath)) {
101
+ await (0, promises_1.writeFile)(implPath, (0, service_1.generateModelImpl)(model, {
102
+ serviceRelative: `../${kebab}.service`,
103
+ createDtoRelative: `../dto/create-${kebab}.dto`,
104
+ updateDtoRelative: `../dto/update-${kebab}.dto`,
105
+ prismaRelative: `../../common/prisma/prisma.service`,
106
+ }));
107
+ files.push(implPath);
108
+ }
109
+ }
110
+ return files;
111
+ }
112
+ async function generateActions(schema, config) {
113
+ if (schema.actions.length === 0)
114
+ return [];
115
+ const files = [];
116
+ for (const action of schema.actions) {
117
+ const kebab = (0, utils_1.toKebab)(action.name);
118
+ const actionDir = (0, node_path_1.resolve)(config.outDir, kebab);
119
+ const implDir = (0, node_path_1.resolve)(actionDir, "impl");
120
+ await ensureDir((0, node_path_1.resolve)(actionDir, "dto"));
121
+ await ensureDir(implDir);
122
+ const dtoPath = (0, node_path_1.resolve)(actionDir, `${kebab}.action-dto.ts`);
123
+ await (0, promises_1.writeFile)(dtoPath, (0, action_1.generateActionDto)(action));
124
+ files.push(dtoPath);
125
+ const servicePath = (0, node_path_1.resolve)(actionDir, `${kebab}.action-service.ts`);
126
+ await (0, promises_1.writeFile)(servicePath, (0, action_1.generateActionService)(action));
127
+ files.push(servicePath);
128
+ const controllerPath = (0, node_path_1.resolve)(actionDir, `${kebab}.action-controller.ts`);
129
+ await (0, promises_1.writeFile)(controllerPath, (0, action_1.generateActionController)(action));
130
+ files.push(controllerPath);
131
+ const modulePath = (0, node_path_1.resolve)(actionDir, `${kebab}.action-module.ts`);
132
+ await (0, promises_1.writeFile)(modulePath, (0, action_1.generateActionModule)(action, {
133
+ implRelative: `./impl/${kebab}.action-impl`,
134
+ }));
135
+ files.push(modulePath);
136
+ const implPath = (0, node_path_1.resolve)(implDir, `${kebab}.action-impl.ts`);
137
+ if (!(0, node_fs_1.existsSync)(implPath)) {
138
+ await (0, promises_1.writeFile)(implPath, (0, action_1.generateActionImpl)(action, {
139
+ serviceRelative: `../${kebab}.action-service`,
140
+ dtoRelative: `../${kebab}.action-dto`,
141
+ }));
142
+ files.push(implPath);
143
+ }
144
+ if (action.emits) {
145
+ for (const eventName of action.emits) {
146
+ const eventPath = (0, node_path_1.resolve)(actionDir, `${kebab}.action-event.ts`);
147
+ if (!(0, node_fs_1.existsSync)(eventPath)) {
148
+ await (0, promises_1.writeFile)(eventPath, (0, action_1.generateActionEvent)(action.name, eventName));
149
+ files.push(eventPath);
150
+ }
151
+ }
152
+ }
153
+ }
154
+ return files;
155
+ }
156
+ async function generateModules(schema, config, _swagger) {
157
+ if (schema.modules.length === 0)
158
+ return [];
159
+ const files = [];
160
+ const guardMap = new Map(schema.guards.map((g) => [g.name, g]));
161
+ for (const mod of schema.modules) {
162
+ const modKebab = (0, utils_1.toKebab)(mod.name);
163
+ const moduleDir = (0, node_path_1.resolve)(config.outDir, modKebab);
164
+ const actionsDir = (0, node_path_1.resolve)(moduleDir, "actions");
165
+ const eventsDir = (0, node_path_1.resolve)(moduleDir, "events");
166
+ const implDir = (0, node_path_1.resolve)(moduleDir, "impl");
167
+ await ensureDir(moduleDir);
168
+ await ensureDir(eventsDir);
169
+ await ensureDir(implDir);
170
+ const modGuards = mod.guards
171
+ .map((g) => guardMap.get(g))
172
+ .filter((g) => g !== undefined);
173
+ for (const action of mod.actions) {
174
+ const kebab = (0, utils_1.toKebab)(action.name);
175
+ const actionDir = (0, node_path_1.resolve)(actionsDir, kebab);
176
+ await ensureDir((0, node_path_1.resolve)(actionDir, "dto"));
177
+ const dtoPath = (0, node_path_1.resolve)(actionDir, `${kebab}.action-dto.ts`);
178
+ await (0, promises_1.writeFile)(dtoPath, (0, action_1.generateActionDto)(action));
179
+ files.push(dtoPath);
180
+ const servicePath = (0, node_path_1.resolve)(actionDir, `${kebab}.action-service.ts`);
181
+ await (0, promises_1.writeFile)(servicePath, (0, action_1.generateActionService)(action));
182
+ files.push(servicePath);
183
+ const controllerPath = (0, node_path_1.resolve)(actionDir, `${kebab}.action-controller.ts`);
184
+ await (0, promises_1.writeFile)(controllerPath, (0, action_1.generateActionController)(action, {
185
+ routePrefix: mod.route.startsWith("/")
186
+ ? mod.route.slice(1)
187
+ : mod.route,
188
+ guards: modGuards,
189
+ }));
190
+ files.push(controllerPath);
191
+ const implFilePath = (0, node_path_1.resolve)(implDir, `${kebab}.action-impl.ts`);
192
+ if (!(0, node_fs_1.existsSync)(implFilePath)) {
193
+ await (0, promises_1.writeFile)(implFilePath, (0, action_1.generateActionImpl)(action, {
194
+ serviceRelative: `../actions/${kebab}/${kebab}.action-service`,
195
+ dtoRelative: `../actions/${kebab}/${kebab}.action-dto`,
196
+ }));
197
+ files.push(implFilePath);
198
+ }
199
+ if (action.emits) {
200
+ for (const eventName of action.emits) {
201
+ const eventPath = (0, node_path_1.resolve)(eventsDir, `${kebab}.action-event.ts`);
202
+ if (!(0, node_fs_1.existsSync)(eventPath)) {
203
+ await (0, promises_1.writeFile)(eventPath, (0, action_1.generateActionEvent)(action.name, eventName));
204
+ files.push(eventPath);
205
+ }
206
+ }
207
+ }
208
+ }
209
+ const modulePath = (0, node_path_1.resolve)(moduleDir, `${modKebab}.module.ts`);
210
+ await (0, promises_1.writeFile)(modulePath, (0, forger_module_1.generateForgerModule)(mod, {
211
+ modelRelativeBase: "..",
212
+ actionBase: "./actions",
213
+ implBase: "./impl",
214
+ }));
215
+ files.push(modulePath);
216
+ }
217
+ return files;
218
+ }
219
+ async function generateGuards(schema, config) {
220
+ const guardsWithStubs = schema.guards.filter((g) => !g.import);
221
+ if (guardsWithStubs.length === 0)
222
+ return [];
223
+ const files = [];
224
+ const guardDir = (0, node_path_1.resolve)(config.outDir, "common", "guards");
225
+ await ensureDir(guardDir);
226
+ for (const guard of guardsWithStubs) {
227
+ const p = (0, node_path_1.resolve)(guardDir, `${(0, utils_1.toKebab)(guard.name)}.guard.ts`);
228
+ await (0, promises_1.writeFile)(p, (0, guard_1.generateGuardStub)(guard));
229
+ files.push(p);
230
+ }
231
+ return files;
232
+ }
233
+ async function generateForgerModulesFile(schema, config) {
234
+ if (schema.models.length === 0 &&
235
+ schema.actions.length === 0 &&
236
+ schema.modules.length === 0)
237
+ return [];
238
+ const p = (0, node_path_1.resolve)(config.outDir, "forger-modules.module.ts");
239
+ await (0, promises_1.writeFile)(p, (0, forger_modules_1.generateForgerModules)(schema.models, schema.actions, schema.modules));
240
+ return [p];
241
+ }
242
+ async function generateEnums(schema, config) {
243
+ if (schema.enums.length === 0)
244
+ return [];
245
+ const commonDir = (0, node_path_1.resolve)(config.outDir, "common", "enums");
246
+ await ensureDir(commonDir);
247
+ const files = [];
248
+ for (const enm of schema.enums) {
249
+ const p = (0, node_path_1.resolve)(commonDir, `${(0, utils_1.toKebab)(enm.name)}.enum.ts`);
250
+ await (0, promises_1.writeFile)(p, (0, enum_1.generateEnum)(enm));
251
+ files.push(p);
252
+ }
253
+ return files;
254
+ }
255
+ async function generatePrismaServiceFile(config) {
256
+ const prismaDir = (0, node_path_1.resolve)(config.outDir, "common", "prisma");
257
+ await ensureDir(prismaDir);
258
+ const p = (0, node_path_1.resolve)(prismaDir, "prisma.service.ts");
259
+ await (0, promises_1.writeFile)(p, (0, prisma_service_1.generatePrismaService)());
260
+ const modulePath = (0, node_path_1.resolve)(prismaDir, "prisma.module.ts");
261
+ await (0, promises_1.writeFile)(modulePath, (0, prisma_module_1.generatePrismaModule)());
262
+ return [p, modulePath];
263
+ }
264
+ async function deleteOrphans(schema, config) {
265
+ if (!config.deleteOrphans)
266
+ return [];
267
+ if (!(0, node_fs_1.existsSync)(config.outDir))
268
+ return [];
269
+ const files = [];
270
+ const validDirs = new Set(schema.models.map((m) => (0, utils_1.toKebab)(m.name)));
271
+ validDirs.add("common");
272
+ for (const action of schema.actions) {
273
+ validDirs.add((0, utils_1.toKebab)(action.name));
274
+ }
275
+ for (const mod of schema.modules) {
276
+ validDirs.add((0, utils_1.toKebab)(mod.name));
277
+ }
278
+ const entries = (0, node_fs_1.readdirSync)(config.outDir, { withFileTypes: true });
279
+ for (const entry of entries) {
280
+ if (entry.isDirectory() && !validDirs.has(entry.name)) {
281
+ const dir = (0, node_path_1.resolve)(config.outDir, entry.name);
282
+ await (0, promises_1.rm)(dir, { recursive: true, force: true });
283
+ files.push(dir);
284
+ }
285
+ }
286
+ return files;
287
+ }
288
+ async function runForger(config) {
289
+ const root = process.cwd();
290
+ const forgerFile = (0, node_path_1.resolve)(root, "schema.forger");
291
+ if (!(0, node_fs_1.existsSync)(forgerFile)) {
292
+ throw new Error("schema.forger file not found in project root");
293
+ }
294
+ const source = (0, node_fs_1.readFileSync)(forgerFile, "utf-8");
295
+ const schema = (0, parser_1.parse)(source);
296
+ (0, parser_1.analyze)(schema);
297
+ const cached = (0, schema_cache_1.readCache)(root);
298
+ const codemodLogs = [];
299
+ if (cached) {
300
+ const diff = (0, schema_cache_1.diffSchemas)(cached, schema);
301
+ if (diff.renames.length > 0) {
302
+ const logs = (0, codemod_1.applyCodemod)(config.outDir, diff.renames);
303
+ codemodLogs.push(...logs);
304
+ }
305
+ }
306
+ (0, schema_cache_1.writeCache)(root, schema);
307
+ const files = await generate(schema, config);
308
+ const hasModules = schema.models.length > 0 ||
309
+ schema.actions.length > 0 ||
310
+ schema.modules.length > 0;
311
+ const registerLog = (0, codemod_1.registerForgerModules)(config.outDir, hasModules);
312
+ if (registerLog)
313
+ codemodLogs.push(registerLog);
314
+ if (codemodLogs.length > 0) {
315
+ console.log("\x1b[33m[codemod]\x1b[0m");
316
+ for (const log of codemodLogs) {
317
+ console.log(log);
318
+ }
319
+ }
320
+ return files;
321
+ }
322
+ function watchForger(config) {
323
+ const forgerFile = (0, node_path_1.resolve)(process.cwd(), "schema.forger");
324
+ let running = false;
325
+ async function regenerate() {
326
+ if (running)
327
+ return;
328
+ running = true;
329
+ try {
330
+ const source = (0, node_fs_1.readFileSync)(forgerFile, "utf-8");
331
+ const schema = (0, parser_1.parse)(source);
332
+ (0, parser_1.analyze)(schema);
333
+ const root = process.cwd();
334
+ const cached = (0, schema_cache_1.readCache)(root);
335
+ const codemodLogs = [];
336
+ if (cached) {
337
+ const diff = (0, schema_cache_1.diffSchemas)(cached, schema);
338
+ if (diff.renames.length > 0) {
339
+ const logs = (0, codemod_1.applyCodemod)(config.outDir, diff.renames);
340
+ codemodLogs.push(...logs);
341
+ }
342
+ }
343
+ (0, schema_cache_1.writeCache)(root, schema);
344
+ const files = await generate(schema, config);
345
+ const hasModules = schema.models.length > 0 ||
346
+ schema.actions.length > 0 ||
347
+ schema.modules.length > 0;
348
+ const registerLog = (0, codemod_1.registerForgerModules)(config.outDir, hasModules);
349
+ if (registerLog)
350
+ codemodLogs.push(registerLog);
351
+ const t = new Date().toLocaleTimeString();
352
+ console.log(`\x1b[36m[${t}]\x1b[0m \x1b[32m✓\x1b[0m ${files.length} files`);
353
+ if (codemodLogs.length > 0) {
354
+ console.log("\x1b[33m[codemod]\x1b[0m");
355
+ for (const log of codemodLogs) {
356
+ console.log(log);
357
+ }
358
+ }
359
+ }
360
+ catch (err) {
361
+ const t = new Date().toLocaleTimeString();
362
+ console.error(`\x1b[36m[${t}]\x1b[0m \x1b[31m✗\x1b[0m ${err.message}`);
363
+ }
364
+ finally {
365
+ running = false;
366
+ }
367
+ }
368
+ regenerate();
369
+ console.log("\x1b[36m[\x1b[35mwatch\x1b[36m]\x1b[0m watching schema.forger");
370
+ let timer = null;
371
+ (0, node_fs_1.watch)(forgerFile, () => {
372
+ if (timer)
373
+ clearTimeout(timer);
374
+ timer = setTimeout(regenerate, 300);
375
+ });
376
+ }
@@ -0,0 +1,25 @@
1
+ import type { ForgerAction, ForgerEnum, ForgerEvent, ForgerModel, ForgerSchema } from "@forgerapi/ast";
2
+ interface CachedSchema {
3
+ enums: ForgerEnum[];
4
+ models: ForgerModel[];
5
+ actions: ForgerAction[];
6
+ events: ForgerEvent[];
7
+ }
8
+ export interface SchemaDiff {
9
+ addedModels: ForgerModel[];
10
+ removedModels: ForgerModel[];
11
+ addedActions: ForgerAction[];
12
+ removedActions: ForgerAction[];
13
+ addedEvents: ForgerEvent[];
14
+ removedEvents: ForgerEvent[];
15
+ renames: RenameInfo[];
16
+ }
17
+ export interface RenameInfo {
18
+ type: "model" | "action" | "event";
19
+ oldName: string;
20
+ newName: string;
21
+ }
22
+ export declare function readCache(root: string): CachedSchema | null;
23
+ export declare function writeCache(root: string, schema: ForgerSchema): void;
24
+ export declare function diffSchemas(old: CachedSchema, current: ForgerSchema): SchemaDiff;
25
+ export {};
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readCache = readCache;
4
+ exports.writeCache = writeCache;
5
+ exports.diffSchemas = diffSchemas;
6
+ const node_fs_1 = require("node:fs");
7
+ const node_path_1 = require("node:path");
8
+ const CACHE_FILE = ".schema-cache.json";
9
+ function readCache(root) {
10
+ const path = (0, node_path_1.resolve)(root, CACHE_FILE);
11
+ if (!(0, node_fs_1.existsSync)(path))
12
+ return null;
13
+ try {
14
+ return JSON.parse((0, node_fs_1.readFileSync)(path, "utf-8"));
15
+ }
16
+ catch {
17
+ return null;
18
+ }
19
+ }
20
+ function writeCache(root, schema) {
21
+ const path = (0, node_path_1.resolve)(root, CACHE_FILE);
22
+ (0, node_fs_1.writeFileSync)(path, JSON.stringify(schema, null, 2), "utf-8");
23
+ }
24
+ function diffSchemas(old, current) {
25
+ const oldModels = new Map(old.models.map((m) => [m.name, m]));
26
+ const currentModels = new Map(current.models.map((m) => [m.name, m]));
27
+ const oldActions = new Map(old.actions.map((a) => [a.name, a]));
28
+ const currentActions = new Map(current.actions.map((a) => [a.name, a]));
29
+ const oldEvents = new Map(old.events.map((e) => [e.name, e]));
30
+ const currentEvents = new Map(current.events.map((e) => [e.name, e]));
31
+ const addedModels = [];
32
+ const removedModels = [];
33
+ const addedActions = [];
34
+ const removedActions = [];
35
+ const addedEvents = [];
36
+ const removedEvents = [];
37
+ const renames = [];
38
+ for (const [name, m] of oldModels) {
39
+ if (!currentModels.has(name))
40
+ removedModels.push(m);
41
+ }
42
+ for (const [name, a] of oldActions) {
43
+ if (!currentActions.has(name))
44
+ removedActions.push(a);
45
+ }
46
+ for (const [name, e] of oldEvents) {
47
+ if (!currentEvents.has(name))
48
+ removedEvents.push(e);
49
+ }
50
+ for (const [name, m] of currentModels) {
51
+ if (!oldModels.has(name))
52
+ addedModels.push(m);
53
+ }
54
+ for (const [name, a] of currentActions) {
55
+ if (!oldActions.has(name))
56
+ addedActions.push(a);
57
+ }
58
+ for (const [name, e] of currentEvents) {
59
+ if (!oldEvents.has(name))
60
+ addedEvents.push(e);
61
+ }
62
+ if (removedModels.length === 1 && addedModels.length === 1) {
63
+ const removed = removedModels[0];
64
+ const added = addedModels[0];
65
+ const ratio = Math.min(removed.fields.length, added.fields.length) /
66
+ Math.max(removed.fields.length, added.fields.length);
67
+ if (ratio >= 0.5) {
68
+ renames.push({
69
+ type: "model",
70
+ oldName: removed.name,
71
+ newName: added.name,
72
+ });
73
+ }
74
+ }
75
+ if (removedActions.length === 1 && addedActions.length === 1) {
76
+ renames.push({
77
+ type: "action",
78
+ oldName: removedActions[0].name,
79
+ newName: addedActions[0].name,
80
+ });
81
+ }
82
+ if (removedEvents.length === 1 && addedEvents.length === 1) {
83
+ renames.push({
84
+ type: "event",
85
+ oldName: removedEvents[0].name,
86
+ newName: addedEvents[0].name,
87
+ });
88
+ }
89
+ return {
90
+ addedModels,
91
+ removedModels,
92
+ addedActions,
93
+ removedActions,
94
+ addedEvents,
95
+ removedEvents,
96
+ renames,
97
+ };
98
+ }
@@ -0,0 +1 @@
1
+ export declare function toKebab(name: string): string;
package/dist/utils.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toKebab = toKebab;
4
+ function toKebab(name) {
5
+ return name.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
6
+ }
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@forgerapi/codegen",
3
+ "version": "0.0.1",
4
+ "main": "dist/index.js",
5
+ "types": "dist/index.d.ts",
6
+ "files": [
7
+ "dist"
8
+ ],
9
+ "publishConfig": {
10
+ "access": "public"
11
+ },
12
+ "license": "MIT",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/linecodesxx/forgerapi.git",
16
+ "directory": "packages/codegen"
17
+ },
18
+ "scripts": {
19
+ "build": "tsc"
20
+ },
21
+ "dependencies": {
22
+ "@forgerapi/ast": "^0.0.1",
23
+ "@forgerapi/parser": "^0.0.1",
24
+ "ts-morph": "^28.0.0"
25
+ },
26
+ "devDependencies": {
27
+ "@types/node": "^26.0.1"
28
+ }
29
+ }