zenstack 1.0.16 → 1.1.1
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/README.md +93 -24
- package/bin/post-install.js +1 -1
- package/cli/actions/generate.d.ts +13 -0
- package/cli/actions/generate.js +71 -0
- package/cli/actions/generate.js.map +1 -0
- package/cli/actions/index.d.ts +3 -0
- package/cli/actions/index.js +20 -0
- package/cli/actions/index.js.map +1 -0
- package/cli/actions/info.d.ts +4 -0
- package/cli/actions/info.js +63 -0
- package/cli/actions/info.js.map +1 -0
- package/cli/actions/init.d.ts +12 -0
- package/cli/actions/init.js +83 -0
- package/cli/actions/init.js.map +1 -0
- package/cli/cli-util.d.ts +14 -11
- package/cli/cli-util.js +150 -82
- package/cli/cli-util.js.map +1 -1
- package/cli/config.d.ts +10 -0
- package/cli/config.js +62 -0
- package/cli/config.js.map +1 -0
- package/cli/index.d.ts +4 -12
- package/cli/index.js +36 -29
- package/cli/index.js.map +1 -1
- package/cli/plugin-runner.d.ts +13 -3
- package/cli/plugin-runner.js +165 -59
- package/cli/plugin-runner.js.map +1 -1
- package/constants.js +1 -1
- package/language-server/constants.d.ts +7 -0
- package/language-server/constants.js +8 -1
- package/language-server/constants.js.map +1 -1
- package/language-server/utils.d.ts +1 -14
- package/language-server/utils.js +2 -38
- package/language-server/utils.js.map +1 -1
- package/language-server/validator/attribute-application-validator.d.ts +15 -0
- package/language-server/validator/attribute-application-validator.js +246 -0
- package/language-server/validator/attribute-application-validator.js.map +1 -0
- package/language-server/validator/attribute-validator.d.ts +1 -1
- package/language-server/validator/attribute-validator.js +4 -1
- package/language-server/validator/attribute-validator.js.map +1 -1
- package/language-server/validator/datamodel-validator.d.ts +7 -0
- package/language-server/validator/datamodel-validator.js +84 -33
- package/language-server/validator/datamodel-validator.js.map +1 -1
- package/language-server/validator/enum-validator.js +3 -6
- package/language-server/validator/enum-validator.js.map +1 -1
- package/language-server/validator/expression-validator.d.ts +1 -1
- package/language-server/validator/expression-validator.js +108 -3
- package/language-server/validator/expression-validator.js.map +1 -1
- package/language-server/validator/function-decl-validator.d.ts +9 -0
- package/language-server/validator/function-decl-validator.js +13 -0
- package/language-server/validator/function-decl-validator.js.map +1 -0
- package/language-server/validator/function-invocation-validator.d.ts +11 -0
- package/language-server/validator/function-invocation-validator.js +135 -0
- package/language-server/validator/function-invocation-validator.js.map +1 -0
- package/language-server/validator/schema-validator.d.ts +4 -1
- package/language-server/validator/schema-validator.js +28 -7
- package/language-server/validator/schema-validator.js.map +1 -1
- package/language-server/validator/utils.d.ts +3 -4
- package/language-server/validator/utils.js +20 -123
- package/language-server/validator/utils.js.map +1 -1
- package/language-server/validator/zmodel-validator.d.ts +5 -1
- package/language-server/validator/zmodel-validator.js +18 -4
- package/language-server/validator/zmodel-validator.js.map +1 -1
- package/language-server/zmodel-code-action.d.ts +2 -1
- package/language-server/zmodel-code-action.js +46 -21
- package/language-server/zmodel-code-action.js.map +1 -1
- package/language-server/zmodel-definition.d.ts +7 -0
- package/language-server/zmodel-definition.js +31 -0
- package/language-server/zmodel-definition.js.map +1 -0
- package/language-server/zmodel-formatter.js +2 -2
- package/language-server/zmodel-formatter.js.map +1 -1
- package/language-server/zmodel-linker.d.ts +3 -0
- package/language-server/zmodel-linker.js +122 -41
- package/language-server/zmodel-linker.js.map +1 -1
- package/language-server/zmodel-module.js +4 -1
- package/language-server/zmodel-module.js.map +1 -1
- package/language-server/zmodel-scope.d.ts +7 -1
- package/language-server/zmodel-scope.js +57 -1
- package/language-server/zmodel-scope.js.map +1 -1
- package/language-server/zmodel-workspace-manager.d.ts +5 -1
- package/language-server/zmodel-workspace-manager.js +101 -0
- package/language-server/zmodel-workspace-manager.js.map +1 -1
- package/package.json +27 -20
- package/plugins/access-policy/expression-writer.d.ts +7 -0
- package/plugins/access-policy/expression-writer.js +325 -106
- package/plugins/access-policy/expression-writer.js.map +1 -1
- package/plugins/access-policy/index.d.ts +3 -3
- package/plugins/access-policy/index.js +3 -5
- package/plugins/access-policy/index.js.map +1 -1
- package/plugins/access-policy/policy-guard-generator.d.ts +10 -3
- package/plugins/access-policy/policy-guard-generator.js +406 -121
- package/plugins/access-policy/policy-guard-generator.js.map +1 -1
- package/plugins/model-meta/index.d.ts +3 -3
- package/plugins/model-meta/index.js +110 -46
- package/plugins/model-meta/index.js.map +1 -1
- package/plugins/plugin-utils.d.ts +8 -7
- package/plugins/plugin-utils.js +55 -21
- package/plugins/plugin-utils.js.map +1 -1
- package/plugins/prisma/index.d.ts +3 -3
- package/plugins/prisma/index.js +3 -5
- package/plugins/prisma/index.js.map +1 -1
- package/plugins/prisma/prisma-builder.d.ts +7 -14
- package/plugins/prisma/prisma-builder.js +29 -34
- package/plugins/prisma/prisma-builder.js.map +1 -1
- package/plugins/prisma/schema-generator.d.ts +7 -3
- package/plugins/prisma/schema-generator.js +146 -102
- package/plugins/prisma/schema-generator.js.map +1 -1
- package/plugins/prisma/zmodel-code-generator.d.ts +3 -1
- package/plugins/prisma/zmodel-code-generator.js +12 -2
- package/plugins/prisma/zmodel-code-generator.js.map +1 -1
- package/plugins/zod/generator.d.ts +4 -0
- package/plugins/zod/generator.js +298 -0
- package/plugins/zod/generator.js.map +1 -0
- package/plugins/zod/index.d.ts +4 -0
- package/plugins/zod/index.js +24 -0
- package/plugins/zod/index.js.map +1 -0
- package/plugins/zod/transformer.d.ts +68 -0
- package/plugins/zod/transformer.js +554 -0
- package/plugins/zod/transformer.js.map +1 -0
- package/plugins/zod/types.d.ts +25 -0
- package/plugins/zod/types.js.map +1 -0
- package/plugins/zod/utils/removeDir.d.ts +1 -0
- package/plugins/zod/utils/removeDir.js +30 -0
- package/plugins/zod/utils/removeDir.js.map +1 -0
- package/plugins/zod/utils/schema-gen.d.ts +3 -0
- package/plugins/zod/utils/schema-gen.js +188 -0
- package/plugins/zod/utils/schema-gen.js.map +1 -0
- package/res/starter.zmodel +6 -8
- package/res/stdlib.zmodel +238 -74
- package/telemetry.d.ts +2 -1
- package/telemetry.js +21 -11
- package/telemetry.js.map +1 -1
- package/utils/ast-utils.d.ts +12 -15
- package/utils/ast-utils.js +117 -66
- package/utils/ast-utils.js.map +1 -1
- package/utils/pkg-utils.d.ts +2 -2
- package/utils/pkg-utils.js +34 -16
- package/utils/pkg-utils.js.map +1 -1
- package/utils/typescript-expression-transformer.d.ts +54 -0
- package/utils/typescript-expression-transformer.js +326 -0
- package/utils/typescript-expression-transformer.js.map +1 -0
- package/utils/version-utils.js +7 -1
- package/utils/version-utils.js.map +1 -1
- package/plugins/access-policy/typescript-expression-transformer.d.ts +0 -26
- package/plugins/access-policy/typescript-expression-transformer.js +0 -111
- package/plugins/access-policy/typescript-expression-transformer.js.map +0 -1
- package/plugins/access-policy/utils.d.ts +0 -5
- package/plugins/access-policy/utils.js +0 -14
- package/plugins/access-policy/utils.js.map +0 -1
- package/plugins/access-policy/zod-schema-generator.d.ts +0 -12
- package/plugins/access-policy/zod-schema-generator.js +0 -158
- package/plugins/access-policy/zod-schema-generator.js.map +0 -1
- package/types.d.ts +0 -12
- package/types.js.map +0 -1
- /package/{types.js → plugins/zod/types.js} +0 -0
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const ast_1 = require("@zenstackhq/language/ast");
|
|
4
|
+
const sdk_1 = require("@zenstackhq/sdk");
|
|
4
5
|
const ast_utils_1 = require("../../utils/ast-utils");
|
|
5
6
|
/**
|
|
6
7
|
* Validates expressions.
|
|
7
8
|
*/
|
|
8
9
|
class ExpressionValidator {
|
|
9
10
|
validate(expr, accept) {
|
|
11
|
+
var _a;
|
|
12
|
+
// deal with a few cases where reference resolution fail silently
|
|
10
13
|
if (!expr.$resolvedType) {
|
|
11
14
|
if ((0, ast_utils_1.isAuthInvocation)(expr)) {
|
|
12
15
|
// check was done at link time
|
|
13
16
|
accept('error', 'auth() cannot be resolved because no "User" model is defined', { node: expr });
|
|
14
17
|
}
|
|
15
|
-
else if (
|
|
18
|
+
else if ((0, ast_utils_1.isCollectionPredicate)(expr)) {
|
|
16
19
|
accept('error', 'collection predicate can only be used on an array of model type', { node: expr });
|
|
17
20
|
}
|
|
18
21
|
else {
|
|
@@ -21,9 +24,111 @@ class ExpressionValidator {
|
|
|
21
24
|
});
|
|
22
25
|
}
|
|
23
26
|
}
|
|
27
|
+
if (((_a = expr.$resolvedType) === null || _a === void 0 ? void 0 : _a.decl) === 'Unsupported') {
|
|
28
|
+
accept('error', 'Field of "Unsupported" type cannot be used in expressions', { node: expr });
|
|
29
|
+
}
|
|
30
|
+
// extra validations by expression type
|
|
31
|
+
switch (expr.$type) {
|
|
32
|
+
case 'BinaryExpr':
|
|
33
|
+
this.validateBinaryExpr(expr, accept);
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
24
36
|
}
|
|
25
|
-
|
|
26
|
-
|
|
37
|
+
validateBinaryExpr(expr, accept) {
|
|
38
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
39
|
+
switch (expr.operator) {
|
|
40
|
+
case 'in': {
|
|
41
|
+
if (typeof ((_a = expr.left.$resolvedType) === null || _a === void 0 ? void 0 : _a.decl) !== 'string' && !(0, ast_1.isEnum)((_b = expr.left.$resolvedType) === null || _b === void 0 ? void 0 : _b.decl)) {
|
|
42
|
+
accept('error', 'left operand of "in" must be of scalar type', { node: expr.left });
|
|
43
|
+
}
|
|
44
|
+
if (!((_c = expr.right.$resolvedType) === null || _c === void 0 ? void 0 : _c.array)) {
|
|
45
|
+
accept('error', 'right operand of "in" must be an array', {
|
|
46
|
+
node: expr.right,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
case '>':
|
|
52
|
+
case '>=':
|
|
53
|
+
case '<':
|
|
54
|
+
case '<=':
|
|
55
|
+
case '&&':
|
|
56
|
+
case '||': {
|
|
57
|
+
if ((_d = expr.left.$resolvedType) === null || _d === void 0 ? void 0 : _d.array) {
|
|
58
|
+
accept('error', 'operand cannot be an array', { node: expr.left });
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
if ((_e = expr.right.$resolvedType) === null || _e === void 0 ? void 0 : _e.array) {
|
|
62
|
+
accept('error', 'operand cannot be an array', { node: expr.right });
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
let supportedShapes;
|
|
66
|
+
if (['>', '>=', '<', '<='].includes(expr.operator)) {
|
|
67
|
+
supportedShapes = ['Int', 'Float', 'DateTime', 'Any'];
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
supportedShapes = ['Boolean', 'Any'];
|
|
71
|
+
}
|
|
72
|
+
if (typeof ((_f = expr.left.$resolvedType) === null || _f === void 0 ? void 0 : _f.decl) !== 'string' ||
|
|
73
|
+
!supportedShapes.includes(expr.left.$resolvedType.decl)) {
|
|
74
|
+
accept('error', `invalid operand type for "${expr.operator}" operator`, {
|
|
75
|
+
node: expr.left,
|
|
76
|
+
});
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (typeof ((_g = expr.right.$resolvedType) === null || _g === void 0 ? void 0 : _g.decl) !== 'string' ||
|
|
80
|
+
!supportedShapes.includes(expr.right.$resolvedType.decl)) {
|
|
81
|
+
accept('error', `invalid operand type for "${expr.operator}" operator`, {
|
|
82
|
+
node: expr.right,
|
|
83
|
+
});
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
// DateTime comparison is only allowed between two DateTime values
|
|
87
|
+
if (expr.left.$resolvedType.decl === 'DateTime' && expr.right.$resolvedType.decl !== 'DateTime') {
|
|
88
|
+
accept('error', 'incompatible operand types', { node: expr });
|
|
89
|
+
}
|
|
90
|
+
else if (expr.right.$resolvedType.decl === 'DateTime' &&
|
|
91
|
+
expr.left.$resolvedType.decl !== 'DateTime') {
|
|
92
|
+
accept('error', 'incompatible operand types', { node: expr });
|
|
93
|
+
}
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
case '==':
|
|
97
|
+
case '!=': {
|
|
98
|
+
if (!!((_h = expr.left.$resolvedType) === null || _h === void 0 ? void 0 : _h.array) !== !!((_j = expr.right.$resolvedType) === null || _j === void 0 ? void 0 : _j.array)) {
|
|
99
|
+
accept('error', 'incompatible operand types', { node: expr });
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
// disallow comparing model type with scalar type or comparison between
|
|
103
|
+
// incompatible model types
|
|
104
|
+
const leftType = (_k = expr.left.$resolvedType) === null || _k === void 0 ? void 0 : _k.decl;
|
|
105
|
+
const rightType = (_l = expr.right.$resolvedType) === null || _l === void 0 ? void 0 : _l.decl;
|
|
106
|
+
if ((0, ast_1.isDataModel)(leftType) && (0, ast_1.isDataModel)(rightType)) {
|
|
107
|
+
if (leftType != rightType) {
|
|
108
|
+
// incompatible model types
|
|
109
|
+
// TODO: inheritance case?
|
|
110
|
+
accept('error', 'incompatible operand types', { node: expr });
|
|
111
|
+
}
|
|
112
|
+
// not supported:
|
|
113
|
+
// - foo == bar
|
|
114
|
+
// - foo == this
|
|
115
|
+
if ((0, sdk_1.isDataModelFieldReference)(expr.left) &&
|
|
116
|
+
((0, ast_1.isThisExpr)(expr.right) || (0, sdk_1.isDataModelFieldReference)(expr.right))) {
|
|
117
|
+
accept('error', 'comparison between model-typed fields are not supported', { node: expr });
|
|
118
|
+
}
|
|
119
|
+
else if ((0, sdk_1.isDataModelFieldReference)(expr.right) &&
|
|
120
|
+
((0, ast_1.isThisExpr)(expr.left) || (0, sdk_1.isDataModelFieldReference)(expr.left))) {
|
|
121
|
+
accept('error', 'comparison between model-typed fields are not supported', { node: expr });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
else if (((0, ast_1.isDataModel)(leftType) && !(0, ast_1.isNullExpr)(expr.right)) ||
|
|
125
|
+
((0, ast_1.isDataModel)(rightType) && !(0, ast_1.isNullExpr)(expr.left))) {
|
|
126
|
+
// comparing model against scalar (except null)
|
|
127
|
+
accept('error', 'incompatible operand types', { node: expr });
|
|
128
|
+
}
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
27
132
|
}
|
|
28
133
|
}
|
|
29
134
|
exports.default = ExpressionValidator;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expression-validator.js","sourceRoot":"","sources":["../../../src/language-server/validator/expression-validator.ts"],"names":[],"mappings":";;AAAA,
|
|
1
|
+
{"version":3,"file":"expression-validator.js","sourceRoot":"","sources":["../../../src/language-server/validator/expression-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FunctionDecl } from '@zenstackhq/language/ast';
|
|
2
|
+
import { ValidationAcceptor } from 'langium';
|
|
3
|
+
import { AstValidator } from '../types';
|
|
4
|
+
/**
|
|
5
|
+
* Validates function declarations.
|
|
6
|
+
*/
|
|
7
|
+
export default class FunctionDeclValidator implements AstValidator<FunctionDecl> {
|
|
8
|
+
validate(funcDecl: FunctionDecl, accept: ValidationAcceptor): void;
|
|
9
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const attribute_application_validator_1 = require("./attribute-application-validator");
|
|
4
|
+
/**
|
|
5
|
+
* Validates function declarations.
|
|
6
|
+
*/
|
|
7
|
+
class FunctionDeclValidator {
|
|
8
|
+
validate(funcDecl, accept) {
|
|
9
|
+
funcDecl.attributes.forEach((attr) => (0, attribute_application_validator_1.validateAttributeApplication)(attr, accept));
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.default = FunctionDeclValidator;
|
|
13
|
+
//# sourceMappingURL=function-decl-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"function-decl-validator.js","sourceRoot":"","sources":["../../../src/language-server/validator/function-decl-validator.ts"],"names":[],"mappings":";;AAGA,uFAAiF;AAEjF;;GAEG;AACH,MAAqB,qBAAqB;IACtC,QAAQ,CAAC,QAAsB,EAAE,MAA0B;QACvD,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAA,8DAA4B,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IACtF,CAAC;CACJ;AAJD,wCAIC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Expression, InvocationExpr } from '@zenstackhq/language/ast';
|
|
2
|
+
import { ValidationAcceptor } from 'langium';
|
|
3
|
+
import { AstValidator } from '../types';
|
|
4
|
+
/**
|
|
5
|
+
* InvocationExpr validation
|
|
6
|
+
*/
|
|
7
|
+
export default class FunctionInvocationValidator implements AstValidator<Expression> {
|
|
8
|
+
validate(expr: InvocationExpr, accept: ValidationAcceptor): void;
|
|
9
|
+
private validateArgs;
|
|
10
|
+
private validateInvocationArg;
|
|
11
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const ast_1 = require("@zenstackhq/language/ast");
|
|
4
|
+
const sdk_1 = require("@zenstackhq/sdk");
|
|
5
|
+
const ts_pattern_1 = require("ts-pattern");
|
|
6
|
+
const ast_utils_1 = require("../../utils/ast-utils");
|
|
7
|
+
const utils_1 = require("./utils");
|
|
8
|
+
/**
|
|
9
|
+
* InvocationExpr validation
|
|
10
|
+
*/
|
|
11
|
+
class FunctionInvocationValidator {
|
|
12
|
+
validate(expr, accept) {
|
|
13
|
+
var _a, _b, _c, _d;
|
|
14
|
+
const funcDecl = expr.function.ref;
|
|
15
|
+
if (!funcDecl) {
|
|
16
|
+
accept('error', 'function cannot be resolved', { node: expr });
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (!this.validateArgs(funcDecl, expr.args, accept)) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if ((0, sdk_1.isFromStdlib)(funcDecl)) {
|
|
23
|
+
// validate standard library functions
|
|
24
|
+
// find the containing attribute context for the invocation
|
|
25
|
+
let curr = expr.$container;
|
|
26
|
+
let containerAttribute;
|
|
27
|
+
while (curr) {
|
|
28
|
+
if ((0, ast_1.isDataModelAttribute)(curr) || (0, ast_1.isDataModelFieldAttribute)(curr)) {
|
|
29
|
+
containerAttribute = curr;
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
curr = curr.$container;
|
|
33
|
+
}
|
|
34
|
+
// validate the context allowed for the function
|
|
35
|
+
const exprContext = (0, ts_pattern_1.match)(containerAttribute === null || containerAttribute === void 0 ? void 0 : containerAttribute.decl.$refText)
|
|
36
|
+
.with('@default', () => sdk_1.ExpressionContext.DefaultValue)
|
|
37
|
+
.with(ts_pattern_1.P.union('@@allow', '@@deny'), () => sdk_1.ExpressionContext.AccessPolicy)
|
|
38
|
+
.with('@@validate', () => sdk_1.ExpressionContext.ValidationRule)
|
|
39
|
+
.otherwise(() => undefined);
|
|
40
|
+
// get the context allowed for the function
|
|
41
|
+
const funcAllowedContext = (0, sdk_1.getFunctionExpressionContext)(funcDecl);
|
|
42
|
+
if (exprContext && !funcAllowedContext.includes(exprContext)) {
|
|
43
|
+
accept('error', `function "${funcDecl.name}" is not allowed in the current context: ${exprContext}`, {
|
|
44
|
+
node: expr,
|
|
45
|
+
});
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (funcAllowedContext.includes(sdk_1.ExpressionContext.AccessPolicy) ||
|
|
49
|
+
funcAllowedContext.includes(sdk_1.ExpressionContext.ValidationRule)) {
|
|
50
|
+
// filter operation functions validation
|
|
51
|
+
// first argument must refer to a model field
|
|
52
|
+
const firstArg = (_b = (_a = expr.args) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.value;
|
|
53
|
+
if (firstArg) {
|
|
54
|
+
if (!(0, ast_utils_1.getDataModelFieldReference)(firstArg)) {
|
|
55
|
+
accept('error', 'first argument must be a field reference', { node: firstArg });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// second argument must be a literal or array of literal
|
|
59
|
+
const secondArg = (_d = (_c = expr.args) === null || _c === void 0 ? void 0 : _c[1]) === null || _d === void 0 ? void 0 : _d.value;
|
|
60
|
+
if (secondArg &&
|
|
61
|
+
// literal
|
|
62
|
+
!(0, ast_1.isLiteralExpr)(secondArg) &&
|
|
63
|
+
// enum field
|
|
64
|
+
!(0, sdk_1.isEnumFieldReference)(secondArg) &&
|
|
65
|
+
// array of literal/enum
|
|
66
|
+
!((0, ast_1.isArrayExpr)(secondArg) &&
|
|
67
|
+
secondArg.items.every((item) => (0, ast_1.isLiteralExpr)(item) || (0, sdk_1.isEnumFieldReference)(item)))) {
|
|
68
|
+
accept('error', 'second argument must be a literal, an enum, or an array of them', {
|
|
69
|
+
node: secondArg,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
validateArgs(funcDecl, args, accept) {
|
|
76
|
+
let success = true;
|
|
77
|
+
for (let i = 0; i < funcDecl.params.length; i++) {
|
|
78
|
+
const param = funcDecl.params[i];
|
|
79
|
+
const arg = args[i];
|
|
80
|
+
if (!arg) {
|
|
81
|
+
if (!param.optional) {
|
|
82
|
+
accept('error', `missing argument for parameter "${param.name}"`, { node: funcDecl });
|
|
83
|
+
success = false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
if (!this.validateInvocationArg(arg, param, accept)) {
|
|
88
|
+
success = false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// TODO: do we need to complain for extra arguments?
|
|
93
|
+
return success;
|
|
94
|
+
}
|
|
95
|
+
validateInvocationArg(arg, param, accept) {
|
|
96
|
+
var _a;
|
|
97
|
+
const argResolvedType = (_a = arg === null || arg === void 0 ? void 0 : arg.value) === null || _a === void 0 ? void 0 : _a.$resolvedType;
|
|
98
|
+
if (!argResolvedType) {
|
|
99
|
+
accept('error', 'argument type cannot be resolved', { node: arg });
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
const dstType = param.type.type;
|
|
103
|
+
if (!dstType) {
|
|
104
|
+
accept('error', 'parameter type cannot be resolved', { node: param });
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
const dstIsArray = param.type.array;
|
|
108
|
+
const dstRef = param.type.reference;
|
|
109
|
+
if (dstType === 'Any' && !dstIsArray) {
|
|
110
|
+
// scalar 'any' can be assigned with anything
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
if (typeof argResolvedType.decl === 'string') {
|
|
114
|
+
// scalar type
|
|
115
|
+
if (!(0, utils_1.typeAssignable)(dstType, argResolvedType.decl, arg.value) || dstIsArray !== argResolvedType.array) {
|
|
116
|
+
accept('error', `argument is not assignable to parameter`, {
|
|
117
|
+
node: arg,
|
|
118
|
+
});
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
// enum or model type
|
|
124
|
+
if (((dstRef === null || dstRef === void 0 ? void 0 : dstRef.ref) !== argResolvedType.decl && dstType !== 'Any') || dstIsArray !== argResolvedType.array) {
|
|
125
|
+
accept('error', `argument is not assignable to parameter`, {
|
|
126
|
+
node: arg,
|
|
127
|
+
});
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
exports.default = FunctionInvocationValidator;
|
|
135
|
+
//# sourceMappingURL=function-invocation-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"function-invocation-validator.js","sourceRoot":"","sources":["../../../src/language-server/validator/function-invocation-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { Model } from '@zenstackhq/language/ast';
|
|
2
2
|
import { AstValidator } from '../types';
|
|
3
|
-
import { ValidationAcceptor } from 'langium';
|
|
3
|
+
import { LangiumDocuments, ValidationAcceptor } from 'langium';
|
|
4
4
|
/**
|
|
5
5
|
* Validates toplevel schema.
|
|
6
6
|
*/
|
|
7
7
|
export default class SchemaValidator implements AstValidator<Model> {
|
|
8
|
+
protected readonly documents: LangiumDocuments;
|
|
9
|
+
constructor(documents: LangiumDocuments);
|
|
8
10
|
validate(model: Model, accept: ValidationAcceptor): void;
|
|
9
11
|
private validateDataSources;
|
|
12
|
+
private validateImports;
|
|
10
13
|
}
|
|
@@ -3,26 +3,47 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const constants_1 = require("../constants");
|
|
4
4
|
const ast_1 = require("@zenstackhq/language/ast");
|
|
5
5
|
const utils_1 = require("./utils");
|
|
6
|
+
const ast_utils_1 = require("../../utils/ast-utils");
|
|
6
7
|
/**
|
|
7
8
|
* Validates toplevel schema.
|
|
8
9
|
*/
|
|
9
10
|
class SchemaValidator {
|
|
11
|
+
constructor(documents) {
|
|
12
|
+
this.documents = documents;
|
|
13
|
+
}
|
|
10
14
|
validate(model, accept) {
|
|
11
|
-
var _a;
|
|
15
|
+
var _a, _b;
|
|
16
|
+
this.validateImports(model, accept);
|
|
12
17
|
(0, utils_1.validateDuplicatedDeclarations)(model.declarations, accept);
|
|
13
|
-
|
|
18
|
+
const importedModels = (0, ast_utils_1.resolveTransitiveImports)(this.documents, model);
|
|
19
|
+
const importedNames = new Set(importedModels.flatMap((m) => m.declarations.map((d) => d.name)));
|
|
20
|
+
for (const declaration of model.declarations) {
|
|
21
|
+
if (importedNames.has(declaration.name)) {
|
|
22
|
+
accept('error', `A ${declaration.name} already exists in an imported module`, {
|
|
23
|
+
node: declaration,
|
|
24
|
+
property: 'name',
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (!((_a = model.$document) === null || _a === void 0 ? void 0 : _a.uri.path.endsWith(constants_1.STD_LIB_MODULE_NAME)) &&
|
|
29
|
+
!((_b = model.$document) === null || _b === void 0 ? void 0 : _b.uri.path.endsWith(constants_1.PLUGIN_MODULE_NAME))) {
|
|
14
30
|
this.validateDataSources(model, accept);
|
|
15
31
|
}
|
|
16
32
|
}
|
|
17
33
|
validateDataSources(model, accept) {
|
|
18
|
-
const dataSources = model.
|
|
19
|
-
if (dataSources.length
|
|
20
|
-
accept('error', 'Model must define a datasource', { node: model });
|
|
21
|
-
}
|
|
22
|
-
else if (dataSources.length > 1) {
|
|
34
|
+
const dataSources = (0, ast_utils_1.getAllDeclarationsFromImports)(this.documents, model).filter((d) => (0, ast_1.isDataSource)(d));
|
|
35
|
+
if (dataSources.length > 1) {
|
|
23
36
|
accept('error', 'Multiple datasource declarations are not allowed', { node: dataSources[1] });
|
|
24
37
|
}
|
|
25
38
|
}
|
|
39
|
+
validateImports(model, accept) {
|
|
40
|
+
model.imports.forEach((imp) => {
|
|
41
|
+
const importedModel = (0, ast_utils_1.resolveImport)(this.documents, imp);
|
|
42
|
+
if (!importedModel) {
|
|
43
|
+
accept('error', `Cannot find model file ${imp.path}.zmodel`, { node: imp });
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
26
47
|
}
|
|
27
48
|
exports.default = SchemaValidator;
|
|
28
49
|
//# sourceMappingURL=schema-validator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-validator.js","sourceRoot":"","sources":["../../../src/language-server/validator/schema-validator.ts"],"names":[],"mappings":";;AAAA,
|
|
1
|
+
{"version":3,"file":"schema-validator.js","sourceRoot":"","sources":["../../../src/language-server/validator/schema-validator.ts"],"names":[],"mappings":";;AAAA,4CAAuE;AACvE,kDAA+D;AAG/D,mCAAyD;AACzD,qDAA+G;AAE/G;;GAEG;AACH,MAAqB,eAAe;IAChC,YAA+B,SAA2B;QAA3B,cAAS,GAAT,SAAS,CAAkB;IAAG,CAAC;IAC9D,QAAQ,CAAC,KAAY,EAAE,MAA0B;;QAC7C,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACpC,IAAA,sCAA8B,EAAC,KAAK,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QAE3D,MAAM,cAAc,GAAG,IAAA,oCAAwB,EAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAEvE,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAEhG,KAAK,MAAM,WAAW,IAAI,KAAK,CAAC,YAAY,EAAE;YAC1C,IAAI,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE;gBACrC,MAAM,CAAC,OAAO,EAAE,KAAK,WAAW,CAAC,IAAI,uCAAuC,EAAE;oBAC1E,IAAI,EAAE,WAAW;oBACjB,QAAQ,EAAE,MAAM;iBACnB,CAAC,CAAC;aACN;SACJ;QAED,IACI,CAAC,CAAA,MAAA,KAAK,CAAC,SAAS,0CAAE,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,+BAAmB,CAAC,CAAA;YACxD,CAAC,CAAA,MAAA,KAAK,CAAC,SAAS,0CAAE,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,8BAAkB,CAAC,CAAA,EACzD;YACE,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;SAC3C;IACL,CAAC;IAEO,mBAAmB,CAAC,KAAY,EAAE,MAA0B;QAChE,MAAM,WAAW,GAAG,IAAA,yCAA6B,EAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,kBAAY,EAAC,CAAC,CAAC,CAAC,CAAC;QACxG,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE;YACxB,MAAM,CAAC,OAAO,EAAE,kDAAkD,EAAE,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SACjG;IACL,CAAC;IAEO,eAAe,CAAC,KAAY,EAAE,MAA0B;QAC5D,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;YAC1B,MAAM,aAAa,GAAG,IAAA,yBAAa,EAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;YACzD,IAAI,CAAC,aAAa,EAAE;gBAChB,MAAM,CAAC,OAAO,EAAE,0BAA0B,GAAG,CAAC,IAAI,SAAS,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;aAC/E;QACL,CAAC,CAAC,CAAC;IACP,CAAC;CACJ;AA1CD,kCA0CC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AttributeArg, AttributeParam, BuiltinType, DataModelAttribute, DataModelFieldAttribute, Expression, ExpressionType } from '@zenstackhq/language/ast';
|
|
1
|
+
import { AttributeArg, AttributeParam, BuiltinType, DataModelAttribute, DataModelFieldAttribute, Expression, ExpressionType, InternalAttribute } from '@zenstackhq/language/ast';
|
|
2
2
|
import { AstNode, ValidationAcceptor } from 'langium';
|
|
3
3
|
/**
|
|
4
4
|
* Checks if the given declarations have duplicated names
|
|
@@ -17,9 +17,8 @@ export declare function typeAssignable(destType: ExpressionType, sourceType: Exp
|
|
|
17
17
|
/**
|
|
18
18
|
* Maps a ZModel builtin type to expression type
|
|
19
19
|
*/
|
|
20
|
-
export declare function mapBuiltinTypeToExpressionType(type: BuiltinType | 'Any' | 'Null'): ExpressionType | 'Any';
|
|
20
|
+
export declare function mapBuiltinTypeToExpressionType(type: BuiltinType | 'Any' | 'Object' | 'Null' | 'Unsupported'): ExpressionType | 'Any';
|
|
21
21
|
/**
|
|
22
22
|
* Determines if the given attribute argument is assignable to the given attribute parameter
|
|
23
23
|
*/
|
|
24
|
-
export declare function assignableToAttributeParam(arg: AttributeArg, param: AttributeParam, attr: DataModelAttribute | DataModelFieldAttribute): boolean;
|
|
25
|
-
export declare function validateAttributeApplication(attr: DataModelAttribute | DataModelFieldAttribute, accept: ValidationAcceptor): boolean | undefined;
|
|
24
|
+
export declare function assignableToAttributeParam(arg: AttributeArg, param: AttributeParam, attr: DataModelAttribute | DataModelFieldAttribute | InternalAttribute): boolean;
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
3
|
+
exports.assignableToAttributeParam = exports.mapBuiltinTypeToExpressionType = exports.typeAssignable = exports.getStringLiteral = exports.validateDuplicatedDeclarations = void 0;
|
|
7
4
|
const ast_1 = require("@zenstackhq/language/ast");
|
|
8
5
|
const sdk_1 = require("@zenstackhq/sdk");
|
|
9
|
-
const pluralize_1 = __importDefault(require("pluralize"));
|
|
10
6
|
/**
|
|
11
7
|
* Checks if the given declarations have duplicated names
|
|
12
8
|
*/
|
|
@@ -19,8 +15,15 @@ function validateDuplicatedDeclarations(decls, accept) {
|
|
|
19
15
|
}, {});
|
|
20
16
|
for (const [name, decls] of Object.entries(groupByName)) {
|
|
21
17
|
if (decls.length > 1) {
|
|
18
|
+
let errorField = decls[1];
|
|
19
|
+
if (decls[0].$type === 'DataModelField') {
|
|
20
|
+
const nonInheritedFields = decls.filter((x) => !x.$isInherited);
|
|
21
|
+
if (nonInheritedFields.length > 0) {
|
|
22
|
+
errorField = nonInheritedFields.slice(-1)[0];
|
|
23
|
+
}
|
|
24
|
+
}
|
|
22
25
|
accept('error', `Duplicated declaration name "${name}"`, {
|
|
23
|
-
node:
|
|
26
|
+
node: errorField,
|
|
24
27
|
});
|
|
25
28
|
}
|
|
26
29
|
}
|
|
@@ -30,12 +33,7 @@ exports.validateDuplicatedDeclarations = validateDuplicatedDeclarations;
|
|
|
30
33
|
* Try getting string value from a potential string literal expression
|
|
31
34
|
*/
|
|
32
35
|
function getStringLiteral(node) {
|
|
33
|
-
|
|
34
|
-
return node.value;
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
return undefined;
|
|
38
|
-
}
|
|
36
|
+
return (0, ast_1.isStringLiteral)(node) ? node.value : undefined;
|
|
39
37
|
}
|
|
40
38
|
exports.getStringLiteral = getStringLiteral;
|
|
41
39
|
const isoDateTimeRegex = /^\d{4}(-\d\d(-\d\d(T\d\d:\d\d(:\d\d)?(\.\d+)?(([+-]\d\d:\d\d)|Z)?)?)?)?$/i;
|
|
@@ -44,7 +42,7 @@ const isoDateTimeRegex = /^\d{4}(-\d\d(-\d\d(T\d\d:\d\d(:\d\d)?(\.\d+)?(([+-]\d\
|
|
|
44
42
|
*/
|
|
45
43
|
function typeAssignable(destType, sourceType, sourceExpr) {
|
|
46
44
|
// implicit conversion from ISO datetime string to datetime
|
|
47
|
-
if (destType === 'DateTime' && sourceType === 'String' && sourceExpr && (0, ast_1.
|
|
45
|
+
if (destType === 'DateTime' && sourceType === 'String' && sourceExpr && (0, ast_1.isStringLiteral)(sourceExpr)) {
|
|
48
46
|
const literal = getStringLiteral(sourceExpr);
|
|
49
47
|
if (literal && isoDateTimeRegex.test(literal)) {
|
|
50
48
|
// implicitly convert to DateTime
|
|
@@ -81,6 +79,10 @@ function mapBuiltinTypeToExpressionType(type) {
|
|
|
81
79
|
case 'Json':
|
|
82
80
|
case 'Bytes':
|
|
83
81
|
return 'Any';
|
|
82
|
+
case 'Object':
|
|
83
|
+
return 'Object';
|
|
84
|
+
case 'Unsupported':
|
|
85
|
+
return 'Unsupported';
|
|
84
86
|
}
|
|
85
87
|
}
|
|
86
88
|
exports.mapBuiltinTypeToExpressionType = mapBuiltinTypeToExpressionType;
|
|
@@ -96,6 +98,9 @@ function assignableToAttributeParam(arg, param, attr) {
|
|
|
96
98
|
let dstType = param.type.type;
|
|
97
99
|
let dstIsArray = param.type.array;
|
|
98
100
|
const dstRef = param.type.reference;
|
|
101
|
+
if (dstType === 'Any' && !dstIsArray) {
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
99
104
|
// destination is field reference or transitive field reference, check if
|
|
100
105
|
// argument is reference or array or reference
|
|
101
106
|
if (dstType === 'FieldReference' || dstType === 'TransitiveFieldReference') {
|
|
@@ -138,120 +143,12 @@ function assignableToAttributeParam(arg, param, attr) {
|
|
|
138
143
|
dstType = 'Any';
|
|
139
144
|
}
|
|
140
145
|
}
|
|
141
|
-
return
|
|
142
|
-
(dstType === 'Any' || dstIsArray === argResolvedType.array));
|
|
146
|
+
return typeAssignable(dstType, argResolvedType.decl, arg.value) && dstIsArray === argResolvedType.array;
|
|
143
147
|
}
|
|
144
148
|
else {
|
|
145
149
|
// reference type
|
|
146
|
-
return (dstRef === null || dstRef === void 0 ? void 0 : dstRef.ref) === argResolvedType.decl && dstIsArray === argResolvedType.array;
|
|
150
|
+
return ((dstRef === null || dstRef === void 0 ? void 0 : dstRef.ref) === argResolvedType.decl || dstType === 'Any') && dstIsArray === argResolvedType.array;
|
|
147
151
|
}
|
|
148
152
|
}
|
|
149
153
|
exports.assignableToAttributeParam = assignableToAttributeParam;
|
|
150
|
-
function validateAttributeApplication(attr, accept) {
|
|
151
|
-
const decl = attr.decl.ref;
|
|
152
|
-
if (!decl) {
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
const targetDecl = attr.$container;
|
|
156
|
-
if (decl.name === '@@@targetField' && !(0, ast_1.isAttribute)(targetDecl)) {
|
|
157
|
-
accept('error', `attribute "${decl.name}" can only be used on attribute declarations`, { node: attr });
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
if ((0, ast_1.isDataModelField)(targetDecl) && !isValidAttributeTarget(decl, targetDecl)) {
|
|
161
|
-
accept('error', `attribute "${decl.name}" cannot be used on this type of field`, { node: attr });
|
|
162
|
-
}
|
|
163
|
-
const filledParams = new Set();
|
|
164
|
-
for (const arg of attr.args) {
|
|
165
|
-
let paramDecl;
|
|
166
|
-
if (!arg.name) {
|
|
167
|
-
paramDecl = decl.params.find((p) => p.default && !filledParams.has(p));
|
|
168
|
-
if (!paramDecl) {
|
|
169
|
-
accept('error', `Unexpected unnamed argument`, {
|
|
170
|
-
node: arg,
|
|
171
|
-
});
|
|
172
|
-
return false;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
paramDecl = decl.params.find((p) => p.name === arg.name);
|
|
177
|
-
if (!paramDecl) {
|
|
178
|
-
accept('error', `Attribute "${decl.name}" doesn't have a parameter named "${arg.name}"`, {
|
|
179
|
-
node: arg,
|
|
180
|
-
});
|
|
181
|
-
return false;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
if (!assignableToAttributeParam(arg, paramDecl, attr)) {
|
|
185
|
-
accept('error', `Value is not assignable to parameter`, {
|
|
186
|
-
node: arg,
|
|
187
|
-
});
|
|
188
|
-
return false;
|
|
189
|
-
}
|
|
190
|
-
if (filledParams.has(paramDecl)) {
|
|
191
|
-
accept('error', `Parameter "${paramDecl.name}" is already provided`, { node: arg });
|
|
192
|
-
return false;
|
|
193
|
-
}
|
|
194
|
-
filledParams.add(paramDecl);
|
|
195
|
-
arg.$resolvedParam = paramDecl;
|
|
196
|
-
}
|
|
197
|
-
const missingParams = decl.params.filter((p) => !p.type.optional && !filledParams.has(p));
|
|
198
|
-
if (missingParams.length > 0) {
|
|
199
|
-
accept('error', `Required ${(0, pluralize_1.default)('parameter', missingParams.length)} not provided: ${missingParams
|
|
200
|
-
.map((p) => p.name)
|
|
201
|
-
.join(', ')}`, { node: attr });
|
|
202
|
-
return false;
|
|
203
|
-
}
|
|
204
|
-
return true;
|
|
205
|
-
}
|
|
206
|
-
exports.validateAttributeApplication = validateAttributeApplication;
|
|
207
|
-
function isValidAttributeTarget(attrDecl, targetDecl) {
|
|
208
|
-
var _a;
|
|
209
|
-
const targetField = attrDecl.attributes.find((attr) => { var _a; return ((_a = attr.decl.ref) === null || _a === void 0 ? void 0 : _a.name) === '@@@targetField'; });
|
|
210
|
-
if (!targetField) {
|
|
211
|
-
// no field type constraint
|
|
212
|
-
return true;
|
|
213
|
-
}
|
|
214
|
-
const fieldTypes = targetField.args[0].value.items.map((item) => { var _a; return (_a = item.target.ref) === null || _a === void 0 ? void 0 : _a.name; });
|
|
215
|
-
let allowed = false;
|
|
216
|
-
for (const allowedType of fieldTypes) {
|
|
217
|
-
switch (allowedType) {
|
|
218
|
-
case 'StringField':
|
|
219
|
-
allowed = allowed || targetDecl.type.type === 'String';
|
|
220
|
-
break;
|
|
221
|
-
case 'IntField':
|
|
222
|
-
allowed = allowed || targetDecl.type.type === 'Int';
|
|
223
|
-
break;
|
|
224
|
-
case 'BigIntField':
|
|
225
|
-
allowed = allowed || targetDecl.type.type === 'BigInt';
|
|
226
|
-
break;
|
|
227
|
-
case 'FloatField':
|
|
228
|
-
allowed = allowed || targetDecl.type.type === 'Float';
|
|
229
|
-
break;
|
|
230
|
-
case 'DecimalField':
|
|
231
|
-
allowed = allowed || targetDecl.type.type === 'Decimal';
|
|
232
|
-
break;
|
|
233
|
-
case 'BooleanField':
|
|
234
|
-
allowed = allowed || targetDecl.type.type === 'Boolean';
|
|
235
|
-
break;
|
|
236
|
-
case 'DateTimeField':
|
|
237
|
-
allowed = allowed || targetDecl.type.type === 'DateTime';
|
|
238
|
-
break;
|
|
239
|
-
case 'JsonField':
|
|
240
|
-
allowed = allowed || targetDecl.type.type === 'Json';
|
|
241
|
-
break;
|
|
242
|
-
case 'BytesField':
|
|
243
|
-
allowed = allowed || targetDecl.type.type === 'Bytes';
|
|
244
|
-
break;
|
|
245
|
-
case 'ModelField':
|
|
246
|
-
allowed = allowed || (0, ast_1.isDataModel)((_a = targetDecl.type.reference) === null || _a === void 0 ? void 0 : _a.ref);
|
|
247
|
-
break;
|
|
248
|
-
default:
|
|
249
|
-
break;
|
|
250
|
-
}
|
|
251
|
-
if (allowed) {
|
|
252
|
-
break;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
return allowed;
|
|
256
|
-
}
|
|
257
154
|
//# sourceMappingURL=utils.js.map
|