@zenstackhq/language 3.0.0-beta.3 → 3.0.0-beta.5

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
@@ -5386,7 +5386,7 @@ function getFunctionExpressionContext(funcDecl) {
5386
5386
  }
5387
5387
  __name(getFunctionExpressionContext, "getFunctionExpressionContext");
5388
5388
  function isCheckInvocation(node) {
5389
- return isInvocationExpr(node) && node.function.ref?.name === "check" && isFromStdlib(node.function.ref);
5389
+ return isInvocationExpr(node) && node.function.ref?.name === "check";
5390
5390
  }
5391
5391
  __name(isCheckInvocation, "isCheckInvocation");
5392
5392
  function resolveTransitiveImports(documents, model) {
@@ -5681,6 +5681,7 @@ var AttributeApplicationValidator = class {
5681
5681
  });
5682
5682
  }
5683
5683
  }
5684
+ // TODO: design a way to let plugin register validation
5684
5685
  _checkModelLevelPolicy(attr, accept) {
5685
5686
  const kind = getStringLiteral(attr.args[0]?.value);
5686
5687
  if (!kind) {
@@ -5696,8 +5697,49 @@ var AttributeApplicationValidator = class {
5696
5697
  "delete",
5697
5698
  "all"
5698
5699
  ], attr, accept);
5699
- this.rejectEncryptedFields(attr, accept);
5700
+ if ((kind === "create" || kind === "all") && attr.args[1]?.value) {
5701
+ this.rejectNonOwnedRelationInExpression(attr.args[1].value, accept);
5702
+ }
5703
+ }
5704
+ rejectNonOwnedRelationInExpression(expr, accept) {
5705
+ const contextModel = import_langium3.AstUtils.getContainerOfType(expr, isDataModel);
5706
+ if (!contextModel) {
5707
+ return;
5708
+ }
5709
+ if (import_langium3.AstUtils.streamAst(expr).some((node) => {
5710
+ if (!isDataFieldReference(node)) {
5711
+ return false;
5712
+ }
5713
+ if (node.target.ref?.$container !== contextModel) {
5714
+ return false;
5715
+ }
5716
+ const field = node.target.ref;
5717
+ if (!isRelationshipField(field)) {
5718
+ return false;
5719
+ }
5720
+ if (isAuthOrAuthMemberAccess(node)) {
5721
+ return false;
5722
+ }
5723
+ const startNode = isCollectionPredicate(node.$container) && node.$container.left === node ? node.$container : node;
5724
+ const collectionPredicate = import_langium3.AstUtils.getContainerOfType(startNode.$container, isCollectionPredicate);
5725
+ if (collectionPredicate && isAuthOrAuthMemberAccess(collectionPredicate.left)) {
5726
+ return false;
5727
+ }
5728
+ const relationAttr = field.attributes.find((attr) => attr.decl.ref?.name === "@relation");
5729
+ if (!relationAttr) {
5730
+ return true;
5731
+ }
5732
+ if (!relationAttr.args.some((arg) => arg.name === "fields")) {
5733
+ return true;
5734
+ }
5735
+ return false;
5736
+ })) {
5737
+ accept("error", `non-owned relation fields are not allowed in "create" rules`, {
5738
+ node: expr
5739
+ });
5740
+ }
5700
5741
  }
5742
+ // TODO: design a way to let plugin register validation
5701
5743
  _checkFieldLevelPolicy(attr, accept) {
5702
5744
  const kind = getStringLiteral(attr.args[0]?.value);
5703
5745
  if (!kind) {
@@ -5725,7 +5767,6 @@ var AttributeApplicationValidator = class {
5725
5767
  });
5726
5768
  }
5727
5769
  }
5728
- this.rejectEncryptedFields(attr, accept);
5729
5770
  }
5730
5771
  _checkValidate(attr, accept) {
5731
5772
  const condition = attr.args[0]?.value;
@@ -5775,15 +5816,6 @@ var AttributeApplicationValidator = class {
5775
5816
  });
