@zenstackhq/language 3.0.0-beta.7 → 3.0.0-beta.9

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/dist/index.cjs CHANGED
@@ -5223,10 +5223,6 @@ function isRelationshipField(field) {
5223
5223
  return isDataModel(field.type.reference?.ref);
5224
5224
  }
5225
5225
  __name(isRelationshipField, "isRelationshipField");
5226
- function isFutureExpr(node) {
5227
- return isInvocationExpr(node) && node.function.ref?.name === "future" && isFromStdlib(node.function.ref);
5228
- }
5229
- __name(isFutureExpr, "isFutureExpr");
5230
5226
  function isDelegateModel(node) {
5231
5227
  return isDataModel(node) && hasAttribute(node, "@@delegate");
5232
5228
  }
@@ -5244,8 +5240,14 @@ function getRecursiveBases(decl, includeDelegate = true, seen = /* @__PURE__ */
5244
5240
  return result;
5245
5241
  }
5246
5242
  seen.add(decl);
5247
- decl.mixins.forEach((mixin) => {
5248
- const baseDecl = decl.$container.declarations.find((d) => isTypeDef(d) && d.name === mixin.$refText);
5243
+ const bases = [
5244
+ ...decl.mixins,
5245
+ ...isDataModel(decl) && decl.baseModel ? [
5246
+ decl.baseModel
5247
+ ] : []
5248
+ ];
5249
+ bases.forEach((base) => {
5250
+ const baseDecl = decl.$container.declarations.find((d) => isTypeDef(d) || isDataModel(d) && d.name === base.$refText);
5249
5251
  if (baseDecl) {
5250
5252
  if (!includeDelegate && isDelegateModel(baseDecl)) {
5251
5253
  return;
@@ -5462,10 +5464,10 @@ function getAuthDecl(decls) {
5462
5464
  return authModel;
5463
5465
  }
5464
5466
  __name(getAuthDecl, "getAuthDecl");
5465
- function isFutureInvocation(node) {
5466
- return isInvocationExpr(node) && node.function.ref?.name === "future" && isFromStdlib(node.function.ref);
5467
+ function isBeforeInvocation(node) {
5468
+ return isInvocationExpr(node) && node.function.ref?.name === "before" && isFromStdlib(node.function.ref);
5467
5469
  }
5468
- __name(isFutureInvocation, "isFutureInvocation");
5470
+ __name(isBeforeInvocation, "isBeforeInvocation");
5469
5471
  function isCollectionPredicate(node) {
5470
5472
  return isBinaryExpr(node) && [
5471
5473
  "?",
@@ -5697,12 +5699,21 @@ var AttributeApplicationValidator = class {
5697
5699
  "create",
5698
5700
  "read",
5699
5701
  "update",
5702
+ "post-update",
5700
5703
  "delete",
5701
5704
  "all"
5702
5705
  ], attr, accept);
5703
5706
  if ((kind === "create" || kind === "all") && attr.args[1]?.value) {
5704
5707
  this.rejectNonOwnedRelationInExpression(attr.args[1].value, accept);
5705
5708
  }
5709
+ if (kind !== "post-update" && attr.args[1]?.value) {
5710
+ const beforeCall = import_langium3.AstUtils.streamAst(attr.args[1]?.value).find(isBeforeInvocation);
5711
+ if (beforeCall) {
5712
+ accept("error", `"before()" is only allowed in "post-update" policy rules`, {
5713
+ node: beforeCall
5714
+ });
5715
+ }
5716
+ }
5706
5717
  }
5707
5718
  rejectNonOwnedRelationInExpression(expr, accept) {
5708
5719
  const contextModel = import_langium3.AstUtils.getContainerOfType(expr, isDataModel);
@@ -5757,8 +5768,8 @@ var AttributeApplicationValidator = class {
5757
5768
  "all"
5758
5769
  ], attr, accept);
5759
5770
  const expr = attr.args[1]?.value;
5760
- if (expr && import_langium3.AstUtils.streamAst(expr).some((node) => isFutureExpr(node))) {
5761
- accept("error", `"future()" is not allowed in field-level policy rules`, {
5771
+ if (expr && import_langium3.AstUtils.streamAst(expr).some((node) => isBeforeInvocation(node))) {
5772
+ accept("error", `"before()" is not allowed in field-level policy rules`, {
5762
5773
  node: expr
5763
5774
  });
5764
5775
  }
@@ -5879,6 +5890,10 @@ function assignableToAttributeParam(arg, param, attr) {
5879
5890
  let dstIsArray = param.type.array;
5880
5891
  if (dstType === "ContextType") {
5881
5892
  if (isDataField(attr.$container)) {
5893
+ const dstIsTypedJson = hasAttribute(attr.$container, "@json");
5894
+ if (dstIsTypedJson && attr.decl.ref?.name === "@default") {
5895
+ return argResolvedType.decl === "String";
5896
+ }
5882
5897
  dstIsArray = attr.$container.type.array;
5883
5898
  }
5884
5899
  }
@@ -5970,6 +5985,9 @@ function isValidAttributeTarget(attrDecl, targetDecl) {
5970
5985
  case "TypeDefField":
5971
5986
  allowed = allowed || isTypeDef(targetDecl.type.reference?.ref);
5972
5987
  break;
5988
+ case "ListField":
5989
+ allowed = allowed || !isDataModel(targetDecl.type.reference?.ref) && targetDecl.type.array;
5990
+ break;
5973
5991
  default:
5974
5992
  break;
5975
5993
  }
@@ -6519,11 +6537,21 @@ var ExpressionValidator = class {
6519
6537
  }
6520
6538
  }
6521
6539
  switch (expr.$type) {
6540
+ case "MemberAccessExpr":
6541
+ this.validateMemberAccessExpr(expr, accept);
6542
+ break;
6522
6543
  case "BinaryExpr":
6523
6544
  this.validateBinaryExpr(expr, accept);
6524
6545
  break;
6525
6546
  }
6526
6547
  }
6548
+ validateMemberAccessExpr(expr, accept) {
6549
+ if (isBeforeInvocation(expr.operand) && isDataModel(expr.$resolvedType?.decl)) {
6550
+ accept("error", "relation fields cannot be accessed from `before()`", {
6551
+ node: expr
6552
+ });
6553
+ }
6554
+ }
6527
6555
  validateBinaryExpr(expr, accept) {
6528
6556
  switch (expr.operator) {
6529
6557
  case "in": {
@@ -6738,7 +6766,7 @@ var FunctionInvocationValidator = class {
6738
6766
  }
6739
6767
  curr = curr.$container;
6740
6768
  }
6741
- const exprContext = (0, import_ts_pattern.match)(containerAttribute?.decl.$refText).with("@default", () => ExpressionContext.DefaultValue).with(import_ts_pattern.P.union("@@allow", "@@deny", "@allow", "@deny"), () => ExpressionContext.AccessPolicy).with("@@validate", () => ExpressionContext.ValidationRule).with("@@index", () => ExpressionContext.Index).otherwise(() => void 0);
6769
+ const exprContext = this.getExpressionContext(containerAttribute);
6742
6770
  const funcAllowedContext = getFunctionExpressionContext(funcDecl);
6743
6771
  if (exprContext && !funcAllowedContext.includes(exprContext)) {
6744
6772
  accept("error", `function "${funcDecl.name}" is not allowed in the current context: ${exprContext}`, {
@@ -6770,6 +6798,18 @@ var FunctionInvocationValidator = class {
6770
6798
  checker.value.call(this, expr, accept);
6771
6799
  }
6772
6800
  }
6801
+ getExpressionContext(containerAttribute) {
6802
+ if (!containerAttribute) {
6803
+ return void 0;
6804
+ }
6805
+ if (this.isValidationAttribute(containerAttribute)) {
6806
+ return ExpressionContext.ValidationRule;
6807
+ }
6808
+ return (0, import_ts_pattern.match)(containerAttribute?.decl.$refText).with("@default", () => ExpressionContext.DefaultValue).with(import_ts_pattern.P.union("@@allow", "@@deny", "@allow", "@deny"), () => ExpressionContext.AccessPolicy).with("@@index", () => ExpressionContext.Index).otherwise(() => void 0);
6809
+ }
6810
+ isValidationAttribute(attr) {
6811
+ return !!attr.decl.ref?.attributes.some((attr2) => attr2.decl.$refText === "@@@validation");
6812
+ }
6773
6813
  validateArgs(funcDecl, args, accept) {
6774
6814
  let success = true;
6775
6815
  for (let i = 0; i < funcDecl.params.length; i++) {
@@ -6830,6 +6870,43 @@ var FunctionInvocationValidator = class {
6830
6870
  }
6831
6871
  return true;
6832
6872
  }
6873
+ _checkLength(expr, accept) {
6874
+ const msg = "argument must be a string or list field";
6875
+ const fieldArg = expr.args[0].value;
6876
+ if (!isDataFieldReference(fieldArg)) {
6877
+ accept("error", msg, {
6878
+ node: expr.args[0]
6879
+ });
6880
+ return;
6881
+ }
6882
+ if (isDataModel(fieldArg.$resolvedType?.decl)) {
6883
+ accept("error", msg, {
6884
+ node: expr.args[0]
6885
+ });
6886
+ return;
6887
+ }
6888
+ if (!fieldArg.$resolvedType?.array && fieldArg.$resolvedType?.decl !== "String") {
6889
+ accept("error", msg, {
6890
+ node: expr.args[0]
6891
+ });
6892
+ }
6893
+ }
6894
+ _checkRegex(expr, accept) {
6895
+ const regex = expr.args[1]?.value;
6896
+ if (!isStringLiteral(regex)) {
6897
+ accept("error", "second argument must be a string literal", {
6898
+ node: expr.args[1]
6899
+ });
6900
+ return;
6901
+ }
6902
+ try {
6903
+ new RegExp(regex.value);
6904
+ } catch (e) {
6905
+ accept("error", "invalid regular expression: " + e.message, {
6906
+ node: expr.args[1]
6907
+ });
6908
+ }
6909
+ }
6833
6910
  // TODO: move this to policy plugin
6834
6911
  _checkCheck(expr, accept) {
6835
6912
  let valid = true;
@@ -6902,6 +6979,24 @@ var FunctionInvocationValidator = class {
6902
6979
  }
6903
6980
  }
6904
6981
  };
6982
+ _ts_decorate2([
6983
+ func("length"),
6984
+ _ts_metadata2("design:type", Function),
6985
+ _ts_metadata2("design:paramtypes", [
6986
+ typeof InvocationExpr === "undefined" ? Object : InvocationExpr,
6987
+ typeof ValidationAcceptor === "undefined" ? Object : ValidationAcceptor
6988
+ ]),
6989
+ _ts_metadata2("design:returntype", void 0)
6990
+ ], FunctionInvocationValidator.prototype, "_checkLength", null);
6991
+ _ts_decorate2([
6992
+ func("regex"),
6993
+ _ts_metadata2("design:type", Function),
6994
+ _ts_metadata2("design:paramtypes", [
6995
+ typeof InvocationExpr === "undefined" ? Object : InvocationExpr,
6996
+ typeof ValidationAcceptor === "undefined" ? Object : ValidationAcceptor
6997
+ ]),
6998
+ _ts_metadata2("design:returntype", void 0)
6999
+ ], FunctionInvocationValidator.prototype, "_checkRegex", null);
6905
7000
  _ts_decorate2([
6906
7001
  func("check"),
6907
7002
  _ts_metadata2("design:type", Function),
@@ -7046,18 +7141,26 @@ var ZModelDocumentBuilder = class extends import_langium7.DefaultDocumentBuilder
7046
7141
  static {
7047
7142
  __name(this, "ZModelDocumentBuilder");
7048
7143
  }
7049
- buildDocuments(documents, options, cancelToken) {
7050
- return super.buildDocuments(documents, {
7051
- ...options,
7052
- validation: (
7053
- // force overriding validation options
7054
- options.validation === false || options.validation === void 0 ? options.validation : {
7055
- stopAfterLexingErrors: true,
7056
- stopAfterParsingErrors: true,
7057
- stopAfterLinkingErrors: true
7058
- }
7059
- )
7060
- }, cancelToken);
7144
+ constructor(services) {
7145
+ super(services);
7146
+ let validationOptions = this.updateBuildOptions.validation;
7147
+ const stopFlags = {
7148
+ stopAfterLinkingErrors: true,
7149
+ stopAfterLexingErrors: true,
7150
+ stopAfterParsingErrors: true
7151
+ };
7152
+ if (validationOptions === true) {
7153
+ validationOptions = stopFlags;
7154
+ } else if (typeof validationOptions === "object") {
7155
+ validationOptions = {
7156
+ ...validationOptions,
7157
+ ...stopFlags
7158
+ };
7159
+ }
7160
+ this.updateBuildOptions = {
7161
+ ...this.updateBuildOptions,
7162
+ validation: validationOptions
7163
+ };
7061
7164
  }
7062
7165
  };
7063
7166
 
@@ -7084,21 +7187,19 @@ var ZModelLinker = class extends import_langium8.DefaultLinker {
7084
7187
  }
7085
7188
  document.state = import_langium8.DocumentState.Linked;
7086
7189
  }
7087
- linkReference(container, property, document, extraScopes) {
7088
- if (this.resolveFromScopeProviders(container, property, document, extraScopes)) {
7190
+ linkReference(refInfo, document, extraScopes) {
7191
+ const defaultRef = refInfo.reference;
7192
+ if (defaultRef._ref) {
7089
7193
  return;
7090
7194
  }
7091
- const reference = container[property];
7092
- this.doLink({
7093
- reference,
7094
- container,
7095
- property
7096
- }, document);
7195
+ if (this.resolveFromScopeProviders(refInfo.reference, document, extraScopes)) {
7196
+ return;
7197
+ }
7198
+ this.doLink(refInfo, document);
7097
7199
  }
7098
7200
  //#endregion
7099
7201
  //#region Expression type resolving
7100
- resolveFromScopeProviders(node, property, document, providers) {
7101
- const reference = node[property];
7202
+ resolveFromScopeProviders(reference, document, providers) {
7102
7203
  for (const provider of providers) {
7103
7204
  const target = provider(reference.$refText);
7104
7205
  if (target) {
@@ -7227,7 +7328,11 @@ var ZModelLinker = class extends import_langium8.DefaultLinker {
7227
7328
  }
7228
7329
  }
7229
7330
  resolveInvocation(node, document, extraScopes) {
7230
- this.linkReference(node, "function", document, extraScopes);
7331
+ this.linkReference({
7332
+ reference: node.function,
7333
+ container: node,
7334
+ property: "function"
7335
+ }, document, extraScopes);
7231
7336
  node.args.forEach((arg) => this.resolve(arg, document, extraScopes));
7232
7337
  if (node.function.ref) {
7233
7338
  const funcDecl = node.function.ref;
@@ -7240,7 +7345,7 @@ var ZModelLinker = class extends import_langium8.DefaultLinker {
7240
7345
  nullable: true
7241
7346
  };
7242
7347
  }
7243
- } else if (isFutureExpr(node)) {
7348
+ } else if (isBeforeInvocation(node)) {
7244
7349
  node.$resolvedType = {
7245
7350
  decl: getContainingDataModel(node)
7246
7351
  };
@@ -7304,7 +7409,7 @@ var ZModelLinker = class extends import_langium8.DefaultLinker {
7304
7409
  if (isArrayExpr(node.value)) {
7305
7410
  node.value.items.forEach((item) => {
7306
7411
  if (isReferenceExpr(item)) {
7307
- const resolved2 = this.resolveFromScopeProviders(item, "target", document, [
7412
+ const resolved2 = this.resolveFromScopeProviders(item.target, document, [
7308
7413
  scopeProvider
7309
7414
  ]);
7310
7415
  if (resolved2) {
@@ -7318,7 +7423,7 @@ var ZModelLinker = class extends import_langium8.DefaultLinker {
7318
7423
  this.resolveToBuiltinTypeOrDecl(node.value, node.value.items[0].$resolvedType.decl, true);
7319
7424
  }
7320
7425
  } else if (isReferenceExpr(node.value)) {
7321
- const resolved2 = this.resolveFromScopeProviders(node.value, "target", document, [
7426
+ const resolved2 = this.resolveFromScopeProviders(node.value.target, document, [
7322
7427
  scopeProvider
7323
7428
  ]);
7324
7429
  if (resolved2) {
@@ -7370,13 +7475,9 @@ var ZModelLinker = class extends import_langium8.DefaultLinker {
7370
7475
  this.resolveDefault(node, document, scopes);
7371
7476
  }
7372
7477
  resolveDefault(node, document, extraScopes) {
7373
- for (const [property, value] of Object.entries(node)) {
7374
- if (!property.startsWith("$")) {
7375
- if ((0, import_langium8.isReference)(value)) {
7376
- this.linkReference(node, property, document, extraScopes);
7377
- }
7378
- }
7379
- }
7478
+ import_langium8.AstUtils.streamReferences(node).forEach((ref) => {
7479
+ this.linkReference(ref, document, extraScopes);
7480
+ });
7380
7481
  for (const child of import_langium8.AstUtils.streamContents(node)) {
7381
7482
  this.resolve(child, document, extraScopes);
7382
7483
  }
@@ -7446,7 +7547,7 @@ var ZModelScopeComputation = class extends import_langium9.DefaultScopeComputati
7446
7547
  }
7447
7548
  processNode(node, document, scopes) {
7448
7549
  super.processNode(node, document, scopes);
7449
- if (isDataModel(node)) {
7550
+ if (isDataModel(node) || isTypeDef(node)) {
7450
7551
  const bases = getRecursiveBases(node);
7451
7552
  for (const base of bases) {
7452
7553
  for (const field of base.fields) {
@@ -7517,7 +7618,7 @@ var ZModelScopeProvider = class extends import_langium9.DefaultScopeProvider {
7517
7618
  if (isAuthInvocation(operand)) {
7518
7619
  return this.createScopeForAuth(node, globalScope);
7519
7620
  }
7520
- if (isFutureInvocation(operand)) {
7621
+ if (isBeforeInvocation(operand)) {
7521
7622
  return this.createScopeForContainingModel(node, globalScope);
7522
7623
  }
7523
7624
  return import_langium9.EMPTY_SCOPE;
@@ -7749,7 +7850,7 @@ var DocumentLoadError = class extends Error {
7749
7850
  super(message);
7750
7851
  }
7751
7852
  };
7752
- async function loadDocument(fileName, pluginModelFiles = []) {
7853
+ async function loadDocument(fileName, additionalModelFiles = []) {
7753
7854
  const { ZModelLanguage: services } = createZModelServices();
7754
7855
  const extensions = services.LanguageMetaData.fileExtensions;
7755
7856
  if (!extensions.includes(import_node_path2.default.extname(fileName))) {
@@ -7772,7 +7873,7 @@ async function loadDocument(fileName, pluginModelFiles = []) {
7772
7873
  }
7773
7874
  const _dirname = typeof __dirname !== "undefined" ? __dirname : import_node_path2.default.dirname((0, import_node_url2.fileURLToPath)(import_meta2.url));
7774
7875
  const stdLib = await services.shared.workspace.LangiumDocuments.getOrCreateDocument(import_langium12.URI.file(import_node_path2.default.resolve(import_node_path2.default.join(_dirname, "../res", STD_LIB_MODULE_NAME))));
7775
- const pluginDocs = await Promise.all(pluginModelFiles.map((file) => services.shared.workspace.LangiumDocuments.getOrCreateDocument(import_langium12.URI.file(import_node_path2.default.resolve(file)))));
7876
+ const pluginDocs = await Promise.all(additionalModelFiles.map((file) => services.shared.workspace.LangiumDocuments.getOrCreateDocument(import_langium12.URI.file(import_node_path2.default.resolve(file)))));
7776
7877
  const langiumDocuments = services.shared.workspace.LangiumDocuments;
7777
7878
  const document = await langiumDocuments.getOrCreateDocument(import_langium12.URI.file(import_node_path2.default.resolve(fileName)));
7778
7879
  const importedURIs = await loadImports(document, langiumDocuments);
@@ -7786,7 +7887,11 @@ async function loadDocument(fileName, pluginModelFiles = []) {
7786
7887
  document,
7787
7888
  ...importedDocuments
7788
7889
  ], {
7789
- validation: true
7890
+ validation: {
7891
+ stopAfterLexingErrors: true,
7892
+ stopAfterParsingErrors: true,
7893
+ stopAfterLinkingErrors: true
7894
+ }
7790
7895
  });
7791
7896
  const diagnostics = langiumDocuments.all.flatMap((doc) => (doc.diagnostics ?? []).map((diag) => ({
7792
7897
  doc,