@valtzu/codemirror-lang-el 0.6.2 → 0.8.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 +1 -29
- package/dist/complete.cjs +54 -20
- package/dist/complete.js +54 -20
- package/dist/index.cjs +116 -41
- package/dist/index.d.cts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +117 -42
- package/dist/linter.cjs +72 -13
- package/dist/linter.js +72 -13
- package/dist/tooltip.cjs +44 -23
- package/dist/tooltip.d.cts +4 -3
- package/dist/tooltip.d.ts +4 -3
- package/dist/tooltip.js +46 -24
- package/dist/utils.cjs +150 -0
- package/dist/utils.d.cts +53 -0
- package/dist/utils.d.ts +53 -0
- package/dist/utils.js +141 -0
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -14,10 +14,16 @@ interface ELIdentifier {
|
|
|
14
14
|
*/
|
|
15
15
|
interface ELFunction {
|
|
16
16
|
name: string;
|
|
17
|
-
args:
|
|
17
|
+
args: ELParameter[];
|
|
18
18
|
info?: string;
|
|
19
19
|
returnType?: string[];
|
|
20
20
|
}
|
|
21
|
+
interface ELParameter {
|
|
22
|
+
name: string;
|
|
23
|
+
type?: string[];
|
|
24
|
+
info?: string;
|
|
25
|
+
optional?: boolean;
|
|
26
|
+
}
|
|
21
27
|
interface ELType {
|
|
22
28
|
identifiers?: ELIdentifier[];
|
|
23
29
|
functions?: ELFunction[];
|
package/dist/index.d.ts
CHANGED
|
@@ -14,10 +14,16 @@ interface ELIdentifier {
|
|
|
14
14
|
*/
|
|
15
15
|
interface ELFunction {
|
|
16
16
|
name: string;
|
|
17
|
-
args:
|
|
17
|
+
args: ELParameter[];
|
|
18
18
|
info?: string;
|
|
19
19
|
returnType?: string[];
|
|
20
20
|
}
|
|
21
|
+
interface ELParameter {
|
|
22
|
+
name: string;
|
|
23
|
+
type?: string[];
|
|
24
|
+
info?: string;
|
|
25
|
+
optional?: boolean;
|
|
26
|
+
}
|
|
21
27
|
interface ELType {
|
|
22
28
|
identifiers?: ELIdentifier[];
|
|
23
29
|
functions?: ELFunction[];
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LRParser } from '@lezer/lr';
|
|
1
|
+
import { LRParser, LocalTokenGroup } from '@lezer/lr';
|
|
2
2
|
import { syntaxTree, LRLanguage, indentNodeProp, delimitedIndent, foldNodeProp, LanguageSupport } from '@codemirror/language';
|
|
3
3
|
import { styleTags, tags } from '@lezer/highlight';
|
|
4
4
|
import { linter } from '@codemirror/lint';
|
|
@@ -6,25 +6,42 @@ import { insertCompletionText } from '@codemirror/autocomplete';
|
|
|
6
6
|
import { StateField } from '@codemirror/state';
|
|
7
7
|
import { showTooltip, hoverTooltip, EditorView } from '@codemirror/view';
|
|
8
8
|
|
|
9
|
+
// @ts-ignore
|
|
10
|
+
const t = {
|
|
11
|
+
deserialize: (str) => str,
|
|
12
|
+
};
|
|
13
|
+
|
|
9
14
|
// This file was generated by lezer-generator. You probably shouldn't edit it.
|
|
10
|
-
const spec_word = {__proto__:null,true:
|
|
11
|
-
const spec_Operator = {__proto__:null,"?":
|
|
15
|
+
const spec_word = {__proto__:null,true:92, TRUE:94, false:96, FALSE:98, null:100, NULL:102, starts:112, with:114, ends:116, contains:118, matches:120, not:122, in:124, and:126, or:128, xor:130};
|
|
16
|
+
const spec_Operator = {__proto__:null,"?":111, "!":133, "~":135, "+":137, "-":139};
|
|
12
17
|
const parser = LRParser.deserialize({
|
|
13
18
|
version: 14,
|
|
14
|
-
states: "
|
|
15
|
-
stateData: "
|
|
16
|
-
goto: "%
|
|
17
|
-
nodeNames: "⚠ Expression ObjectAccess MemberOf NullSafeMemberOf Property ArrayAccess Call Function Arguments ObjectAccess Method Arguments Number String Boolean Null Object Array Variable TernaryExpression Operator BinaryExpression OperatorKeyword UnaryExpression UnaryOperator Application",
|
|
18
|
-
maxTerm:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
states: ")rOYQPOOP!aOPOOQ!fQPOOO#dQPO'#CeO$wQPO'#CnO%OQPO'#CoOYQPO'#CuOYQPO'#CwOOQO'#DS'#DSO%VQPO'#CdO%[QPO'#CdOOQO'#Cl'#ClOOQO'#Cm'#CmOOQO'#Cv'#CvP%aOQO'#C]POOO)C>r)C>rO%lQPO,58yOYQPO,58}OYQPO,59_OYQPO,59]O%qQPO'#CtOOQO'#Ct'#CtO%vQPO'#CtO'QQPO,59YOOQO,59Y,59YO'XQPO'#DYO'fQPO,59ZO'kQPO,59aO(RQPO,59cO(YQPO'#CfOOQO,59O,59OO(YQPO'#CiPOOO'#Cx'#CxP(aOQO,58wPOOO,58w,58wO(lQPO'#CbOOQO1G.e1G.eOOQO1G.m1G.mO*PQPO1G.iO*WQPO1G.yO*nQPO1G.wOOQO,59`,59`OYQPO1G.tOYQPO'#CyO*uQPO,59tOOQO1G.u1G.uOOQO1G.}1G.}O+QQPO,59QO+VQPO,59TPOOO-E6v-E6vPOOO1G.c1G.cOOQO7+$T7+$TOYQPO7+$cO+[QPO7+$`O+fQPO,59eOOQO-E6w-E6wOOQO1G.l1G.lOOQO1G.o1G.oO+sQPO<<G}OYQPO'#CzO,ZQPO<<GzOOQO<<Gz<<GzO,cQPO,59fOOQO-E6x-E6xOOQOAN=fAN=fOYQPO1G/QO,jQPO7+$l",
|
|
20
|
+
stateData: ",|~OqOSrPQ~O^WO_WOwROyTO{VO!OZO!PZO!QZO!RZO!S[O!T[O!VSO!_]O!d]O!e]O!f]O!g]O~Or^O~OS`OT`OfbOyaO!XcO!YdO![dO!]eO!^eO!_fO!`eO!aeO!beO!ceO~OSdXTdXfdXodXydX{XX!XdX!YdX![dX!]dX!^dX!_dX!`dX!adX!bdX!cdX!WdXxdX}dXzdX!UdX~O!UhO~PYOx|P~PYO{mO~O{oO~OspOtpOurO~OwsO~O!ZyO~O!`yO^hX_hXwhXyhX{hX!OhX!PhX!QhX!RhX!ShX!ThX!VhX!_hX!dhX!ehX!fhX!ghX~O!WzO~P!fO}{Ox|Xz|X~P!fOx}O~Ooia!Wiaxia}iazia!Uia~P!fOz!OO~P!fOz|P~PYOspOtpOu!SO~OSUXTUXfUXoUXyUX{[X!XUX!YUX![UX!]UX!^UX!_UX!`UX!aUX!bUX!cUX!WUXxUX}UXzUX!UUX~Ox!TO~P!fOogi!Wgixgi}gizgi!Ugi~P!fO!W!UO~P!fO}{Ox|az|a~Oz!YO~Oz!ZO~O}!]O!U!_O~P!fOxma}mazma~P!fOoey!Weyxey}eyzey!Uey~P!fO}!]O!U!bO~O!W!cO~P!fO}nq!Unq~P!fO_TfS^wS~",
|
|
21
|
+
goto: "%l}P!OP!RPP!d!R!R!g!x!{#^#aPP!R!R!R!R!R!RP!R#d!R#s!R$U$[$bPPPPPPP$hPPPPP%cR_PoWOSTUVabcmoz{!U!]!cRt`oXOSTUVabcmoz{!U!]!cRnXoYOSTUVabcmoz{!U!]!cRu`RnYkbQgiklvwx!V!W![!`!doUOSTUVabcmoz{!U!]!cQq^R!RqQ|iR!X|Q!^!VR!a!^QQOQgSUiTmoQkUQlVQvaQwbQxcQ!VzQ!W{Q![!UQ!`!]R!d!cQjTQ!PmR!Qo",
|
|
22
|
+
nodeNames: "⚠ BlockComment Expression ObjectAccess MemberOf NullSafeMemberOf Property ArrayAccess Call Function Arguments ObjectAccess Method Arguments Number String Boolean Null Object Array Variable TernaryExpression Operator BinaryExpression OperatorKeyword UnaryExpression UnaryOperator Application",
|
|
23
|
+
maxTerm: 69,
|
|
24
|
+
nodeProps: [
|
|
25
|
+
[t, 14,"number",15,"string",16,"bool",17,"null",18,"object",19,"array"]
|
|
26
|
+
],
|
|
27
|
+
skippedNodes: [0,1,28],
|
|
28
|
+
repeatNodeCount: 3,
|
|
29
|
+
tokenData: "-a~RqXY#YYZ#Y]^#Ypq#Yqr#krs$Quv#{vw%zwx&Sxy'wyz'|z{(R{|#{|}(Z}!O#{!O!P(`!P!Q(h!Q![(u![!]+[!^!_+a!_!`+l!`!a+r!a!b+}!c!},b!}#O,s#P#Q,x#Q#R#{#R#S,b#T#o,b#o#p,}#p#q-S#q#r-[#r#s#{~#_Sq~XY#YYZ#Y]^#Ypq#Y~#pPf~!_!`#s~#xPf~!_!`#{~$QOf~~$TXOr$Qrs$ps#O$Q#O#P$u#P;'S$Q;'S;=`%t<%l~$Q~O$Q~~$p~$uO_~~$xRO;'S$Q;'S;=`%R;=`O$Q~%UYOr$Qrs$ps#O$Q#O#P$u#P;'S$Q;'S;=`%t;=`<%l$Q<%l~$Q~O$Q~~$p~%wP;=`<%l$Q~&PPf~vw#{~&VXOw&Swx$px#O&S#O#P&r#P;'S&S;'S;=`'q<%l~&S~O&S~~$p~&uRO;'S&S;'S;=`'O;=`O&S~'RYOw&Swx$px#O&S#O#P&r#P;'S&S;'S;=`'q;=`<%l&S<%l~&S~O&S~~$p~'tP;=`<%l&S~'|O{~~(ROz~~(WPf~z{#{~(`O}~~(ePS~!O!P#{~(mPf~z{(p~(uOr~~(zT^~!O!P)Z!Q![(u!g!h*Z#R#S+U#X#Y*Z~)^SO!O)j!P;'S)j;'S;=`+O<%lO)j~)oR^~!Q![)x!g!h*Z#X#Y*Z~)}S^~!Q![)x!g!h*Z#R#S*x#X#Y*Z~*^R{|*g}!O*g!Q![*m~*jP!Q![*m~*rQ^~!Q![*m#R#S*g~*{P!Q![)x~+RP;=`<%l)j~+XP!Q![(u~+aO!W~~+fQf~!^!_#{!_!`#{~+oP!_!`#s~+wQf~!_!`#{!`!a#{~,SRf~!O!P,]![!]#{!a!b#{~,bOT~~,gSw~!Q![,b!c!},b#R#S,b#T#o,b~,xOy~~,}Ox~~-SO!V~~-XPf~#p#q#{~-aO!U~",
|
|
30
|
+
tokenizers: [1, new LocalTokenGroup("j~RQYZXz{^~^Ot~~aP!P!Qd~iOu~~", 25, 35)],
|
|
31
|
+
topRules: {"Expression":[0,2]},
|
|
32
|
+
specialized: [{term: 39, get: (value) => spec_word[value] || -1},{term: 22, get: (value) => spec_Operator[value] || -1}],
|
|
33
|
+
tokenPrec: 542
|
|
26
34
|
});
|
|
27
35
|
|
|
36
|
+
var ELScalar;
|
|
37
|
+
(function (ELScalar) {
|
|
38
|
+
ELScalar["Bool"] = "bool";
|
|
39
|
+
ELScalar["Number"] = "number";
|
|
40
|
+
ELScalar["String"] = "string";
|
|
41
|
+
ELScalar["Null"] = "null";
|
|
42
|
+
ELScalar["Any"] = "any";
|
|
43
|
+
})(ELScalar || (ELScalar = {}));
|
|
44
|
+
|
|
28
45
|
const createInfoElement = (html) => {
|
|
29
46
|
const dom = document.createElement("div");
|
|
30
47
|
dom.innerHTML = html;
|
|
@@ -61,12 +78,16 @@ const resolveIdentifier = (nodeName, identifier, config) => {
|
|
|
61
78
|
}
|
|
62
79
|
};
|
|
63
80
|
function resolveTypes(state, node, config, matchExact) {
|
|
64
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
81
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
65
82
|
let types = new Set();
|
|
66
83
|
if (!node) {
|
|
67
84
|
return types;
|
|
68
85
|
}
|
|
69
|
-
|
|
86
|
+
let type;
|
|
87
|
+
if (typeof (type = node.type.prop(t)) !== "undefined") {
|
|
88
|
+
types.add(type);
|
|
89
|
+
}
|
|
90
|
+
else if (node.name === 'Call' && node.firstChild && node.lastChild) {
|
|
70
91
|
resolveTypes(state, node.firstChild, config).forEach(x => types.add(x));
|
|
71
92
|
}
|
|
72
93
|
else if (node.name === 'Variable') {
|
|
@@ -102,17 +123,32 @@ function resolveTypes(state, node, config, matchExact) {
|
|
|
102
123
|
resolveTypes(state, node.firstChild.nextSibling, config).forEach(x => types.add(x));
|
|
103
124
|
resolveTypes(state, node.firstChild.nextSibling.nextSibling, config).forEach(x => types.add(x));
|
|
104
125
|
}
|
|
105
|
-
else if (node.name === 'BinaryExpression' && ((
|
|
126
|
+
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)) {
|
|
106
127
|
const operator = state.sliceDoc(node.firstChild.nextSibling.from, node.firstChild.nextSibling.to);
|
|
107
|
-
if (operator == '?:' || operator == '??') {
|
|
108
|
-
resolveTypes(state, node.firstChild, config).forEach(x => types.add(x));
|
|
109
|
-
}
|
|
110
128
|
if (operator == '?:' || operator == '??' || operator == '?') {
|
|
111
|
-
|
|
129
|
+
if (operator == '?:' || operator == '??') {
|
|
130
|
+
resolveTypes(state, node.firstChild, config).forEach(x => types.add(x));
|
|
131
|
+
}
|
|
132
|
+
resolveTypes(state, node.firstChild.nextSibling.nextSibling, config).forEach(x => types.add(x));
|
|
133
|
+
}
|
|
134
|
+
else if (['||', '&&', '==', '!=', '===', '!==', '>=', '<=', '>', '<'].includes(operator) || keywords.find(x => x.name == operator)) {
|
|
135
|
+
types.add(ELScalar.Bool);
|
|
136
|
+
}
|
|
137
|
+
else if (['**', '|', '^', '&', '<<', '>>', '+', '-', '*', '/', '%'].includes(operator)) {
|
|
138
|
+
types.add(ELScalar.Number);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
else if (node.name === 'UnaryExpression' && node.firstChild) {
|
|
142
|
+
const operator = state.sliceDoc(node.firstChild.from, node.firstChild.to);
|
|
143
|
+
if (['not', '!'].includes(operator)) {
|
|
144
|
+
types.add(ELScalar.Bool);
|
|
145
|
+
}
|
|
146
|
+
else if (['+', '-'].includes(operator)) {
|
|
147
|
+
types.add(ELScalar.Number);
|
|
112
148
|
}
|
|
113
149
|
}
|
|
114
150
|
if (types.size === 0) {
|
|
115
|
-
types.add(
|
|
151
|
+
types.add(ELScalar.Any);
|
|
116
152
|
}
|
|
117
153
|
return types;
|
|
118
154
|
}
|
|
@@ -129,6 +165,7 @@ const keywords = [
|
|
|
129
165
|
{ name: 'not' },
|
|
130
166
|
{ name: 'or' },
|
|
131
167
|
{ name: 'and' },
|
|
168
|
+
{ name: 'xor' },
|
|
132
169
|
];
|
|
133
170
|
|
|
134
171
|
/**
|
|
@@ -161,13 +198,20 @@ const expressionLanguageLinterSource = (state) => {
|
|
|
161
198
|
if (!args) {
|
|
162
199
|
return;
|
|
163
200
|
}
|
|
164
|
-
let i = 0;
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
201
|
+
for (let n = node.node.firstChild, i = 0; n != null; n = n.nextSibling) {
|
|
202
|
+
if (n.name === 'BlockComment') {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
if (i > args.length - 1) {
|
|
168
206
|
diagnostics.push({ from: n.from, to: n.to, severity: 'error', message: `Unexpected argument` });
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
const typesUsed = Array.from(resolveTypes(state, n, config));
|
|
210
|
+
const typesExpected = args[i].type;
|
|
211
|
+
if (typesExpected && !typesExpected.includes(ELScalar.Any) && !typesUsed.some(x => typesExpected.includes(x))) {
|
|
212
|
+
diagnostics.push({ from: n.from, to: n.to, severity: 'error', message: `<code>${typesExpected.join('|')}</code> expected, got <code>${typesUsed.join('|')}</code>` });
|
|
169
213
|
}
|
|
170
|
-
|
|
214
|
+
i++;
|
|
171
215
|
}
|
|
172
216
|
break;
|
|
173
217
|
case 'Property':
|
|
@@ -191,20 +235,27 @@ const expressionLanguageLinterSource = (state) => {
|
|
|
191
235
|
diagnostics.push({ from, to, severity: 'error', message: `Unexpected identifier "${identifier}"` });
|
|
192
236
|
}
|
|
193
237
|
});
|
|
238
|
+
diagnostics.forEach(d => {
|
|
239
|
+
d.renderMessage = () => {
|
|
240
|
+
const span = document.createElement('span');
|
|
241
|
+
span.innerHTML = d.message;
|
|
242
|
+
return span;
|
|
243
|
+
};
|
|
244
|
+
});
|
|
194
245
|
return diagnostics;
|
|
195
246
|
};
|
|
196
247
|
const expressionLanguageLinter = linter(view => expressionLanguageLinterSource(view.state));
|
|
197
248
|
|
|
198
249
|
const autocompleteFunction = (x) => {
|
|
199
|
-
var _a, _b;
|
|
250
|
+
var _a, _b, _c;
|
|
200
251
|
return ({
|
|
201
|
-
label: `${x.name}(${((_a = x.args) === null || _a === void 0 ? void 0 : _a.join(',')) || ''})`,
|
|
252
|
+
label: `${x.name}(${((_b = (_a = x.args) === null || _a === void 0 ? void 0 : _a.map(x => x.name)) === null || _b === void 0 ? void 0 : _b.join(',')) || ''})`,
|
|
202
253
|
apply: (view, completion, from, to) => {
|
|
203
254
|
var _a;
|
|
204
255
|
view.dispatch(Object.assign(Object.assign({}, insertCompletionText(view.state, `${x.name}()`, from, to)), { selection: { anchor: from + x.name.length + (((_a = x.args) === null || _a === void 0 ? void 0 : _a.length) > 0 ? 1 : 2) } }));
|
|
205
256
|
},
|
|
206
|
-
detail: (
|
|
207
|
-
info:
|
|
257
|
+
detail: (_c = x.returnType) === null || _c === void 0 ? void 0 : _c.join('|'),
|
|
258
|
+
info: x.info,
|
|
208
259
|
type: "function",
|
|
209
260
|
});
|
|
210
261
|
};
|
|
@@ -213,7 +264,7 @@ const autocompleteIdentifier = (x) => {
|
|
|
213
264
|
return ({
|
|
214
265
|
label: x.name,
|
|
215
266
|
apply: x.name,
|
|
216
|
-
info:
|
|
267
|
+
info: x.info,
|
|
217
268
|
detail: x.detail || ((_a = x.type) === null || _a === void 0 ? void 0 : _a.join('|')),
|
|
218
269
|
type: 'variable',
|
|
219
270
|
});
|
|
@@ -223,7 +274,13 @@ function completeOperatorKeyword(state, config, tree, from, to, explicit) {
|
|
|
223
274
|
return {
|
|
224
275
|
from,
|
|
225
276
|
to,
|
|
226
|
-
options: (_a = keywords.map(({ name, info, detail }) => ({
|
|
277
|
+
options: (_a = keywords.map(({ name, info, detail }) => ({
|
|
278
|
+
label: name,
|
|
279
|
+
apply: `${name} `,
|
|
280
|
+
info: info,
|
|
281
|
+
detail,
|
|
282
|
+
type: "keyword"
|
|
283
|
+
}))) !== null && _a !== void 0 ? _a : [],
|
|
227
284
|
validFor: (text) => { var _a; return (_a = keywords.some(({ name }) => explicit || name.includes(text))) !== null && _a !== void 0 ? _a : false; },
|
|
228
285
|
};
|
|
229
286
|
}
|
|
@@ -268,7 +325,7 @@ function expressionLanguageCompletion(context) {
|
|
|
268
325
|
const config = getExpressionLanguageConfig(state);
|
|
269
326
|
const isIdentifier = (node) => { var _a; return ['Variable', 'Function'].includes((_a = node === null || node === void 0 ? void 0 : node.name) !== null && _a !== void 0 ? _a : ''); };
|
|
270
327
|
const isMember = (node) => { var _a; return ['Property', 'Method'].includes((_a = node === null || node === void 0 ? void 0 : node.name) !== null && _a !== void 0 ? _a : ''); };
|
|
271
|
-
if (prevNode.name == 'String') {
|
|
328
|
+
if (prevNode.name == 'String' || prevNode.name == 'BlockComment') {
|
|
272
329
|
return null;
|
|
273
330
|
}
|
|
274
331
|
if (((_a = prevNode.parent) === null || _a === void 0 ? void 0 : _a.name) == 'ObjectAccess' && ['ObjectAccess', 'ArrayAccess', 'Variable', 'Call', 'Application'].includes(((_b = prevNode.parent.firstChild) === null || _b === void 0 ? void 0 : _b.name) || '')) {
|
|
@@ -308,7 +365,7 @@ function getCursorTooltips(state) {
|
|
|
308
365
|
return state.selection.ranges
|
|
309
366
|
.filter(range => range.empty)
|
|
310
367
|
.map(range => {
|
|
311
|
-
var _a;
|
|
368
|
+
var _a, _b;
|
|
312
369
|
const tree = syntaxTree(state);
|
|
313
370
|
const node = tree.resolveInner(range.from, 0);
|
|
314
371
|
const args = resolveArguments(node);
|
|
@@ -320,7 +377,7 @@ function getCursorTooltips(state) {
|
|
|
320
377
|
return null;
|
|
321
378
|
}
|
|
322
379
|
const n = args.childAfter(range.from - 1);
|
|
323
|
-
const argName = (_a = fn.args) === null || _a === void 0 ? void 0 : _a[n ? getNodeOrdinal(n) : 0];
|
|
380
|
+
const argName = (_b = (_a = fn.args) === null || _a === void 0 ? void 0 : _a[n ? getNodeOrdinal(n) : 0]) === null || _b === void 0 ? void 0 : _b.name;
|
|
324
381
|
if (n && n.from !== range.from || !argName) {
|
|
325
382
|
return null;
|
|
326
383
|
}
|
|
@@ -395,17 +452,34 @@ const keywordTooltip = hoverTooltip((view, pos, side) => {
|
|
|
395
452
|
create: () => ({ dom: createInfoElement(info) }),
|
|
396
453
|
};
|
|
397
454
|
});
|
|
398
|
-
|
|
455
|
+
|
|
456
|
+
const baseTheme = EditorView.baseTheme({
|
|
399
457
|
".cm-tooltip.cm-tooltip-cursor": {
|
|
400
458
|
boxShadow: 'rgba(0, 0, 0, .15) 0 1px 2px',
|
|
401
459
|
border: "1px solid rgba(127, 127, 127, .2)",
|
|
402
|
-
|
|
460
|
+
fontSize: ".85rem",
|
|
461
|
+
padding: ".4rem .5rem",
|
|
403
462
|
borderRadius: "4px",
|
|
404
463
|
"& .cm-tooltip-arrow:before": {},
|
|
405
464
|
"& .cm-tooltip-arrow:after": {
|
|
406
465
|
borderTopColor: "transparent"
|
|
407
|
-
}
|
|
408
|
-
}
|
|
466
|
+
},
|
|
467
|
+
},
|
|
468
|
+
".cm-tooltip.cm-completionInfo, .cm-diagnostic": {
|
|
469
|
+
boxShadow: "rgba(0, 0, 0, .15) 0 2px 5px",
|
|
470
|
+
fontSize: ".85rem",
|
|
471
|
+
padding: ".8rem !important", // Couldn't figure out other means to override https://github.com/codemirror/autocomplete/blob/6.18.1/src/theme.ts#L65
|
|
472
|
+
},
|
|
473
|
+
".cm-completionDetail": {
|
|
474
|
+
float: "right",
|
|
475
|
+
opacity: 0.5,
|
|
476
|
+
fontStyle: "inherit !important",
|
|
477
|
+
},
|
|
478
|
+
"code": {
|
|
479
|
+
fontSize: ".8em",
|
|
480
|
+
fontStyle: "monospace",
|
|
481
|
+
backgroundColor: "rgba(127, 127, 127, .3)",
|
|
482
|
+
},
|
|
409
483
|
});
|
|
410
484
|
|
|
411
485
|
const ELLanguage = LRLanguage.define({
|
|
@@ -439,6 +513,7 @@ const ELLanguage = LRLanguage.define({
|
|
|
439
513
|
OperatorKeyword: tags.operatorKeyword,
|
|
440
514
|
UnaryOperator: tags.operator,
|
|
441
515
|
Operator: tags.operator,
|
|
516
|
+
BlockComment: tags.comment,
|
|
442
517
|
})
|
|
443
518
|
]
|
|
444
519
|
}),
|
|
@@ -453,7 +528,7 @@ function expressionlanguage(config = {}, extensions = []) {
|
|
|
453
528
|
expressionLanguageLinter,
|
|
454
529
|
keywordTooltip,
|
|
455
530
|
cursorTooltipField,
|
|
456
|
-
|
|
531
|
+
baseTheme,
|
|
457
532
|
...extensions,
|
|
458
533
|
]);
|
|
459
534
|
}
|
package/dist/linter.cjs
CHANGED
|
@@ -5,6 +5,20 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
var lint = require('@codemirror/lint');
|
|
6
6
|
var language = require('@codemirror/language');
|
|
7
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
|
+
|
|
8
22
|
function resolveFunctionDefinition(node, state, config) {
|
|
9
23
|
var _a;
|
|
10
24
|
if (!node) {
|
|
@@ -35,12 +49,16 @@ const resolveIdentifier = (nodeName, identifier, config) => {
|
|
|
35
49
|
}
|
|
36
50
|
};
|
|
37
51
|
function resolveTypes(state, node, config, matchExact) {
|
|
38
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
52
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
39
53
|
let types = new Set();
|
|
40
54
|
if (!node) {
|
|
41
55
|
return types;
|
|
42
56
|
}
|
|
43
|
-
|
|
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) {
|
|
44
62
|
resolveTypes(state, node.firstChild, config).forEach(x => types.add(x));
|
|
45
63
|
}
|
|
46
64
|
else if (node.name === 'Variable') {
|
|
@@ -76,23 +94,50 @@ function resolveTypes(state, node, config, matchExact) {
|
|
|
76
94
|
resolveTypes(state, node.firstChild.nextSibling, config).forEach(x => types.add(x));
|
|
77
95
|
resolveTypes(state, node.firstChild.nextSibling.nextSibling, config).forEach(x => types.add(x));
|
|
78
96
|
}
|
|
79
|
-
else if (node.name === 'BinaryExpression' && ((
|
|
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)) {
|
|
80
98
|
const operator = state.sliceDoc(node.firstChild.nextSibling.from, node.firstChild.nextSibling.to);
|
|
81
|
-
if (operator == '?:' || operator == '??') {
|
|
82
|
-
resolveTypes(state, node.firstChild, config).forEach(x => types.add(x));
|
|
83
|
-
}
|
|
84
99
|
if (operator == '?:' || operator == '??' || operator == '?') {
|
|
85
|
-
|
|
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);
|
|
86
119
|
}
|
|
87
120
|
}
|
|
88
121
|
if (types.size === 0) {
|
|
89
|
-
types.add(
|
|
122
|
+
types.add(ELScalar.Any);
|
|
90
123
|
}
|
|
91
124
|
return types;
|
|
92
125
|
}
|
|
93
126
|
function getExpressionLanguageConfig(state) {
|
|
94
127
|
return state.languageDataAt('expressionLanguageConfig', 0)[0];
|
|
95
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
|
+
];
|
|
96
141
|
|
|
97
142
|
/**
|
|
98
143
|
* @internal
|
|
@@ -124,13 +169,20 @@ const expressionLanguageLinterSource = (state) => {
|
|
|
124
169
|
if (!args) {
|
|
125
170
|
return;
|
|
126
171
|
}
|
|
127
|
-
let i = 0;
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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) {
|
|
131
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>` });
|
|
132
184
|
}
|
|
133
|
-
|
|
185
|
+
i++;
|
|
134
186
|
}
|
|
135
187
|
break;
|
|
136
188
|
case 'Property':
|
|
@@ -154,6 +206,13 @@ const expressionLanguageLinterSource = (state) => {
|
|
|
154
206
|
diagnostics.push({ from, to, severity: 'error', message: `Unexpected identifier "${identifier}"` });
|
|
155
207
|
}
|
|
156
208
|
});
|
|
209
|
+
diagnostics.forEach(d => {
|
|
210
|
+
d.renderMessage = () => {
|
|
211
|
+
const span = document.createElement('span');
|
|
212
|
+
span.innerHTML = d.message;
|
|
213
|
+
return span;
|
|
214
|
+
};
|
|
215
|
+
});
|
|
157
216
|
return diagnostics;
|
|
158
217
|
};
|
|
159
218
|
const expressionLanguageLinter = lint.linter(view => expressionLanguageLinterSource(view.state));
|
package/dist/linter.js
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import { linter } from '@codemirror/lint';
|
|
2
2
|
import { syntaxTree } from '@codemirror/language';
|
|
3
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
|
+
|
|
4
18
|
function resolveFunctionDefinition(node, state, config) {
|
|
5
19
|
var _a;
|
|
6
20
|
if (!node) {
|
|
@@ -31,12 +45,16 @@ const resolveIdentifier = (nodeName, identifier, config) => {
|
|
|
31
45
|
}
|
|
32
46
|
};
|
|
33
47
|
function resolveTypes(state, node, config, matchExact) {
|
|
34
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
48
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
35
49
|
let types = new Set();
|
|
36
50
|
if (!node) {
|
|
37
51
|
return types;
|
|
38
52
|
}
|
|
39
|
-
|
|
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) {
|
|
40
58
|
resolveTypes(state, node.firstChild, config).forEach(x => types.add(x));
|
|
41
59
|
}
|
|
42
60
|
else if (node.name === 'Variable') {
|
|
@@ -72,23 +90,50 @@ function resolveTypes(state, node, config, matchExact) {
|
|
|
72
90
|
resolveTypes(state, node.firstChild.nextSibling, config).forEach(x => types.add(x));
|
|
73
91
|
resolveTypes(state, node.firstChild.nextSibling.nextSibling, config).forEach(x => types.add(x));
|
|
74
92
|
}
|
|
75
|
-
else if (node.name === 'BinaryExpression' && ((
|
|
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)) {
|
|
76
94
|
const operator = state.sliceDoc(node.firstChild.nextSibling.from, node.firstChild.nextSibling.to);
|
|
77
|
-
if (operator == '?:' || operator == '??') {
|
|
78
|
-
resolveTypes(state, node.firstChild, config).forEach(x => types.add(x));
|
|
79
|
-
}
|
|
80
95
|
if (operator == '?:' || operator == '??' || operator == '?') {
|
|
81
|
-
|
|
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);
|
|
82
115
|
}
|
|
83
116
|
}
|
|
84
117
|
if (types.size === 0) {
|
|
85
|
-
types.add(
|
|
118
|
+
types.add(ELScalar.Any);
|
|
86
119
|
}
|
|
87
120
|
return types;
|
|
88
121
|
}
|
|
89
122
|
function getExpressionLanguageConfig(state) {
|
|
90
123
|
return state.languageDataAt('expressionLanguageConfig', 0)[0];
|
|
91
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
|
+
];
|
|
92
137
|
|
|
93
138
|
/**
|
|
94
139
|
* @internal
|
|
@@ -120,13 +165,20 @@ const expressionLanguageLinterSource = (state) => {
|
|
|
120
165
|
if (!args) {
|
|
121
166
|
return;
|
|
122
167
|
}
|
|
123
|
-
let i = 0;
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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) {
|
|
127
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>` });
|
|
128
180
|
}
|
|
129
|
-
|
|
181
|
+
i++;
|
|
130
182
|
}
|
|
131
183
|
break;
|
|
132
184
|
case 'Property':
|
|
@@ -150,6 +202,13 @@ const expressionLanguageLinterSource = (state) => {
|
|
|
150
202
|
diagnostics.push({ from, to, severity: 'error', message: `Unexpected identifier "${identifier}"` });
|
|
151
203
|
}
|
|
152
204
|
});
|
|
205
|
+
diagnostics.forEach(d => {
|
|
206
|
+
d.renderMessage = () => {
|
|
207
|
+
const span = document.createElement('span');
|
|
208
|
+
span.innerHTML = d.message;
|
|
209
|
+
return span;
|
|
210
|
+
};
|
|
211
|
+
});
|
|
153
212
|
return diagnostics;
|
|
154
213
|
};
|
|
155
214
|
const expressionLanguageLinter = linter(view => expressionLanguageLinterSource(view.state));
|