@zenstackhq/language 3.5.6 → 3.6.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 (45) hide show
  1. package/dist/ast-Clidp86c.cjs +1465 -0
  2. package/dist/ast-Clidp86c.cjs.map +1 -0
  3. package/dist/ast-DEfhnj8j.mjs +765 -0
  4. package/dist/ast-DEfhnj8j.mjs.map +1 -0
  5. package/dist/ast-DQDdBZQ3.d.mts +525 -0
  6. package/dist/ast-W2h6Qtfk.d.cts +525 -0
  7. package/dist/ast.cjs +130 -1432
  8. package/dist/ast.cjs.map +1 -1
  9. package/dist/ast.d.cts +2 -541
  10. package/dist/ast.d.mts +2 -0
  11. package/dist/ast.mjs +20 -0
  12. package/dist/ast.mjs.map +1 -0
  13. package/dist/factory.cjs +754 -2030
  14. package/dist/factory.cjs.map +1 -1
  15. package/dist/factory.d.cts +220 -215
  16. package/dist/factory.d.mts +289 -0
  17. package/dist/factory.mjs +778 -0
  18. package/dist/factory.mjs.map +1 -0
  19. package/dist/index.cjs +2691 -5454
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +104 -103
  22. package/dist/index.d.mts +170 -0
  23. package/dist/index.mjs +6925 -0
  24. package/dist/index.mjs.map +1 -0
  25. package/dist/utils-BB6L7ug2.mjs +529 -0
  26. package/dist/utils-BB6L7ug2.mjs.map +1 -0
  27. package/dist/utils-CfXGZkv7.cjs +842 -0
  28. package/dist/utils-CfXGZkv7.cjs.map +1 -0
  29. package/dist/utils.cjs +47 -1650
  30. package/dist/utils.d.cts +101 -10
  31. package/dist/{utils.d.ts → utils.d.mts} +101 -10
  32. package/dist/utils.mjs +2 -0
  33. package/package.json +16 -15
  34. package/dist/ast.d.ts +0 -541
  35. package/dist/ast.js +0 -1288
  36. package/dist/ast.js.map +0 -1
  37. package/dist/factory.d.ts +0 -284
  38. package/dist/factory.js +0 -2020
  39. package/dist/factory.js.map +0 -1
  40. package/dist/index.d.ts +0 -169
  41. package/dist/index.js +0 -9656
  42. package/dist/index.js.map +0 -1
  43. package/dist/utils.cjs.map +0 -1
  44. package/dist/utils.js +0 -1572
  45. package/dist/utils.js.map +0 -1
