@valtzu/codemirror-lang-el 0.8.0 → 0.9.0
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/CHANGELOG.md +13 -0
- package/README.md +17 -3
- package/dist/index.cjs +160 -110
- package/dist/index.d.cts +73 -4
- package/dist/index.d.ts +73 -4
- package/dist/index.js +167 -120
- package/package.json +8 -13
- package/dist/complete.cjs +0 -224
- package/dist/complete.d.cts +0 -3
- package/dist/complete.d.ts +0 -3
- package/dist/complete.js +0 -220
- package/dist/linter.cjs +0 -221
- package/dist/linter.d.cts +0 -8
- package/dist/linter.d.ts +0 -8
- package/dist/linter.js +0 -216
- package/dist/tooltip.cjs +0 -258
- package/dist/tooltip.d.cts +0 -7
- package/dist/tooltip.d.ts +0 -7
- package/dist/tooltip.js +0 -253
- package/dist/utils.cjs +0 -150
- package/dist/utils.d.cts +0 -53
- package/dist/utils.d.ts +0 -53
- package/dist/utils.js +0 -141
package/dist/linter.cjs
DELETED
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
-
|
|
5
|
-
var lint = require('@codemirror/lint');
|
|
6
|
-
var language = require('@codemirror/language');
|
|
7
|
-
|
|
8
|
-
var ELScalar;
|
|
9
|
-
(function (ELScalar) {
|
|
10
|
-
ELScalar["Bool"] = "bool";
|
|
11
|
-
ELScalar["Number"] = "number";
|
|
12
|
-
ELScalar["String"] = "string";
|
|
13
|
-
ELScalar["Null"] = "null";
|
|
14
|
-
ELScalar["Any"] = "any";
|
|
15
|
-
})(ELScalar || (ELScalar = {}));
|
|
16
|
-
|
|
17
|
-
// @ts-ignore
|
|
18
|
-
const t = {
|
|
19
|
-
deserialize: (str) => str,
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
function resolveFunctionDefinition(node, state, config) {
|
|
23
|
-
var _a;
|
|
24
|
-
if (!node) {
|
|
25
|
-
return undefined;
|
|
26
|
-
}
|
|
27
|
-
let identifier;
|
|
28
|
-
if (node.name === 'ObjectAccess' && node.lastChild) {
|
|
29
|
-
const leftArgument = (_a = node.firstChild) === null || _a === void 0 ? void 0 : _a.node;
|
|
30
|
-
const types = Array.from(resolveTypes(state, leftArgument, config));
|
|
31
|
-
identifier = state.sliceDoc(node.lastChild.from, node.lastChild.to);
|
|
32
|
-
return types.map(type => { var _a; return resolveCallable(identifier, (_a = config.types) === null || _a === void 0 ? void 0 : _a[type]); }).find(x => x);
|
|
33
|
-
}
|
|
34
|
-
else if (node.name === 'Function') {
|
|
35
|
-
identifier = state.sliceDoc(node.from, node.node.firstChild ? node.node.firstChild.from - 1 : node.to);
|
|
36
|
-
return resolveCallable(identifier, config);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
const resolveCallable = (identifier, config) => { var _a; return (_a = config === null || config === void 0 ? void 0 : config.functions) === null || _a === void 0 ? void 0 : _a.find(x => x.name === identifier); };
|
|
40
|
-
const resolveIdentifier = (nodeName, identifier, config) => {
|
|
41
|
-
var _a;
|
|
42
|
-
switch (nodeName) {
|
|
43
|
-
case 'Method':
|
|
44
|
-
case 'Function':
|
|
45
|
-
return resolveCallable(identifier, config);
|
|
46
|
-
case 'Property':
|
|
47
|
-
case 'Variable':
|
|
48
|
-
return (_a = config === null || config === void 0 ? void 0 : config.identifiers) === null || _a === void 0 ? void 0 : _a.find(x => x.name === identifier);
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
function resolveTypes(state, node, config, matchExact) {
|
|
52
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
53
|
-
let types = new Set();
|
|
54
|
-
if (!node) {
|
|
55
|
-
return types;
|
|
56
|
-
}
|
|
57
|
-
let type;
|
|
58
|
-
if (typeof (type = node.type.prop(t)) !== "undefined") {
|
|
59
|
-
types.add(type);
|
|
60
|
-
}
|
|
61
|
-
else if (node.name === 'Call' && node.firstChild && node.lastChild) {
|
|
62
|
-
resolveTypes(state, node.firstChild, config).forEach(x => types.add(x));
|
|
63
|
-
}
|
|
64
|
-
else if (node.name === 'Variable') {
|
|
65
|
-
const varName = state.sliceDoc(node.from, node.to) || '';
|
|
66
|
-
// @ts-ignore
|
|
67
|
-
(_b = (_a = resolveIdentifier(node.name, varName, config)) === null || _a === void 0 ? void 0 : _a.type) === null || _b === void 0 ? void 0 : _b.forEach((x) => types.add(x));
|
|
68
|
-
}
|
|
69
|
-
else if (node.name === 'Function') {
|
|
70
|
-
const varName = state.sliceDoc(node.from, node.to) || '';
|
|
71
|
-
// @ts-ignore
|
|
72
|
-
(_d = (_c = resolveIdentifier(node.name, varName, config)) === null || _c === void 0 ? void 0 : _c.returnType) === null || _d === void 0 ? void 0 : _d.forEach((x) => types.add(x));
|
|
73
|
-
}
|
|
74
|
-
else if (node.name === 'ObjectAccess' && node.firstChild && ((_e = node.lastChild) === null || _e === void 0 ? void 0 : _e.name) === 'Property') {
|
|
75
|
-
const varName = state.sliceDoc(node.lastChild.from, node.lastChild.to) || '';
|
|
76
|
-
(_f = resolveTypes(state, node.firstChild, config)) === null || _f === void 0 ? void 0 : _f.forEach(baseType => {
|
|
77
|
-
var _a, _b, _c, _d;
|
|
78
|
-
// @ts-ignore
|
|
79
|
-
(_d = (_c = resolveIdentifier((_a = node.lastChild) === null || _a === void 0 ? void 0 : _a.name, varName, (_b = config.types) === null || _b === void 0 ? void 0 : _b[baseType])) === null || _c === void 0 ? void 0 : _c.type) === null || _d === void 0 ? void 0 : _d.forEach((x) => types.add(x));
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
else if (node.name === 'ObjectAccess' && node.firstChild && ((_g = node.lastChild) === null || _g === void 0 ? void 0 : _g.name) === 'Method') {
|
|
83
|
-
const varName = state.sliceDoc(node.lastChild.from, node.lastChild.to) || '';
|
|
84
|
-
(_h = resolveTypes(state, node.firstChild, config)) === null || _h === void 0 ? void 0 : _h.forEach(baseType => {
|
|
85
|
-
var _a, _b, _c, _d;
|
|
86
|
-
// @ts-ignore
|
|
87
|
-
(_d = (_c = resolveIdentifier((_a = node.lastChild) === null || _a === void 0 ? void 0 : _a.name, varName, (_b = config.types) === null || _b === void 0 ? void 0 : _b[baseType])) === null || _c === void 0 ? void 0 : _c.returnType) === null || _d === void 0 ? void 0 : _d.forEach((x) => types.add(x));
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
else if (node.name === 'Application' && node.firstChild) {
|
|
91
|
-
resolveTypes(state, node.firstChild, config).forEach(x => types.add(x));
|
|
92
|
-
}
|
|
93
|
-
else if (node.name === 'TernaryExpression' && node.firstChild && node.firstChild.nextSibling && node.firstChild.nextSibling.nextSibling) {
|
|
94
|
-
resolveTypes(state, node.firstChild.nextSibling, config).forEach(x => types.add(x));
|
|
95
|
-
resolveTypes(state, node.firstChild.nextSibling.nextSibling, config).forEach(x => types.add(x));
|
|
96
|
-
}
|
|
97
|
-
else if (node.name === 'BinaryExpression' && ((_j = node.firstChild) === null || _j === void 0 ? void 0 : _j.nextSibling) && ((_l = (_k = node.firstChild) === null || _k === void 0 ? void 0 : _k.nextSibling) === null || _l === void 0 ? void 0 : _l.nextSibling)) {
|
|
98
|
-
const operator = state.sliceDoc(node.firstChild.nextSibling.from, node.firstChild.nextSibling.to);
|
|
99
|
-
if (operator == '?:' || operator == '??' || operator == '?') {
|
|
100
|
-
if (operator == '?:' || operator == '??') {
|
|
101
|
-
resolveTypes(state, node.firstChild, config).forEach(x => types.add(x));
|
|
102
|
-
}
|
|
103
|
-
resolveTypes(state, node.firstChild.nextSibling.nextSibling, config).forEach(x => types.add(x));
|
|
104
|
-
}
|
|
105
|
-
else if (['||', '&&', '==', '!=', '===', '!==', '>=', '<=', '>', '<'].includes(operator) || keywords.find(x => x.name == operator)) {
|
|
106
|
-
types.add(ELScalar.Bool);
|
|
107
|
-
}
|
|
108
|
-
else if (['**', '|', '^', '&', '<<', '>>', '+', '-', '*', '/', '%'].includes(operator)) {
|
|
109
|
-
types.add(ELScalar.Number);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
else if (node.name === 'UnaryExpression' && node.firstChild) {
|
|
113
|
-
const operator = state.sliceDoc(node.firstChild.from, node.firstChild.to);
|
|
114
|
-
if (['not', '!'].includes(operator)) {
|
|
115
|
-
types.add(ELScalar.Bool);
|
|
116
|
-
}
|
|
117
|
-
else if (['+', '-'].includes(operator)) {
|
|
118
|
-
types.add(ELScalar.Number);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
if (types.size === 0) {
|
|
122
|
-
types.add(ELScalar.Any);
|
|
123
|
-
}
|
|
124
|
-
return types;
|
|
125
|
-
}
|
|
126
|
-
function getExpressionLanguageConfig(state) {
|
|
127
|
-
return state.languageDataAt('expressionLanguageConfig', 0)[0];
|
|
128
|
-
}
|
|
129
|
-
const keywords = [
|
|
130
|
-
{ name: 'starts with', info: 'Check if a string starts with a specific string' },
|
|
131
|
-
{ name: 'ends with', info: 'Check if a string ends with a specific string' },
|
|
132
|
-
{ name: 'contains', info: 'Check if a string is not included in another string' },
|
|
133
|
-
{ name: 'matches', info: 'Check if a string matches a regex pattern' },
|
|
134
|
-
{ name: 'not in', info: 'Check if a value is not included in an array' },
|
|
135
|
-
{ name: 'in', info: 'Check if a value is included in an array' },
|
|
136
|
-
{ name: 'not' },
|
|
137
|
-
{ name: 'or' },
|
|
138
|
-
{ name: 'and' },
|
|
139
|
-
{ name: 'xor' },
|
|
140
|
-
];
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* @internal
|
|
144
|
-
*/
|
|
145
|
-
const expressionLanguageLinterSource = (state) => {
|
|
146
|
-
const config = getExpressionLanguageConfig(state);
|
|
147
|
-
let diagnostics = [];
|
|
148
|
-
language.syntaxTree(state).cursor().iterate(node => {
|
|
149
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
150
|
-
const { from, to, name } = node;
|
|
151
|
-
let identifier;
|
|
152
|
-
switch (name) {
|
|
153
|
-
case '⚠':
|
|
154
|
-
if (state.doc.length === 0 || from === 0) {
|
|
155
|
-
// Don't show error on empty doc (even though it is an error)
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
identifier = state.sliceDoc(from, to);
|
|
159
|
-
if (identifier.length === 0) {
|
|
160
|
-
diagnostics.push({ from, to: (_c = (_b = (_a = node.node.parent) === null || _a === void 0 ? void 0 : _a.parent) === null || _b === void 0 ? void 0 : _b.to) !== null && _c !== void 0 ? _c : to, severity: 'error', message: `Expression expected` });
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
const type = /^[a-zA-Z_]+[a-zA-Z_0-9]*$/.test(identifier) ? 'identifier' : 'operator';
|
|
164
|
-
diagnostics.push({ from, to, severity: 'error', message: `Unexpected ${type} '${identifier}'` });
|
|
165
|
-
}
|
|
166
|
-
return;
|
|
167
|
-
case 'Arguments':
|
|
168
|
-
const args = (_d = resolveFunctionDefinition(node.node.prevSibling, state, config)) === null || _d === void 0 ? void 0 : _d.args;
|
|
169
|
-
if (!args) {
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
for (let n = node.node.firstChild, i = 0; n != null; n = n.nextSibling) {
|
|
173
|
-
if (n.name === 'BlockComment') {
|
|
174
|
-
continue;
|
|
175
|
-
}
|
|
176
|
-
if (i > args.length - 1) {
|
|
177
|
-
diagnostics.push({ from: n.from, to: n.to, severity: 'error', message: `Unexpected argument` });
|
|
178
|
-
continue;
|
|
179
|
-
}
|
|
180
|
-
const typesUsed = Array.from(resolveTypes(state, n, config));
|
|
181
|
-
const typesExpected = args[i].type;
|
|
182
|
-
if (typesExpected && !typesExpected.includes(ELScalar.Any) && !typesUsed.some(x => typesExpected.includes(x))) {
|
|
183
|
-
diagnostics.push({ from: n.from, to: n.to, severity: 'error', message: `<code>${typesExpected.join('|')}</code> expected, got <code>${typesUsed.join('|')}</code>` });
|
|
184
|
-
}
|
|
185
|
-
i++;
|
|
186
|
-
}
|
|
187
|
-
break;
|
|
188
|
-
case 'Property':
|
|
189
|
-
case 'Method':
|
|
190
|
-
const leftArgument = (_f = (_e = node.node.parent) === null || _e === void 0 ? void 0 : _e.firstChild) === null || _f === void 0 ? void 0 : _f.node;
|
|
191
|
-
const types = Array.from(resolveTypes(state, leftArgument, config));
|
|
192
|
-
identifier = state.sliceDoc(from, to);
|
|
193
|
-
if (!types.find(type => { var _a; return resolveIdentifier(name, identifier, (_a = config.types) === null || _a === void 0 ? void 0 : _a[type]); })) {
|
|
194
|
-
diagnostics.push({ from, to, severity: 'error', message: `${node.name} "${identifier}" not found in ${types.join('|')}` });
|
|
195
|
-
}
|
|
196
|
-
break;
|
|
197
|
-
case 'Variable':
|
|
198
|
-
case 'Function':
|
|
199
|
-
identifier = state.sliceDoc(from, node.node.firstChild ? node.node.firstChild.from - 1 : to);
|
|
200
|
-
if (!resolveIdentifier(name, identifier, config)) {
|
|
201
|
-
diagnostics.push({ from, to, severity: 'error', message: `${node.node.name} "${identifier}" not found` });
|
|
202
|
-
}
|
|
203
|
-
break;
|
|
204
|
-
}
|
|
205
|
-
if (identifier && ((_g = node.node.parent) === null || _g === void 0 ? void 0 : _g.type.isError)) {
|
|
206
|
-
diagnostics.push({ from, to, severity: 'error', message: `Unexpected identifier "${identifier}"` });
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
diagnostics.forEach(d => {
|
|
210
|
-
d.renderMessage = () => {
|
|
211
|
-
const span = document.createElement('span');
|
|
212
|
-
span.innerHTML = d.message;
|
|
213
|
-
return span;
|
|
214
|
-
};
|
|
215
|
-
});
|
|
216
|
-
return diagnostics;
|
|
217
|
-
};
|
|
218
|
-
const expressionLanguageLinter = lint.linter(view => expressionLanguageLinterSource(view.state));
|
|
219
|
-
|
|
220
|
-
exports.expressionLanguageLinter = expressionLanguageLinter;
|
|
221
|
-
exports.expressionLanguageLinterSource = expressionLanguageLinterSource;
|
package/dist/linter.d.cts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { EditorState } from "@codemirror/state";
|
|
2
|
-
import { Diagnostic } from "@codemirror/lint";
|
|
3
|
-
/**
|
|
4
|
-
* @internal
|
|
5
|
-
*/
|
|
6
|
-
declare const expressionLanguageLinterSource: (state: EditorState) => Diagnostic[];
|
|
7
|
-
declare const expressionLanguageLinter: import("@codemirror/state").Extension;
|
|
8
|
-
export { expressionLanguageLinterSource, expressionLanguageLinter };
|
package/dist/linter.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { EditorState } from "@codemirror/state";
|
|
2
|
-
import { Diagnostic } from "@codemirror/lint";
|
|
3
|
-
/**
|
|
4
|
-
* @internal
|
|
5
|
-
*/
|
|
6
|
-
declare const expressionLanguageLinterSource: (state: EditorState) => Diagnostic[];
|
|
7
|
-
declare const expressionLanguageLinter: import("@codemirror/state").Extension;
|
|
8
|
-
export { expressionLanguageLinterSource, expressionLanguageLinter };
|
package/dist/linter.js
DELETED
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
import { linter } from '@codemirror/lint';
|
|
2
|
-
import { syntaxTree } from '@codemirror/language';
|
|
3
|
-
|
|
4
|
-
var ELScalar;
|
|
5
|
-
(function (ELScalar) {
|
|
6
|
-
ELScalar["Bool"] = "bool";
|
|
7
|
-
ELScalar["Number"] = "number";
|
|
8
|
-
ELScalar["String"] = "string";
|
|
9
|
-
ELScalar["Null"] = "null";
|
|
10
|
-
ELScalar["Any"] = "any";
|
|
11
|
-
})(ELScalar || (ELScalar = {}));
|
|
12
|
-
|
|
13
|
-
// @ts-ignore
|
|
14
|
-
const t = {
|
|
15
|
-
deserialize: (str) => str,
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
function resolveFunctionDefinition(node, state, config) {
|
|
19
|
-
var _a;
|
|
20
|
-
if (!node) {
|
|
21
|
-
return undefined;
|
|
22
|
-
}
|
|
23
|
-
let identifier;
|
|
24
|
-
if (node.name === 'ObjectAccess' && node.lastChild) {
|
|
25
|
-
const leftArgument = (_a = node.firstChild) === null || _a === void 0 ? void 0 : _a.node;
|
|
26
|
-
const types = Array.from(resolveTypes(state, leftArgument, config));
|
|
27
|
-
identifier = state.sliceDoc(node.lastChild.from, node.lastChild.to);
|
|
28
|
-
return types.map(type => { var _a; return resolveCallable(identifier, (_a = config.types) === null || _a === void 0 ? void 0 : _a[type]); }).find(x => x);
|
|
29
|
-
}
|
|
30
|
-
else if (node.name === 'Function') {
|
|
31
|
-
identifier = state.sliceDoc(node.from, node.node.firstChild ? node.node.firstChild.from - 1 : node.to);
|
|
32
|
-
return resolveCallable(identifier, config);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
const resolveCallable = (identifier, config) => { var _a; return (_a = config === null || config === void 0 ? void 0 : config.functions) === null || _a === void 0 ? void 0 : _a.find(x => x.name === identifier); };
|
|
36
|
-
const resolveIdentifier = (nodeName, identifier, config) => {
|
|
37
|
-
var _a;
|
|
38
|
-
switch (nodeName) {
|
|
39
|
-
case 'Method':
|
|
40
|
-
case 'Function':
|
|
41
|
-
return resolveCallable(identifier, config);
|
|
42
|
-
case 'Property':
|
|
43
|
-
case 'Variable':
|
|
44
|
-
return (_a = config === null || config === void 0 ? void 0 : config.identifiers) === null || _a === void 0 ? void 0 : _a.find(x => x.name === identifier);
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
function resolveTypes(state, node, config, matchExact) {
|
|
48
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
49
|
-
let types = new Set();
|
|
50
|
-
if (!node) {
|
|
51
|
-
return types;
|
|
52
|
-
}
|
|
53
|
-
let type;
|
|
54
|
-
if (typeof (type = node.type.prop(t)) !== "undefined") {
|
|
55
|
-
types.add(type);
|
|
56
|
-
}
|
|
57
|
-
else if (node.name === 'Call' && node.firstChild && node.lastChild) {
|
|
58
|
-
resolveTypes(state, node.firstChild, config).forEach(x => types.add(x));
|
|
59
|
-
}
|
|
60
|
-
else if (node.name === 'Variable') {
|
|
61
|
-
const varName = state.sliceDoc(node.from, node.to) || '';
|
|
62
|
-
// @ts-ignore
|
|
63
|
-
(_b = (_a = resolveIdentifier(node.name, varName, config)) === null || _a === void 0 ? void 0 : _a.type) === null || _b === void 0 ? void 0 : _b.forEach((x) => types.add(x));
|
|
64
|
-
}
|
|
65
|
-
else if (node.name === 'Function') {
|
|
66
|
-
const varName = state.sliceDoc(node.from, node.to) || '';
|
|
67
|
-
// @ts-ignore
|
|
68
|
-
(_d = (_c = resolveIdentifier(node.name, varName, config)) === null || _c === void 0 ? void 0 : _c.returnType) === null || _d === void 0 ? void 0 : _d.forEach((x) => types.add(x));
|
|
69
|
-
}
|
|
70
|
-
else if (node.name === 'ObjectAccess' && node.firstChild && ((_e = node.lastChild) === null || _e === void 0 ? void 0 : _e.name) === 'Property') {
|
|
71
|
-
const varName = state.sliceDoc(node.lastChild.from, node.lastChild.to) || '';
|
|
72
|
-
(_f = resolveTypes(state, node.firstChild, config)) === null || _f === void 0 ? void 0 : _f.forEach(baseType => {
|
|
73
|
-
var _a, _b, _c, _d;
|
|
74
|
-
// @ts-ignore
|
|
75
|
-
(_d = (_c = resolveIdentifier((_a = node.lastChild) === null || _a === void 0 ? void 0 : _a.name, varName, (_b = config.types) === null || _b === void 0 ? void 0 : _b[baseType])) === null || _c === void 0 ? void 0 : _c.type) === null || _d === void 0 ? void 0 : _d.forEach((x) => types.add(x));
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
else if (node.name === 'ObjectAccess' && node.firstChild && ((_g = node.lastChild) === null || _g === void 0 ? void 0 : _g.name) === 'Method') {
|
|
79
|
-
const varName = state.sliceDoc(node.lastChild.from, node.lastChild.to) || '';
|
|
80
|
-
(_h = resolveTypes(state, node.firstChild, config)) === null || _h === void 0 ? void 0 : _h.forEach(baseType => {
|
|
81
|
-
var _a, _b, _c, _d;
|
|
82
|
-
// @ts-ignore
|
|
83
|
-
(_d = (_c = resolveIdentifier((_a = node.lastChild) === null || _a === void 0 ? void 0 : _a.name, varName, (_b = config.types) === null || _b === void 0 ? void 0 : _b[baseType])) === null || _c === void 0 ? void 0 : _c.returnType) === null || _d === void 0 ? void 0 : _d.forEach((x) => types.add(x));
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
else if (node.name === 'Application' && node.firstChild) {
|
|
87
|
-
resolveTypes(state, node.firstChild, config).forEach(x => types.add(x));
|
|
88
|
-
}
|
|
89
|
-
else if (node.name === 'TernaryExpression' && node.firstChild && node.firstChild.nextSibling && node.firstChild.nextSibling.nextSibling) {
|
|
90
|
-
resolveTypes(state, node.firstChild.nextSibling, config).forEach(x => types.add(x));
|
|
91
|
-
resolveTypes(state, node.firstChild.nextSibling.nextSibling, config).forEach(x => types.add(x));
|
|
92
|
-
}
|
|
93
|
-
else if (node.name === 'BinaryExpression' && ((_j = node.firstChild) === null || _j === void 0 ? void 0 : _j.nextSibling) && ((_l = (_k = node.firstChild) === null || _k === void 0 ? void 0 : _k.nextSibling) === null || _l === void 0 ? void 0 : _l.nextSibling)) {
|
|
94
|
-
const operator = state.sliceDoc(node.firstChild.nextSibling.from, node.firstChild.nextSibling.to);
|
|
95
|
-
if (operator == '?:' || operator == '??' || operator == '?') {
|
|
96
|
-
if (operator == '?:' || operator == '??') {
|
|
97
|
-
resolveTypes(state, node.firstChild, config).forEach(x => types.add(x));
|
|
98
|
-
}
|
|
99
|
-
resolveTypes(state, node.firstChild.nextSibling.nextSibling, config).forEach(x => types.add(x));
|
|
100
|
-
}
|
|
101
|
-
else if (['||', '&&', '==', '!=', '===', '!==', '>=', '<=', '>', '<'].includes(operator) || keywords.find(x => x.name == operator)) {
|
|
102
|
-
types.add(ELScalar.Bool);
|
|
103
|
-
}
|
|
104
|
-
else if (['**', '|', '^', '&', '<<', '>>', '+', '-', '*', '/', '%'].includes(operator)) {
|
|
105
|
-
types.add(ELScalar.Number);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
else if (node.name === 'UnaryExpression' && node.firstChild) {
|
|
109
|
-
const operator = state.sliceDoc(node.firstChild.from, node.firstChild.to);
|
|
110
|
-
if (['not', '!'].includes(operator)) {
|
|
111
|
-
types.add(ELScalar.Bool);
|
|
112
|
-
}
|
|
113
|
-
else if (['+', '-'].includes(operator)) {
|
|
114
|
-
types.add(ELScalar.Number);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
if (types.size === 0) {
|
|
118
|
-
types.add(ELScalar.Any);
|
|
119
|
-
}
|
|
120
|
-
return types;
|
|
121
|
-
}
|
|
122
|
-
function getExpressionLanguageConfig(state) {
|
|
123
|
-
return state.languageDataAt('expressionLanguageConfig', 0)[0];
|
|
124
|
-
}
|
|
125
|
-
const keywords = [
|
|
126
|
-
{ name: 'starts with', info: 'Check if a string starts with a specific string' },
|
|
127
|
-
{ name: 'ends with', info: 'Check if a string ends with a specific string' },
|
|
128
|
-
{ name: 'contains', info: 'Check if a string is not included in another string' },
|
|
129
|
-
{ name: 'matches', info: 'Check if a string matches a regex pattern' },
|
|
130
|
-
{ name: 'not in', info: 'Check if a value is not included in an array' },
|
|
131
|
-
{ name: 'in', info: 'Check if a value is included in an array' },
|
|
132
|
-
{ name: 'not' },
|
|
133
|
-
{ name: 'or' },
|
|
134
|
-
{ name: 'and' },
|
|
135
|
-
{ name: 'xor' },
|
|
136
|
-
];
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* @internal
|
|
140
|
-
*/
|
|
141
|
-
const expressionLanguageLinterSource = (state) => {
|
|
142
|
-
const config = getExpressionLanguageConfig(state);
|
|
143
|
-
let diagnostics = [];
|
|
144
|
-
syntaxTree(state).cursor().iterate(node => {
|
|
145
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
146
|
-
const { from, to, name } = node;
|
|
147
|
-
let identifier;
|
|
148
|
-
switch (name) {
|
|
149
|
-
case '⚠':
|
|
150
|
-
if (state.doc.length === 0 || from === 0) {
|
|
151
|
-
// Don't show error on empty doc (even though it is an error)
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
identifier = state.sliceDoc(from, to);
|
|
155
|
-
if (identifier.length === 0) {
|
|
156
|
-
diagnostics.push({ from, to: (_c = (_b = (_a = node.node.parent) === null || _a === void 0 ? void 0 : _a.parent) === null || _b === void 0 ? void 0 : _b.to) !== null && _c !== void 0 ? _c : to, severity: 'error', message: `Expression expected` });
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
const type = /^[a-zA-Z_]+[a-zA-Z_0-9]*$/.test(identifier) ? 'identifier' : 'operator';
|
|
160
|
-
diagnostics.push({ from, to, severity: 'error', message: `Unexpected ${type} '${identifier}'` });
|
|
161
|
-
}
|
|
162
|
-
return;
|
|
163
|
-
case 'Arguments':
|
|
164
|
-
const args = (_d = resolveFunctionDefinition(node.node.prevSibling, state, config)) === null || _d === void 0 ? void 0 : _d.args;
|
|
165
|
-
if (!args) {
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
for (let n = node.node.firstChild, i = 0; n != null; n = n.nextSibling) {
|
|
169
|
-
if (n.name === 'BlockComment') {
|
|
170
|
-
continue;
|
|
171
|
-
}
|
|
172
|
-
if (i > args.length - 1) {
|
|
173
|
-
diagnostics.push({ from: n.from, to: n.to, severity: 'error', message: `Unexpected argument` });
|
|
174
|
-
continue;
|
|
175
|
-
}
|
|
176
|
-
const typesUsed = Array.from(resolveTypes(state, n, config));
|
|
177
|
-
const typesExpected = args[i].type;
|
|
178
|
-
if (typesExpected && !typesExpected.includes(ELScalar.Any) && !typesUsed.some(x => typesExpected.includes(x))) {
|
|
179
|
-
diagnostics.push({ from: n.from, to: n.to, severity: 'error', message: `<code>${typesExpected.join('|')}</code> expected, got <code>${typesUsed.join('|')}</code>` });
|
|
180
|
-
}
|
|
181
|
-
i++;
|
|
182
|
-
}
|
|
183
|
-
break;
|
|
184
|
-
case 'Property':
|
|
185
|
-
case 'Method':
|
|
186
|
-
const leftArgument = (_f = (_e = node.node.parent) === null || _e === void 0 ? void 0 : _e.firstChild) === null || _f === void 0 ? void 0 : _f.node;
|
|
187
|
-
const types = Array.from(resolveTypes(state, leftArgument, config));
|
|
188
|
-
identifier = state.sliceDoc(from, to);
|
|
189
|
-
if (!types.find(type => { var _a; return resolveIdentifier(name, identifier, (_a = config.types) === null || _a === void 0 ? void 0 : _a[type]); })) {
|
|
190
|
-
diagnostics.push({ from, to, severity: 'error', message: `${node.name} "${identifier}" not found in ${types.join('|')}` });
|
|
191
|
-
}
|
|
192
|
-
break;
|
|
193
|
-
case 'Variable':
|
|
194
|
-
case 'Function':
|
|
195
|
-
identifier = state.sliceDoc(from, node.node.firstChild ? node.node.firstChild.from - 1 : to);
|
|
196
|
-
if (!resolveIdentifier(name, identifier, config)) {
|
|
197
|
-
diagnostics.push({ from, to, severity: 'error', message: `${node.node.name} "${identifier}" not found` });
|
|
198
|
-
}
|
|
199
|
-
break;
|
|
200
|
-
}
|
|
201
|
-
if (identifier && ((_g = node.node.parent) === null || _g === void 0 ? void 0 : _g.type.isError)) {
|
|
202
|
-
diagnostics.push({ from, to, severity: 'error', message: `Unexpected identifier "${identifier}"` });
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
diagnostics.forEach(d => {
|
|
206
|
-
d.renderMessage = () => {
|
|
207
|
-
const span = document.createElement('span');
|
|
208
|
-
span.innerHTML = d.message;
|
|
209
|
-
return span;
|
|
210
|
-
};
|
|
211
|
-
});
|
|
212
|
-
return diagnostics;
|
|
213
|
-
};
|
|
214
|
-
const expressionLanguageLinter = linter(view => expressionLanguageLinterSource(view.state));
|
|
215
|
-
|
|
216
|
-
export { expressionLanguageLinter, expressionLanguageLinterSource };
|