ormbridge 0.0.0-stage → 0.3.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.
Files changed (93) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +459 -2
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +20 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/cliRunner.d.ts +20 -0
  7. package/dist/cliRunner.js +363 -0
  8. package/dist/cliRunner.js.map +1 -0
  9. package/dist/config.d.ts +44 -0
  10. package/dist/config.js +220 -0
  11. package/dist/config.js.map +1 -0
  12. package/dist/convert.d.ts +20 -0
  13. package/dist/convert.js +61 -0
  14. package/dist/convert.js.map +1 -0
  15. package/dist/emitters/django.d.ts +4 -0
  16. package/dist/emitters/django.js +501 -0
  17. package/dist/emitters/django.js.map +1 -0
  18. package/dist/emitters/doctrine.d.ts +20 -0
  19. package/dist/emitters/doctrine.js +1134 -0
  20. package/dist/emitters/doctrine.js.map +1 -0
  21. package/dist/emitters/gorm.d.ts +38 -0
  22. package/dist/emitters/gorm.js +1507 -0
  23. package/dist/emitters/gorm.js.map +1 -0
  24. package/dist/emitters/graphene.d.ts +4 -0
  25. package/dist/emitters/graphene.js +431 -0
  26. package/dist/emitters/graphene.js.map +1 -0
  27. package/dist/emitters/laravel.d.ts +33 -0
  28. package/dist/emitters/laravel.js +1695 -0
  29. package/dist/emitters/laravel.js.map +1 -0
  30. package/dist/emitters/prisma.d.ts +21 -0
  31. package/dist/emitters/prisma.js +1058 -0
  32. package/dist/emitters/prisma.js.map +1 -0
  33. package/dist/emitters/typeorm.d.ts +9 -0
  34. package/dist/emitters/typeorm.js +838 -0
  35. package/dist/emitters/typeorm.js.map +1 -0
  36. package/dist/emitters/typescriptInterfaces.d.ts +15 -0
  37. package/dist/emitters/typescriptInterfaces.js +350 -0
  38. package/dist/emitters/typescriptInterfaces.js.map +1 -0
  39. package/dist/formats.d.ts +82 -0
  40. package/dist/formats.js +238 -0
  41. package/dist/formats.js.map +1 -0
  42. package/dist/index.d.ts +37 -0
  43. package/dist/index.js +20 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/io.d.ts +48 -0
  46. package/dist/io.js +343 -0
  47. package/dist/io.js.map +1 -0
  48. package/dist/ir.d.ts +197 -0
  49. package/dist/ir.js +10 -0
  50. package/dist/ir.js.map +1 -0
  51. package/dist/naming.d.ts +11 -0
  52. package/dist/naming.js +88 -0
  53. package/dist/naming.js.map +1 -0
  54. package/dist/parsers/django.d.ts +14 -0
  55. package/dist/parsers/django.js +1161 -0
  56. package/dist/parsers/django.js.map +1 -0
  57. package/dist/parsers/doctrine.d.ts +12 -0
  58. package/dist/parsers/doctrine.js +1984 -0
  59. package/dist/parsers/doctrine.js.map +1 -0
  60. package/dist/parsers/goSyntax.d.ts +105 -0
  61. package/dist/parsers/goSyntax.js +435 -0
  62. package/dist/parsers/goSyntax.js.map +1 -0
  63. package/dist/parsers/gorm.d.ts +16 -0
  64. package/dist/parsers/gorm.js +1857 -0
  65. package/dist/parsers/gorm.js.map +1 -0
  66. package/dist/parsers/laravel.d.ts +17 -0
  67. package/dist/parsers/laravel.js +2824 -0
  68. package/dist/parsers/laravel.js.map +1 -0
  69. package/dist/parsers/phpSyntax.d.ts +124 -0
  70. package/dist/parsers/phpSyntax.js +429 -0
  71. package/dist/parsers/phpSyntax.js.map +1 -0
  72. package/dist/parsers/prisma.d.ts +12 -0
  73. package/dist/parsers/prisma.js +964 -0
  74. package/dist/parsers/prisma.js.map +1 -0
  75. package/dist/parsers/pythonSyntax.d.ts +38 -0
  76. package/dist/parsers/pythonSyntax.js +120 -0
  77. package/dist/parsers/pythonSyntax.js.map +1 -0
  78. package/dist/parsers/typeorm.d.ts +12 -0
  79. package/dist/parsers/typeorm.js +1614 -0
  80. package/dist/parsers/typeorm.js.map +1 -0
  81. package/dist/parsers/typescriptSyntax.d.ts +57 -0
  82. package/dist/parsers/typescriptSyntax.js +200 -0
  83. package/dist/parsers/typescriptSyntax.js.map +1 -0
  84. package/dist/prismaOnlyConstructs.d.ts +7 -0
  85. package/dist/prismaOnlyConstructs.js +76 -0
  86. package/dist/prismaOnlyConstructs.js.map +1 -0
  87. package/dist/result.d.ts +20 -0
  88. package/dist/result.js +18 -0
  89. package/dist/result.js.map +1 -0
  90. package/dist/transforms.d.ts +13 -0
  91. package/dist/transforms.js +142 -0
  92. package/dist/transforms.js.map +1 -0
  93. package/package.json +83 -4