5776
5817
  }
5777
5818
  }
5778
- rejectEncryptedFields(attr, accept) {
5779
- import_langium3.AstUtils.streamAllContents(attr).forEach((node) => {
5780
- if (isDataFieldReference(node) && hasAttribute(node.target.ref, "@encrypted")) {
5781
- accept("error", `Encrypted fields cannot be used in policy rules`, {
5782
- node
5783
- });
5784
- }
5785
- });
5786
- }
5787
5819
  validatePolicyKinds(kind, candidates, attr, accept) {
5788
5820
  const items = kind.split(",").map((x) => x.trim());
5789
5821
  items.forEach((item) => {
@@ -6541,23 +6573,25 @@ var ExpressionValidator = class {
6541
6573
  "Any"
6542
6574
  ];
6543
6575
  }
6544
- if (typeof expr.left.$resolvedType?.decl !== "string" || !supportedShapes.includes(expr.left.$resolvedType.decl)) {
6576
+ const leftResolvedDecl = expr.left.$resolvedType?.decl;
6577
+ const rightResolvedDecl = expr.right.$resolvedType?.decl;
6578
+ if (leftResolvedDecl && (typeof leftResolvedDecl !== "string" || !supportedShapes.includes(leftResolvedDecl))) {
6545
6579
  accept("error", `invalid operand type for "${expr.operator}" operator`, {
6546
6580
  node: expr.left
6547
6581
  });
6548
6582
  return;
6549
6583
  }
6550
- if (typeof expr.right.$resolvedType?.decl !== "string" || !supportedShapes.includes(expr.right.$resolvedType.decl)) {
6584
+ if (rightResolvedDecl && (typeof rightResolvedDecl !== "string" || !supportedShapes.includes(rightResolvedDecl))) {
6551
6585
  accept("error", `invalid operand type for "${expr.operator}" operator`, {
6552
6586
  node: expr.right
6553
6587
  });
6554
6588
  return;
6555
6589
  }
6556
- if (expr.left.$resolvedType.decl === "DateTime" && expr.right.$resolvedType.decl !== "DateTime") {
6590
+ if (leftResolvedDecl === "DateTime" && rightResolvedDecl && rightResolvedDecl !== "DateTime") {
6557
6591
  accept("error", "incompatible operand types", {
6558
6592
  node: expr
6559
6593
  });
6560
- } else if (expr.right.$resolvedType.decl === "DateTime" && expr.left.$resolvedType.decl !== "DateTime") {
6594
+ } else if (rightResolvedDecl === "DateTime" && leftResolvedDecl && leftResolvedDecl !== "DateTime") {
6561
6595
  accept("error", "incompatible operand types", {
6562
6596
  node: expr
6563
6597
  });
@@ -6597,11 +6631,11 @@ var ExpressionValidator = class {
6597
6631
  });
6598
6632
  }
6599
6633
  if (isDataFieldReference(expr.left) && (isThisExpr(expr.right) || isDataFieldReference(expr.right))) {
6600
- accept("error", "comparison between model-typed fields are not supported", {
6634
+ accept("error", "comparison between models is not supported", {
6601
6635
  node: expr
6602
6636
  });
6603
6637
  } else if (isDataFieldReference(expr.right) && (isThisExpr(expr.left) || isDataFieldReference(expr.left))) {
6604
- accept("error", "comparison between model-typed fields are not supported", {
6638
+ accept("error", "comparison between models is not supported", {
6605
6639
  node: expr
6606
6640
  });
6607
6641
  }
@@ -6793,6 +6827,7 @@ var FunctionInvocationValidator = class {
6793
6827
  }
6794
6828
  return true;
6795
6829
  }
6830
+ // TODO: move this to policy plugin
6796
6831
  _checkCheck(expr, accept) {
6797
6832
  let valid = true;
6798
6833
  const fieldArg = expr.args[0].value;