zenstack 0.6.0-pre.8 → 1.0.0-alpha.19

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 (133) hide show
  1. package/cli/cli-error.d.ts +5 -0
  2. package/cli/cli-error.js +12 -0
  3. package/cli/cli-error.js.map +1 -0
  4. package/cli/cli-util.d.ts +18 -0
  5. package/cli/cli-util.js +122 -0
  6. package/cli/cli-util.js.map +1 -0
  7. package/cli/index.d.ts +14 -0
  8. package/cli/index.js +72 -6529
  9. package/cli/index.js.map +1 -0
  10. package/cli/plugin-runner.d.ts +14 -0
  11. package/cli/plugin-runner.js +133 -0
  12. package/cli/plugin-runner.js.map +1 -0
  13. package/global.d.js +1 -0
  14. package/global.d.js.map +1 -0
  15. package/language-server/constants.d.ts +12 -0
  16. package/language-server/constants.js +24 -0
  17. package/language-server/constants.js.map +1 -0
  18. package/language-server/main.d.ts +1 -0
  19. package/language-server/main.js +20 -6436
  20. package/language-server/main.js.map +1 -0
  21. package/language-server/types.d.ts +10 -0
  22. package/language-server/types.js +1 -0
  23. package/language-server/types.js.map +1 -0
  24. package/language-server/utils.d.ts +10 -0
  25. package/language-server/utils.js +28 -0
  26. package/language-server/utils.js.map +1 -0
  27. package/language-server/validator/attribute-validator.d.ts +9 -0
  28. package/language-server/validator/attribute-validator.js +15 -0
  29. package/language-server/validator/attribute-validator.js.map +1 -0
  30. package/language-server/validator/datamodel-validator.d.ts +16 -0
  31. package/language-server/validator/datamodel-validator.js +365 -0
  32. package/language-server/validator/datamodel-validator.js.map +1 -0
  33. package/language-server/validator/datasource-validator.d.ts +13 -0
  34. package/language-server/validator/datasource-validator.js +85 -0
  35. package/language-server/validator/datasource-validator.js.map +1 -0
  36. package/language-server/validator/enum-validator.d.ts +9 -0
  37. package/language-server/validator/enum-validator.js +18 -0
  38. package/language-server/validator/enum-validator.js.map +1 -0
  39. package/language-server/validator/expression-validator.d.ts +11 -0
  40. package/language-server/validator/expression-validator.js +40 -0
  41. package/language-server/validator/expression-validator.js.map +1 -0
  42. package/language-server/validator/schema-validator.d.ts +10 -0
  43. package/language-server/validator/schema-validator.js +35 -0
  44. package/language-server/validator/schema-validator.js.map +1 -0
  45. package/language-server/validator/utils.d.ts +24 -0
  46. package/language-server/validator/utils.js +116 -0
  47. package/language-server/validator/utils.js.map +1 -0
  48. package/language-server/validator/zmodel-validator.d.ts +21 -0
  49. package/language-server/validator/zmodel-validator.js +72 -0
  50. package/language-server/validator/zmodel-validator.js.map +1 -0
  51. package/language-server/zmodel-linker.d.ts +29 -0
  52. package/language-server/zmodel-linker.js +364 -0
  53. package/language-server/zmodel-linker.js.map +1 -0
  54. package/language-server/zmodel-module.d.ts +41 -0
  55. package/language-server/zmodel-module.js +83 -0
  56. package/language-server/zmodel-module.js.map +1 -0
  57. package/language-server/zmodel-scope.d.ts +10 -0
  58. package/language-server/zmodel-scope.js +34 -0
  59. package/language-server/zmodel-scope.js.map +1 -0
  60. package/language-server/zmodel-workspace-manager.d.ts +8 -0
  61. package/language-server/zmodel-workspace-manager.js +25 -0
  62. package/language-server/zmodel-workspace-manager.js.map +1 -0
  63. package/package.json +23 -18
  64. package/plugins/access-policy/expression-writer.d.ts +38 -0
  65. package/plugins/access-policy/expression-writer.js +323 -0
  66. package/plugins/access-policy/expression-writer.js.map +1 -0
  67. package/plugins/access-policy/index.d.ts +4 -0
  68. package/plugins/access-policy/index.js +15 -0
  69. package/plugins/access-policy/index.js.map +1 -0
  70. package/plugins/access-policy/policy-guard-generator.d.ts +15 -0
  71. package/plugins/access-policy/policy-guard-generator.js +345 -0
  72. package/plugins/access-policy/policy-guard-generator.js.map +1 -0
  73. package/plugins/access-policy/typescript-expression-transformer.d.ts +26 -0
  74. package/plugins/access-policy/typescript-expression-transformer.js +110 -0
  75. package/plugins/access-policy/typescript-expression-transformer.js.map +1 -0
  76. package/plugins/access-policy/utils.d.ts +5 -0
  77. package/plugins/access-policy/utils.js +16 -0
  78. package/plugins/access-policy/utils.js.map +1 -0
  79. package/plugins/access-policy/zod-schema-generator.d.ts +12 -0
  80. package/plugins/access-policy/zod-schema-generator.js +174 -0
  81. package/plugins/access-policy/zod-schema-generator.js.map +1 -0
  82. package/plugins/model-meta/index.d.ts +4 -0
  83. package/plugins/model-meta/index.js +130 -0
  84. package/plugins/model-meta/index.js.map +1 -0
  85. package/plugins/plugin-utils.d.ts +16 -0
  86. package/plugins/plugin-utils.js +58 -0
  87. package/plugins/plugin-utils.js.map +1 -0
  88. package/plugins/prisma/indent-string.d.ts +4 -0
  89. package/plugins/prisma/indent-string.js +16 -0
  90. package/plugins/prisma/indent-string.js.map +1 -0
  91. package/plugins/prisma/index.d.ts +4 -0
  92. package/plugins/prisma/index.js +15 -3740
  93. package/plugins/prisma/index.js.map +1 -0
  94. package/plugins/prisma/prisma-builder.d.ts +130 -0
  95. package/plugins/prisma/prisma-builder.js +271 -0
  96. package/plugins/prisma/prisma-builder.js.map +1 -0
  97. package/plugins/prisma/schema-generator.d.ts +24 -0
  98. package/plugins/prisma/schema-generator.js +212 -0
  99. package/plugins/prisma/schema-generator.js.map +1 -0
  100. package/plugins/prisma/zmodel-code-generator.d.ts +27 -0
  101. package/plugins/prisma/zmodel-code-generator.js +110 -0
  102. package/plugins/prisma/zmodel-code-generator.js.map +1 -0
  103. package/res/prism-zmodel.js +2 -4
  104. package/res/starter.zmodel +47 -0
  105. package/res/stdlib.zmodel +12 -1
  106. package/telemetry.d.ts +21 -0
  107. package/telemetry.js +102 -0
  108. package/telemetry.js.map +1 -0
  109. package/types.d.ts +11 -0
  110. package/types.js +1 -0
  111. package/types.js.map +1 -0
  112. package/utils/ast-utils.d.ts +15 -0
  113. package/utils/ast-utils.js +79 -0
  114. package/utils/ast-utils.js.map +1 -0
  115. package/utils/exec-utils.d.ts +6 -0
  116. package/utils/exec-utils.js +22 -0
  117. package/utils/exec-utils.js.map +1 -0
  118. package/utils/pkg-utils.d.ts +3 -0
  119. package/utils/pkg-utils.js +43 -0
  120. package/utils/pkg-utils.js.map +1 -0
  121. package/utils/version-utils.d.ts +1 -0
  122. package/utils/version-utils.js +15 -0
  123. package/utils/version-utils.js.map +1 -0
  124. package/asset/logo-256-bg.png +0 -0
  125. package/asset/logo-dark-256.png +0 -0
  126. package/asset/logo-light-256.png +0 -0
  127. package/extension.js +0 -39
  128. package/plugins/policy-guard/index.js +0 -4289
  129. package/plugins/react-hooks/index.js +0 -4318
  130. package/plugins/trpc/index.js +0 -5386
  131. package/plugins/zod/index.js +0 -4808
  132. package/res/package.template.json +0 -9
  133. package/res/tsconfig.template.json +0 -17
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","names":["connection","createConnection","ProposedFeatures","all","shared","createZModelServices","NodeFileSystem","startLanguageServer"],"sources":["../../src/language-server/main.ts"],"sourcesContent":["import { startLanguageServer } from 'langium';\nimport { NodeFileSystem } from 'langium/node';\nimport { createConnection, ProposedFeatures } from 'vscode-languageserver/node';\nimport { createZModelServices } from './zmodel-module';\n\n// Create a connection to the client\nconst connection = createConnection(ProposedFeatures.all);\n\n// Inject the shared services and language-specific services\nconst { shared } = createZModelServices({ connection, ...NodeFileSystem });\n\n// Start the language server with the shared services\nstartLanguageServer(shared);\n"],"mappings":";;AAAA;AACA;AACA;AACA;AAEA;AACA,MAAMA,UAAU,GAAG,IAAAC,uBAAgB,EAACC,uBAAgB,CAACC,GAAG,CAAC;;AAEzD;AACA,MAAM;EAAEC;AAAO,CAAC,GAAG,IAAAC,kCAAoB,EAAC;EAAEL,UAAU;EAAE,GAAGM;AAAe,CAAC,CAAC;;AAE1E;AACA,IAAAC,4BAAmB,EAACH,MAAM,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { AstNode, ValidationAcceptor } from 'langium';
2
+ /**
3
+ * AST validator contract
4
+ */
5
+ export interface AstValidator<T extends AstNode> {
6
+ /**
7
+ * Validates an AST node
8
+ */
9
+ validate(node: T, accept: ValidationAcceptor): void;
10
+ }
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../src/language-server/types.ts"],"sourcesContent":["import { AstNode, ValidationAcceptor } from 'langium';\n\n/**\n * AST validator contract\n */\nexport interface AstValidator<T extends AstNode> {\n /**\n * Validates an AST node\n */\n validate(node: T, accept: ValidationAcceptor): void;\n}\n"],"mappings":""}
@@ -0,0 +1,10 @@
1
+ import { AstNode } from 'langium';
2
+ import { Model } from '@zenstackhq/language/ast';
3
+ /**
4
+ * Gets the toplevel Model containing the given node.
5
+ */
6
+ export declare function getContainingModel(node: AstNode | undefined): Model | null;
7
+ /**
8
+ * Returns if the given node is declared in stdlib.
9
+ */
10
+ export declare function isFromStdlib(node: AstNode): boolean | null | undefined;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getContainingModel = getContainingModel;
7
+ exports.isFromStdlib = isFromStdlib;
8
+ var _constants = require("./constants");
9
+ var _ast = require("@zenstackhq/language/ast");
10
+ /**
11
+ * Gets the toplevel Model containing the given node.
12
+ */
13
+ function getContainingModel(node) {
14
+ if (!node) {
15
+ return null;
16
+ }
17
+ return (0, _ast.isModel)(node) ? node : getContainingModel(node.$container);
18
+ }
19
+
20
+ /**
21
+ * Returns if the given node is declared in stdlib.
22
+ */
23
+ function isFromStdlib(node) {
24
+ var _model$$document;
25
+ const model = getContainingModel(node);
26
+ return model && ((_model$$document = model.$document) === null || _model$$document === void 0 ? void 0 : _model$$document.uri.path.endsWith(_constants.STD_LIB_MODULE_NAME));
27
+ }
28
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","names":["getContainingModel","node","isModel","$container","isFromStdlib","model","$document","uri","path","endsWith","STD_LIB_MODULE_NAME"],"sources":["../../src/language-server/utils.ts"],"sourcesContent":["import { AstNode } from 'langium';\nimport { STD_LIB_MODULE_NAME } from './constants';\nimport { isModel, Model } from '@zenstackhq/language/ast';\n\n/**\n * Gets the toplevel Model containing the given node.\n */\nexport function getContainingModel(node: AstNode | undefined): Model | null {\n if (!node) {\n return null;\n }\n return isModel(node) ? node : getContainingModel(node.$container);\n}\n\n/**\n * Returns if the given node is declared in stdlib.\n */\nexport function isFromStdlib(node: AstNode) {\n const model = getContainingModel(node);\n return model && model.$document?.uri.path.endsWith(STD_LIB_MODULE_NAME);\n}\n"],"mappings":";;;;;;;AACA;AACA;AAEA;AACA;AACA;AACO,SAASA,kBAAkB,CAACC,IAAyB,EAAgB;EACxE,IAAI,CAACA,IAAI,EAAE;IACP,OAAO,IAAI;EACf;EACA,OAAO,IAAAC,YAAO,EAACD,IAAI,CAAC,GAAGA,IAAI,GAAGD,kBAAkB,CAACC,IAAI,CAACE,UAAU,CAAC;AACrE;;AAEA;AACA;AACA;AACO,SAASC,YAAY,CAACH,IAAa,EAAE;EAAA;EACxC,MAAMI,KAAK,GAAGL,kBAAkB,CAACC,IAAI,CAAC;EACtC,OAAOI,KAAK,yBAAIA,KAAK,CAACC,SAAS,qDAAf,iBAAiBC,GAAG,CAACC,IAAI,CAACC,QAAQ,CAACC,8BAAmB,CAAC;AAC3E"}
@@ -0,0 +1,9 @@
1
+ import { Attribute } from '@zenstackhq/language/ast';
2
+ import { AstValidator } from '../types';
3
+ import { ValidationAcceptor } from 'langium';
4
+ /**
5
+ * Validates attribute declarations.
6
+ */
7
+ export default class AttributeValidator implements AstValidator<Attribute> {
8
+ validate(attr: Attribute, accept: ValidationAcceptor): void;
9
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ /**
8
+ * Validates attribute declarations.
9
+ */
10
+ class AttributeValidator {
11
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
12
+ validate(attr, accept) {}
13
+ }
14
+ exports.default = AttributeValidator;
15
+ //# sourceMappingURL=attribute-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attribute-validator.js","names":["AttributeValidator","validate","attr","accept"],"sources":["../../../src/language-server/validator/attribute-validator.ts"],"sourcesContent":["import { Attribute } from '@zenstackhq/language/ast';\nimport { AstValidator } from '../types';\nimport { ValidationAcceptor } from 'langium';\n\n/**\n * Validates attribute declarations.\n */\nexport default class AttributeValidator implements AstValidator<Attribute> {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function\n validate(attr: Attribute, accept: ValidationAcceptor): void {}\n}\n"],"mappings":";;;;;;AAIA;AACA;AACA;AACe,MAAMA,kBAAkB,CAAoC;EACvE;EACAC,QAAQ,CAACC,IAAe,EAAEC,MAA0B,EAAQ,CAAC;AACjE;AAAC"}
@@ -0,0 +1,16 @@
1
+ import { DataModel } from '@zenstackhq/language/ast';
2
+ import { AstValidator } from '../types';
3
+ import { ValidationAcceptor } from 'langium';
4
+ /**
5
+ * Validates data model declarations.
6
+ */
7
+ export default class DataModelValidator implements AstValidator<DataModel> {
8
+ validate(dm: DataModel, accept: ValidationAcceptor): void;
9
+ private validateFields;
10
+ private validateField;
11
+ private validateAttributes;
12
+ private validateAttributeApplication;
13
+ private isValidAttributeTarget;
14
+ private parseRelation;
15
+ private validateRelationField;
16
+ }
@@ -0,0 +1,365 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _constants = require("../constants");
8
+ var _ast = require("@zenstackhq/language/ast");
9
+ var _utils = require("./utils");
10
+ var _pluralize = _interopRequireDefault(require("pluralize"));
11
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12
+ /**
13
+ * Validates data model declarations.
14
+ */
15
+ class DataModelValidator {
16
+ validate(dm, accept) {
17
+ (0, _utils.validateDuplicatedDeclarations)(dm.fields, accept);
18
+ this.validateFields(dm, accept);
19
+ this.validateAttributes(dm, accept);
20
+ }
21
+ validateFields(dm, accept) {
22
+ const idFields = dm.fields.filter(f => f.attributes.find(attr => {
23
+ var _attr$decl$ref;
24
+ return ((_attr$decl$ref = attr.decl.ref) === null || _attr$decl$ref === void 0 ? void 0 : _attr$decl$ref.name) === '@id';
25
+ }));
26
+ if (idFields.length === 0) {
27
+ accept('error', 'Model must include a field with @id attribute', {
28
+ node: dm
29
+ });
30
+ } else if (idFields.length > 1) {
31
+ accept('error', 'Model can include at most one field with @id attribute', {
32
+ node: dm
33
+ });
34
+ } else {
35
+ if (idFields[0].type.optional) {
36
+ accept('error', 'Field with @id attribute must not be optional', {
37
+ node: idFields[0]
38
+ });
39
+ }
40
+ if (idFields[0].type.array || !idFields[0].type.type || !_constants.SCALAR_TYPES.includes(idFields[0].type.type)) {
41
+ accept('error', 'Field with @id attribute must be of scalar type', {
42
+ node: idFields[0]
43
+ });
44
+ }
45
+ }
46
+ dm.fields.forEach(field => this.validateField(field, accept));
47
+ }
48
+ validateField(field, accept) {
49
+ var _field$type$reference;
50
+ if (field.type.array && field.type.optional) {
51
+ accept('error', 'Optional lists are not supported. Use either `Type[]` or `Type?`', {
52
+ node: field.type
53
+ });
54
+ }
55
+ field.attributes.forEach(attr => this.validateAttributeApplication(attr, accept));
56
+ if ((0, _ast.isDataModel)((_field$type$reference = field.type.reference) === null || _field$type$reference === void 0 ? void 0 : _field$type$reference.ref)) {
57
+ this.validateRelationField(field, accept);
58
+ }
59
+ }
60
+ validateAttributes(dm, accept) {
61
+ dm.attributes.forEach(attr => {
62
+ this.validateAttributeApplication(attr, accept);
63
+ });
64
+ }
65
+ validateAttributeApplication(attr, accept) {
66
+ const decl = attr.decl.ref;
67
+ if (!decl) {
68
+ return;
69
+ }
70
+ const targetDecl = attr.$container;
71
+ if (decl.name === '@@@targetField' && !(0, _ast.isAttribute)(targetDecl)) {
72
+ accept('error', `attribute "${decl.name}" can only be used on attribute declarations`, {
73
+ node: attr
74
+ });
75
+ return;
76
+ }
77
+ if ((0, _ast.isDataModelField)(targetDecl) && !this.isValidAttributeTarget(decl, targetDecl)) {
78
+ accept('error', `attribute "${decl.name}" cannot be used on this type of field`, {
79
+ node: attr
80
+ });
81
+ }
82
+ const filledParams = new Set();
83
+ for (const arg of attr.args) {
84
+ let paramDecl;
85
+ if (!arg.name) {
86
+ paramDecl = decl.params.find(p => p.default && !filledParams.has(p));
87
+ if (!paramDecl) {
88
+ accept('error', `Unexpected unnamed argument`, {
89
+ node: arg
90
+ });
91
+ return false;
92
+ }
93
+ } else {
94
+ paramDecl = decl.params.find(p => p.name === arg.name);
95
+ if (!paramDecl) {
96
+ accept('error', `Attribute "${decl.name}" doesn't have a parameter named "${arg.name}"`, {
97
+ node: arg
98
+ });
99
+ return false;
100
+ }
101
+ }
102
+ if (!(0, _utils.assignableToAttributeParam)(arg, paramDecl, attr)) {
103
+ accept('error', `Value is not assignable to parameter`, {
104
+ node: arg
105
+ });
106
+ return false;
107
+ }
108
+ if (filledParams.has(paramDecl)) {
109
+ accept('error', `Parameter "${paramDecl.name}" is already provided`, {
110
+ node: arg
111
+ });
112
+ return false;
113
+ }
114
+ filledParams.add(paramDecl);
115
+ arg.$resolvedParam = paramDecl;
116
+ }
117
+ const missingParams = decl.params.filter(p => !p.type.optional && !filledParams.has(p));
118
+ if (missingParams.length > 0) {
119
+ accept('error', `Required ${(0, _pluralize.default)('parameter', missingParams.length)} not provided: ${missingParams.map(p => p.name).join(', ')}`, {
120
+ node: attr
121
+ });
122
+ return false;
123
+ }
124
+ return true;
125
+ }
126
+ isValidAttributeTarget(attrDecl, targetDecl) {
127
+ var _targetDecl$type$refe;
128
+ const targetField = attrDecl.attributes.find(attr => {
129
+ var _attr$decl$ref2;
130
+ return ((_attr$decl$ref2 = attr.decl.ref) === null || _attr$decl$ref2 === void 0 ? void 0 : _attr$decl$ref2.name) === '@@@targetField';
131
+ });
132
+ if (!targetField) {
133
+ // no field type constraint
134
+ return true;
135
+ }
136
+ const fieldTypes = targetField.args[0].value.items.map(item => {
137
+ var _target$ref;
138
+ return (_target$ref = item.target.ref) === null || _target$ref === void 0 ? void 0 : _target$ref.name;
139
+ });
140
+ let allowed = false;
141
+ for (const allowedType of fieldTypes) {
142
+ switch (allowedType) {
143
+ case 'StringField':
144
+ allowed = allowed || targetDecl.type.type === 'String';
145
+ break;
146
+ case 'IntField':
147
+ allowed = allowed || targetDecl.type.type === 'Int';
148
+ break;
149
+ case 'FloatField':
150
+ allowed = allowed || targetDecl.type.type === 'Float';
151
+ break;
152
+ case 'DecimalField':
153
+ allowed = allowed || targetDecl.type.type === 'Decimal';
154
+ break;
155
+ case 'BooleanField':
156
+ allowed = allowed || targetDecl.type.type === 'Boolean';
157
+ break;
158
+ case 'DateTimeField':
159
+ allowed = allowed || targetDecl.type.type === 'DateTime';
160
+ break;
161
+ case 'JsonField':
162
+ allowed = allowed || targetDecl.type.type === 'Json';
163
+ break;
164
+ case 'BytesField':
165
+ allowed = allowed || targetDecl.type.type === 'Bytes';
166
+ break;
167
+ case 'ModelField':
168
+ allowed = allowed || (0, _ast.isDataModel)((_targetDecl$type$refe = targetDecl.type.reference) === null || _targetDecl$type$refe === void 0 ? void 0 : _targetDecl$type$refe.ref);
169
+ break;
170
+ default:
171
+ break;
172
+ }
173
+ if (allowed) {
174
+ break;
175
+ }
176
+ }
177
+ return allowed;
178
+ }
179
+ parseRelation(field, accept) {
180
+ const relAttr = field.attributes.find(attr => {
181
+ var _attr$decl$ref3;
182
+ return ((_attr$decl$ref3 = attr.decl.ref) === null || _attr$decl$ref3 === void 0 ? void 0 : _attr$decl$ref3.name) === '@relation';
183
+ });
184
+ let name;
185
+ let fields;
186
+ let references;
187
+ let valid = true;
188
+ if (!relAttr) {
189
+ return {
190
+ attr: relAttr,
191
+ name,
192
+ fields,
193
+ references,
194
+ valid: true
195
+ };
196
+ }
197
+ for (const arg of relAttr.args) {
198
+ if (!arg.name || arg.name === 'name') {
199
+ if ((0, _ast.isLiteralExpr)(arg.value)) {
200
+ name = arg.value.value;
201
+ }
202
+ } else if (arg.name === 'fields') {
203
+ fields = arg.value.items;
204
+ if (fields.length === 0) {
205
+ if (accept) {
206
+ accept('error', `"fields" value cannot be emtpy`, {
207
+ node: arg
208
+ });
209
+ }
210
+ valid = false;
211
+ }
212
+ } else if (arg.name === 'references') {
213
+ references = arg.value.items;
214
+ if (references.length === 0) {
215
+ if (accept) {
216
+ accept('error', `"references" value cannot be emtpy`, {
217
+ node: arg
218
+ });
219
+ }
220
+ valid = false;
221
+ }
222
+ }
223
+ }
224
+ if (!fields || !references) {
225
+ if (accept) {
226
+ accept('error', `Both "fields" and "references" must be provided`, {
227
+ node: relAttr
228
+ });
229
+ }
230
+ } else {
231
+ // validate "fields" and "references" typing consistency
232
+ if (fields.length !== references.length) {
233
+ if (accept) {
234
+ accept('error', `"references" and "fields" must have the same length`, {
235
+ node: relAttr
236
+ });
237
+ }
238
+ } else {
239
+ for (let i = 0; i < fields.length; i++) {
240
+ var _fields$i$$resolvedTy, _references$i$$resolv, _fields$i$$resolvedTy2, _references$i$$resolv2;
241
+ if (!fields[i].$resolvedType) {
242
+ if (accept) {
243
+ accept('error', `field reference is unresolved`, {
244
+ node: fields[i]
245
+ });
246
+ }
247
+ }
248
+ if (!references[i].$resolvedType) {
249
+ if (accept) {
250
+ accept('error', `field reference is unresolved`, {
251
+ node: references[i]
252
+ });
253
+ }
254
+ }
255
+ if (((_fields$i$$resolvedTy = fields[i].$resolvedType) === null || _fields$i$$resolvedTy === void 0 ? void 0 : _fields$i$$resolvedTy.decl) !== ((_references$i$$resolv = references[i].$resolvedType) === null || _references$i$$resolv === void 0 ? void 0 : _references$i$$resolv.decl) || ((_fields$i$$resolvedTy2 = fields[i].$resolvedType) === null || _fields$i$$resolvedTy2 === void 0 ? void 0 : _fields$i$$resolvedTy2.array) !== ((_references$i$$resolv2 = references[i].$resolvedType) === null || _references$i$$resolv2 === void 0 ? void 0 : _references$i$$resolv2.array)) {
256
+ if (accept) {
257
+ accept('error', `values of "references" and "fields" must have the same type`, {
258
+ node: relAttr
259
+ });
260
+ }
261
+ }
262
+ }
263
+ }
264
+ }
265
+ return {
266
+ attr: relAttr,
267
+ name,
268
+ fields,
269
+ references,
270
+ valid
271
+ };
272
+ }
273
+ validateRelationField(field, accept) {
274
+ var _thisRelation$referen, _thisRelation$fields, _oppositeRelation$ref, _oppositeRelation$fie;
275
+ const thisRelation = this.parseRelation(field, accept);
276
+ if (!thisRelation.valid) {
277
+ return;
278
+ }
279
+
280
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
281
+ const oppositeModel = field.type.reference.ref;
282
+ let oppositeFields = oppositeModel.fields.filter(f => {
283
+ var _f$type$reference;
284
+ return ((_f$type$reference = f.type.reference) === null || _f$type$reference === void 0 ? void 0 : _f$type$reference.ref) === field.$container;
285
+ });
286
+ oppositeFields = oppositeFields.filter(f => {
287
+ const fieldRel = this.parseRelation(f);
288
+ return fieldRel.valid && fieldRel.name === thisRelation.name;
289
+ });
290
+ if (oppositeFields.length === 0) {
291
+ accept('error', `The relation field "${field.name}" on model "${field.$container.name}" is missing an opposite relation field on model "${oppositeModel.name}"`, {
292
+ node: field
293
+ });
294
+ return;
295
+ } else if (oppositeFields.length > 1) {
296
+ oppositeFields.forEach(f => accept('error', `Fields ${oppositeFields.map(f => '"' + f.name + '"').join(', ')} on model "${oppositeModel.name}" refer to the same relation to model "${field.$container.name}"`, {
297
+ node: f
298
+ }));
299
+ return;
300
+ }
301
+ const oppositeField = oppositeFields[0];
302
+ const oppositeRelation = this.parseRelation(oppositeField);
303
+ let relationOwner;
304
+ if (thisRelation !== null && thisRelation !== void 0 && (_thisRelation$referen = thisRelation.references) !== null && _thisRelation$referen !== void 0 && _thisRelation$referen.length && (_thisRelation$fields = thisRelation.fields) !== null && _thisRelation$fields !== void 0 && _thisRelation$fields.length) {
305
+ if (oppositeRelation !== null && oppositeRelation !== void 0 && oppositeRelation.references || oppositeRelation !== null && oppositeRelation !== void 0 && oppositeRelation.fields) {
306
+ accept('error', '"fields" and "references" must be provided only on one side of relation field', {
307
+ node: oppositeField
308
+ });
309
+ return;
310
+ } else {
311
+ relationOwner = oppositeField;
312
+ }
313
+ } else if (oppositeRelation !== null && oppositeRelation !== void 0 && (_oppositeRelation$ref = oppositeRelation.references) !== null && _oppositeRelation$ref !== void 0 && _oppositeRelation$ref.length && (_oppositeRelation$fie = oppositeRelation.fields) !== null && _oppositeRelation$fie !== void 0 && _oppositeRelation$fie.length) {
314
+ if (thisRelation !== null && thisRelation !== void 0 && thisRelation.references || thisRelation !== null && thisRelation !== void 0 && thisRelation.fields) {
315
+ accept('error', '"fields" and "references" must be provided only on one side of relation field', {
316
+ node: field
317
+ });
318
+ return;
319
+ } else {
320
+ relationOwner = field;
321
+ }
322
+ } else {
323
+ [field, oppositeField].forEach(f => accept('error', 'Field for one side of relation must carry @relation attribute with both "fields" and "references" fields', {
324
+ node: f
325
+ }));
326
+ return;
327
+ }
328
+ if (!relationOwner.type.array && !relationOwner.type.optional) {
329
+ accept('error', 'Relation field needs to be list or optional', {
330
+ node: relationOwner
331
+ });
332
+ return;
333
+ }
334
+ if (relationOwner !== field && !relationOwner.type.array) {
335
+ var _thisRelation$fields2;
336
+ // one-to-one relation requires defining side's reference field to be @unique
337
+ // e.g.:
338
+ // model User {
339
+ // id String @id @default(cuid())
340
+ // data UserData?
341
+ // }
342
+ // model UserData {
343
+ // id String @id @default(cuid())
344
+ // user User @relation(fields: [userId], references: [id])
345
+ // userId String
346
+ // }
347
+ //
348
+ // UserData.userId field needs to be @unique
349
+
350
+ (_thisRelation$fields2 = thisRelation.fields) === null || _thisRelation$fields2 === void 0 ? void 0 : _thisRelation$fields2.forEach(ref => {
351
+ const refField = ref.target.ref;
352
+ if (refField && !refField.attributes.find(a => {
353
+ var _a$decl$ref;
354
+ return ((_a$decl$ref = a.decl.ref) === null || _a$decl$ref === void 0 ? void 0 : _a$decl$ref.name) === '@unique';
355
+ })) {
356
+ accept('error', `Field "${refField.name}" is part of a one-to-one relation and must be marked as @unique`, {
357
+ node: refField
358
+ });
359
+ }
360
+ });
361
+ }
362
+ }
363
+ }
364
+ exports.default = DataModelValidator;
365
+ //# sourceMappingURL=datamodel-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"datamodel-validator.js","names":["DataModelValidator","validate","dm","accept","validateDuplicatedDeclarations","fields","validateFields","validateAttributes","idFields","filter","f","attributes","find","attr","decl","ref","name","length","node","type","optional","array","SCALAR_TYPES","includes","forEach","field","validateField","validateAttributeApplication","isDataModel","reference","validateRelationField","targetDecl","$container","isAttribute","isDataModelField","isValidAttributeTarget","filledParams","Set","arg","args","paramDecl","params","p","default","has","assignableToAttributeParam","add","$resolvedParam","missingParams","pluralize","map","join","attrDecl","targetField","fieldTypes","value","items","item","target","allowed","allowedType","parseRelation","relAttr","references","valid","isLiteralExpr","i","$resolvedType","thisRelation","oppositeModel","oppositeFields","fieldRel","oppositeField","oppositeRelation","relationOwner","refField","a"],"sources":["../../../src/language-server/validator/datamodel-validator.ts"],"sourcesContent":["import { SCALAR_TYPES } from '../constants';\nimport {\n ArrayExpr,\n Attribute,\n AttributeParam,\n DataModel,\n DataModelAttribute,\n DataModelField,\n DataModelFieldAttribute,\n isAttribute,\n isDataModel,\n isDataModelField,\n isLiteralExpr,\n ReferenceExpr,\n} from '@zenstackhq/language/ast';\nimport { AstValidator } from '../types';\nimport { ValidationAcceptor } from 'langium';\nimport { assignableToAttributeParam, validateDuplicatedDeclarations } from './utils';\nimport pluralize from 'pluralize';\n\n/**\n * Validates data model declarations.\n */\nexport default class DataModelValidator implements AstValidator<DataModel> {\n validate(dm: DataModel, accept: ValidationAcceptor): void {\n validateDuplicatedDeclarations(dm.fields, accept);\n this.validateFields(dm, accept);\n this.validateAttributes(dm, accept);\n }\n\n private validateFields(dm: DataModel, accept: ValidationAcceptor) {\n const idFields = dm.fields.filter((f) => f.attributes.find((attr) => attr.decl.ref?.name === '@id'));\n if (idFields.length === 0) {\n accept('error', 'Model must include a field with @id attribute', {\n node: dm,\n });\n } else if (idFields.length > 1) {\n accept('error', 'Model can include at most one field with @id attribute', {\n node: dm,\n });\n } else {\n if (idFields[0].type.optional) {\n accept('error', 'Field with @id attribute must not be optional', { node: idFields[0] });\n }\n\n if (idFields[0].type.array || !idFields[0].type.type || !SCALAR_TYPES.includes(idFields[0].type.type)) {\n accept('error', 'Field with @id attribute must be of scalar type', { node: idFields[0] });\n }\n }\n\n dm.fields.forEach((field) => this.validateField(field, accept));\n }\n\n private validateField(field: DataModelField, accept: ValidationAcceptor): void {\n if (field.type.array && field.type.optional) {\n accept('error', 'Optional lists are not supported. Use either `Type[]` or `Type?`', { node: field.type });\n }\n\n field.attributes.forEach((attr) => this.validateAttributeApplication(attr, accept));\n\n if (isDataModel(field.type.reference?.ref)) {\n this.validateRelationField(field, accept);\n }\n }\n\n private validateAttributes(dm: DataModel, accept: ValidationAcceptor) {\n dm.attributes.forEach((attr) => {\n this.validateAttributeApplication(attr, accept);\n });\n }\n\n private validateAttributeApplication(\n attr: DataModelAttribute | DataModelFieldAttribute,\n accept: ValidationAcceptor\n ) {\n const decl = attr.decl.ref;\n if (!decl) {\n return;\n }\n\n const targetDecl = attr.$container;\n if (decl.name === '@@@targetField' && !isAttribute(targetDecl)) {\n accept('error', `attribute \"${decl.name}\" can only be used on attribute declarations`, { node: attr });\n return;\n }\n\n if (isDataModelField(targetDecl) && !this.isValidAttributeTarget(decl, targetDecl)) {\n accept('error', `attribute \"${decl.name}\" cannot be used on this type of field`, { node: attr });\n }\n\n const filledParams = new Set<AttributeParam>();\n\n for (const arg of attr.args) {\n let paramDecl: AttributeParam | undefined;\n if (!arg.name) {\n paramDecl = decl.params.find((p) => p.default && !filledParams.has(p));\n if (!paramDecl) {\n accept('error', `Unexpected unnamed argument`, {\n node: arg,\n });\n return false;\n }\n } else {\n paramDecl = decl.params.find((p) => p.name === arg.name);\n if (!paramDecl) {\n accept('error', `Attribute \"${decl.name}\" doesn't have a parameter named \"${arg.name}\"`, {\n node: arg,\n });\n return false;\n }\n }\n\n if (!assignableToAttributeParam(arg, paramDecl, attr)) {\n accept('error', `Value is not assignable to parameter`, {\n node: arg,\n });\n return false;\n }\n\n if (filledParams.has(paramDecl)) {\n accept('error', `Parameter \"${paramDecl.name}\" is already provided`, { node: arg });\n return false;\n }\n filledParams.add(paramDecl);\n arg.$resolvedParam = paramDecl;\n }\n\n const missingParams = decl.params.filter((p) => !p.type.optional && !filledParams.has(p));\n if (missingParams.length > 0) {\n accept(\n 'error',\n `Required ${pluralize('parameter', missingParams.length)} not provided: ${missingParams\n .map((p) => p.name)\n .join(', ')}`,\n { node: attr }\n );\n return false;\n }\n\n return true;\n }\n\n private isValidAttributeTarget(attrDecl: Attribute, targetDecl: DataModelField) {\n const targetField = attrDecl.attributes.find((attr) => attr.decl.ref?.name === '@@@targetField');\n if (!targetField) {\n // no field type constraint\n return true;\n }\n\n const fieldTypes = (targetField.args[0].value as ArrayExpr).items.map(\n (item) => (item as ReferenceExpr).target.ref?.name\n );\n\n let allowed = false;\n for (const allowedType of fieldTypes) {\n switch (allowedType) {\n case 'StringField':\n allowed = allowed || targetDecl.type.type === 'String';\n break;\n case 'IntField':\n allowed = allowed || targetDecl.type.type === 'Int';\n break;\n case 'FloatField':\n allowed = allowed || targetDecl.type.type === 'Float';\n break;\n case 'DecimalField':\n allowed = allowed || targetDecl.type.type === 'Decimal';\n break;\n case 'BooleanField':\n allowed = allowed || targetDecl.type.type === 'Boolean';\n break;\n case 'DateTimeField':\n allowed = allowed || targetDecl.type.type === 'DateTime';\n break;\n case 'JsonField':\n allowed = allowed || targetDecl.type.type === 'Json';\n break;\n case 'BytesField':\n allowed = allowed || targetDecl.type.type === 'Bytes';\n break;\n case 'ModelField':\n allowed = allowed || isDataModel(targetDecl.type.reference?.ref);\n break;\n default:\n break;\n }\n if (allowed) {\n break;\n }\n }\n\n return allowed;\n }\n\n private parseRelation(field: DataModelField, accept?: ValidationAcceptor) {\n const relAttr = field.attributes.find((attr) => attr.decl.ref?.name === '@relation');\n\n let name: string | undefined;\n let fields: ReferenceExpr[] | undefined;\n let references: ReferenceExpr[] | undefined;\n let valid = true;\n\n if (!relAttr) {\n return { attr: relAttr, name, fields, references, valid: true };\n }\n\n for (const arg of relAttr.args) {\n if (!arg.name || arg.name === 'name') {\n if (isLiteralExpr(arg.value)) {\n name = arg.value.value as string;\n }\n } else if (arg.name === 'fields') {\n fields = (arg.value as ArrayExpr).items as ReferenceExpr[];\n if (fields.length === 0) {\n if (accept) {\n accept('error', `\"fields\" value cannot be emtpy`, {\n node: arg,\n });\n }\n valid = false;\n }\n } else if (arg.name === 'references') {\n references = (arg.value as ArrayExpr).items as ReferenceExpr[];\n if (references.length === 0) {\n if (accept) {\n accept('error', `\"references\" value cannot be emtpy`, {\n node: arg,\n });\n }\n valid = false;\n }\n }\n }\n\n if (!fields || !references) {\n if (accept) {\n accept('error', `Both \"fields\" and \"references\" must be provided`, { node: relAttr });\n }\n } else {\n // validate \"fields\" and \"references\" typing consistency\n if (fields.length !== references.length) {\n if (accept) {\n accept('error', `\"references\" and \"fields\" must have the same length`, { node: relAttr });\n }\n } else {\n for (let i = 0; i < fields.length; i++) {\n if (!fields[i].$resolvedType) {\n if (accept) {\n accept('error', `field reference is unresolved`, { node: fields[i] });\n }\n }\n if (!references[i].$resolvedType) {\n if (accept) {\n accept('error', `field reference is unresolved`, { node: references[i] });\n }\n }\n\n if (\n fields[i].$resolvedType?.decl !== references[i].$resolvedType?.decl ||\n fields[i].$resolvedType?.array !== references[i].$resolvedType?.array\n ) {\n if (accept) {\n accept('error', `values of \"references\" and \"fields\" must have the same type`, {\n node: relAttr,\n });\n }\n }\n }\n }\n }\n\n return { attr: relAttr, name, fields, references, valid };\n }\n\n private validateRelationField(field: DataModelField, accept: ValidationAcceptor) {\n const thisRelation = this.parseRelation(field, accept);\n if (!thisRelation.valid) {\n return;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const oppositeModel = field.type.reference!.ref! as DataModel;\n\n let oppositeFields = oppositeModel.fields.filter((f) => f.type.reference?.ref === field.$container);\n oppositeFields = oppositeFields.filter((f) => {\n const fieldRel = this.parseRelation(f);\n return fieldRel.valid && fieldRel.name === thisRelation.name;\n });\n\n if (oppositeFields.length === 0) {\n accept(\n 'error',\n `The relation field \"${field.name}\" on model \"${field.$container.name}\" is missing an opposite relation field on model \"${oppositeModel.name}\"`,\n { node: field }\n );\n return;\n } else if (oppositeFields.length > 1) {\n oppositeFields.forEach((f) =>\n accept(\n 'error',\n `Fields ${oppositeFields.map((f) => '\"' + f.name + '\"').join(', ')} on model \"${\n oppositeModel.name\n }\" refer to the same relation to model \"${field.$container.name}\"`,\n { node: f }\n )\n );\n return;\n }\n\n const oppositeField = oppositeFields[0];\n const oppositeRelation = this.parseRelation(oppositeField);\n\n let relationOwner: DataModelField;\n\n if (thisRelation?.references?.length && thisRelation.fields?.length) {\n if (oppositeRelation?.references || oppositeRelation?.fields) {\n accept('error', '\"fields\" and \"references\" must be provided only on one side of relation field', {\n node: oppositeField,\n });\n return;\n } else {\n relationOwner = oppositeField;\n }\n } else if (oppositeRelation?.references?.length && oppositeRelation.fields?.length) {\n if (thisRelation?.references || thisRelation?.fields) {\n accept('error', '\"fields\" and \"references\" must be provided only on one side of relation field', {\n node: field,\n });\n return;\n } else {\n relationOwner = field;\n }\n } else {\n [field, oppositeField].forEach((f) =>\n accept(\n 'error',\n 'Field for one side of relation must carry @relation attribute with both \"fields\" and \"references\" fields',\n { node: f }\n )\n );\n return;\n }\n\n if (!relationOwner.type.array && !relationOwner.type.optional) {\n accept('error', 'Relation field needs to be list or optional', {\n node: relationOwner,\n });\n return;\n }\n\n if (relationOwner !== field && !relationOwner.type.array) {\n // one-to-one relation requires defining side's reference field to be @unique\n // e.g.:\n // model User {\n // id String @id @default(cuid())\n // data UserData?\n // }\n // model UserData {\n // id String @id @default(cuid())\n // user User @relation(fields: [userId], references: [id])\n // userId String\n // }\n //\n // UserData.userId field needs to be @unique\n\n thisRelation.fields?.forEach((ref) => {\n const refField = ref.target.ref as DataModelField;\n if (refField && !refField.attributes.find((a) => a.decl.ref?.name === '@unique')) {\n accept(\n 'error',\n `Field \"${refField.name}\" is part of a one-to-one relation and must be marked as @unique`,\n { node: refField }\n );\n }\n });\n }\n }\n}\n"],"mappings":";;;;;;AAAA;AACA;AAgBA;AACA;AAAkC;AAElC;AACA;AACA;AACe,MAAMA,kBAAkB,CAAoC;EACvEC,QAAQ,CAACC,EAAa,EAAEC,MAA0B,EAAQ;IACtD,IAAAC,qCAA8B,EAACF,EAAE,CAACG,MAAM,EAAEF,MAAM,CAAC;IACjD,IAAI,CAACG,cAAc,CAACJ,EAAE,EAAEC,MAAM,CAAC;IAC/B,IAAI,CAACI,kBAAkB,CAACL,EAAE,EAAEC,MAAM,CAAC;EACvC;EAEQG,cAAc,CAACJ,EAAa,EAAEC,MAA0B,EAAE;IAC9D,MAAMK,QAAQ,GAAGN,EAAE,CAACG,MAAM,CAACI,MAAM,CAAEC,CAAC,IAAKA,CAAC,CAACC,UAAU,CAACC,IAAI,CAAEC,IAAI;MAAA;MAAA,OAAK,mBAAAA,IAAI,CAACC,IAAI,CAACC,GAAG,mDAAb,eAAeC,IAAI,MAAK,KAAK;IAAA,EAAC,CAAC;IACpG,IAAIR,QAAQ,CAACS,MAAM,KAAK,CAAC,EAAE;MACvBd,MAAM,CAAC,OAAO,EAAE,+CAA+C,EAAE;QAC7De,IAAI,EAAEhB;MACV,CAAC,CAAC;IACN,CAAC,MAAM,IAAIM,QAAQ,CAACS,MAAM,GAAG,CAAC,EAAE;MAC5Bd,MAAM,CAAC,OAAO,EAAE,wDAAwD,EAAE;QACtEe,IAAI,EAAEhB;MACV,CAAC,CAAC;IACN,CAAC,MAAM;MACH,IAAIM,QAAQ,CAAC,CAAC,CAAC,CAACW,IAAI,CAACC,QAAQ,EAAE;QAC3BjB,MAAM,CAAC,OAAO,EAAE,+CAA+C,EAAE;UAAEe,IAAI,EAAEV,QAAQ,CAAC,CAAC;QAAE,CAAC,CAAC;MAC3F;MAEA,IAAIA,QAAQ,CAAC,CAAC,CAAC,CAACW,IAAI,CAACE,KAAK,IAAI,CAACb,QAAQ,CAAC,CAAC,CAAC,CAACW,IAAI,CAACA,IAAI,IAAI,CAACG,uBAAY,CAACC,QAAQ,CAACf,QAAQ,CAAC,CAAC,CAAC,CAACW,IAAI,CAACA,IAAI,CAAC,EAAE;QACnGhB,MAAM,CAAC,OAAO,EAAE,iDAAiD,EAAE;UAAEe,IAAI,EAAEV,QAAQ,CAAC,CAAC;QAAE,CAAC,CAAC;MAC7F;IACJ;IAEAN,EAAE,CAACG,MAAM,CAACmB,OAAO,CAAEC,KAAK,IAAK,IAAI,CAACC,aAAa,CAACD,KAAK,EAAEtB,MAAM,CAAC,CAAC;EACnE;EAEQuB,aAAa,CAACD,KAAqB,EAAEtB,MAA0B,EAAQ;IAAA;IAC3E,IAAIsB,KAAK,CAACN,IAAI,CAACE,KAAK,IAAII,KAAK,CAACN,IAAI,CAACC,QAAQ,EAAE;MACzCjB,MAAM,CAAC,OAAO,EAAE,kEAAkE,EAAE;QAAEe,IAAI,EAAEO,KAAK,CAACN;MAAK,CAAC,CAAC;IAC7G;IAEAM,KAAK,CAACd,UAAU,CAACa,OAAO,CAAEX,IAAI,IAAK,IAAI,CAACc,4BAA4B,CAACd,IAAI,EAAEV,MAAM,CAAC,CAAC;IAEnF,IAAI,IAAAyB,gBAAW,2BAACH,KAAK,CAACN,IAAI,CAACU,SAAS,0DAApB,sBAAsBd,GAAG,CAAC,EAAE;MACxC,IAAI,CAACe,qBAAqB,CAACL,KAAK,EAAEtB,MAAM,CAAC;IAC7C;EACJ;EAEQI,kBAAkB,CAACL,EAAa,EAAEC,MAA0B,EAAE;IAClED,EAAE,CAACS,UAAU,CAACa,OAAO,CAAEX,IAAI,IAAK;MAC5B,IAAI,CAACc,4BAA4B,CAACd,IAAI,EAAEV,MAAM,CAAC;IACnD,CAAC,CAAC;EACN;EAEQwB,4BAA4B,CAChCd,IAAkD,EAClDV,MAA0B,EAC5B;IACE,MAAMW,IAAI,GAAGD,IAAI,CAACC,IAAI,CAACC,GAAG;IAC1B,IAAI,CAACD,IAAI,EAAE;MACP;IACJ;IAEA,MAAMiB,UAAU,GAAGlB,IAAI,CAACmB,UAAU;IAClC,IAAIlB,IAAI,CAACE,IAAI,KAAK,gBAAgB,IAAI,CAAC,IAAAiB,gBAAW,EAACF,UAAU,CAAC,EAAE;MAC5D5B,MAAM,CAAC,OAAO,EAAG,cAAaW,IAAI,CAACE,IAAK,8CAA6C,EAAE;QAAEE,IAAI,EAAEL;MAAK,CAAC,CAAC;MACtG;IACJ;IAEA,IAAI,IAAAqB,qBAAgB,EAACH,UAAU,CAAC,IAAI,CAAC,IAAI,CAACI,sBAAsB,CAACrB,IAAI,EAAEiB,UAAU,CAAC,EAAE;MAChF5B,MAAM,CAAC,OAAO,EAAG,cAAaW,IAAI,CAACE,IAAK,wCAAuC,EAAE;QAAEE,IAAI,EAAEL;MAAK,CAAC,CAAC;IACpG;IAEA,MAAMuB,YAAY,GAAG,IAAIC,GAAG,EAAkB;IAE9C,KAAK,MAAMC,GAAG,IAAIzB,IAAI,CAAC0B,IAAI,EAAE;MACzB,IAAIC,SAAqC;MACzC,IAAI,CAACF,GAAG,CAACtB,IAAI,EAAE;QACXwB,SAAS,GAAG1B,IAAI,CAAC2B,MAAM,CAAC7B,IAAI,CAAE8B,CAAC,IAAKA,CAAC,CAACC,OAAO,IAAI,CAACP,YAAY,CAACQ,GAAG,CAACF,CAAC,CAAC,CAAC;QACtE,IAAI,CAACF,SAAS,EAAE;UACZrC,MAAM,CAAC,OAAO,EAAG,6BAA4B,EAAE;YAC3Ce,IAAI,EAAEoB;UACV,CAAC,CAAC;UACF,OAAO,KAAK;QAChB;MACJ,CAAC,MAAM;QACHE,SAAS,GAAG1B,IAAI,CAAC2B,MAAM,CAAC7B,IAAI,CAAE8B,CAAC,IAAKA,CAAC,CAAC1B,IAAI,KAAKsB,GAAG,CAACtB,IAAI,CAAC;QACxD,IAAI,CAACwB,SAAS,EAAE;UACZrC,MAAM,CAAC,OAAO,EAAG,cAAaW,IAAI,CAACE,IAAK,qCAAoCsB,GAAG,CAACtB,IAAK,GAAE,EAAE;YACrFE,IAAI,EAAEoB;UACV,CAAC,CAAC;UACF,OAAO,KAAK;QAChB;MACJ;MAEA,IAAI,CAAC,IAAAO,iCAA0B,EAACP,GAAG,EAAEE,SAAS,EAAE3B,IAAI,CAAC,EAAE;QACnDV,MAAM,CAAC,OAAO,EAAG,sCAAqC,EAAE;UACpDe,IAAI,EAAEoB;QACV,CAAC,CAAC;QACF,OAAO,KAAK;MAChB;MAEA,IAAIF,YAAY,CAACQ,GAAG,CAACJ,SAAS,CAAC,EAAE;QAC7BrC,MAAM,CAAC,OAAO,EAAG,cAAaqC,SAAS,CAACxB,IAAK,uBAAsB,EAAE;UAAEE,IAAI,EAAEoB;QAAI,CAAC,CAAC;QACnF,OAAO,KAAK;MAChB;MACAF,YAAY,CAACU,GAAG,CAACN,SAAS,CAAC;MAC3BF,GAAG,CAACS,cAAc,GAAGP,SAAS;IAClC;IAEA,MAAMQ,aAAa,GAAGlC,IAAI,CAAC2B,MAAM,CAAChC,MAAM,CAAEiC,CAAC,IAAK,CAACA,CAAC,CAACvB,IAAI,CAACC,QAAQ,IAAI,CAACgB,YAAY,CAACQ,GAAG,CAACF,CAAC,CAAC,CAAC;IACzF,IAAIM,aAAa,CAAC/B,MAAM,GAAG,CAAC,EAAE;MAC1Bd,MAAM,CACF,OAAO,EACN,YAAW,IAAA8C,kBAAS,EAAC,WAAW,EAAED,aAAa,CAAC/B,MAAM,CAAE,kBAAiB+B,aAAa,CAClFE,GAAG,CAAER,CAAC,IAAKA,CAAC,CAAC1B,IAAI,CAAC,CAClBmC,IAAI,CAAC,IAAI,CAAE,EAAC,EACjB;QAAEjC,IAAI,EAAEL;MAAK,CAAC,CACjB;MACD,OAAO,KAAK;IAChB;IAEA,OAAO,IAAI;EACf;EAEQsB,sBAAsB,CAACiB,QAAmB,EAAErB,UAA0B,EAAE;IAAA;IAC5E,MAAMsB,WAAW,GAAGD,QAAQ,CAACzC,UAAU,CAACC,IAAI,CAAEC,IAAI;MAAA;MAAA,OAAK,oBAAAA,IAAI,CAACC,IAAI,CAACC,GAAG,oDAAb,gBAAeC,IAAI,MAAK,gBAAgB;IAAA,EAAC;IAChG,IAAI,CAACqC,WAAW,EAAE;MACd;MACA,OAAO,IAAI;IACf;IAEA,MAAMC,UAAU,GAAID,WAAW,CAACd,IAAI,CAAC,CAAC,CAAC,CAACgB,KAAK,CAAeC,KAAK,CAACN,GAAG,CAChEO,IAAI;MAAA;MAAA,sBAAMA,IAAI,CAAmBC,MAAM,CAAC3C,GAAG,gDAAlC,YAAoCC,IAAI;IAAA,EACrD;IAED,IAAI2C,OAAO,GAAG,KAAK;IACnB,KAAK,MAAMC,WAAW,IAAIN,UAAU,EAAE;MAClC,QAAQM,WAAW;QACf,KAAK,aAAa;UACdD,OAAO,GAAGA,OAAO,IAAI5B,UAAU,CAACZ,IAAI,CAACA,IAAI,KAAK,QAAQ;UACtD;QACJ,KAAK,UAAU;UACXwC,OAAO,GAAGA,OAAO,IAAI5B,UAAU,CAACZ,IAAI,CAACA,IAAI,KAAK,KAAK;UACnD;QACJ,KAAK,YAAY;UACbwC,OAAO,GAAGA,OAAO,IAAI5B,UAAU,CAACZ,IAAI,CAACA,IAAI,KAAK,OAAO;UACrD;QACJ,KAAK,cAAc;UACfwC,OAAO,GAAGA,OAAO,IAAI5B,UAAU,CAACZ,IAAI,CAACA,IAAI,KAAK,SAAS;UACvD;QACJ,KAAK,cAAc;UACfwC,OAAO,GAAGA,OAAO,IAAI5B,UAAU,CAACZ,IAAI,CAACA,IAAI,KAAK,SAAS;UACvD;QACJ,KAAK,eAAe;UAChBwC,OAAO,GAAGA,OAAO,IAAI5B,UAAU,CAACZ,IAAI,CAACA,IAAI,KAAK,UAAU;UACxD;QACJ,KAAK,WAAW;UACZwC,OAAO,GAAGA,OAAO,IAAI5B,UAAU,CAACZ,IAAI,CAACA,IAAI,KAAK,MAAM;UACpD;QACJ,KAAK,YAAY;UACbwC,OAAO,GAAGA,OAAO,IAAI5B,UAAU,CAACZ,IAAI,CAACA,IAAI,KAAK,OAAO;UACrD;QACJ,KAAK,YAAY;UACbwC,OAAO,GAAGA,OAAO,IAAI,IAAA/B,gBAAW,2BAACG,UAAU,CAACZ,IAAI,CAACU,SAAS,0DAAzB,sBAA2Bd,GAAG,CAAC;UAChE;QACJ;UACI;MAAM;MAEd,IAAI4C,OAAO,EAAE;QACT;MACJ;IACJ;IAEA,OAAOA,OAAO;EAClB;EAEQE,aAAa,CAACpC,KAAqB,EAAEtB,MAA2B,EAAE;IACtE,MAAM2D,OAAO,GAAGrC,KAAK,CAACd,UAAU,CAACC,IAAI,CAAEC,IAAI;MAAA;MAAA,OAAK,oBAAAA,IAAI,CAACC,IAAI,CAACC,GAAG,oDAAb,gBAAeC,IAAI,MAAK,WAAW;IAAA,EAAC;IAEpF,IAAIA,IAAwB;IAC5B,IAAIX,MAAmC;IACvC,IAAI0D,UAAuC;IAC3C,IAAIC,KAAK,GAAG,IAAI;IAEhB,IAAI,CAACF,OAAO,EAAE;MACV,OAAO;QAAEjD,IAAI,EAAEiD,OAAO;QAAE9C,IAAI;QAAEX,MAAM;QAAE0D,UAAU;QAAEC,KAAK,EAAE;MAAK,CAAC;IACnE;IAEA,KAAK,MAAM1B,GAAG,IAAIwB,OAAO,CAACvB,IAAI,EAAE;MAC5B,IAAI,CAACD,GAAG,CAACtB,IAAI,IAAIsB,GAAG,CAACtB,IAAI,KAAK,MAAM,EAAE;QAClC,IAAI,IAAAiD,kBAAa,EAAC3B,GAAG,CAACiB,KAAK,CAAC,EAAE;UAC1BvC,IAAI,GAAGsB,GAAG,CAACiB,KAAK,CAACA,KAAe;QACpC;MACJ,CAAC,MAAM,IAAIjB,GAAG,CAACtB,IAAI,KAAK,QAAQ,EAAE;QAC9BX,MAAM,GAAIiC,GAAG,CAACiB,KAAK,CAAeC,KAAwB;QAC1D,IAAInD,MAAM,CAACY,MAAM,KAAK,CAAC,EAAE;UACrB,IAAId,MAAM,EAAE;YACRA,MAAM,CAAC,OAAO,EAAG,gCAA+B,EAAE;cAC9Ce,IAAI,EAAEoB;YACV,CAAC,CAAC;UACN;UACA0B,KAAK,GAAG,KAAK;QACjB;MACJ,CAAC,MAAM,IAAI1B,GAAG,CAACtB,IAAI,KAAK,YAAY,EAAE;QAClC+C,UAAU,GAAIzB,GAAG,CAACiB,KAAK,CAAeC,KAAwB;QAC9D,IAAIO,UAAU,CAAC9C,MAAM,KAAK,CAAC,EAAE;UACzB,IAAId,MAAM,EAAE;YACRA,MAAM,CAAC,OAAO,EAAG,oCAAmC,EAAE;cAClDe,IAAI,EAAEoB;YACV,CAAC,CAAC;UACN;UACA0B,KAAK,GAAG,KAAK;QACjB;MACJ;IACJ;IAEA,IAAI,CAAC3D,MAAM,IAAI,CAAC0D,UAAU,EAAE;MACxB,IAAI5D,MAAM,EAAE;QACRA,MAAM,CAAC,OAAO,EAAG,iDAAgD,EAAE;UAAEe,IAAI,EAAE4C;QAAQ,CAAC,CAAC;MACzF;IACJ,CAAC,MAAM;MACH;MACA,IAAIzD,MAAM,CAACY,MAAM,KAAK8C,UAAU,CAAC9C,MAAM,EAAE;QACrC,IAAId,MAAM,EAAE;UACRA,MAAM,CAAC,OAAO,EAAG,qDAAoD,EAAE;YAAEe,IAAI,EAAE4C;UAAQ,CAAC,CAAC;QAC7F;MACJ,CAAC,MAAM;QACH,KAAK,IAAII,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAG7D,MAAM,CAACY,MAAM,EAAEiD,CAAC,EAAE,EAAE;UAAA;UACpC,IAAI,CAAC7D,MAAM,CAAC6D,CAAC,CAAC,CAACC,aAAa,EAAE;YAC1B,IAAIhE,MAAM,EAAE;cACRA,MAAM,CAAC,OAAO,EAAG,+BAA8B,EAAE;gBAAEe,IAAI,EAAEb,MAAM,CAAC6D,CAAC;cAAE,CAAC,CAAC;YACzE;UACJ;UACA,IAAI,CAACH,UAAU,CAACG,CAAC,CAAC,CAACC,aAAa,EAAE;YAC9B,IAAIhE,MAAM,EAAE;cACRA,MAAM,CAAC,OAAO,EAAG,+BAA8B,EAAE;gBAAEe,IAAI,EAAE6C,UAAU,CAACG,CAAC;cAAE,CAAC,CAAC;YAC7E;UACJ;UAEA,IACI,0BAAA7D,MAAM,CAAC6D,CAAC,CAAC,CAACC,aAAa,0DAAvB,sBAAyBrD,IAAI,gCAAKiD,UAAU,CAACG,CAAC,CAAC,CAACC,aAAa,0DAA3B,sBAA6BrD,IAAI,KACnE,2BAAAT,MAAM,CAAC6D,CAAC,CAAC,CAACC,aAAa,2DAAvB,uBAAyB9C,KAAK,iCAAK0C,UAAU,CAACG,CAAC,CAAC,CAACC,aAAa,2DAA3B,uBAA6B9C,KAAK,GACvE;YACE,IAAIlB,MAAM,EAAE;cACRA,MAAM,CAAC,OAAO,EAAG,6DAA4D,EAAE;gBAC3Ee,IAAI,EAAE4C;cACV,CAAC,CAAC;YACN;UACJ;QACJ;MACJ;IACJ;IAEA,OAAO;MAAEjD,IAAI,EAAEiD,OAAO;MAAE9C,IAAI;MAAEX,MAAM;MAAE0D,UAAU;MAAEC;IAAM,CAAC;EAC7D;EAEQlC,qBAAqB,CAACL,KAAqB,EAAEtB,MAA0B,EAAE;IAAA;IAC7E,MAAMiE,YAAY,GAAG,IAAI,CAACP,aAAa,CAACpC,KAAK,EAAEtB,MAAM,CAAC;IACtD,IAAI,CAACiE,YAAY,CAACJ,KAAK,EAAE;MACrB;IACJ;;IAEA;IACA,MAAMK,aAAa,GAAG5C,KAAK,CAACN,IAAI,CAACU,SAAS,CAAEd,GAAiB;IAE7D,IAAIuD,cAAc,GAAGD,aAAa,CAAChE,MAAM,CAACI,MAAM,CAAEC,CAAC;MAAA;MAAA,OAAK,sBAAAA,CAAC,CAACS,IAAI,CAACU,SAAS,sDAAhB,kBAAkBd,GAAG,MAAKU,KAAK,CAACO,UAAU;IAAA,EAAC;IACnGsC,cAAc,GAAGA,cAAc,CAAC7D,MAAM,CAAEC,CAAC,IAAK;MAC1C,MAAM6D,QAAQ,GAAG,IAAI,CAACV,aAAa,CAACnD,CAAC,CAAC;MACtC,OAAO6D,QAAQ,CAACP,KAAK,IAAIO,QAAQ,CAACvD,IAAI,KAAKoD,YAAY,CAACpD,IAAI;IAChE,CAAC,CAAC;IAEF,IAAIsD,cAAc,CAACrD,MAAM,KAAK,CAAC,EAAE;MAC7Bd,MAAM,CACF,OAAO,EACN,uBAAsBsB,KAAK,CAACT,IAAK,eAAcS,KAAK,CAACO,UAAU,CAAChB,IAAK,qDAAoDqD,aAAa,CAACrD,IAAK,GAAE,EAC/I;QAAEE,IAAI,EAAEO;MAAM,CAAC,CAClB;MACD;IACJ,CAAC,MAAM,IAAI6C,cAAc,CAACrD,MAAM,GAAG,CAAC,EAAE;MAClCqD,cAAc,CAAC9C,OAAO,CAAEd,CAAC,IACrBP,MAAM,CACF,OAAO,EACN,UAASmE,cAAc,CAACpB,GAAG,CAAExC,CAAC,IAAK,GAAG,GAAGA,CAAC,CAACM,IAAI,GAAG,GAAG,CAAC,CAACmC,IAAI,CAAC,IAAI,CAAE,cAC/DkB,aAAa,CAACrD,IACjB,0CAAyCS,KAAK,CAACO,UAAU,CAAChB,IAAK,GAAE,EAClE;QAAEE,IAAI,EAAER;MAAE,CAAC,CACd,CACJ;MACD;IACJ;IAEA,MAAM8D,aAAa,GAAGF,cAAc,CAAC,CAAC,CAAC;IACvC,MAAMG,gBAAgB,GAAG,IAAI,CAACZ,aAAa,CAACW,aAAa,CAAC;IAE1D,IAAIE,aAA6B;IAEjC,IAAIN,YAAY,aAAZA,YAAY,wCAAZA,YAAY,CAAEL,UAAU,kDAAxB,sBAA0B9C,MAAM,4BAAImD,YAAY,CAAC/D,MAAM,iDAAnB,qBAAqBY,MAAM,EAAE;MACjE,IAAIwD,gBAAgB,aAAhBA,gBAAgB,eAAhBA,gBAAgB,CAAEV,UAAU,IAAIU,gBAAgB,aAAhBA,gBAAgB,eAAhBA,gBAAgB,CAAEpE,MAAM,EAAE;QAC1DF,MAAM,CAAC,OAAO,EAAE,+EAA+E,EAAE;UAC7Fe,IAAI,EAAEsD;QACV,CAAC,CAAC;QACF;MACJ,CAAC,MAAM;QACHE,aAAa,GAAGF,aAAa;MACjC;IACJ,CAAC,MAAM,IAAIC,gBAAgB,aAAhBA,gBAAgB,wCAAhBA,gBAAgB,CAAEV,UAAU,kDAA5B,sBAA8B9C,MAAM,6BAAIwD,gBAAgB,CAACpE,MAAM,kDAAvB,sBAAyBY,MAAM,EAAE;MAChF,IAAImD,YAAY,aAAZA,YAAY,eAAZA,YAAY,CAAEL,UAAU,IAAIK,YAAY,aAAZA,YAAY,eAAZA,YAAY,CAAE/D,MAAM,EAAE;QAClDF,MAAM,CAAC,OAAO,EAAE,+EAA+E,EAAE;UAC7Fe,IAAI,EAAEO;QACV,CAAC,CAAC;QACF;MACJ,CAAC,MAAM;QACHiD,aAAa,GAAGjD,KAAK;MACzB;IACJ,CAAC,MAAM;MACH,CAACA,KAAK,EAAE+C,aAAa,CAAC,CAAChD,OAAO,CAAEd,CAAC,IAC7BP,MAAM,CACF,OAAO,EACP,0GAA0G,EAC1G;QAAEe,IAAI,EAAER;MAAE,CAAC,CACd,CACJ;MACD;IACJ;IAEA,IAAI,CAACgE,aAAa,CAACvD,IAAI,CAACE,KAAK,IAAI,CAACqD,aAAa,CAACvD,IAAI,CAACC,QAAQ,EAAE;MAC3DjB,MAAM,CAAC,OAAO,EAAE,6CAA6C,EAAE;QAC3De,IAAI,EAAEwD;MACV,CAAC,CAAC;MACF;IACJ;IAEA,IAAIA,aAAa,KAAKjD,KAAK,IAAI,CAACiD,aAAa,CAACvD,IAAI,CAACE,KAAK,EAAE;MAAA;MACtD;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;;MAEA,yBAAA+C,YAAY,CAAC/D,MAAM,0DAAnB,sBAAqBmB,OAAO,CAAET,GAAG,IAAK;QAClC,MAAM4D,QAAQ,GAAG5D,GAAG,CAAC2C,MAAM,CAAC3C,GAAqB;QACjD,IAAI4D,QAAQ,IAAI,CAACA,QAAQ,CAAChE,UAAU,CAACC,IAAI,CAAEgE,CAAC;UAAA;UAAA,OAAK,gBAAAA,CAAC,CAAC9D,IAAI,CAACC,GAAG,gDAAV,YAAYC,IAAI,MAAK,SAAS;QAAA,EAAC,EAAE;UAC9Eb,MAAM,CACF,OAAO,EACN,UAASwE,QAAQ,CAAC3D,IAAK,kEAAiE,EACzF;YAAEE,IAAI,EAAEyD;UAAS,CAAC,CACrB;QACL;MACJ,CAAC,CAAC;IACN;EACJ;AACJ;AAAC"}
@@ -0,0 +1,13 @@
1
+ import { DataSource } from '@zenstackhq/language/ast';
2
+ import { AstValidator } from '../types';
3
+ import { ValidationAcceptor } from 'langium';
4
+ /**
5
+ * Validates data source declarations.
6
+ */
7
+ export default class DataSourceValidator implements AstValidator<DataSource> {
8
+ validate(ds: DataSource, accept: ValidationAcceptor): void;
9
+ private validateFields;
10
+ private validateProvider;
11
+ private validateUrl;
12
+ private validateRelationMode;
13
+ }
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _ast = require("@zenstackhq/language/ast");
8
+ var _utils = require("./utils");
9
+ var _constants = require("../constants");
10
+ const supportedFields = ['provider', 'url', 'shadowDatabaseUrl', 'relationMode'];
11
+
12
+ /**
13
+ * Validates data source declarations.
14
+ */
15
+ class DataSourceValidator {
16
+ validate(ds, accept) {
17
+ (0, _utils.validateDuplicatedDeclarations)(ds.fields, accept);
18
+ this.validateFields(ds, accept);
19
+ this.validateProvider(ds, accept);
20
+ this.validateUrl(ds, accept);
21
+ this.validateRelationMode(ds, accept);
22
+ }
23
+ validateFields(ds, accept) {
24
+ ds.fields.forEach(f => {
25
+ if (!supportedFields.includes(f.name)) {
26
+ accept('error', `Unexpected field "${f.name}"`, {
27
+ node: f
28
+ });
29
+ }
30
+ });
31
+ }
32
+ validateProvider(ds, accept) {
33
+ const provider = ds.fields.find(f => f.name === 'provider');
34
+ if (!provider) {
35
+ accept('error', 'datasource must include a "provider" field', {
36
+ node: ds
37
+ });
38
+ return;
39
+ }
40
+ const value = (0, _utils.getStringLiteral)(provider.value);
41
+ if (!value) {
42
+ accept('error', '"provider" must be set to a string literal', {
43
+ node: provider.value
44
+ });
45
+ } else if (!_constants.SUPPORTED_PROVIDERS.includes(value)) {
46
+ accept('error', `Provider "${value}" is not supported. Choose from ${_constants.SUPPORTED_PROVIDERS.map(p => '"' + p + '"').join(' | ')}.`, {
47
+ node: provider.value
48
+ });
49
+ }
50
+ }
51
+ validateUrl(ds, accept) {
52
+ const url = ds.fields.find(f => f.name === 'url');
53
+ if (!url) {
54
+ accept('error', 'datasource must include a "url" field', {
55
+ node: ds
56
+ });
57
+ }
58
+ for (const fieldName of ['url', 'shadowDatabaseUrl']) {
59
+ var _field$value$function;
60
+ const field = ds.fields.find(f => f.name === fieldName);
61
+ if (!field) {
62
+ continue;
63
+ }
64
+ const value = (0, _utils.getStringLiteral)(field.value);
65
+ if (!value && !((0, _ast.isInvocationExpr)(field.value) && ((_field$value$function = field.value.function.ref) === null || _field$value$function === void 0 ? void 0 : _field$value$function.name) === 'env')) {
66
+ accept('error', `"${fieldName}" must be set to a string literal or an invocation of "env" function`, {
67
+ node: field.value
68
+ });
69
+ }
70
+ }
71
+ }
72
+ validateRelationMode(ds, accept) {
73
+ const field = ds.fields.find(f => f.name === 'relationMode');
74
+ if (field) {
75
+ const val = (0, _utils.getStringLiteral)(field.value);
76
+ if (!val || !['foreignKeys', 'prisma'].includes(val)) {
77
+ accept('error', '"relationMode" must be set to "foreignKeys" or "prisma"', {
78
+ node: field.value
79
+ });
80
+ }
81
+ }
82
+ }
83
+ }
84
+ exports.default = DataSourceValidator;
85
+ //# sourceMappingURL=datasource-validator.js.map