package/dist/io.js ADDED
@@ -0,0 +1,343 @@
1
+ import { mkdir, readdir, readFile, stat, writeFile } from 'node:fs/promises';
2
+ import { basename, dirname, extname, isAbsolute, join, resolve, } from 'node:path';
3
+ import { convertText, } from './convert.js';
4
+ import { describeThrown, err, ok } from './result.js';
5
+ /** Directories skipped only when reading PHP projects: Composer packages and Symfony's cache/log directory. */
6
+ const PHP_SKIPPED_DIRECTORIES = new Set(['vendor', 'var']);
7
+ /** Directories skipped when reading Go projects: vendored modules and Go's conventional test data. */
8
+ const GO_SKIPPED_DIRECTORIES = new Set([
9
+ 'vendor',
10
+ 'node_modules',
11
+ 'testdata',
12
+ '.git',
13
+ ]);
14
+ /**
15
+ * Directories skipped when reading a Laravel project. The Django list does not
16
+ * apply: `migrations` is where Laravel keeps its schema, and `build` / `env` /
17
+ * `dist` are ordinary names there.
18
+ */
19
+ const LARAVEL_SKIPPED_DIRECTORIES = new Set([
20
+ 'vendor',
21
+ 'storage',
22
+ 'node_modules',
23
+ 'tests',
24
+ '.git',
25
+ ]);
26
+ const SKIPPED_DIRECTORIES = new Set([
27
+ 'node_modules',
28
+ 'venv',
29
+ '.venv',
30
+ 'env',
31
+ '.git',
32
+ '__pycache__',
33
+ 'migrations',
34
+ 'site-packages',
35
+ 'dist',
36
+ 'build',
37
+ ]);
38
+ /** Reads the inputs, converts them, and writes the result to the output path when one is given. */
39
+ export async function runConversion(options) {
40
+ const discovered = await discoverInputFiles(options.inputs, options.from);
41
+ if (!discovered.ok) {
42
+ return discovered;
43
+ }
44
+ const sources = [];
45
+ for (const filePath of discovered.value) {
46
+ const read = await readTextFile(filePath);
47
+ if (!read.ok) {
48
+ return read;
49
+ }
50
+ sources.push({
51
+ path: filePath,
52
+ text: read.value,
53
+ appLabel: deriveAppLabel(filePath),
54
+ });
55
+ }
56
+ const converted = await convertText(sources, options);
57
+ if (!converted.ok) {
58
+ return converted;
59
+ }
60
+ const summary = {
61
+ ...converted.value,
62
+ inputFiles: discovered.value,
63
+ plannedFiles: [],
64
+ written: false,
65
+ };
66
+ if (options.output === undefined) {
67
+ if (converted.value.files !== undefined) {
68
+ return err('INVALID_OPTION', `The "${options.to}" format produces ${Object.keys(converted.value.files).length} files, so it needs an output directory. Pass -o <directory>.`);
69
+ }
70
+ return ok(summary);
71
+ }
72
+ const planned = await planOutput(resolve(options.output), converted.value, options.to);
73
+ if (!planned.ok) {
74
+ return planned;
75
+ }
76
+ const outputPath = resolve(options.output);
77
+ const withPlan = {
78
+ ...summary,
79
+ outputPath,
80
+ plannedFiles: planned.value,
81
+ };
82
+ if (options.dryRun === true || options.check === true) {
83
+ return ok(withPlan);
84
+ }
85
+ for (const file of planned.value) {
86
+ if (file.state === 'unchanged') {
87
+ continue;
88
+ }
89
+ const written = await writeTextFile(file.path, file.text);
90
+ if (!written.ok) {
91
+ return written;
92
+ }
93
+ }
94
+ return ok({ ...withPlan, written: true });
95
+ }
96
+ /** Works out the destination files and compares each with what is already on disk. */
97
+ async function planOutput(outputPath, converted, format) {
98
+ const existing = await classifyPath(outputPath);
99
+ const entries = [];
100
+ if (converted.files === undefined) {
101
+ if (existing === 'directory') {
102
+ return err('INVALID_OPTION', `The output path "${outputPath}" is a directory, but the "${format}" format produces a single file. Pass a file path to -o.`);
103
+ }
104
+ entries.push([outputPath, converted.output]);
105
+ }
106
+ else {
107
+ const names = Object.keys(converted.files).sort();
108
+ if (existing === 'file' ||
109
+ (existing === 'missing' && extname(outputPath) !== '')) {
110
+ return err('INVALID_OPTION', `The "${format}" format produces ${names.length} files (${names.join(', ')}), so -o must be a directory, but "${outputPath}" is a file path. Pass a directory such as "${join(dirname(outputPath), basename(outputPath, extname(outputPath)))}".`);
111
+ }
112
+ for (const name of names) {
113
+ const target = resolveInside(outputPath, name);
114
+ if (!target.ok) {
115
+ return target;
116
+ }
117
+ entries.push([target.value, converted.files[name] ?? '']);
118
+ }
119
+ }
120
+ const planned = [];
121
+ for (const [path, text] of entries) {
122
+ const current = await readIfExists(path);
123
+ const file = {
124
+ path,
125
+ text,
126
+ bytes: Buffer.byteLength(text, 'utf8'),
127
+ lines: countLines(text),
128
+ state: current === undefined
129
+ ? 'created'
130
+ : current === text
131
+ ? 'unchanged'
132
+ : 'changed',
133
+ };
134
+ if (current !== undefined && current !== text) {
135
+ file.diff = summarizeDiff(current, text);
136
+ }
137
+ planned.push(file);
138
+ }
139
+ return ok(planned);
140
+ }
141
+ async function classifyPath(path) {
142
+ try {
143
+ const info = await stat(path);
144
+ if (info.isDirectory()) {
145
+ return 'directory';
146
+ }
147
+ return info.isFile() ? 'file' : 'other';
148
+ }
149
+ catch {
150
+ return 'missing';
151
+ }
152
+ }
153
+ async function readIfExists(path) {
154
+ try {
155
+ return await readFile(path, 'utf8');
156
+ }
157
+ catch {
158
+ return undefined;
159
+ }
160
+ }
161
+ /** Resolves an emitter-provided relative path under the output directory, rejecting escapes. */
162
+ function resolveInside(directory, relativePath) {
163
+ if (relativePath === '' ||
164
+ isAbsolute(relativePath) ||
165
+ relativePath.split(/[\\/]/).includes('..')) {
166
+ return err('EMIT_FAILED', `The emitter returned the file path "${relativePath}", which is not a relative path inside the output directory.`);
167
+ }
168
+ return ok(resolve(directory, relativePath));
169
+ }
170
+ /** Counts lines the way an editor does: a trailing newline does not add a line. */
171
+ export function countLines(text) {
172
+ if (text === '') {
173
+ return 0;
174
+ }
175
+ const newlines = text.split('\n').length - 1;
176
+ return text.endsWith('\n') ? newlines : newlines + 1;
177
+ }
178
+ /**
179
+ * Describes how two texts differ in a short line, for example
180
+ * "+3 -1 lines (first difference at line 12)".
181
+ */
182
+ export function summarizeDiff(before, after) {
183
+ const oldLines = before.split('\n');
184
+ const newLines = after.split('\n');
185
+ const counts = new Map();
186
+ for (const line of oldLines) {
187
+ counts.set(line, (counts.get(line) ?? 0) + 1);
188
+ }
189
+ let added = 0;
190
+ for (const line of newLines) {
191
+ const remaining = counts.get(line) ?? 0;
192
+ if (remaining > 0) {
193
+ counts.set(line, remaining - 1);
194
+ }
195
+ else {
196
+ added += 1;
197
+ }
198
+ }
199
+ let removed = 0;
200
+ for (const remaining of counts.values()) {
201
+ removed += remaining;
202
+ }
203
+ let first = 0;
204
+ while (first < oldLines.length &&
205
+ first < newLines.length &&
206
+ oldLines[first] === newLines[first]) {
207
+ first += 1;
208
+ }
209
+ return `+${added} -${removed} lines (first difference at line ${first + 1})`;
210
+ }
211
+ async function readTextFile(filePath) {
212
+ try {
213
+ return ok(await readFile(filePath, 'utf8'));
214
+ }
215
+ catch (thrown) {
216
+ return err('INPUT_READ_FAILED', `Could not read "${filePath}": ${describeThrown(thrown)}`);
217
+ }
218
+ }
219
+ async function writeTextFile(outputPath, text) {
220
+ const absolutePath = resolve(outputPath);
221
+ try {
222
+ await mkdir(dirname(absolutePath), { recursive: true });
223
+ await writeFile(absolutePath, text, 'utf8');
224
+ return ok(absolutePath);
225
+ }
226
+ catch (thrown) {
227
+ return err('OUTPUT_WRITE_FAILED', `Could not write the output file "${absolutePath}": ${describeThrown(thrown)}`);
228
+ }
229
+ }
230
+ /** Derives a Django app label from the location of a models.py file or models/ package. */
231
+ export function deriveAppLabel(filePath) {
232
+ const absolutePath = resolve(filePath);
233
+ const directory = dirname(absolutePath);
234
+ if (basename(directory) === 'models') {
235
+ return basename(dirname(directory));
236
+ }
237
+ return basename(directory);
238
+ }
239
+ async function discoverInputFiles(inputs, format) {
240
+ const files = [];
241
+ for (const input of inputs) {
242
+ let inputStat;
243
+ try {
244
+ inputStat = await stat(input);
245
+ }
246
+ catch {
247
+ return err('INPUT_NOT_FOUND', `The input path "${input}" does not exist or is not readable.`);
248
+ }
249
+ if (inputStat.isDirectory()) {
250
+ const roots = format === 'laravel' ? await laravelRoots(input) : [input];
251
+ for (const root of roots) {
252
+ files.push(...(await walkDirectory(root, format)));
253
+ }
254
+ }
255
+ else {
256
+ files.push(input);
257
+ }
258
+ }
259
+ if (files.length === 0) {
260
+ const expected = format === 'django'
261
+ ? 'models.py files (or a models/ package)'
262
+ : format === 'typeorm'
263
+ ? 'TypeScript (.ts) entity files'
264
+ : format === 'doctrine'
265
+ ? 'PHP (.php) entity files'
266
+ : format === 'laravel'
267
+ ? 'PHP (.php) migration and model files (database/migrations and app/)'
268
+ : format === 'gorm'
269
+ ? 'Go (.go) model files'
270
+ : '.prisma files';
271
+ return err('NO_INPUT_FILES', `No ${expected} were found in: ${inputs.join(', ')}.`);
272
+ }
273
+ return ok(files);
274
+ }
275
+ function isRelevantFile(filePath, format) {
276
+ if (format === 'prisma') {
277
+ return extname(filePath) === '.prisma';
278
+ }
279
+ if (format === 'typeorm') {
280
+ return (extname(filePath) === '.ts' &&
281
+ !/\.(d|test|spec)\.ts$/.test(basename(filePath)));
282
+ }
283
+ if (format === 'gorm') {
284
+ return (extname(filePath) === '.go' && !/_test\.go$/.test(basename(filePath)));
285
+ }
286
+ if (format === 'doctrine' || format === 'laravel') {
287
+ return (extname(filePath) === '.php' && !/Test\.php$/.test(basename(filePath)));
288
+ }
289
+ const parentName = basename(dirname(filePath));
290
+ const fileName = basename(filePath);
291
+ if (fileName === 'models.py') {
292
+ return true;
293
+ }
294
+ return (parentName === 'models' &&
295
+ extname(fileName) === '.py' &&
296
+ fileName !== '__init__.py');
297
+ }
298
+ function isSkippedDirectory(name, parent, format) {
299
+ if (format === 'laravel') {
300
+ // bootstrap/cache holds generated files; the rest of bootstrap/ is ordinary code.
301
+ return (LARAVEL_SKIPPED_DIRECTORIES.has(name) ||
302
+ (name === 'cache' && basename(parent) === 'bootstrap'));
303
+ }
304
+ if (format === 'gorm') {
305
+ return GO_SKIPPED_DIRECTORIES.has(name);
306
+ }
307
+ return (SKIPPED_DIRECTORIES.has(name) ||
308
+ (format === 'doctrine' && PHP_SKIPPED_DIRECTORIES.has(name)));
309
+ }
310
+ /**
311
+ * For a Laravel project root (it has `database/migrations` or `app`), only those
312
+ * two directories are read. Any other directory, such as `app/Models` or
313
+ * `database/migrations` passed on its own, is read as given.
314
+ */
315
+ async function laravelRoots(directory) {
316
+ const roots = [];
317
+ for (const candidate of [
318
+ join(directory, 'database', 'migrations'),
319
+ join(directory, 'app'),
320
+ ]) {
321
+ if ((await classifyPath(candidate)) === 'directory') {
322
+ roots.push(candidate);
323
+ }
324
+ }
325
+ return roots.length > 0 ? roots : [directory];
326
+ }
327
+ async function walkDirectory(directory, format) {
328
+ const entries = await readdir(directory, { withFileTypes: true });
329
+ const found = [];
330
+ for (const entry of entries.sort((first, second) => first.name.localeCompare(second.name))) {
331
+ const entryPath = join(directory, entry.name);
332
+ if (entry.isDirectory()) {
333
+ if (!isSkippedDirectory(entry.name, directory, format)) {
334
+ found.push(...(await walkDirectory(entryPath, format)));
335
+ }
336
+ }
337
+ else if (isRelevantFile(entryPath, format)) {
338
+ found.push(entryPath);
339
+ }
340
+ }
341
+ return found;
342
+ }
343
+ //# sourceMappingURL=io.js.map
package/dist/io.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"io.js","sourceRoot":"","sources":["../src/io.ts"],"names":[],"mappings":"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"}
package/dist/ir.d.ts ADDED
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Intermediate representation (IR) shared by every parser and emitter.
3
+ *
4
+ * Each supported format (Django, Prisma, and later TypeORM / Graphene) only
5
+ * needs to know how to read into and write out of this model.
6
+ */
7
+ export type IrScalarType = 'string' | 'text' | 'int' | 'bigInt' | 'float' | 'decimal' | 'boolean' | 'dateTime' | 'date' | 'time' | 'uuid' | 'json' | 'bytes' | 'duration' | 'ipAddress' | 'hstore' | 'range' | 'unsupported';
8
+ /** Element type of a `range` field (Django's django.contrib.postgres range fields). */
9
+ export type IrRangeSubtype = 'int' | 'bigInt' | 'decimal' | 'date' | 'dateTime';
10
+ /** A provider-specific column type attribute, e.g. Prisma `@db.VarChar(255)` as `{ name: "VarChar", args: ["255"] }`. */
11
+ export interface IrNativeType {
12
+ name: string;
13
+ args: string[];
14
+ }
15
+ /** A database-computed column (Django GeneratedField). */
16
+ export interface IrGenerated {
17
+ /** Expression source as written in the input, e.g. `F("a") + F("b")`. */
18
+ expression: string;
19
+ /** True when the value is stored (db_persist=True), false when computed on read. */
20
+ isStored: boolean;
21
+ }
22
+ export type IrDefault = {
23
+ kind: 'literal';
24
+ value: string | number | boolean;
25
+ } | {
26
+ kind: 'autoIncrement';
27
+ } | {
28
+ kind: 'now';
29
+ } | {
30
+ kind: 'uuid';
31
+ version?: number;
32
+ } | {
33
+ kind: 'enumValue';
34
+ value: string;
35
+ }
36
+ /** Generated by the ORM client rather than the database (Prisma cuid(), ulid(), nanoid()). */
37
+ | {
38
+ kind: 'clientGenerated';
39
+ generator: string;
40
+ args?: string;
41
+ }
42
+ /**
43
+ * A raw database expression, stored without the quotes (Prisma `dbgenerated("gen_random_uuid()")`).
44
+ * With `isFunction`, the expression is a Prisma default function written as-is, e.g. `auto()` or `sequence()`.
45
+ */
46
+ | {
47
+ kind: 'dbExpression';
48
+ expression: string;
49
+ isFunction?: boolean;
50
+ };
51
+ export interface IrField {
52
+ /** Field name as written in the source format. */
53
+ name: string;
54
+ /** Database column name. */
55
+ columnName: string;
56
+ type: IrScalarType;
57
+ isPrimaryKey: boolean;
58
+ isUnique: boolean;
59
+ isNullable: boolean;
60
+ default?: IrDefault;
61
+ maxLength?: number;
62
+ maxDigits?: number;
63
+ decimalPlaces?: number;
64
+ /** True when the value is refreshed on every save (Django auto_now, Prisma @updatedAt). */
65
+ isAutoUpdated: boolean;
66
+ /** Name of an IrEnum when the field is enum-backed. */
67
+ enumName?: string;
68
+ /**
69
+ * Number of array dimensions (Django ArrayField, nested ArrayFields add one each).
70
+ * When set, `type` (and maxLength, enumName, ...) describe the innermost element.
71
+ */
72
+ arrayDepth?: number;
73
+ /** Element type of the field when `type` is "range". */
74
+ rangeOf?: IrRangeSubtype;
75
+ /** Set when the column is computed by the database from an expression. */
76
+ generated?: IrGenerated;
77
+ /** True when `default` is a database-level default (Django db_default). */
78
+ isDbDefault?: boolean;
79
+ /** Native column type as written in the source (Prisma `@db.*`); only valid for that provider family. */
80
+ nativeType?: IrNativeType;
81
+ /** Raw database type text of an `unsupported` field, e.g. `circle` for Prisma `Unsupported("circle")`. */
82
+ unsupportedType?: string;
83
+ /** True when the field is excluded from the generated client (Prisma @ignore). */
84
+ isIgnored?: boolean;
85
+ /** Database name of the unique constraint (Prisma `@unique(map: "...")`). */
86
+ uniqueName?: string;
87
+ }
88
+ export type IrOnDelete = 'cascade' | 'setNull' | 'restrict' | 'noAction' | 'setDefault';
89
+ export type IrRelationKind = 'foreignKey' | 'oneToOne' | 'manyToMany';
90
+ export interface IrRelation {
91
+ /** Relation field name, e.g. "author". */
92
+ name: string;
93
+ kind: IrRelationKind;
94
+ /** Target model name. */
95
+ targetModel: string;
96
+ /** Foreign-key column on this model (unused for manyToMany). */
97
+ columnName: string;
98
+ isNullable: boolean;
99
+ onDelete: IrOnDelete;
100
+ /** Name of the reverse accessor on the target model. */
101
+ relatedName?: string;
102
+ /** Target column when it is not the primary key. */
103
+ toField?: string;
104
+ /** True when this relation is the primary key (multi-table inheritance). */
105
+ isPrimaryKey?: boolean;
106
+ /** Referential action on update (Prisma onUpdate). */
107
+ onUpdate?: IrOnDelete;
108
+ /** Database name of the foreign-key constraint (Prisma `@relation(map: "...")`). */
109
+ constraintName?: string;
110
+ }
111
+ /**
112
+ * A foreign key made of several columns (Prisma `@relation(fields: [a, b], references: [x, y])`).
113
+ * The local columns stay ordinary fields of the model; only Prisma reads and writes this.
114
+ */
115
+ export interface IrCompositeForeignKey {
116
+ /** Relation field name, e.g. "order". */
117
+ name: string;
118
+ targetModel: string;
119
+ /** Local field names, in key order. */
120
+ fields: string[];
121
+ /** Referenced field names on the target model, in the same order. */
122
+ references: string[];
123
+ kind: 'foreignKey' | 'oneToOne';
124
+ isNullable: boolean;
125
+ onDelete: IrOnDelete;
126
+ onUpdate?: IrOnDelete;
127
+ relatedName?: string;
128
+ /** Database name of the constraint. */
129
+ constraintName?: string;
130
+ }
131
+ /** Per-field options of an index entry (Prisma `a(sort: Desc, length: 10, ops: ...)`). */
132
+ export interface IrIndexFieldOptions {
133
+ sort?: 'asc' | 'desc';
134
+ length?: number;
135
+ /** Operator class as written, e.g. `JsonbPathOps` or `raw("gin_trgm_ops")`. */
136
+ ops?: string;
137
+ }
138
+ export interface IrIndex {
139
+ /** Field or relation names (IR names, not column names). */
140
+ fields: string[];
141
+ isUnique: boolean;
142
+ /** Explicit database name, when the source specified one. */
143
+ name?: string;
144
+ /** "fulltext" for Prisma @@fulltext; absent for ordinary indexes. */
145
+ kind?: 'fulltext';
146
+ /** Access method as written (Prisma `type: Hash | Gin | Gist | SpGist | Brin | BTree`). */
147
+ method?: string;
148
+ /** SQL Server clustered / non-clustered; absent when unspecified. */
149
+ clustered?: boolean;
150
+ /** Options for individual entries of `fields`, keyed by field name. */
151
+ fieldOptions?: Record<string, IrIndexFieldOptions>;
152
+ }
153
+ export interface IrModel {
154
+ name: string;
155
+ tableName: string;
156
+ /** Django app label, used to build default table names. */
157
+ appLabel: string;
158
+ fields: IrField[];
159
+ relations: IrRelation[];
160
+ indexes: IrIndex[];
161
+ /** Composite primary key made of IR field/relation names (Prisma @@id). */
162
+ compositePrimaryKey?: string[];
163
+ /** True for join models synthesized from a many-to-many field. */
164
+ isJoinTable?: boolean;
165
+ /** True for database views (Prisma `view` blocks). */
166
+ isView?: boolean;
167
+ /** True when the model is excluded from the generated client (Prisma @@ignore). */
168
+ isIgnored?: boolean;
169
+ /** Database schema the table lives in (Prisma @@schema, multiSchema). */
170
+ schema?: string;
171
+ /** Database name of the primary-key constraint (Prisma `@id(map:)` / `@@id(map:)`). */
172
+ primaryKeyName?: string;
173
+ /** Multi-column foreign keys (Prisma). Single-column keys are in `relations`. */
174
+ compositeForeignKeys?: IrCompositeForeignKey[];
175
+ }
176
+ export interface IrEnumValue {
177
+ /** Member name, e.g. "ADMIN". */
178
+ name: string;
179
+ /** Stored database value, e.g. "admin". */
180
+ dbValue: string;
181
+ /** Human-readable label (Django TextChoices). */
182
+ label?: string;
183
+ }
184
+ export interface IrEnum {
185
+ name: string;
186
+ values: IrEnumValue[];
187
+ /** Database type name when it differs from `name` (Prisma @@map on an enum). */
188
+ dbName?: string;
189
+ /** Database schema the enum lives in (Prisma @@schema). */
190
+ schema?: string;
191
+ }
192
+ export interface IrSchema {
193
+ models: IrModel[];
194
+ enums: IrEnum[];
195
+ warnings: string[];
196
+ }
197
+ export declare function findModel(schema: IrSchema, modelName: string): IrModel | undefined;
package/dist/ir.js ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Intermediate representation (IR) shared by every parser and emitter.
3
+ *
4
+ * Each supported format (Django, Prisma, and later TypeORM / Graphene) only
5
+ * needs to know how to read into and write out of this model.
6
+ */
7
+ export function findModel(schema, modelName) {
8
+ return schema.models.find((model) => model.name === modelName);
9
+ }
10
+ //# sourceMappingURL=ir.js.map
package/dist/ir.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ir.js","sourceRoot":"","sources":["../src/ir.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAmNH,MAAM,UAAU,SAAS,CACvB,MAAgB,EAChB,SAAiB;IAEjB,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;AACjE,CAAC"}
@@ -0,0 +1,11 @@
1
+ /** String casing and pluralization helpers. */
2
+ export declare function splitWords(input: string): string[];
3
+ export declare function toSnakeCase(input: string): string;
4
+ export declare function toPascalCase(input: string): string;
5
+ export declare function toCamelCase(input: string): string;
6
+ /** Singularizes the last word of a snake_case identifier using simple rules. */
7
+ export declare function singularize(snakeName: string): string;
8
+ /** Deterministic short hash used to keep generated database names within length limits. */
9
+ export declare function shortHash(input: string): string;
10
+ /** Truncates a database identifier to maxLength, appending a hash when shortened. */
11
+ export declare function limitIdentifier(identifier: string, maxLength: number): string;
package/dist/naming.js ADDED
@@ -0,0 +1,88 @@
1
+ /** String casing and pluralization helpers. */
2
+ const UNCOUNTABLE_WORDS = new Set([
3
+ 'series',
4
+ 'news',
5
+ 'species',
6
+ 'data',
7
+ 'media',
8
+ 'metadata',
9
+ 'status',
10
+ 'address',
11
+ 'access',
12
+ 'analysis',
13
+ ]);
14
+ const IRREGULAR_PLURALS = {
15
+ people: 'person',
16
+ children: 'child',
17
+ men: 'man',
18
+ women: 'woman',
19
+ };
20
+ export function splitWords(input) {
21
+ const spaced = input
22
+ .replace(/([a-z0-9])([A-Z])/g, '$1 $2')
23
+ .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2');
24
+ return spaced
25
+ .split(/[^A-Za-z0-9]+/)
26
+ .filter((word) => word.length > 0);
27
+ }
28
+ export function toSnakeCase(input) {
29
+ return splitWords(input)
30
+ .map((word) => word.toLowerCase())
31
+ .join('_');
32
+ }
33
+ export function toPascalCase(input) {
34
+ return splitWords(input)
35
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
36
+ .join('');
37
+ }
38
+ export function toCamelCase(input) {
39
+ const pascal = toPascalCase(input);
40
+ return pascal.charAt(0).toLowerCase() + pascal.slice(1);
41
+ }
42
+ /** Singularizes the last word of a snake_case identifier using simple rules. */
43
+ export function singularize(snakeName) {
44
+ const parts = snakeName.split('_');
45
+ const lastWord = parts[parts.length - 1] ?? '';
46
+ parts[parts.length - 1] = singularizeWord(lastWord);
47
+ return parts.join('_');
48
+ }
49
+ function singularizeWord(word) {
50
+ const lower = word.toLowerCase();
51
+ if (UNCOUNTABLE_WORDS.has(lower)) {
52
+ return word;
53
+ }
54
+ const irregular = IRREGULAR_PLURALS[lower];
55
+ if (irregular !== undefined) {
56
+ return irregular;
57
+ }
58
+ if (/ies$/.test(lower) && lower.length > 3) {
59
+ return word.slice(0, -3) + 'y';
60
+ }
61
+ if (/(ss|us|is)$/.test(lower)) {
62
+ return word;
63
+ }
64
+ if (/(x|ch|sh|ss)es$/.test(lower)) {
65
+ return word.slice(0, -2);
66
+ }
67
+ if (/s$/.test(lower) && lower.length > 1) {
68
+ return word.slice(0, -1);
69
+ }
70
+ return word;
71
+ }
72
+ /** Deterministic short hash used to keep generated database names within length limits. */
73
+ export function shortHash(input) {
74
+ let hash = 5381;
75
+ for (let index = 0; index < input.length; index += 1) {
76
+ hash = ((hash << 5) + hash + input.charCodeAt(index)) >>> 0;
77
+ }
78
+ return hash.toString(16).padStart(8, '0').slice(0, 6);
79
+ }
80
+ /** Truncates a database identifier to maxLength, appending a hash when shortened. */
81
+ export function limitIdentifier(identifier, maxLength) {
82
+ if (identifier.length <= maxLength) {
83
+ return identifier;
84
+ }
85
+ const hash = shortHash(identifier);
86
+ return `${identifier.slice(0, maxLength - hash.length - 1)}_${hash}`;
87
+ }
88
+ //# sourceMappingURL=naming.js.map