@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.d.cts CHANGED
@@ -80,7 +80,7 @@ declare function createZModelServices(): {
80
80
  declare class DocumentLoadError extends Error {
81
81
  constructor(message: string);
82
82
  }
83
- declare function loadDocument(fileName: string, pluginModelFiles?: string[]): Promise<{
83
+ declare function loadDocument(fileName: string, additionalModelFiles?: string[]): Promise<{
84
84
  success: true;
85
85
  model: Model;
86
86
  warnings: string[];
package/dist/index.d.ts CHANGED
@@ -80,7 +80,7 @@ declare function createZModelServices(): {
80
80
  declare class DocumentLoadError extends Error {
81
81
  constructor(message: string);
82
82
  }
83
- declare function loadDocument(fileName: string, pluginModelFiles?: string[]): Promise<{
83
+ declare function loadDocument(fileName: string, additionalModelFiles?: string[]): Promise<{
84
84
  success: true;
85
85
  model: Model;
86
86
  warnings: string[];
package/dist/index.js CHANGED
@@ -5191,10 +5191,6 @@ function isRelationshipField(field) {
5191
5191
  return isDataModel(field.type.reference?.ref);
5192
5192
  }
5193
5193
  __name(isRelationshipField, "isRelationshipField");
5194
- function isFutureExpr(node) {
5195
- return isInvocationExpr(node) && node.function.ref?.name === "future" && isFromStdlib(node.function.ref);
5196
- }
5197
- __name(isFutureExpr, "isFutureExpr");
5198
5194
  function isDelegateModel(node) {
5199
5195
  return isDataModel(node) && hasAttribute(node, "@@delegate");
5200
5196
  }
@@ -5212,8 +5208,14 @@ function getRecursiveBases(decl, includeDelegate = true, seen = /* @__PURE__ */
5212
5208
  return result;
5213
5209
  }
5214
5210
  seen.add(decl);
5215
- decl.mixins.forEach((mixin) => {
5216
- const baseDecl = decl.$container.declarations.find((d) => isTypeDef(d) && d.name === mixin.$refText);
5211
+ const bases = [
5212
+ ...decl.mixins,
5213
+ ...isDataModel(decl) && decl.baseModel ? [
5214
+ decl.baseModel
5215
+ ] : []
5216
+ ];
5217
+ bases.forEach((base) => {
5218
+ const baseDecl = decl.$container.declarations.find((d) => isTypeDef(d) || isDataModel(d) && d.name === base.$refText);
5217
5219
  if (baseDecl) {
5218
5220
  if (!includeDelegate && isDelegateModel(baseDecl)) {
5219
5221
  return;
@@ -5430,10 +5432,10 @@ function getAuthDecl(decls) {
5430
5432
  return authModel;
5431
5433
  }
5432
5434
  __name(getAuthDecl, "getAuthDecl");
5433
- function isFutureInvocation(node) {
5434
- return isInvocationExpr(node) && node.function.ref?.name === "future" && isFromStdlib(node.function.ref);
5435
+ function isBeforeInvocation(node) {
5436
+ return isInvocationExpr(node) && node.function.ref?.name === "before" && isFromStdlib(node.function.ref);
5435
5437
  }
5436
- __name(isFutureInvocation, "isFutureInvocation");
5438
+ __name(isBeforeInvocation, "isBeforeInvocation");
5437
5439
  function isCollectionPredicate(node) {
5438
5440
  return isBinaryExpr(node) && [
5439
5441
  "?",
@@ -5665,12 +5667,21 @@ var AttributeApplicationValidator = class {
5665
5667
  "create",
5666
5668
  "read",
5667
5669
  "update",
5670
+ "post-update",
5668
5671
  "delete",
5669
5672
  "all"
5670
5673
  ], attr, accept);
5671
5674
  if ((kind === "create" || kind === "all") && attr.args[1]?.value) {
5672
5675
  this.rejectNonOwnedRelationInExpression(attr.args[1].value, accept);
5673
5676
  }
5677
+ if (kind !== "post-update" && attr.args[1]?.value) {
5678
+ const beforeCall = AstUtils2.streamAst(attr.args[1]?.value).find(isBeforeInvocation);
5679
+ if (beforeCall) {
5680
+ accept("error", `"before()" is only allowed in "post-update" policy rules`, {
5681
+ node: beforeCall
5682
+ });
5683
+ }
5684
+ }
5674
5685
  }
5675
5686
  rejectNonOwnedRelationInExpression(expr, accept) {
5676
5687
  const contextModel = AstUtils2.getContainerOfType(expr, isDataModel);
@@ -5725,8 +5736,8 @@ var AttributeApplicationValidator = class {
5725
5736
  "all"
5726
5737
  ], attr, accept);
5727
5738
  const expr = attr.args[1]?.value;
5728
- if (expr && AstUtils2.streamAst(expr).some((node) => isFutureExpr(node))) {
5729
- accept("error", `"future()" is not allowed in field-level policy rules`, {
5739
+ if (expr && AstUtils2.streamAst(expr).some((node) => isBeforeInvocation(node))) {
5740
+ accept("error", `"before()" is not allowed in field-level policy rules`, {
5730
5741
  node: expr
5731
5742
  });
5732
5743
  }
@@ -5847,6 +5858,10 @@ function assignableToAttributeParam(arg, param, attr) {
5847
5858
  let dstIsArray = param.type.array;
5848
5859
  if (dstType === "ContextType") {
5849
5860
  if (isDataField(attr.$container)) {
5861
+ const dstIsTypedJson = hasAttribute(attr.$container, "@json");
5862
+ if (dstIsTypedJson && attr.decl.ref?.name === "@default") {
5863
+ return argResolvedType.decl === "String";
5864
+ }
5850
5865
  dstIsArray = attr.$container.type.array;
5851
5866
  }
5852
5867
  }
@@ -5938,6 +5953,9 @@ function isValidAttributeTarget(attrDecl, targetDecl) {
5938
5953
  case "TypeDefField":
5939
5954
  allowed = allowed || isTypeDef(targetDecl.type.reference?.ref);
5940
5955
  break;
5956
+ case "ListField":
5957
+ allowed = allowed || !isDataModel(targetDecl.type.reference?.ref) && targetDecl.type.array;
5958
+ break;
5941
5959
  default:
5942
5960
  break;
5943
5961
  }
@@ -6487,11 +6505,21 @@ var ExpressionValidator = class {
6487
6505
  }
6488
6506
  }
6489
6507
  switch (expr.$type) {
6508
+ case "MemberAccessExpr":
6509
+ this.validateMemberAccessExpr(expr, accept);
6510
+ break;
6490
6511
  case "BinaryExpr":
6491
6512
  this.validateBinaryExpr(expr, accept);
6492
6513
  break;
6493
6514
  }
6494
6515
  }
6516
+ validateMemberAccessExpr(expr, accept) {
6517
+ if (isBeforeInvocation(expr.operand) && isDataModel(expr.$resolvedType?.decl)) {
6518
+ accept("error", "relation fields cannot be accessed from `before()`", {
6519
+ node: expr
6520
+ });
6521
+ }
6522
+ }
6495
6523
  validateBinaryExpr(expr, accept) {
6496
6524
  switch (expr.operator) {
6497
6525
  case "in": {
@@ -6706,7 +6734,7 @@ var FunctionInvocationValidator = class {
6706
6734
  }
6707
6735
  curr = curr.$container;
6708
6736
  }
6709
- const exprContext = match(containerAttribute?.decl.$refText).with("@default", () => ExpressionContext.DefaultValue).with(P.union("@@allow", "@@deny", "@allow", "@deny"), () => ExpressionContext.AccessPolicy).with("@@validate", () => ExpressionContext.ValidationRule).with("@@index", () => ExpressionContext.Index).otherwise(() => void 0);
6737
+ const exprContext = this.getExpressionContext(containerAttribute);
6710
6738
  const funcAllowedContext = getFunctionExpressionContext(funcDecl);
6711
6739
  if (exprContext && !funcAllowedContext.includes(exprContext)) {
6712
6740
  accept("error", `function "${funcDecl.name}" is not allowed in the current context: ${exprContext}`, {
@@ -6738,6 +6766,18 @@ var FunctionInvocationValidator = class {
6738
6766
  checker.value.call(this, expr, accept);
6739
6767
  }
6740
6768
  }
6769
+ getExpressionContext(containerAttribute) {
6770
+ if (!containerAttribute) {
6771
+ return void 0;
6772
+ }
6773
+ if (this.isValidationAttribute(containerAttribute)) {
6774
+ return ExpressionContext.ValidationRule;
6775
+ }
6776
+ return match(containerAttribute?.decl.$refText).with("@default", () => ExpressionContext.DefaultValue).with(P.union("@@allow", "@@deny", "@allow", "@deny"), () => ExpressionContext.AccessPolicy).with("@@index", () => ExpressionContext.Index).otherwise(() => void 0);
6777
+ }
6778
+ isValidationAttribute(attr) {
6779
+ return !!attr.decl.ref?.attributes.some((attr2) => attr2.decl.$refText === "@@@validation");
6780
+ }
6741
6781
  validateArgs(funcDecl, args, accept) {
6742
6782
  let success = true;
6743
6783
  for (let i = 0; i < funcDecl.params.length; i++) {
@@ -6798,6 +6838,43 @@ var FunctionInvocationValidator = class {
6798
6838
  }
6799
6839
  return true;
6800
6840
  }
6841
+ _checkLength(expr, accept) {
6842
+ const msg = "argument must be a string or list field";
6843
+ const fieldArg = expr.args[0].value;
6844
+ if (!isDataFieldReference(fieldArg)) {
6845
+ accept("error", msg, {
6846
+ node: expr.args[0]
6847
+ });
6848
+ return;
6849
+ }
6850
+ if (isDataModel(fieldArg.$resolvedType?.decl)) {
6851
+ accept("error", msg, {
6852
+ node: expr.args[0]
6853
+ });
6854
+ return;
6855
+ }
6856
+ if (!fieldArg.$resolvedType?.array && fieldArg.$resolvedType?.decl !== "String") {
6857
+ accept("error", msg, {
6858
+ node: expr.args[0]
6859
+ });
6860
+ }
6861
+ }
6862
+ _checkRegex(expr, accept) {
6863
+ const regex = expr.args[1]?.value;
6864
+ if (!isStringLiteral(regex)) {
6865
+ accept("error", "second argument must be a string literal", {
6866
+ node: expr.args[1]
6867
+ });
6868
+ return;
6869
+ }
6870
+ try {
6871
+ new RegExp(regex.value);
6872
+ } catch (e) {
6873
+ accept("error", "invalid regular expression: " + e.message, {
6874
+ node: expr.args[1]
6875
+ });
6876
+ }
6877
+ }
6801
6878
  // TODO: move this to policy plugin
6802
6879
  _checkCheck(expr, accept) {
6803
6880
  let valid = true;
@@ -6870,6 +6947,24 @@ var FunctionInvocationValidator = class {
6870
6947
  }
6871
6948
  }
6872
6949
  };
6950
+ _ts_decorate2([
6951
+ func("length"),
6952
+ _ts_metadata2("design:type", Function),
6953
+ _ts_metadata2("design:paramtypes", [
6954
+ typeof InvocationExpr === "undefined" ? Object : InvocationExpr,
6955
+ typeof ValidationAcceptor === "undefined" ? Object : ValidationAcceptor
6956
+ ]),
6957
+ _ts_metadata2("design:returntype", void 0)
6958
+ ], FunctionInvocationValidator.prototype, "_checkLength", null);
6959
+ _ts_decorate2([
6960
+ func("regex"),
6961
+ _ts_metadata2("design:type", Function),
6962
+ _ts_metadata2("design:paramtypes", [
6963
+ typeof InvocationExpr === "undefined" ? Object : InvocationExpr,
6964
+ typeof ValidationAcceptor === "undefined" ? Object : ValidationAcceptor
6965
+ ]),
6966
+ _ts_metadata2("design:returntype", void 0)
6967
+ ], FunctionInvocationValidator.prototype, "_checkRegex", null);
6873
6968
  _ts_decorate2([
6874
6969
  func("check"),
6875
6970
  _ts_metadata2("design:type", Function),
@@ -7014,23 +7109,31 @@ var ZModelDocumentBuilder = class extends DefaultDocumentBuilder {
7014
7109
  static {
7015
7110
  __name(this, "ZModelDocumentBuilder");
7016
7111
  }
7017
- buildDocuments(documents, options, cancelToken) {
7018
- return super.buildDocuments(documents, {
7019
- ...options,
7020
- validation: (
7021
- // force overriding validation options
7022
- options.validation === false || options.validation === void 0 ? options.validation : {
7023
- stopAfterLexingErrors: true,
7024
- stopAfterParsingErrors: true,
7025
- stopAfterLinkingErrors: true
7026
- }
7027
- )
7028
- }, cancelToken);
7112
+ constructor(services) {
7113
+ super(services);
7114
+ let validationOptions = this.updateBuildOptions.validation;
7115
+ const stopFlags = {
7116
+ stopAfterLinkingErrors: true,
7117
+ stopAfterLexingErrors: true,
7118
+ stopAfterParsingErrors: true
7119
+ };
7120
+ if (validationOptions === true) {
7121
+ validationOptions = stopFlags;
7122
+ } else if (typeof validationOptions === "object") {
7123
+ validationOptions = {
7124
+ ...validationOptions,
7125
+ ...stopFlags
7126
+ };
7127
+ }
7128
+ this.updateBuildOptions = {
7129
+ ...this.updateBuildOptions,
7130
+ validation: validationOptions
7131
+ };
7029
7132
  }
7030
7133
  };
7031
7134
 
7032
7135
  // src/zmodel-linker.ts
7033
- import { AstUtils as AstUtils6, Cancellation, DefaultLinker, DocumentState, interruptAndCheck, isReference } from "langium";
7136
+ import { AstUtils as AstUtils6, Cancellation, DefaultLinker, DocumentState, interruptAndCheck } from "langium";
7034
7137
  import { match as match2 } from "ts-pattern";
7035
7138
  var ZModelLinker = class extends DefaultLinker {
7036
7139
  static {
@@ -7052,21 +7155,19 @@ var ZModelLinker = class extends DefaultLinker {
7052
7155
  }
7053
7156
  document.state = DocumentState.Linked;
7054
7157
  }
7055
- linkReference(container, property, document, extraScopes) {
7056
- if (this.resolveFromScopeProviders(container, property, document, extraScopes)) {
7158
+ linkReference(refInfo, document, extraScopes) {
7159
+ const defaultRef = refInfo.reference;
7160
+ if (defaultRef._ref) {
7057
7161
  return;
7058
7162
  }
7059
- const reference = container[property];
7060
- this.doLink({
7061
- reference,
7062
- container,
7063
- property
7064
- }, document);
7163
+ if (this.resolveFromScopeProviders(refInfo.reference, document, extraScopes)) {
7164
+ return;
7165
+ }
7166
+ this.doLink(refInfo, document);
7065
7167
  }
7066
7168
  //#endregion
7067
7169
  //#region Expression type resolving
7068
- resolveFromScopeProviders(node, property, document, providers) {
7069
- const reference = node[property];
7170
+ resolveFromScopeProviders(reference, document, providers) {
7070
7171
  for (const provider of providers) {
7071
7172
  const target = provider(reference.$refText);
7072
7173
  if (target) {
@@ -7195,7 +7296,11 @@ var ZModelLinker = class extends DefaultLinker {
7195
7296
  }
7196
7297
  }
7197
7298
  resolveInvocation(node, document, extraScopes) {
7198
- this.linkReference(node, "function", document, extraScopes);
7299
+ this.linkReference({
7300
+ reference: node.function,
7301
+ container: node,
7302
+ property: "function"
7303
+ }, document, extraScopes);
7199
7304
  node.args.forEach((arg) => this.resolve(arg, document, extraScopes));
7200
7305
  if (node.function.ref) {
7201
7306
  const funcDecl = node.function.ref;
@@ -7208,7 +7313,7 @@ var ZModelLinker = class extends DefaultLinker {
7208
7313
  nullable: true
7209
7314
  };
7210
7315
  }
7211
- } else if (isFutureExpr(node)) {
7316
+ } else if (isBeforeInvocation(node)) {
7212
7317
  node.$resolvedType = {
7213
7318
  decl: getContainingDataModel(node)
7214
7319
  };
@@ -7272,7 +7377,7 @@ var ZModelLinker = class extends DefaultLinker {
7272
7377
  if (isArrayExpr(node.value)) {
7273
7378
  node.value.items.forEach((item) => {
7274
7379
  if (isReferenceExpr(item)) {
7275
- const resolved2 = this.resolveFromScopeProviders(item, "target", document, [
7380
+ const resolved2 = this.resolveFromScopeProviders(item.target, document, [
7276
7381
  scopeProvider
7277
7382
  ]);
7278
7383
  if (resolved2) {
@@ -7286,7 +7391,7 @@ var ZModelLinker = class extends DefaultLinker {
7286
7391
  this.resolveToBuiltinTypeOrDecl(node.value, node.value.items[0].$resolvedType.decl, true);
7287
7392
  }
7288
7393
  } else if (isReferenceExpr(node.value)) {
7289
- const resolved2 = this.resolveFromScopeProviders(node.value, "target", document, [
7394
+ const resolved2 = this.resolveFromScopeProviders(node.value.target, document, [
7290
7395
  scopeProvider
7291
7396
  ]);
7292
7397
  if (resolved2) {
@@ -7338,13 +7443,9 @@ var ZModelLinker = class extends DefaultLinker {
7338
7443
  this.resolveDefault(node, document, scopes);
7339
7444
  }
7340
7445
  resolveDefault(node, document, extraScopes) {
7341
- for (const [property, value] of Object.entries(node)) {
7342
- if (!property.startsWith("$")) {
7343
- if (isReference(value)) {
7344
- this.linkReference(node, property, document, extraScopes);
7345
- }
7346
- }
7347
- }
7446
+ AstUtils6.streamReferences(node).forEach((ref) => {
7447
+ this.linkReference(ref, document, extraScopes);
7448
+ });
7348
7449
  for (const child of AstUtils6.streamContents(node)) {
7349
7450
  this.resolve(child, document, extraScopes);
7350
7451
  }
@@ -7414,7 +7515,7 @@ var ZModelScopeComputation = class extends DefaultScopeComputation {
7414
7515
  }
7415
7516
  processNode(node, document, scopes) {
7416
7517
  super.processNode(node, document, scopes);
7417
- if (isDataModel(node)) {
7518
+ if (isDataModel(node) || isTypeDef(node)) {
7418
7519
  const bases = getRecursiveBases(node);
7419
7520
  for (const base of bases) {
7420
7521
  for (const field of base.fields) {
@@ -7485,7 +7586,7 @@ var ZModelScopeProvider = class extends DefaultScopeProvider {
7485
7586
  if (isAuthInvocation(operand)) {
7486
7587
  return this.createScopeForAuth(node, globalScope);
7487
7588
  }
7488
- if (isFutureInvocation(operand)) {
7589
+ if (isBeforeInvocation(operand)) {
7489
7590
  return this.createScopeForContainingModel(node, globalScope);
7490
7591
  }
7491
7592
  return EMPTY_SCOPE;
@@ -7715,7 +7816,7 @@ var DocumentLoadError = class extends Error {
7715
7816
  super(message);
7716
7817
  }
7717
7818
  };
7718
- async function loadDocument(fileName, pluginModelFiles = []) {
7819
+ async function loadDocument(fileName, additionalModelFiles = []) {
7719
7820
  const { ZModelLanguage: services } = createZModelServices();
7720
7821
  const extensions = services.LanguageMetaData.fileExtensions;
7721
7822
  if (!extensions.includes(path3.extname(fileName))) {
@@ -7738,7 +7839,7 @@ async function loadDocument(fileName, pluginModelFiles = []) {
7738
7839
  }
7739
7840
  const _dirname = typeof __dirname !== "undefined" ? __dirname : path3.dirname(fileURLToPath2(import.meta.url));
7740
7841
  const stdLib = await services.shared.workspace.LangiumDocuments.getOrCreateDocument(URI3.file(path3.resolve(path3.join(_dirname, "../res", STD_LIB_MODULE_NAME))));
7741
- const pluginDocs = await Promise.all(pluginModelFiles.map((file) => services.shared.workspace.LangiumDocuments.getOrCreateDocument(URI3.file(path3.resolve(file)))));
7842
+ const pluginDocs = await Promise.all(additionalModelFiles.map((file) => services.shared.workspace.LangiumDocuments.getOrCreateDocument(URI3.file(path3.resolve(file)))));
7742
7843
  const langiumDocuments = services.shared.workspace.LangiumDocuments;
7743
7844
  const document = await langiumDocuments.getOrCreateDocument(URI3.file(path3.resolve(fileName)));
7744
7845
  const importedURIs = await loadImports(document, langiumDocuments);
@@ -7752,7 +7853,11 @@ async function loadDocument(fileName, pluginModelFiles = []) {
7752
7853
  document,
7753
7854
  ...importedDocuments
7754
7855
  ], {
7755
- validation: true
7856
+ validation: {
7857
+ stopAfterLexingErrors: true,
7858
+ stopAfterParsingErrors: true,
7859
+ stopAfterLinkingErrors: true
7860
+ }
7756
7861
  });
7757
7862
  const diagnostics = langiumDocuments.all.flatMap((doc) => (doc.diagnostics ?? []).map((diag) => ({
7758
7863
  doc,