ormbridge 0.8.0 → 0.9.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.
- package/README.md +1 -0
- package/dist/cliRunner.js +3 -3
- package/dist/cliRunner.js.map +1 -1
- package/dist/config.d.ts +3 -2
- package/dist/config.js.map +1 -1
- package/dist/emitters/efcore.d.ts +40 -0
- package/dist/emitters/efcore.js +686 -0
- package/dist/emitters/efcore.js.map +1 -0
- package/dist/emitters/efcoreColumns.d.ts +75 -0
- package/dist/emitters/efcoreColumns.js +492 -0
- package/dist/emitters/efcoreColumns.js.map +1 -0
- package/dist/emitters/efcoreNames.d.ts +30 -0
- package/dist/emitters/efcoreNames.js +268 -0
- package/dist/emitters/efcoreNames.js.map +1 -0
- package/dist/emitters/efcoreRender.d.ts +2 -0
- package/dist/emitters/efcoreRender.js +570 -0
- package/dist/emitters/efcoreRender.js.map +1 -0
- package/dist/emitters/efcoreTypes.d.ts +114 -0
- package/dist/emitters/efcoreTypes.js +2 -0
- package/dist/emitters/efcoreTypes.js.map +1 -0
- package/dist/formats.d.ts +7 -4
- package/dist/formats.js +34 -0
- package/dist/formats.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/io.js +25 -1
- package/dist/io.js.map +1 -1
- package/dist/parsers/csharpChains.d.ts +36 -0
- package/dist/parsers/csharpChains.js +157 -0
- package/dist/parsers/csharpChains.js.map +1 -0
- package/dist/parsers/csharpDeclarations.d.ts +3 -0
- package/dist/parsers/csharpDeclarations.js +293 -0
- package/dist/parsers/csharpDeclarations.js.map +1 -0
- package/dist/parsers/csharpSyntax.d.ts +130 -0
- package/dist/parsers/csharpSyntax.js +339 -0
- package/dist/parsers/csharpSyntax.js.map +1 -0
- package/dist/parsers/efcore.d.ts +17 -0
- package/dist/parsers/efcore.js +265 -0
- package/dist/parsers/efcore.js.map +1 -0
- package/dist/parsers/efcoreAnnotations.d.ts +19 -0
- package/dist/parsers/efcoreAnnotations.js +293 -0
- package/dist/parsers/efcoreAnnotations.js.map +1 -0
- package/dist/parsers/efcoreBuild.d.ts +13 -0
- package/dist/parsers/efcoreBuild.js +523 -0
- package/dist/parsers/efcoreBuild.js.map +1 -0
- package/dist/parsers/efcoreEntities.d.ts +13 -0
- package/dist/parsers/efcoreEntities.js +468 -0
- package/dist/parsers/efcoreEntities.js.map +1 -0
- package/dist/parsers/efcoreFields.d.ts +22 -0
- package/dist/parsers/efcoreFields.js +285 -0
- package/dist/parsers/efcoreFields.js.map +1 -0
- package/dist/parsers/efcoreFluent.d.ts +47 -0
- package/dist/parsers/efcoreFluent.js +375 -0
- package/dist/parsers/efcoreFluent.js.map +1 -0
- package/dist/parsers/efcoreModel.d.ts +209 -0
- package/dist/parsers/efcoreModel.js +2 -0
- package/dist/parsers/efcoreModel.js.map +1 -0
- package/dist/parsers/efcoreRelations.d.ts +46 -0
- package/dist/parsers/efcoreRelations.js +317 -0
- package/dist/parsers/efcoreRelations.js.map +1 -0
- package/dist/parsers/efcoreSteps.d.ts +89 -0
- package/dist/parsers/efcoreSteps.js +793 -0
- package/dist/parsers/efcoreSteps.js.map +1 -0
- package/dist/parsers/efcoreTypes.d.ts +35 -0
- package/dist/parsers/efcoreTypes.js +404 -0
- package/dist/parsers/efcoreTypes.js.map +1 -0
- package/dist/styles.d.ts +3 -2
- package/dist/styles.js +4 -1
- package/dist/styles.js.map +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import Parser from 'web-tree-sitter';
|
|
3
|
+
import { describeThrown, err, ok } from '../result.js';
|
|
4
|
+
let cachedParser;
|
|
5
|
+
/** Lazily loads the tree-sitter C# grammar (WebAssembly, no native build step). */
|
|
6
|
+
export async function getCSharpParser() {
|
|
7
|
+
if (cachedParser !== undefined) {
|
|
8
|
+
return ok(cachedParser);
|
|
9
|
+
}
|
|
10
|
+
try {
|
|
11
|
+
const requireFromHere = createRequire(import.meta.url);
|
|
12
|
+
const wasmPath = requireFromHere.resolve('tree-sitter-wasms/out/tree-sitter-c_sharp.wasm');
|
|
13
|
+
await Parser.init();
|
|
14
|
+
const language = await Parser.Language.load(wasmPath);
|
|
15
|
+
const parser = new Parser();
|
|
16
|
+
parser.setLanguage(language);
|
|
17
|
+
cachedParser = parser;
|
|
18
|
+
return ok(parser);
|
|
19
|
+
}
|
|
20
|
+
catch (thrown) {
|
|
21
|
+
return err('PARSER_INIT_FAILED', `Failed to initialize the tree-sitter C# grammar. Check that the "web-tree-sitter" (0.22.x) and ` +
|
|
22
|
+
`"tree-sitter-wasms" packages are installed. Underlying error: ${describeThrown(thrown)}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Types
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
/** Splits at commas that are not inside `<...>`, `(...)` or `[...]`. */
|
|
29
|
+
export function splitTopLevel(text) {
|
|
30
|
+
const parts = [];
|
|
31
|
+
let depth = 0;
|
|
32
|
+
let current = '';
|
|
33
|
+
for (const character of text) {
|
|
34
|
+
if (character === '<' || character === '(' || character === '[') {
|
|
35
|
+
depth += 1;
|
|
36
|
+
}
|
|
37
|
+
else if (character === '>' || character === ')' || character === ']') {
|
|
38
|
+
depth -= 1;
|
|
39
|
+
}
|
|
40
|
+
if (character === ',' && depth === 0) {
|
|
41
|
+
parts.push(current);
|
|
42
|
+
current = '';
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
current += character;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (current.trim() !== '') {
|
|
49
|
+
parts.push(current);
|
|
50
|
+
}
|
|
51
|
+
return parts.map((part) => part.trim());
|
|
52
|
+
}
|
|
53
|
+
const MAX_TYPE_DEPTH = 16;
|
|
54
|
+
/** Reads a type from its source text. Never fails: unreadable text becomes a type named after the text. */
|
|
55
|
+
export function parseTypeText(text, depth = 0) {
|
|
56
|
+
let rest = text.replace(/\s+/g, ' ').trim();
|
|
57
|
+
let nullable = false;
|
|
58
|
+
let arrayDepth = 0;
|
|
59
|
+
// Trailing markers, in any order: `string?[]`, `int[]?`, `Order?`.
|
|
60
|
+
for (;;) {
|
|
61
|
+
if (rest.endsWith('?')) {
|
|
62
|
+
nullable = true;
|
|
63
|
+
rest = rest.slice(0, -1).trim();
|
|
64
|
+
}
|
|
65
|
+
else if (/\[\s*,*\s*\]$/.test(rest)) {
|
|
66
|
+
arrayDepth += 1;
|
|
67
|
+
rest = rest.replace(/\[\s*,*\s*\]$/, '').trim();
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
rest = rest.replace(/^global::/, '');
|
|
74
|
+
const open = rest.indexOf('<');
|
|
75
|
+
const head = open === -1 ? rest : rest.slice(0, open);
|
|
76
|
+
const name = head.split('.').pop()?.trim() ?? head;
|
|
77
|
+
let args = [];
|
|
78
|
+
if (open !== -1 && rest.endsWith('>') && depth < MAX_TYPE_DEPTH) {
|
|
79
|
+
args = splitTopLevel(rest.slice(open + 1, -1)).map((part) => parseTypeText(part, depth + 1));
|
|
80
|
+
}
|
|
81
|
+
const first = args[0];
|
|
82
|
+
if (name === 'Nullable' && args.length === 1 && first !== undefined) {
|
|
83
|
+
return { ...first, nullable: true, arrayDepth: first.arrayDepth };
|
|
84
|
+
}
|
|
85
|
+
return { name, text: head.trim(), args, nullable, arrayDepth };
|
|
86
|
+
}
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
// Literals and expressions
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
function unescapeRegular(body) {
|
|
91
|
+
return body.replace(/\\(?:u([0-9a-fA-F]{4})|x([0-9a-fA-F]{1,4})|([\s\S]))/g, (_whole, unicode, hex, single) => {
|
|
92
|
+
if (unicode !== undefined) {
|
|
93
|
+
return String.fromCharCode(parseInt(unicode, 16));
|
|
94
|
+
}
|
|
95
|
+
if (hex !== undefined) {
|
|
96
|
+
return String.fromCharCode(parseInt(hex, 16));
|
|
97
|
+
}
|
|
98
|
+
switch (single) {
|
|
99
|
+
case 'n':
|
|
100
|
+
return '\n';
|
|
101
|
+
case 't':
|
|
102
|
+
return '\t';
|
|
103
|
+
case 'r':
|
|
104
|
+
return '\r';
|
|
105
|
+
case '0':
|
|
106
|
+
return '\0';
|
|
107
|
+
default:
|
|
108
|
+
return single ?? '';
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
/** Decodes the text of a regular, verbatim (`@"..."`) or raw (`"""..."""`) string literal. */
|
|
113
|
+
export function unquoteCSharpString(literal) {
|
|
114
|
+
if (literal.startsWith('@"')) {
|
|
115
|
+
return literal.slice(2, -1).replace(/""/g, '"');
|
|
116
|
+
}
|
|
117
|
+
if (literal.startsWith('"""')) {
|
|
118
|
+
return literal.replace(/^"{3,}\s*/, '').replace(/\s*"{3,}$/, '');
|
|
119
|
+
}
|
|
120
|
+
if (literal.startsWith('"') && literal.endsWith('"') && literal.length >= 2) {
|
|
121
|
+
return unescapeRegular(literal.slice(1, -1));
|
|
122
|
+
}
|
|
123
|
+
return literal;
|
|
124
|
+
}
|
|
125
|
+
function parseNumber(text) {
|
|
126
|
+
const cleaned = text.replace(/_/g, '');
|
|
127
|
+
if (/^0[xX][0-9a-fA-F]+[uUlL]*$/.test(cleaned)) {
|
|
128
|
+
return parseInt(cleaned.replace(/[uUlL]+$/, ''), 16);
|
|
129
|
+
}
|
|
130
|
+
if (/^0[bB][01]+[uUlL]*$/.test(cleaned)) {
|
|
131
|
+
return parseInt(cleaned.slice(2).replace(/[uUlL]+$/, ''), 2);
|
|
132
|
+
}
|
|
133
|
+
const stripped = cleaned.replace(/[uUlLfFdDmM]+$/, '');
|
|
134
|
+
const value = Number(stripped);
|
|
135
|
+
return Number.isNaN(value) ? undefined : value;
|
|
136
|
+
}
|
|
137
|
+
const MAX_EXPRESSION_DEPTH = 64;
|
|
138
|
+
/** Evaluates literals, constants, `nameof`, `typeof`, enum-like member paths, unary minus and `+`. */
|
|
139
|
+
export function evaluate(node, consts, depth = 0) {
|
|
140
|
+
const other = { kind: 'other', text: node.text };
|
|
141
|
+
if (depth > MAX_EXPRESSION_DEPTH) {
|
|
142
|
+
return other;
|
|
143
|
+
}
|
|
144
|
+
const recurse = (child) => child === null ? other : evaluate(child, consts, depth + 1);
|
|
145
|
+
switch (node.type) {
|
|
146
|
+
case 'string_literal':
|
|
147
|
+
case 'verbatim_string_literal':
|
|
148
|
+
case 'raw_string_literal':
|
|
149
|
+
return { kind: 'string', value: unquoteCSharpString(node.text) };
|
|
150
|
+
case 'character_literal':
|
|
151
|
+
return { kind: 'string', value: unescapeRegular(node.text.slice(1, -1)) };
|
|
152
|
+
case 'integer_literal':
|
|
153
|
+
case 'real_literal': {
|
|
154
|
+
const value = parseNumber(node.text);
|
|
155
|
+
return value === undefined
|
|
156
|
+
? other
|
|
157
|
+
: { kind: 'number', value, text: node.text };
|
|
158
|
+
}
|
|
159
|
+
case 'boolean_literal':
|
|
160
|
+
return { kind: 'bool', value: node.text === 'true' };
|
|
161
|
+
case 'null_literal':
|
|
162
|
+
return { kind: 'null' };
|
|
163
|
+
case 'parenthesized_expression':
|
|
164
|
+
return recurse(node.namedChild(0));
|
|
165
|
+
case 'cast_expression':
|
|
166
|
+
return recurse(node.childForFieldName('value'));
|
|
167
|
+
case 'postfix_unary_expression':
|
|
168
|
+
return recurse(node.namedChild(0));
|
|
169
|
+
case 'prefix_unary_expression': {
|
|
170
|
+
const operand = recurse(node.namedChild(0));
|
|
171
|
+
if (node.text.startsWith('-') && operand.kind === 'number') {
|
|
172
|
+
return {
|
|
173
|
+
kind: 'number',
|
|
174
|
+
value: -operand.value,
|
|
175
|
+
text: `-${operand.text}`,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
return operand.kind === 'number' && node.text.startsWith('+')
|
|
179
|
+
? operand
|
|
180
|
+
: other;
|
|
181
|
+
}
|
|
182
|
+
case 'identifier': {
|
|
183
|
+
const known = consts([node.text]);
|
|
184
|
+
return known ?? { kind: 'member', path: [node.text] };
|
|
185
|
+
}
|
|
186
|
+
case 'member_access_expression': {
|
|
187
|
+
const path = memberPath(node);
|
|
188
|
+
if (path === undefined) {
|
|
189
|
+
return other;
|
|
190
|
+
}
|
|
191
|
+
return consts(path) ?? { kind: 'member', path };
|
|
192
|
+
}
|
|
193
|
+
case 'invocation_expression': {
|
|
194
|
+
const fn = node.childForFieldName('function');
|
|
195
|
+
const args = node.childForFieldName('arguments');
|
|
196
|
+
if (fn?.text === 'nameof' && args !== null) {
|
|
197
|
+
const inner = args.namedChild(0);
|
|
198
|
+
const text = inner?.text ?? '';
|
|
199
|
+
return { kind: 'nameof', name: text.split('.').pop() ?? text };
|
|
200
|
+
}
|
|
201
|
+
return other;
|
|
202
|
+
}
|
|
203
|
+
case 'typeof_expression': {
|
|
204
|
+
const inner = node.namedChild(0);
|
|
205
|
+
return { kind: 'typeof', type: parseTypeText(inner?.text ?? '').name };
|
|
206
|
+
}
|
|
207
|
+
case 'binary_expression': {
|
|
208
|
+
const left = recurse(node.childForFieldName('left'));
|
|
209
|
+
const right = recurse(node.childForFieldName('right'));
|
|
210
|
+
const operator = node.childForFieldName('operator')?.text ??
|
|
211
|
+
node.text.replace(left.kind === 'other' ? '' : /\s*$/, '');
|
|
212
|
+
return foldBinary(operator, left, right, node, other);
|
|
213
|
+
}
|
|
214
|
+
case 'array_creation_expression':
|
|
215
|
+
case 'implicit_array_creation_expression':
|
|
216
|
+
case 'initializer_expression':
|
|
217
|
+
case 'collection_expression':
|
|
218
|
+
return {
|
|
219
|
+
kind: 'array',
|
|
220
|
+
items: itemsOf(node).map((item) => recurse(item)),
|
|
221
|
+
};
|
|
222
|
+
default:
|
|
223
|
+
return other;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function foldBinary(operator, left, right, node, other) {
|
|
227
|
+
if (left.kind === 'string' && right.kind === 'string') {
|
|
228
|
+
return { kind: 'string', value: left.value + right.value };
|
|
229
|
+
}
|
|
230
|
+
if (left.kind === 'number' && right.kind === 'number') {
|
|
231
|
+
const text = node.text;
|
|
232
|
+
if (operator === '<<' || /<</.test(text)) {
|
|
233
|
+
return {
|
|
234
|
+
kind: 'number',
|
|
235
|
+
value: left.value * 2 ** right.value,
|
|
236
|
+
text,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
if (operator === '|' || /\|/.test(text)) {
|
|
240
|
+
return { kind: 'number', value: left.value | right.value, text };
|
|
241
|
+
}
|
|
242
|
+
if (operator === '+' || /\+/.test(text)) {
|
|
243
|
+
return { kind: 'number', value: left.value + right.value, text };
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return other;
|
|
247
|
+
}
|
|
248
|
+
/** The expressions inside an array or collection initializer. */
|
|
249
|
+
function itemsOf(node) {
|
|
250
|
+
const container = node.type === 'array_creation_expression' ||
|
|
251
|
+
node.type === 'implicit_array_creation_expression'
|
|
252
|
+
? (node.namedChildren.find((child) => child.type === 'initializer_expression') ?? node)
|
|
253
|
+
: node;
|
|
254
|
+
if (container === node && node.type !== 'initializer_expression') {
|
|
255
|
+
return node.namedChildren.filter((child) => child.type !== 'array_type');
|
|
256
|
+
}
|
|
257
|
+
return container.namedChildren;
|
|
258
|
+
}
|
|
259
|
+
/** `A.B.C` as ['A', 'B', 'C'], or undefined when a part is not a plain name. */
|
|
260
|
+
export function memberPath(node) {
|
|
261
|
+
if (node.type === 'identifier') {
|
|
262
|
+
return [node.text];
|
|
263
|
+
}
|
|
264
|
+
if (node.type === 'generic_name') {
|
|
265
|
+
return [node.namedChild(0)?.text ?? node.text];
|
|
266
|
+
}
|
|
267
|
+
if (node.type !== 'member_access_expression') {
|
|
268
|
+
return undefined;
|
|
269
|
+
}
|
|
270
|
+
const target = node.childForFieldName('expression');
|
|
271
|
+
const name = node.childForFieldName('name');
|
|
272
|
+
if (target === null || name === null) {
|
|
273
|
+
return undefined;
|
|
274
|
+
}
|
|
275
|
+
const prefix = memberPath(target);
|
|
276
|
+
const last = memberPath(name);
|
|
277
|
+
return prefix === undefined || last === undefined
|
|
278
|
+
? undefined
|
|
279
|
+
: [...prefix, ...last];
|
|
280
|
+
}
|
|
281
|
+
// ---------------------------------------------------------------------------
|
|
282
|
+
// Attributes
|
|
283
|
+
// ---------------------------------------------------------------------------
|
|
284
|
+
function attributeName(node) {
|
|
285
|
+
const text = node.text.split('<')[0] ?? node.text;
|
|
286
|
+
const last = text.split('.').pop() ?? text;
|
|
287
|
+
return last.replace(/Attribute$/, '');
|
|
288
|
+
}
|
|
289
|
+
function readAttribute(node) {
|
|
290
|
+
const nameNode = node.childForFieldName('name');
|
|
291
|
+
const args = [];
|
|
292
|
+
const named = new Map();
|
|
293
|
+
const list = node.namedChildren.find((child) => child.type === 'attribute_argument_list');
|
|
294
|
+
for (const argument of list?.namedChildren ?? []) {
|
|
295
|
+
if (argument.type !== 'attribute_argument') {
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
const label = argument.namedChildren.find((child) => child.type === 'name_equals' || child.type === 'name_colon');
|
|
299
|
+
const valueNode = argument.namedChildren.find((child) => child.type !== 'name_equals' && child.type !== 'name_colon');
|
|
300
|
+
if (valueNode === undefined) {
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
if (label === undefined) {
|
|
304
|
+
args.push(valueNode);
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
named.set(label.namedChild(0)?.text ?? label.text, valueNode);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return {
|
|
311
|
+
name: attributeName(nameNode ?? node),
|
|
312
|
+
args,
|
|
313
|
+
named,
|
|
314
|
+
node,
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
/** The attributes of a declaration, skipping those aimed at the field, return value or parameters. */
|
|
318
|
+
export function readAttributes(declaration) {
|
|
319
|
+
const attributes = [];
|
|
320
|
+
for (const list of declaration.namedChildren) {
|
|
321
|
+
if (list.type !== 'attribute_list') {
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
const target = list.namedChildren.find((child) => child.type === 'attribute_target_specifier');
|
|
325
|
+
const targetName = target?.text.replace(/:$/, '').trim() ?? '';
|
|
326
|
+
if (targetName !== '' &&
|
|
327
|
+
targetName !== 'property' &&
|
|
328
|
+
targetName !== 'type') {
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
for (const child of list.namedChildren) {
|
|
332
|
+
if (child.type === 'attribute') {
|
|
333
|
+
attributes.push(readAttribute(child));
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return attributes;
|
|
338
|
+
}
|
|
339
|
+
//# sourceMappingURL=csharpSyntax.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csharpSyntax.js","sourceRoot":"","sources":["../../src/parsers/csharpSyntax.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { IrSchema } from '../ir.js';
|
|
2
|
+
import { type Result } from '../result.js';
|
|
3
|
+
export interface EfcoreSourceFile {
|
|
4
|
+
path: string;
|
|
5
|
+
text: string;
|
|
6
|
+
}
|
|
7
|
+
export interface EfcoreParseOptions {
|
|
8
|
+
/** App label stored on each model (EF Core has no equivalent). */
|
|
9
|
+
appLabel: string;
|
|
10
|
+
}
|
|
11
|
+
/** True for the migrations folder, build output and the generated Designer and ModelSnapshot files. */
|
|
12
|
+
export declare function isSkippedEfcorePath(path: string): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Parses Entity Framework Core models (C#) into the shared IR using tree-sitter. The source is only read:
|
|
15
|
+
* nothing is compiled or run, so models built with reflection, loops or computed values are not seen.
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseEfcore(sources: EfcoreSourceFile[], options: EfcoreParseOptions): Promise<Result<IrSchema>>;
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { describeThrown, err, ok } from '../result.js';
|
|
2
|
+
import { getCSharpParser, } from './csharpSyntax.js';
|
|
3
|
+
import { readCSharpFile } from './csharpDeclarations.js';
|
|
4
|
+
import { hasEntityAnnotations, isOwnedByAttribute, } from './efcoreAnnotations.js';
|
|
5
|
+
import { buildSchema, mergeHierarchies } from './efcoreBuild.js';
|
|
6
|
+
import { buildEntities, classChain, expandEntities } from './efcoreEntities.js';
|
|
7
|
+
import { ConfigStore } from './efcoreFluent.js';
|
|
8
|
+
import { keyOf, resolveRelationships } from './efcoreRelations.js';
|
|
9
|
+
import { isKnownScalar, isValueType } from './efcoreTypes.js';
|
|
10
|
+
/** Paths of files EF Core generates or that hold migrations; they describe history, not the model. */
|
|
11
|
+
const SKIPPED_PATH = /(?:^|[\\/])(?:Migrations|bin|obj)[\\/]|\.Designer\.cs$|ModelSnapshot\.cs$/i;
|
|
12
|
+
/** True for the migrations folder, build output and the generated Designer and ModelSnapshot files. */
|
|
13
|
+
export function isSkippedEfcorePath(path) {
|
|
14
|
+
return SKIPPED_PATH.test(path);
|
|
15
|
+
}
|
|
16
|
+
const CONTEXT_BASE = /DbContext$/;
|
|
17
|
+
/**
|
|
18
|
+
* Parses Entity Framework Core models (C#) into the shared IR using tree-sitter. The source is only read:
|
|
19
|
+
* nothing is compiled or run, so models built with reflection, loops or computed values are not seen.
|
|
20
|
+
*/
|
|
21
|
+
export async function parseEfcore(sources, options) {
|
|
22
|
+
const parserResult = await getCSharpParser();
|
|
23
|
+
if (!parserResult.ok) {
|
|
24
|
+
return parserResult;
|
|
25
|
+
}
|
|
26
|
+
const trees = [];
|
|
27
|
+
try {
|
|
28
|
+
return readEfcore(parserResult.value, sources, options, trees);
|
|
29
|
+
}
|
|
30
|
+
catch (thrown) {
|
|
31
|
+
return err('PARSE_FAILED', `Failed to read Entity Framework Core models from ${sources.map((source) => source.path).join(', ')}. ` +
|
|
32
|
+
`Underlying error: ${describeThrown(thrown)}`);
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
for (const tree of trees) {
|
|
36
|
+
tree.delete();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function readEfcore(parser, sources, options, trees) {
|
|
41
|
+
const warnings = [];
|
|
42
|
+
const files = [];
|
|
43
|
+
const classes = new Map();
|
|
44
|
+
const classOrder = new Map();
|
|
45
|
+
const enums = new Map();
|
|
46
|
+
const lookup = (path) => {
|
|
47
|
+
const name = path[path.length - 1];
|
|
48
|
+
if (name === undefined) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
const owner = path[path.length - 2];
|
|
52
|
+
if (owner !== undefined) {
|
|
53
|
+
return classes.get(owner)?.consts.get(name);
|
|
54
|
+
}
|
|
55
|
+
for (const cls of classes.values()) {
|
|
56
|
+
const value = cls.consts.get(name);
|
|
57
|
+
if (value !== undefined) {
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return undefined;
|
|
62
|
+
};
|
|
63
|
+
for (const source of sources) {
|
|
64
|
+
if (isSkippedEfcorePath(source.path)) {
|
|
65
|
+
warnings.push(`${source.path}: skipped (EF Core migrations, snapshots and build output describe history, not the model).`);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const tree = parser.parse(source.text);
|
|
69
|
+
trees.push(tree);
|
|
70
|
+
const file = readCSharpFile(tree.rootNode, source.path, lookup);
|
|
71
|
+
files.push(file);
|
|
72
|
+
if (file.hasErrors) {
|
|
73
|
+
warnings.push(`${source.path}: the file contains C# syntax errors; some classes or properties may be missing from the output.`);
|
|
74
|
+
}
|
|
75
|
+
for (const cls of file.classes) {
|
|
76
|
+
const existing = classes.get(cls.name);
|
|
77
|
+
if (existing === undefined) {
|
|
78
|
+
classes.set(cls.name, cls);
|
|
79
|
+
classOrder.set(cls.name, classOrder.size);
|
|
80
|
+
}
|
|
81
|
+
else if (existing.modifiers.includes('partial') &&
|
|
82
|
+
cls.modifiers.includes('partial')) {
|
|
83
|
+
existing.properties.push(...cls.properties);
|
|
84
|
+
existing.methods.push(...cls.methods);
|
|
85
|
+
existing.attributes.push(...cls.attributes);
|
|
86
|
+
existing.bases.push(...cls.bases);
|
|
87
|
+
for (const [name, value] of cls.consts) {
|
|
88
|
+
existing.consts.set(name, value);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
warnings.push(`Duplicate type name "${cls.name}" (${cls.path}); only the first definition (${existing.path}) was read.`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
for (const declared of file.enums) {
|
|
96
|
+
if (!enums.has(declared.name)) {
|
|
97
|
+
enums.set(declared.name, declared);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const project = {
|
|
102
|
+
classes,
|
|
103
|
+
enums,
|
|
104
|
+
contexts: [],
|
|
105
|
+
configurations: [],
|
|
106
|
+
dbSets: new Map(),
|
|
107
|
+
nullableReferences: false,
|
|
108
|
+
nullableByPath: new Map(files.map((file) => [
|
|
109
|
+
file.path,
|
|
110
|
+
file.nullableDirective,
|
|
111
|
+
])),
|
|
112
|
+
classOrder,
|
|
113
|
+
warnings,
|
|
114
|
+
};
|
|
115
|
+
const enumNames = new Set(enums.keys());
|
|
116
|
+
project.nullableReferences = detectNullableReferences(project, enumNames);
|
|
117
|
+
findContextsAndConfigurations(project);
|
|
118
|
+
const store = new ConfigStore(project, lookup, (cls) => classChain(cls, project));
|
|
119
|
+
// Entities named by DbSet<T> properties come first, in declaration order.
|
|
120
|
+
for (const context of project.contexts) {
|
|
121
|
+
for (const property of context.properties) {
|
|
122
|
+
const set = property.type;
|
|
123
|
+
if (set.name !== 'DbSet' || set.args.length !== 1) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const entity = set.args[0]?.name;
|
|
127
|
+
if (entity === undefined) {
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (store.addEntity(entity) === undefined) {
|
|
131
|
+
warnings.push(`${context.name}.${property.name}: DbSet<${entity}> refers to a type that is not a class in the input; it was skipped.`);
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (!project.dbSets.has(entity)) {
|
|
135
|
+
project.dbSets.set(entity, property.name);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
for (const context of project.contexts) {
|
|
140
|
+
store.runContext(context);
|
|
141
|
+
}
|
|
142
|
+
const unapplied = store.unappliedConfigurations();
|
|
143
|
+
if (project.contexts.length > 0 && unapplied.length > 0) {
|
|
144
|
+
warnings.push(`${unapplied.map((cls) => cls.name).join(', ')} implement${unapplied.length === 1 ? 's' : ''} IEntityTypeConfiguration but ${unapplied.length === 1 ? 'is' : 'are'} not applied by an ApplyConfiguration call in the input; ${unapplied.length === 1 ? 'it was' : 'they were'} read anyway.`);
|
|
145
|
+
}
|
|
146
|
+
store.applyAllConfigurations();
|
|
147
|
+
for (const { entity } of project.configurations) {
|
|
148
|
+
store.addEntity(entity);
|
|
149
|
+
}
|
|
150
|
+
addAnnotatedEntities(store, project);
|
|
151
|
+
// HasOne<T>() and UsingEntity<T> name entities that no property mentions.
|
|
152
|
+
for (const config of [...store.entities.values()]) {
|
|
153
|
+
for (const rel of config.relations) {
|
|
154
|
+
if (rel.target !== undefined) {
|
|
155
|
+
store.addEntity(rel.target);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
expandEntities(store, project, enumNames);
|
|
160
|
+
const entityInfos = buildEntities(store, project, enumNames);
|
|
161
|
+
if (entityInfos.length === 0) {
|
|
162
|
+
const checkedPaths = sources
|
|
163
|
+
.map((source) => source.path)
|
|
164
|
+
.join(', ');
|
|
165
|
+
return err('NO_MODELS_FOUND', `No Entity Framework Core entities were found in: ${checkedPaths}. An entity is a class used in a DbSet<T> property of a DbContext, ` +
|
|
166
|
+
`named by modelBuilder.Entity<T>() or an IEntityTypeConfiguration<T> class, reached through a navigation property, or ` +
|
|
167
|
+
`marked with an EF Core data annotation such as [Table], [Key], [Index] or [ForeignKey].`);
|
|
168
|
+
}
|
|
169
|
+
const roots = mergeHierarchies(entityInfos, (message) => warnings.push(message));
|
|
170
|
+
const byName = new Map();
|
|
171
|
+
for (const info of roots) {
|
|
172
|
+
byName.set(info.name, info);
|
|
173
|
+
for (const derived of info.derived) {
|
|
174
|
+
byName.set(derived, info);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const relationships = resolveRelationships(roots, store, (name) => byName.get(name), (message) => warnings.push(message));
|
|
178
|
+
// The join entity of UsingEntity<T> gets the two foreign keys as its composite key unless it names one.
|
|
179
|
+
for (const info of roots) {
|
|
180
|
+
if (info.config.joinEntity === true && keyOf(info).length === 0) {
|
|
181
|
+
const position = (name) => info.members.findIndex((member) => member.kind === 'scalar' && member.name === name);
|
|
182
|
+
info.config.key = relationships.links
|
|
183
|
+
.filter((link) => link.dependent === info)
|
|
184
|
+
.flatMap((link) => link.foreignKey)
|
|
185
|
+
.sort((first, second) => position(first) - position(second));
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return ok(buildSchema(roots, relationships, store, project, options));
|
|
189
|
+
}
|
|
190
|
+
/** Nullable reference types are on when a file says `#nullable enable`, or reference types are written with `?`. */
|
|
191
|
+
function detectNullableReferences(project, enumNames) {
|
|
192
|
+
for (const directive of project.nullableByPath.values()) {
|
|
193
|
+
if (directive === 'enable') {
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
for (const cls of project.classes.values()) {
|
|
198
|
+
for (const property of cls.properties) {
|
|
199
|
+
const type = property.type;
|
|
200
|
+
if (type.nullable &&
|
|
201
|
+
!isValueType(type, enumNames) &&
|
|
202
|
+
(isKnownScalar({ ...type, nullable: false }, enumNames) ||
|
|
203
|
+
project.classes.has(type.name)) &&
|
|
204
|
+
type.name !== 'Nullable') {
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
function findContextsAndConfigurations(project) {
|
|
212
|
+
const contextNames = new Set();
|
|
213
|
+
let changed = true;
|
|
214
|
+
while (changed) {
|
|
215
|
+
changed = false;
|
|
216
|
+
for (const cls of project.classes.values()) {
|
|
217
|
+
if (!contextNames.has(cls.name) &&
|
|
218
|
+
(cls.bases.some((base) => CONTEXT_BASE.test(base.name) || contextNames.has(base.name)) ||
|
|
219
|
+
// A context whose base class is not in the input is recognised by its DbSet<T> properties.
|
|
220
|
+
cls.properties.some((property) => property.type.name === 'DbSet' && property.type.args.length === 1))) {
|
|
221
|
+
contextNames.add(cls.name);
|
|
222
|
+
changed = true;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
for (const cls of project.classes.values()) {
|
|
227
|
+
if (contextNames.has(cls.name)) {
|
|
228
|
+
project.contexts.push(cls);
|
|
229
|
+
}
|
|
230
|
+
const configuration = cls.bases.find((base) => base.name === 'IEntityTypeConfiguration' && base.args.length === 1);
|
|
231
|
+
const entity = configuration?.args[0]?.name;
|
|
232
|
+
if (entity !== undefined) {
|
|
233
|
+
project.configurations.push({ cls, entity });
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/** Adds classes that carry EF Core data annotations and are not mapped-superclass or owned types. */
|
|
238
|
+
function addAnnotatedEntities(store, project) {
|
|
239
|
+
const isBase = new Set();
|
|
240
|
+
for (const cls of project.classes.values()) {
|
|
241
|
+
for (const ancestor of classChain(cls, project).slice(0, -1)) {
|
|
242
|
+
isBase.add(ancestor.name);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
const contextNames = new Set(project.contexts.map((cls) => cls.name));
|
|
246
|
+
const configNames = new Set(project.configurations.map(({ cls }) => cls.name));
|
|
247
|
+
for (const cls of project.classes.values()) {
|
|
248
|
+
if ((cls.kind !== 'class' && cls.kind !== 'record') ||
|
|
249
|
+
cls.modifiers.includes('static') ||
|
|
250
|
+
cls.modifiers.includes('abstract') ||
|
|
251
|
+
contextNames.has(cls.name) ||
|
|
252
|
+
configNames.has(cls.name) ||
|
|
253
|
+
isOwnedByAttribute(cls) ||
|
|
254
|
+
store.ownedTypes.has(cls.name) ||
|
|
255
|
+
cls.attributes.some((item) => item.name === 'NotMapped') ||
|
|
256
|
+
store.ignoredEntities.has(cls.name) ||
|
|
257
|
+
(isBase.has(cls.name) && !store.has(cls.name))) {
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
if (hasEntityAnnotations(classChain(cls, project))) {
|
|
261
|
+
store.addEntity(cls.name);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
//# sourceMappingURL=efcore.js.map
|