@@ -0,0 +1,529 @@
1
+ import { Et as isExpression, Ft as isLiteralExpr, Ht as isObjectExpr, It as isMemberAccessExpr, Jt as isReferenceExpr, Pt as isInvocationExpr, Qt as isStringLiteral, Rt as isModel, Tt as isEnumField, Ut as isPlugin, ct as isBinaryExpr, pt as isConfigArrayExpr, rt as isArrayExpr, tn as isTypeDef, vt as isDataField, xt as isDataModel } from "./ast-DEfhnj8j.mjs";
2
+ import { createRequire } from "node:module";
3
+ import { AstUtils, URI } from "langium";
4
+ import fs from "node:fs";
5
+ import path from "node:path";
6
+ import { fileURLToPath, pathToFileURL } from "node:url";
7
+ //#region src/constants.ts
8
+ /**
9
+ * Supported db providers
10
+ */
11
+ const SUPPORTED_PROVIDERS = [
12
+ "sqlite",
13
+ "postgresql",
14
+ "mysql"
15
+ ];
16
+ /**
17
+ * All scalar types
18
+ */
19
+ const SCALAR_TYPES = [
20
+ "String",
21
+ "Int",
22
+ "Float",
23
+ "Decimal",
24
+ "BigInt",
25
+ "Boolean",
26
+ "Bytes",
27
+ "DateTime"
28
+ ];
29
+ /**
30
+ * Name of standard library module
31
+ */
32
+ const STD_LIB_MODULE_NAME = "stdlib.zmodel";
33
+ /**
34
+ * Name of module contributed by plugins
35
+ */
36
+ const PLUGIN_MODULE_NAME = "plugin.zmodel";
37
+ /**
38
+ * Validation issues
39
+ */
40
+ let IssueCodes = /* @__PURE__ */ function(IssueCodes) {
41
+ IssueCodes["MissingOppositeRelation"] = "miss-opposite-relation";
42
+ return IssueCodes;
43
+ }({});
44
+ /**
45
+ * Expression context
46
+ */
47
+ let ExpressionContext = /* @__PURE__ */ function(ExpressionContext) {
48
+ ExpressionContext["DefaultValue"] = "DefaultValue";
49
+ ExpressionContext["AccessPolicy"] = "AccessPolicy";
50
+ ExpressionContext["ValidationRule"] = "ValidationRule";
51
+ ExpressionContext["Index"] = "Index";
52
+ return ExpressionContext;
53
+ }({});
54
+ /**
55
+ * Database providers that support list field types.
56
+ */
57
+ const DB_PROVIDERS_SUPPORTING_LIST_TYPE = ["postgresql"];
58
+ //#endregion
59
+ //#region src/utils.ts
60
+ function hasAttribute(decl, name) {
61
+ return !!getAttribute(decl, name);
62
+ }
63
+ function getAttribute(decl, name) {
64
+ return decl.attributes.find((attr) => attr.decl.$refText === name);
65
+ }
66
+ function isFromStdlib(node) {
67
+ const model = AstUtils.getContainerOfType(node, isModel);
68
+ return !!model && !!model.$document && model.$document.uri.path.endsWith("stdlib.zmodel");
69
+ }
70
+ function isAuthInvocation(node) {
71
+ return isInvocationExpr(node) && node.function.ref?.name === "auth" && isFromStdlib(node.function.ref);
72
+ }
73
+ /**
74
+ * Try getting string value from a potential string literal expression
75
+ */
76
+ function getStringLiteral(node) {
77
+ return isStringLiteral(node) ? node.value : void 0;
78
+ }
79
+ const isoDateTimeRegex = /^\d{4}(-\d\d(-\d\d(T\d\d:\d\d(:\d\d)?(\.\d+)?(([+-]\d\d:\d\d)|Z)?)?)?)?$/i;
80
+ /**
81
+ * Determines if the given sourceType is assignable to a destination of destType
82
+ */
83
+ function typeAssignable(destType, sourceType, sourceExpr) {
84
+ if (destType === "DateTime" && sourceType === "String" && sourceExpr && isStringLiteral(sourceExpr)) {
85
+ const literal = getStringLiteral(sourceExpr);
86
+ if (literal && isoDateTimeRegex.test(literal)) sourceType = "DateTime";
87
+ }
88
+ switch (destType) {
89
+ case "Any": return true;
90
+ case "Float": return sourceType === "Any" || sourceType === "Int" || sourceType === "Float";
91
+ default: return sourceType === "Any" || sourceType === destType;
92
+ }
93
+ }
94
+ /**
95
+ * Maps a ZModel builtin type to expression type
96
+ */
97
+ function mapBuiltinTypeToExpressionType(type) {
98
+ switch (type) {
99
+ case "Any":
100
+ case "Boolean":
101
+ case "String":
102
+ case "DateTime":
103
+ case "Int":
104
+ case "Float":
105
+ case "Null":
106
+ case "Object":
107
+ case "Unsupported":
108
+ case "Void":
109
+ case "Undefined": return type;
110
+ case "BigInt": return "Int";
111
+ case "Decimal": return "Float";
112
+ case "Json":
113
+ case "Bytes": return "Any";
114
+ }
115
+ }
116
+ /**
117
+ * Determines if the given expression is an invocation of `auth` or a member access on the result of an `auth` invocation (e.g. `auth().role`).
118
+ */
119
+ function isAuthOrAuthMemberAccess(expr) {
120
+ return isAuthInvocation(expr) || isMemberAccessExpr(expr) && isAuthOrAuthMemberAccess(expr.operand);
121
+ }
122
+ /**
123
+ * Determines if the given expression is a reference to an enum field.
124
+ */
125
+ function isEnumFieldReference(node) {
126
+ return isReferenceExpr(node) && isEnumField(node.target.ref);
127
+ }
128
+ /**
129
+ * Determines if the given expression is a reference to a data field.
130
+ */
131
+ function isDataFieldReference(node) {
132
+ return isReferenceExpr(node) && isDataField(node.target.ref);
133
+ }
134
+ /**
135
+ * Returns if the given field is a relation field.
136
+ */
137
+ function isRelationshipField(field) {
138
+ return isDataModel(field.type.reference?.ref);
139
+ }
140
+ /**
141
+ * Returns if the given field is a computed field.
142
+ */
143
+ function isComputedField(field) {
144
+ return hasAttribute(field, "@computed");
145
+ }
146
+ /**
147
+ * Determines if the given data model is a delegate model (i.e. marked with `@@delegate` attribute).
148
+ */
149
+ function isDelegateModel(node) {
150
+ return isDataModel(node) && hasAttribute(node, "@@delegate");
151
+ }
152
+ /**
153
+ * Resolves the given reference and returns the target AST node. Throws an error if the reference is not resolved.
154
+ */
155
+ function resolved(ref) {
156
+ if (!ref.ref) throw new Error(`Reference not resolved: ${ref.$refText}`);
157
+ return ref.ref;
158
+ }
159
+ /**
160
+ * Gets all base models and mixins of a data model or type def, recursively.
161
+ */
162
+ function getRecursiveBases(decl, includeDelegate = true, documents, seen = /* @__PURE__ */ new Set()) {
163
+ const result = [];
164
+ if (seen.has(decl)) return result;
165
+ seen.add(decl);
166
+ [...decl.mixins, ...isDataModel(decl) && decl.baseModel ? [decl.baseModel] : []].forEach((base) => {
167
+ let baseDecl;
168
+ if (base.ref && (isTypeDef(base.ref) || isDataModel(base.ref))) baseDecl = base.ref;
169
+ else baseDecl = (documents ? getAllDeclarationsIncludingImports(documents, decl.$container) : decl.$container.declarations).find((d) => (isTypeDef(d) || isDataModel(d)) && d.name === base.$refText);
170
+ if (baseDecl) {
171
+ if (!includeDelegate && isDelegateModel(baseDecl)) return;
172
+ result.push(baseDecl);
173
+ result.push(...getRecursiveBases(baseDecl, includeDelegate, documents, seen));
174
+ }
175
+ });
176
+ return result;
177
+ }
178
+ /**
179
+ * Gets `@@id` fields declared at the data model level (including search in base models)
180
+ */
181
+ function getModelIdFields(model) {
182
+ const modelsToCheck = [model, ...getRecursiveBases(model)];
183
+ for (const modelToCheck of modelsToCheck) {
184
+ const idAttr = getAllAttributes(modelToCheck).find((attr) => attr.decl.$refText === "@@id");
185
+ if (!idAttr) continue;
186
+ const fieldsArg = idAttr.args.find((a) => a.$resolvedParam?.name === "fields");
187
+ if (!fieldsArg || !isArrayExpr(fieldsArg.value)) continue;
188
+ return fieldsArg.value.items.filter((item) => isReferenceExpr(item)).map((item) => resolved(item.target));
189
+ }
190
+ return [];
191
+ }
192
+ /**
193
+ * Gets `@@unique` fields declared at the data model level (including search in base models)
194
+ */
195
+ function getModelUniqueFields(model) {
196
+ const modelsToCheck = [model, ...getRecursiveBases(model)];
197
+ for (const modelToCheck of modelsToCheck) {
198
+ const uniqueAttr = getAllAttributes(modelToCheck).find((attr) => attr.decl.$refText === "@@unique");
199
+ if (!uniqueAttr) continue;
200
+ const fieldsArg = uniqueAttr.args.find((a) => a.$resolvedParam?.name === "fields");
201
+ if (!fieldsArg || !isArrayExpr(fieldsArg.value)) continue;
202
+ return fieldsArg.value.items.filter((item) => isReferenceExpr(item)).map((item) => resolved(item.target));
203
+ }
204
+ return [];
205
+ }
206
+ /**
207
+ * Gets lists of unique fields declared at the data model level
208
+ *
209
+ * TODO: merge this with {@link getModelUniqueFields}
210
+ */
211
+ function getUniqueFields(model) {
212
+ return model.attributes.filter((attr) => attr.decl.ref?.name === "@@unique" || attr.decl.ref?.name === "@@id").map((uniqueAttr) => {
213
+ const fieldsArg = uniqueAttr.args.find((a) => a.$resolvedParam?.name === "fields");
214
+ if (!fieldsArg || !isArrayExpr(fieldsArg.value)) return [];
215
+ return fieldsArg.value.items.filter((item) => isReferenceExpr(item)).map((item) => resolved(item.target));
216
+ });
217
+ }
218
+ /**
219
+ * Finds the first ancestor of the given AST node that satisfies the given predicate function. Returns `undefined` if no such ancestor is found.
220
+ */
221
+ function findUpAst(node, predicate) {
222
+ let curr = node;
223
+ while (curr) {
224
+ if (predicate(curr)) return curr;
225
+ curr = curr.$container;
226
+ }
227
+ }
228
+ /**
229
+ * Tries to get the literal value from the given expression. Returns `undefined` if the expression is not a literal or if the literal value cannot be determined.
230
+ */
231
+ function getLiteral(expr) {
232
+ switch (expr?.$type) {
233
+ case "ObjectExpr": return getObjectLiteral(expr);
234
+ case "StringLiteral":
235
+ case "BooleanLiteral": return expr.value;
236
+ case "NumberLiteral": return parseFloat(expr.value);
237
+ default: return;
238
+ }
239
+ }
240
+ /**
241
+ * Tries to get an object literal from the given expression. Returns `undefined` if the expression is not an object literal or if any of the field values cannot be determined.
242
+ */
243
+ function getObjectLiteral(expr) {
244
+ if (!expr || !isObjectExpr(expr)) return;
245
+ const result = {};
246
+ for (const field of expr.fields) {
247
+ let fieldValue;
248
+ if (isLiteralExpr(field.value)) fieldValue = getLiteral(field.value);
249
+ else if (isArrayExpr(field.value)) fieldValue = getLiteralArray(field.value);
250
+ else if (isObjectExpr(field.value)) fieldValue = getObjectLiteral(field.value);
251
+ if (fieldValue === void 0) return;
252
+ else result[field.name] = fieldValue;
253
+ }
254
+ return result;
255
+ }
256
+ function getLiteralArray(expr) {
257
+ const arr = getArray(expr);
258
+ if (!arr) return;
259
+ return arr.map((item) => isExpression(item) && getLiteral(item)).filter((v) => v !== void 0);
260
+ }
261
+ function getArray(expr) {
262
+ return isArrayExpr(expr) || isConfigArrayExpr(expr) ? expr.items : void 0;
263
+ }
264
+ /**
265
+ * Gets the value of the argument with the given name from the given attribute. Returns `undefined` if no such argument is found or if the argument value cannot be determined.
266
+ */
267
+ function getAttributeArg(attr, name) {
268
+ return attr.args.find((arg) => arg.$resolvedParam?.name === name)?.value;
269
+ }
270
+ /**
271
+ * Gets the literal value of the argument with the given name from the given attribute. Returns `undefined` if no such argument is found or if the argument value cannot be determined or is not a literal.
272
+ */
273
+ function getAttributeArgLiteral(attr, name) {
274
+ for (const arg of attr.args) if (arg.$resolvedParam?.name === name) return getLiteral(arg.value);
275
+ }
276
+ /**
277
+ * Gets the allowed expression contexts for the given function declaration by looking for `@@expressionContext` attribute.
278
+ * Returns an empty array if no such attribute is found or if the attribute value cannot be determined.
279
+ */
280
+ function getFunctionExpressionContext(funcDecl) {
281
+ const funcAllowedContext = [];
282
+ const funcAttr = funcDecl.attributes.find((attr) => attr.decl.$refText === "@@@expressionContext");
283
+ if (funcAttr) {
284
+ const contextArg = funcAttr.args[0]?.value;
285
+ if (isArrayExpr(contextArg)) contextArg.items.forEach((item) => {
286
+ if (isEnumFieldReference(item)) funcAllowedContext.push(item.target.$refText);
287
+ });
288
+ }
289
+ return funcAllowedContext;
290
+ }
291
+ /**
292
+ * Gets the data field referenced by the given expression, if any. Returns `undefined` if the expression is not a reference to a data field.
293
+ */
294
+ function getFieldReference(expr) {
295
+ if (isReferenceExpr(expr) && isDataField(expr.target.ref)) return expr.target.ref;
296
+ else if (isMemberAccessExpr(expr) && isDataField(expr.member.ref)) return expr.member.ref;
297
+ else return;
298
+ }
299
+ function isCheckInvocation(node) {
300
+ return isInvocationExpr(node) && node.function.ref?.name === "check";
301
+ }
302
+ /**
303
+ * Resolves the transitive imports of the given model and returns the list of imported models. The given model itself is not included in the result.
304
+ */
305
+ function resolveTransitiveImports(documents, model) {
306
+ return resolveTransitiveImportsInternal(documents, model);
307
+ }
308
+ function resolveTransitiveImportsInternal(documents, model, initialModel = model, visited = /* @__PURE__ */ new Set(), models = /* @__PURE__ */ new Set()) {
309
+ const doc = AstUtils.getDocument(model);
310
+ if (AstUtils.getDocument(initialModel).uri.fsPath.toLowerCase() !== doc.uri.fsPath.toLowerCase()) models.add(model);
311
+ const normalizedPath = doc.uri.fsPath.toLowerCase();
312
+ if (!visited.has(normalizedPath)) {
313
+ visited.add(normalizedPath);
314
+ for (const imp of model.imports) {
315
+ const importedModel = resolveImport(documents, imp);
316
+ if (importedModel) resolveTransitiveImportsInternal(documents, importedModel, initialModel, visited, models);
317
+ }
318
+ }
319
+ return Array.from(models);
320
+ }
321
+ /**
322
+ * Resolves the given import and returns the imported model. Returns `undefined`
323
+ * if the import cannot be resolved.
324
+ */
325
+ function resolveImport(documents, imp) {
326
+ const resolvedUri = resolveImportUri(imp);
327
+ try {
328
+ if (resolvedUri) {
329
+ let resolvedDocument = documents.getDocument(resolvedUri);
330
+ if (!resolvedDocument) {
331
+ const content = fs.readFileSync(resolvedUri.fsPath, "utf-8");
332
+ resolvedDocument = documents.createDocument(resolvedUri, content);
333
+ }
334
+ const node = resolvedDocument.parseResult.value;
335
+ if (isModel(node)) return node;
336
+ }
337
+ } catch {}
338
+ }
339
+ /**
340
+ * Resolves the given import and returns the URI of the imported model.
341
+ * Returns `undefined` if the import cannot be resolved.
342
+ */
343
+ function resolveImportUri(imp) {
344
+ if (!imp.path) return;
345
+ const doc = AstUtils.getDocument(imp);
346
+ const dir = path.dirname(doc.uri.fsPath);
347
+ const importPath = imp.path.endsWith(".zmodel") ? imp.path : `${imp.path}.zmodel`;
348
+ return URI.file(path.resolve(dir, importPath));
349
+ }
350
+ /**
351
+ * Gets data models and type defs in the ZModel schema.
352
+ */
353
+ function getDataModelAndTypeDefs(model, includeIgnored = false) {
354
+ const r = model.declarations.filter((d) => isDataModel(d) || isTypeDef(d));
355
+ if (includeIgnored) return r;
356
+ else return r.filter((model) => !hasAttribute(model, "@@ignore"));
357
+ }
358
+ /**
359
+ * Gets all declarations of the given model and its transitive imports.
360
+ */
361
+ function getAllDeclarationsIncludingImports(documents, model) {
362
+ const imports = resolveTransitiveImports(documents, model);
363
+ return model.declarations.concat(...imports.map((imp) => imp.declarations));
364
+ }
365
+ /**
366
+ * Gets the model used for auth context, by looking for a model with `@@auth` attribute or a model named `User`.
367
+ * Returns `undefined` if no such model is found.
368
+ */
369
+ function getAuthDecl(decls) {
370
+ let authModel = decls.find((d) => hasAttribute(d, "@@auth"));
371
+ if (!authModel) authModel = decls.find((d) => d.name === "User");
372
+ return authModel;
373
+ }
374
+ function isBeforeInvocation(node) {
375
+ return isInvocationExpr(node) && node.function.ref?.name === "before";
376
+ }
377
+ /**
378
+ * Determines if the given AST node is a collection predicate.
379
+ */
380
+ function isCollectionPredicate(node) {
381
+ return isBinaryExpr(node) && [
382
+ "?",
383
+ "!",
384
+ "^"
385
+ ].includes(node.operator);
386
+ }
387
+ /**
388
+ * Gets all data models and type defs from the given documents registry.
389
+ */
390
+ function getAllLoadedDataModelsAndTypeDefs(langiumDocuments) {
391
+ return langiumDocuments.all.map((doc) => doc.parseResult.value).flatMap((model) => model.declarations.filter((d) => isDataModel(d) || isTypeDef(d))).toArray();
392
+ }
393
+ /**
394
+ * Gets all data models from the given documents registry and the transitive imports of the given model.
395
+ */
396
+ function getAllDataModelsIncludingImports(documents, model) {
397
+ return getAllDeclarationsIncludingImports(documents, model).filter(isDataModel);
398
+ }
399
+ /**
400
+ * Gets all data models and type defs from the given documents registry and the transitive imports
401
+ * of the given model. If `fromModel` is not provided, returns all loaded data models and type defs.
402
+ */
403
+ function getAllLoadedAndReachableDataModelsAndTypeDefs(langiumDocuments, fromModel) {
404
+ const allDataModels = getAllLoadedDataModelsAndTypeDefs(langiumDocuments);
405
+ if (fromModel) {
406
+ const model = AstUtils.getContainerOfType(fromModel, isModel);
407
+ if (model) getAllDataModelsIncludingImports(langiumDocuments, model).forEach((dm) => {
408
+ if (!allDataModels.includes(dm)) allDataModels.push(dm);
409
+ });
410
+ }
411
+ return allDataModels;
412
+ }
413
+ /**
414
+ * Gets the containing data model of the given AST node, if any.
415
+ * Returns `undefined` if the node is not contained in a data model.
416
+ */
417
+ function getContainingDataModel(node) {
418
+ let curr = node.$container;
419
+ while (curr) {
420
+ if (isDataModel(curr)) return curr;
421
+ curr = curr.$container;
422
+ }
423
+ }
424
+ /**
425
+ * Determines if the given AST node can contain members.
426
+ */
427
+ function isMemberContainer(node) {
428
+ return isDataModel(node) || isTypeDef(node);
429
+ }
430
+ /**
431
+ * Gets all fields of a data model or type def, including inherited fields from base models and mixins.
432
+ */
433
+ function getAllFields(decl, includeIgnored = false, seen = /* @__PURE__ */ new Set()) {
434
+ if (seen.has(decl)) return [];
435
+ seen.add(decl);
436
+ const fields = [];
437
+ for (const mixin of decl.mixins) if (mixin.ref) fields.push(...getAllFields(mixin.ref, includeIgnored, seen));
438
+ if (isDataModel(decl) && decl.baseModel) {
439
+ if (decl.baseModel.ref) fields.push(...getAllFields(decl.baseModel.ref, includeIgnored, seen));
440
+ }
441
+ fields.push(...decl.fields.filter((f) => includeIgnored || !hasAttribute(f, "@ignore")));
442
+ return fields;
443
+ }
444
+ /**
445
+ * Gets all attributes of a data model or type def, including inherited attributes
446
+ * from base models and mixins.
447
+ */
448
+ function getAllAttributes(decl, seen = /* @__PURE__ */ new Set()) {
449
+ if (seen.has(decl)) return [];
450
+ seen.add(decl);
451
+ const attributes = [];
452
+ for (const mixin of decl.mixins) if (mixin.ref) attributes.push(...getAllAttributes(mixin.ref, seen));
453
+ if (isDataModel(decl) && decl.baseModel) {
454
+ if (decl.baseModel.ref) {
455
+ const attrs = getAllAttributes(decl.baseModel.ref, seen).filter((attr) => !isNonInheritableAttribute(attr));
456
+ attributes.push(...attrs);
457
+ }
458
+ }
459
+ attributes.push(...decl.attributes);
460
+ return attributes;
461
+ }
462
+ function isNonInheritableAttribute(attr) {
463
+ const attrName = attr.decl.ref?.name ?? attr.decl.$refText;
464
+ return [
465
+ "@@map",
466
+ "@@unique",
467
+ "@@index"
468
+ ].includes(attrName);
469
+ }
470
+ /**
471
+ * Retrieve the document in which the given AST node is contained. A reference to the document is
472
+ * usually held by the root node of the AST.
473
+ *
474
+ * @throws an error if the node is not contained in a document.
475
+ */
476
+ function getDocument(node) {
477
+ const result = findRootNode(node).$document;
478
+ if (!result) throw new Error("AST node has no document.");
479
+ return result;
480
+ }
481
+ /**
482
+ * Gets the list of plugin documents from the given model.
483
+ */
484
+ function getPluginDocuments(model, schemaPath) {
485
+ const result = [];
486
+ for (const decl of model.declarations.filter(isPlugin)) {
487
+ const providerField = decl.fields.find((f) => f.name === "provider");
488
+ if (!providerField) continue;
489
+ const provider = getLiteral(providerField.value);
490
+ if (!provider) continue;
491
+ let pluginModelFile;
492
+ let providerPath = path.resolve(path.dirname(schemaPath), provider);
493
+ if (fs.existsSync(providerPath)) {
494
+ if (fs.statSync(providerPath).isDirectory()) providerPath = path.join(providerPath, "index.js");
495
+ pluginModelFile = path.resolve(path.dirname(providerPath), PLUGIN_MODULE_NAME);
496
+ if (!fs.existsSync(pluginModelFile)) pluginModelFile = findUp([PLUGIN_MODULE_NAME], path.dirname(providerPath));
497
+ }
498
+ if (!pluginModelFile) {
499
+ if (typeof import.meta.resolve === "function") try {
500
+ pluginModelFile = fileURLToPath(import.meta.resolve(`${provider}/${PLUGIN_MODULE_NAME}`));
501
+ } catch {}
502
+ }
503
+ if (!pluginModelFile) try {
504
+ pluginModelFile = createRequire(pathToFileURL(schemaPath)).resolve(`${provider}/${PLUGIN_MODULE_NAME}`);
505
+ } catch {}
506
+ if (pluginModelFile && fs.existsSync(pluginModelFile)) result.push(pluginModelFile);
507
+ }
508
+ return result;
509
+ }
510
+ function findUp(names, cwd = process.cwd(), multiple = false, result = []) {
511
+ if (!names.some((name) => !!name)) return;
512
+ const target = names.find((name) => fs.existsSync(path.join(cwd, name)));
513
+ if (multiple === false && target) return path.join(cwd, target);
514
+ if (target) result.push(path.join(cwd, target));
515
+ const up = path.resolve(cwd, "..");
516
+ if (up === cwd) return multiple && result.length > 0 ? result : void 0;
517
+ return findUp(names, up, multiple, result);
518
+ }
519
+ /**
520
+ * Returns the root node of the given AST node by following the `$container` references.
521
+ */
522
+ function findRootNode(node) {
523
+ while (node.$container) node = node.$container;
524
+ return node;
525
+ }
526
+ //#endregion
527
+ export { isBeforeInvocation as A, mapBuiltinTypeToExpressionType as B, getPluginDocuments as C, hasAttribute as D, getUniqueFields as E, isDelegateModel as F, typeAssignable as G, resolveImportUri as H, isEnumFieldReference as I, IssueCodes as J, DB_PROVIDERS_SUPPORTING_LIST_TYPE as K, isFromStdlib as L, isCollectionPredicate as M, isComputedField as N, isAuthInvocation as O, isDataFieldReference as P, SUPPORTED_PROVIDERS as Q, isMemberContainer as R, getObjectLiteral as S, getStringLiteral as T, resolveTransitiveImports as U, resolveImport as V, resolved as W, SCALAR_TYPES as X, PLUGIN_MODULE_NAME as Y, STD_LIB_MODULE_NAME as Z, getFunctionExpressionContext as _, getAllDeclarationsIncludingImports as a, getModelIdFields as b, getAllLoadedDataModelsAndTypeDefs as c, getAttributeArgLiteral as d, getAuthDecl as f, getFieldReference as g, getDocument as h, getAllDataModelsIncludingImports as i, isCheckInvocation as j, isAuthOrAuthMemberAccess as k, getAttribute as l, getDataModelAndTypeDefs as m, findUpAst as n, getAllFields as o, getContainingDataModel as p, ExpressionContext as q, getAllAttributes as r, getAllLoadedAndReachableDataModelsAndTypeDefs as s, findRootNode as t, getAttributeArg as u, getLiteral as v, getRecursiveBases as w, getModelUniqueFields as x, getLiteralArray as y, isRelationshipField as z };
528
+
529
+ //# sourceMappingURL=utils-BB6L7ug2.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils-BB6L7ug2.mjs","names":[],"sources":["../src/constants.ts","../src/utils.ts"],"sourcesContent":["/**\n * Supported db providers\n */\nexport const SUPPORTED_PROVIDERS = ['sqlite', 'postgresql', 'mysql'];\n\n/**\n * All scalar types\n */\nexport const SCALAR_TYPES = ['String', 'Int', 'Float', 'Decimal', 'BigInt', 'Boolean', 'Bytes', 'DateTime'];\n\n/**\n * Name of standard library module\n */\nexport const STD_LIB_MODULE_NAME = 'stdlib.zmodel';\n\n/**\n * Name of module contributed by plugins\n */\nexport const PLUGIN_MODULE_NAME = 'plugin.zmodel';\n\n/**\n * Validation issues\n */\nexport enum IssueCodes {\n MissingOppositeRelation = 'miss-opposite-relation',\n}\n\n/**\n * Expression context\n */\nexport enum ExpressionContext {\n DefaultValue = 'DefaultValue',\n AccessPolicy = 'AccessPolicy',\n ValidationRule = 'ValidationRule',\n Index = 'Index',\n}\n\n/**\n * Database providers that support list field types.\n */\nexport const DB_PROVIDERS_SUPPORTING_LIST_TYPE = ['postgresql'];\n","import { AstUtils, URI, type AstNode, type LangiumDocument, type LangiumDocuments, type Reference } from 'langium';\nimport fs from 'node:fs';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport { PLUGIN_MODULE_NAME, STD_LIB_MODULE_NAME, type ExpressionContext } from './constants';\nimport {\n InternalAttribute,\n isArrayExpr,\n isBinaryExpr,\n isConfigArrayExpr,\n isDataField,\n isDataModel,\n isEnumField,\n isExpression,\n isInvocationExpr,\n isLiteralExpr,\n isMemberAccessExpr,\n isModel,\n isObjectExpr,\n isPlugin,\n isReferenceExpr,\n isStringLiteral,\n isTypeDef,\n type Attribute,\n type AttributeParam,\n type BinaryExpr,\n type BuiltinType,\n type ConfigExpr,\n type DataField,\n type DataFieldAttribute,\n type DataModel,\n type DataModelAttribute,\n type Enum,\n type EnumField,\n type Expression,\n type ExpressionType,\n type FunctionDecl,\n type Model,\n type ModelImport,\n type ReferenceExpr,\n type TypeDef,\n} from './generated/ast';\n\nexport type AttributeTarget =\n | DataModel\n | TypeDef\n | DataField\n | Enum\n | EnumField\n | FunctionDecl\n | Attribute\n | AttributeParam;\n\nexport function hasAttribute(decl: AttributeTarget, name: string) {\n return !!getAttribute(decl, name);\n}\n\nexport function getAttribute(decl: AttributeTarget, name: string) {\n return (decl.attributes as (DataModelAttribute | DataFieldAttribute)[]).find((attr) => attr.decl.$refText === name);\n}\n\nexport function isFromStdlib(node: AstNode) {\n const model = AstUtils.getContainerOfType(node, isModel);\n return !!model && !!model.$document && model.$document.uri.path.endsWith(STD_LIB_MODULE_NAME);\n}\n\nexport function isAuthInvocation(node: AstNode) {\n return isInvocationExpr(node) && node.function.ref?.name === 'auth' && isFromStdlib(node.function.ref);\n}\n\n/**\n * Try getting string value from a potential string literal expression\n */\nexport function getStringLiteral(node: AstNode | undefined): string | undefined {\n return isStringLiteral(node) ? node.value : undefined;\n}\n\nconst isoDateTimeRegex = /^\\d{4}(-\\d\\d(-\\d\\d(T\\d\\d:\\d\\d(:\\d\\d)?(\\.\\d+)?(([+-]\\d\\d:\\d\\d)|Z)?)?)?)?$/i;\n\n/**\n * Determines if the given sourceType is assignable to a destination of destType\n */\nexport function typeAssignable(destType: ExpressionType, sourceType: ExpressionType, sourceExpr?: Expression): boolean {\n // implicit conversion from ISO datetime string to datetime\n if (destType === 'DateTime' && sourceType === 'String' && sourceExpr && isStringLiteral(sourceExpr)) {\n const literal = getStringLiteral(sourceExpr);\n if (literal && isoDateTimeRegex.test(literal)) {\n // implicitly convert to DateTime\n sourceType = 'DateTime';\n }\n }\n\n switch (destType) {\n case 'Any':\n return true;\n case 'Float':\n return sourceType === 'Any' || sourceType === 'Int' || sourceType === 'Float';\n default:\n return sourceType === 'Any' || sourceType === destType;\n }\n}\n\n/**\n * Maps a ZModel builtin type to expression type\n */\nexport function mapBuiltinTypeToExpressionType(type: BuiltinType | ExpressionType): ExpressionType {\n switch (type) {\n case 'Any':\n case 'Boolean':\n case 'String':\n case 'DateTime':\n case 'Int':\n case 'Float':\n case 'Null':\n case 'Object':\n case 'Unsupported':\n case 'Void':\n case 'Undefined':\n return type;\n case 'BigInt':\n return 'Int';\n case 'Decimal':\n return 'Float';\n case 'Json':\n case 'Bytes':\n return 'Any';\n }\n}\n\n/**\n * Determines if the given expression is an invocation of `auth` or a member access on the result of an `auth` invocation (e.g. `auth().role`).\n */\nexport function isAuthOrAuthMemberAccess(expr: Expression): boolean {\n return isAuthInvocation(expr) || (isMemberAccessExpr(expr) && isAuthOrAuthMemberAccess(expr.operand));\n}\n\n/**\n * Determines if the given expression is a reference to an enum field.\n */\nexport function isEnumFieldReference(node: AstNode): node is ReferenceExpr {\n return isReferenceExpr(node) && isEnumField(node.target.ref);\n}\n\n/**\n * Determines if the given expression is a reference to a data field.\n */\nexport function isDataFieldReference(node: AstNode): node is ReferenceExpr {\n return isReferenceExpr(node) && isDataField(node.target.ref);\n}\n\n/**\n * Returns if the given field is a relation field.\n */\nexport function isRelationshipField(field: DataField) {\n return isDataModel(field.type.reference?.ref);\n}\n\n/**\n * Returns if the given field is a computed field.\n */\nexport function isComputedField(field: DataField) {\n return hasAttribute(field, '@computed');\n}\n\n/**\n * Determines if the given data model is a delegate model (i.e. marked with `@@delegate` attribute).\n */\nexport function isDelegateModel(node: AstNode) {\n return isDataModel(node) && hasAttribute(node, '@@delegate');\n}\n\n/**\n * Resolves the given reference and returns the target AST node. Throws an error if the reference is not resolved.\n */\nexport function resolved<T extends AstNode>(ref: Reference<T>): T {\n if (!ref.ref) {\n throw new Error(`Reference not resolved: ${ref.$refText}`);\n }\n return ref.ref;\n}\n\n/**\n * Gets all base models and mixins of a data model or type def, recursively.\n */\nexport function getRecursiveBases(\n decl: DataModel | TypeDef,\n includeDelegate = true,\n documents?: LangiumDocuments,\n seen = new Set<DataModel | TypeDef>(),\n): (TypeDef | DataModel)[] {\n const result: (TypeDef | DataModel)[] = [];\n if (seen.has(decl)) {\n return result;\n }\n seen.add(decl);\n const bases = [...decl.mixins, ...(isDataModel(decl) && decl.baseModel ? [decl.baseModel] : [])];\n bases.forEach((base) => {\n let baseDecl: TypeDef | DataModel | undefined;\n\n if (base.ref && (isTypeDef(base.ref) || isDataModel(base.ref))) {\n // base is already resolved\n baseDecl = base.ref;\n } else {\n // otherwise, search by name, in all imported documents if provided\n const declarations = documents\n ? getAllDeclarationsIncludingImports(documents, decl.$container)\n : decl.$container.declarations;\n\n baseDecl = declarations.find(\n (d): d is TypeDef | DataModel => (isTypeDef(d) || isDataModel(d)) && d.name === base.$refText,\n );\n }\n\n if (baseDecl) {\n if (!includeDelegate && isDelegateModel(baseDecl)) {\n return;\n }\n result.push(baseDecl);\n result.push(...getRecursiveBases(baseDecl, includeDelegate, documents, seen));\n }\n });\n return result;\n}\n\n/**\n * Gets `@@id` fields declared at the data model level (including search in base models)\n */\nexport function getModelIdFields(model: DataModel) {\n const modelsToCheck = [model, ...getRecursiveBases(model)];\n\n for (const modelToCheck of modelsToCheck) {\n const allAttributes = getAllAttributes(modelToCheck);\n const idAttr = allAttributes.find((attr) => attr.decl.$refText === '@@id');\n if (!idAttr) {\n continue;\n }\n const fieldsArg = idAttr.args.find((a) => a.$resolvedParam?.name === 'fields');\n if (!fieldsArg || !isArrayExpr(fieldsArg.value)) {\n continue;\n }\n\n return fieldsArg.value.items\n .filter((item): item is ReferenceExpr => isReferenceExpr(item))\n .map((item) => resolved(item.target) as DataField);\n }\n\n return [];\n}\n\n/**\n * Gets `@@unique` fields declared at the data model level (including search in base models)\n */\nexport function getModelUniqueFields(model: DataModel) {\n const modelsToCheck = [model, ...getRecursiveBases(model)];\n\n for (const modelToCheck of modelsToCheck) {\n const allAttributes = getAllAttributes(modelToCheck);\n const uniqueAttr = allAttributes.find((attr) => attr.decl.$refText === '@@unique');\n if (!uniqueAttr) {\n continue;\n }\n const fieldsArg = uniqueAttr.args.find((a) => a.$resolvedParam?.name === 'fields');\n if (!fieldsArg || !isArrayExpr(fieldsArg.value)) {\n continue;\n }\n\n return fieldsArg.value.items\n .filter((item): item is ReferenceExpr => isReferenceExpr(item))\n .map((item) => resolved(item.target) as DataField);\n }\n\n return [];\n}\n\n/**\n * Gets lists of unique fields declared at the data model level\n *\n * TODO: merge this with {@link getModelUniqueFields}\n */\nexport function getUniqueFields(model: DataModel) {\n const uniqueAttrs = model.attributes.filter(\n (attr) => attr.decl.ref?.name === '@@unique' || attr.decl.ref?.name === '@@id',\n );\n return uniqueAttrs.map((uniqueAttr) => {\n const fieldsArg = uniqueAttr.args.find((a) => a.$resolvedParam?.name === 'fields');\n if (!fieldsArg || !isArrayExpr(fieldsArg.value)) {\n return [];\n }\n\n return fieldsArg.value.items\n .filter((item): item is ReferenceExpr => isReferenceExpr(item))\n .map((item) => resolved(item.target) as DataField);\n });\n}\n\n/**\n * Finds the first ancestor of the given AST node that satisfies the given predicate function. Returns `undefined` if no such ancestor is found.\n */\nexport function findUpAst(node: AstNode, predicate: (node: AstNode) => boolean): AstNode | undefined {\n let curr: AstNode | undefined = node;\n while (curr) {\n if (predicate(curr)) {\n return curr;\n }\n curr = curr.$container;\n }\n return undefined;\n}\n\n/**\n * Tries to get the literal value from the given expression. Returns `undefined` if the expression is not a literal or if the literal value cannot be determined.\n */\nexport function getLiteral<T extends string | number | boolean | any = any>(\n expr: Expression | ConfigExpr | undefined,\n): T | undefined {\n switch (expr?.$type) {\n case 'ObjectExpr':\n return getObjectLiteral<T>(expr);\n case 'StringLiteral':\n case 'BooleanLiteral':\n return expr.value as T;\n case 'NumberLiteral':\n return parseFloat(expr.value) as T;\n default:\n return undefined;\n }\n}\n\n/**\n * Tries to get an object literal from the given expression. Returns `undefined` if the expression is not an object literal or if any of the field values cannot be determined.\n */\nexport function getObjectLiteral<T>(expr: Expression | ConfigExpr | undefined): T | undefined {\n if (!expr || !isObjectExpr(expr)) {\n return undefined;\n }\n const result: Record<string, unknown> = {};\n for (const field of expr.fields) {\n let fieldValue: unknown;\n if (isLiteralExpr(field.value)) {\n fieldValue = getLiteral(field.value);\n } else if (isArrayExpr(field.value)) {\n fieldValue = getLiteralArray(field.value);\n } else if (isObjectExpr(field.value)) {\n fieldValue = getObjectLiteral(field.value);\n }\n if (fieldValue === undefined) {\n return undefined;\n } else {\n result[field.name] = fieldValue;\n }\n }\n return result as T;\n}\n\nexport function getLiteralArray<T extends string | number | boolean | any = any>(\n expr: Expression | ConfigExpr | undefined,\n): T[] | undefined {\n const arr = getArray(expr);\n if (!arr) {\n return undefined;\n }\n return arr.map((item) => isExpression(item) && getLiteral<T>(item)).filter((v): v is T => v !== undefined);\n}\n\nfunction getArray(expr: Expression | ConfigExpr | undefined) {\n return isArrayExpr(expr) || isConfigArrayExpr(expr) ? expr.items : undefined;\n}\n\n/**\n * Gets the value of the argument with the given name from the given attribute. Returns `undefined` if no such argument is found or if the argument value cannot be determined.\n */\nexport function getAttributeArg(\n attr: DataModelAttribute | DataFieldAttribute | InternalAttribute,\n name: string,\n): Expression | undefined {\n return attr.args.find((arg) => arg.$resolvedParam?.name === name)?.value;\n}\n\n/**\n * Gets the literal value of the argument with the given name from the given attribute. Returns `undefined` if no such argument is found or if the argument value cannot be determined or is not a literal.\n */\nexport function getAttributeArgLiteral<T extends string | number | boolean>(\n attr: DataModelAttribute | DataFieldAttribute | InternalAttribute,\n name: string,\n): T | undefined {\n for (const arg of attr.args) {\n if (arg.$resolvedParam?.name === name) {\n return getLiteral<T>(arg.value);\n }\n }\n return undefined;\n}\n\n/**\n * Gets the allowed expression contexts for the given function declaration by looking for `@@expressionContext` attribute.\n * Returns an empty array if no such attribute is found or if the attribute value cannot be determined.\n */\nexport function getFunctionExpressionContext(funcDecl: FunctionDecl) {\n const funcAllowedContext: ExpressionContext[] = [];\n const funcAttr = funcDecl.attributes.find((attr) => attr.decl.$refText === '@@@expressionContext');\n if (funcAttr) {\n const contextArg = funcAttr.args[0]?.value;\n if (isArrayExpr(contextArg)) {\n contextArg.items.forEach((item) => {\n if (isEnumFieldReference(item)) {\n funcAllowedContext.push(item.target.$refText as ExpressionContext);\n }\n });\n }\n }\n return funcAllowedContext;\n}\n\n/**\n * Gets the data field referenced by the given expression, if any. Returns `undefined` if the expression is not a reference to a data field.\n */\nexport function getFieldReference(expr: Expression): DataField | undefined {\n if (isReferenceExpr(expr) && isDataField(expr.target.ref)) {\n return expr.target.ref;\n } else if (isMemberAccessExpr(expr) && isDataField(expr.member.ref)) {\n return expr.member.ref;\n } else {\n return undefined;\n }\n}\n\n// TODO: move to policy plugin\nexport function isCheckInvocation(node: AstNode) {\n return isInvocationExpr(node) && node.function.ref?.name === 'check';\n}\n\n/**\n * Resolves the transitive imports of the given model and returns the list of imported models. The given model itself is not included in the result.\n */\nexport function resolveTransitiveImports(documents: LangiumDocuments, model: Model) {\n return resolveTransitiveImportsInternal(documents, model);\n}\n\nfunction resolveTransitiveImportsInternal(\n documents: LangiumDocuments,\n model: Model,\n initialModel = model,\n visited: Set<string> = new Set(),\n models: Set<Model> = new Set(),\n) {\n const doc = AstUtils.getDocument(model);\n const initialDoc = AstUtils.getDocument(initialModel);\n\n if (initialDoc.uri.fsPath.toLowerCase() !== doc.uri.fsPath.toLowerCase()) {\n models.add(model);\n }\n\n const normalizedPath = doc.uri.fsPath.toLowerCase();\n if (!visited.has(normalizedPath)) {\n visited.add(normalizedPath);\n for (const imp of model.imports) {\n const importedModel = resolveImport(documents, imp);\n if (importedModel) {\n resolveTransitiveImportsInternal(documents, importedModel, initialModel, visited, models);\n }\n }\n }\n return Array.from(models);\n}\n\n/**\n * Resolves the given import and returns the imported model. Returns `undefined`\n * if the import cannot be resolved.\n */\nexport function resolveImport(documents: LangiumDocuments, imp: ModelImport) {\n const resolvedUri = resolveImportUri(imp);\n try {\n if (resolvedUri) {\n let resolvedDocument = documents.getDocument(resolvedUri);\n if (!resolvedDocument) {\n const content = fs.readFileSync(resolvedUri.fsPath, 'utf-8');\n resolvedDocument = documents.createDocument(resolvedUri, content);\n }\n const node = resolvedDocument.parseResult.value;\n if (isModel(node)) {\n return node;\n }\n }\n } catch {\n // NOOP\n }\n return undefined;\n}\n\n/**\n * Resolves the given import and returns the URI of the imported model.\n * Returns `undefined` if the import cannot be resolved.\n */\nexport function resolveImportUri(imp: ModelImport) {\n if (!imp.path) {\n return undefined;\n }\n const doc = AstUtils.getDocument(imp);\n const dir = path.dirname(doc.uri.fsPath);\n const importPath = imp.path.endsWith('.zmodel') ? imp.path : `${imp.path}.zmodel`;\n return URI.file(path.resolve(dir, importPath));\n}\n\n/**\n * Gets data models and type defs in the ZModel schema.\n */\nexport function getDataModelAndTypeDefs(model: Model, includeIgnored = false) {\n const r = model.declarations.filter((d): d is DataModel | TypeDef => isDataModel(d) || isTypeDef(d));\n if (includeIgnored) {\n return r;\n } else {\n return r.filter((model) => !hasAttribute(model, '@@ignore'));\n }\n}\n\n/**\n * Gets all declarations of the given model and its transitive imports.\n */\nexport function getAllDeclarationsIncludingImports(documents: LangiumDocuments, model: Model) {\n const imports = resolveTransitiveImports(documents, model);\n return model.declarations.concat(...imports.map((imp) => imp.declarations));\n}\n\n/**\n * Gets the model used for auth context, by looking for a model with `@@auth` attribute or a model named `User`.\n * Returns `undefined` if no such model is found.\n */\nexport function getAuthDecl(decls: (DataModel | TypeDef)[]) {\n let authModel = decls.find((d) => hasAttribute(d, '@@auth'));\n if (!authModel) {\n authModel = decls.find((d) => d.name === 'User');\n }\n return authModel;\n}\n\n// TODO: move to policy plugin\nexport function isBeforeInvocation(node: AstNode) {\n return isInvocationExpr(node) && node.function.ref?.name === 'before';\n}\n\n/**\n * Determines if the given AST node is a collection predicate.\n */\nexport function isCollectionPredicate(node: AstNode): node is BinaryExpr {\n return isBinaryExpr(node) && ['?', '!', '^'].includes(node.operator);\n}\n\n/**\n * Gets all data models and type defs from the given documents registry.\n */\nexport function getAllLoadedDataModelsAndTypeDefs(langiumDocuments: LangiumDocuments) {\n return langiumDocuments.all\n .map((doc) => doc.parseResult.value as Model)\n .flatMap((model) => model.declarations.filter((d): d is DataModel | TypeDef => isDataModel(d) || isTypeDef(d)))\n .toArray();\n}\n\n/**\n * Gets all data models from the given documents registry and the transitive imports of the given model.\n */\nexport function getAllDataModelsIncludingImports(documents: LangiumDocuments, model: Model) {\n return getAllDeclarationsIncludingImports(documents, model).filter(isDataModel);\n}\n\n/**\n * Gets all data models and type defs from the given documents registry and the transitive imports\n * of the given model. If `fromModel` is not provided, returns all loaded data models and type defs.\n */\nexport function getAllLoadedAndReachableDataModelsAndTypeDefs(\n langiumDocuments: LangiumDocuments,\n fromModel?: DataModel,\n) {\n // get all data models from loaded documents\n const allDataModels = getAllLoadedDataModelsAndTypeDefs(langiumDocuments);\n\n if (fromModel) {\n // merge data models transitively reached from the current model\n const model = AstUtils.getContainerOfType(fromModel, isModel);\n if (model) {\n const transitiveDataModels = getAllDataModelsIncludingImports(langiumDocuments, model);\n transitiveDataModels.forEach((dm) => {\n if (!allDataModels.includes(dm)) {\n allDataModels.push(dm);\n }\n });\n }\n }\n\n return allDataModels;\n}\n\n/**\n * Gets the containing data model of the given AST node, if any.\n * Returns `undefined` if the node is not contained in a data model.\n */\nexport function getContainingDataModel(node: AstNode): DataModel | undefined {\n let curr: AstNode | undefined = node.$container;\n while (curr) {\n if (isDataModel(curr)) {\n return curr;\n }\n curr = curr.$container;\n }\n return undefined;\n}\n\n/**\n * Determines if the given AST node can contain members.\n */\nexport function isMemberContainer(node: unknown): node is DataModel | TypeDef {\n return isDataModel(node) || isTypeDef(node);\n}\n\n/**\n * Gets all fields of a data model or type def, including inherited fields from base models and mixins.\n */\nexport function getAllFields(\n decl: DataModel | TypeDef,\n includeIgnored = false,\n seen: Set<DataModel | TypeDef> = new Set(),\n): DataField[] {\n if (seen.has(decl)) {\n return [];\n }\n seen.add(decl);\n\n const fields: DataField[] = [];\n for (const mixin of decl.mixins) {\n if (mixin.ref) {\n fields.push(...getAllFields(mixin.ref, includeIgnored, seen));\n }\n }\n\n if (isDataModel(decl) && decl.baseModel) {\n if (decl.baseModel.ref) {\n fields.push(...getAllFields(decl.baseModel.ref, includeIgnored, seen));\n }\n }\n\n fields.push(...decl.fields.filter((f) => includeIgnored || !hasAttribute(f, '@ignore')));\n return fields;\n}\n\n/**\n * Gets all attributes of a data model or type def, including inherited attributes\n * from base models and mixins.\n */\nexport function getAllAttributes(\n decl: DataModel | TypeDef,\n seen: Set<DataModel | TypeDef> = new Set(),\n): DataModelAttribute[] {\n if (seen.has(decl)) {\n return [];\n }\n seen.add(decl);\n\n const attributes: DataModelAttribute[] = [];\n for (const mixin of decl.mixins) {\n if (mixin.ref) {\n attributes.push(...getAllAttributes(mixin.ref, seen));\n }\n }\n\n if (isDataModel(decl) && decl.baseModel) {\n if (decl.baseModel.ref) {\n const attrs = getAllAttributes(decl.baseModel.ref, seen).filter((attr) => !isNonInheritableAttribute(attr));\n attributes.push(...attrs);\n }\n }\n\n attributes.push(...decl.attributes);\n return attributes;\n}\n\nfunction isNonInheritableAttribute(attr: DataModelAttribute) {\n const attrName = attr.decl.ref?.name ?? attr.decl.$refText;\n return ['@@map', '@@unique', '@@index'].includes(attrName);\n}\n\n/**\n * Retrieve the document in which the given AST node is contained. A reference to the document is\n * usually held by the root node of the AST.\n *\n * @throws an error if the node is not contained in a document.\n */\nexport function getDocument<T extends AstNode = AstNode>(node: AstNode): LangiumDocument<T> {\n const rootNode = findRootNode(node);\n const result = rootNode.$document;\n if (!result) {\n throw new Error('AST node has no document.');\n }\n return result as LangiumDocument<T>;\n}\n\n/**\n * Gets the list of plugin documents from the given model.\n */\nexport function getPluginDocuments(model: Model, schemaPath: string): string[] {\n // traverse plugins and collect \"plugin.zmodel\" documents\n const result: string[] = [];\n for (const decl of model.declarations.filter(isPlugin)) {\n const providerField = decl.fields.find((f) => f.name === 'provider');\n if (!providerField) {\n continue;\n }\n\n const provider = getLiteral<string>(providerField.value);\n if (!provider) {\n continue;\n }\n\n let pluginModelFile: string | undefined;\n\n // first try to treat provider as a path\n let providerPath = path.resolve(path.dirname(schemaPath), provider);\n if (fs.existsSync(providerPath)) {\n if (fs.statSync(providerPath).isDirectory()) {\n providerPath = path.join(providerPath, 'index.js');\n }\n\n // try plugin.zmodel next to the provider file\n pluginModelFile = path.resolve(path.dirname(providerPath), PLUGIN_MODULE_NAME);\n if (!fs.existsSync(pluginModelFile)) {\n // try to find upwards\n pluginModelFile = findUp([PLUGIN_MODULE_NAME], path.dirname(providerPath));\n }\n }\n\n if (!pluginModelFile) {\n if (typeof import.meta.resolve === 'function') {\n try {\n // try loading as a ESM module\n const resolvedUrl = import.meta.resolve(`${provider}/${PLUGIN_MODULE_NAME}`);\n pluginModelFile = fileURLToPath(resolvedUrl);\n } catch {\n // noop\n }\n }\n }\n\n if (!pluginModelFile) {\n // try loading as a CJS module\n try {\n const require = createRequire(pathToFileURL(schemaPath));\n pluginModelFile = require.resolve(`${provider}/${PLUGIN_MODULE_NAME}`);\n } catch {\n // noop\n }\n }\n\n if (pluginModelFile && fs.existsSync(pluginModelFile)) {\n result.push(pluginModelFile);\n }\n }\n return result;\n}\n\ntype FindUpResult<Multiple extends boolean> = Multiple extends true ? string[] | undefined : string | undefined;\n\nfunction findUp<Multiple extends boolean = false>(\n names: string[],\n cwd: string = process.cwd(),\n multiple: Multiple = false as Multiple,\n result: string[] = [],\n): FindUpResult<Multiple> {\n if (!names.some((name) => !!name)) {\n return undefined;\n }\n const target = names.find((name) => fs.existsSync(path.join(cwd, name)));\n if (multiple === false && target) {\n return path.join(cwd, target) as FindUpResult<Multiple>;\n }\n if (target) {\n result.push(path.join(cwd, target));\n }\n const up = path.resolve(cwd, '..');\n if (up === cwd) {\n return (multiple && result.length > 0 ? result : undefined) as FindUpResult<Multiple>;\n }\n return findUp(names, up, multiple, result);\n}\n\n/**\n * Returns the root node of the given AST node by following the `$container` references.\n */\nexport function findRootNode(node: AstNode): AstNode {\n while (node.$container) {\n node = node.$container;\n }\n return node;\n}\n"],"mappings":"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"}