@valtzu/codemirror-lang-el 0.2.3 → 0.3.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/README.md CHANGED
@@ -8,37 +8,48 @@
8
8
  ```html
9
9
  <div id="editor"></div>
10
10
  <script type="importmap">
11
- {
12
- "imports": {
13
- "codemirror": "https://esm.sh/codemirror@6.0.1",
14
- "@codemirror/autocomplete": "https://esm.sh/@codemirror/autocomplete@6.9.0",
15
- "@codemirror/view": "https://esm.sh/@codemirror/view@6.17.1",
16
- "@valtzu/codemirror-lang-el": "https://esm.sh/@valtzu/codemirror-lang-el@0.2.3"
17
- }
18
- }
11
+ {
12
+ "imports": {
13
+ "codemirror": "https://esm.sh/*codemirror@6.0.1",
14
+ "@codemirror/state": "https://esm.sh/*@codemirror/state@6.4.1",
15
+ "@codemirror/search": "https://esm.sh/*@codemirror/search@6.5.6",
16
+ "@codemirror/autocomplete": "https://esm.sh/*@codemirror/autocomplete@6.9.0",
17
+ "@codemirror/view": "https://esm.sh/*@codemirror/view@6.17.1",
18
+ "@codemirror/commands": "https://esm.sh/*@codemirror/commands@6.2.5",
19
+ "@codemirror/language": "https://esm.sh/*@codemirror/language@6.9.0",
20
+ "@codemirror/lint": "https://esm.sh/*@codemirror/lint@6.4.1",
21
+ "@lezer/lr": "https://esm.sh/*@lezer/lr@1.3.9",
22
+ "@lezer/highlight": "https://esm.sh/*@lezer/highlight@1.1.6",
23
+ "@lezer/common": "https://esm.sh/*@lezer/common@1.2.1",
24
+ "style-mod": "https://esm.sh/*style-mod@4.1.2",
25
+ "w3c-keyname": "https://esm.sh/*w3c-keyname@2.2.8",
26
+ "crelt": "https://esm.sh/*crelt@1.0.6",
27
+ "@valtzu/codemirror-lang-el": "https://esm.sh/*@valtzu/codemirror-lang-el@0.2.3"
28
+ }
29
+ }
19
30
  </script>
20
31
  <script type="module">
21
- import {EditorView, basicSetup} from "codemirror";
22
- import { expressionlanguage } from "@valtzu/codemirror-lang-el";
23
- import {acceptCompletion} from "@codemirror/autocomplete";
24
- import {keymap} from "@codemirror/view";
32
+ import { EditorView, basicSetup } from "codemirror";
33
+ import { acceptCompletion } from "@codemirror/autocomplete";
34
+ import { keymap } from "@codemirror/view";
35
+ import { expressionlanguage } from "@valtzu/codemirror-lang-el";
25
36
 
26
- let editor = new EditorView({
27
- extensions: [
28
- basicSetup,
29
- keymap.of([{key: "Tab", run: acceptCompletion}]),
30
- expressionlanguage({
31
- identifiers: [
32
- { name: 'foo', info: 'Foo is a variable' },
33
- { name: 'bar' }
34
- ],
35
- functions: [
36
- { name: 'smh' },
37
- { name: 'smash_my_head', args: ['object'] },
38
- ],
39
- })
40
- ],
41
- parent: document.getElementById('editor'),
42
- });
37
+ let editor = new EditorView({
38
+ extensions: [
39
+ basicSetup,
40
+ keymap.of([{key: "Tab", run: acceptCompletion}]),
41
+ expressionlanguage({
42
+ identifiers: [
43
+ { name: 'foo', info: 'Foo is a variable' },
44
+ { name: 'bar' }
45
+ ],
46
+ functions: [
47
+ { name: 'smh' },
48
+ { name: 'smash_my_head', args: ['object'], info: 'This is a function' },
49
+ ],
50
+ })
51
+ ],
52
+ parent: document.getElementById('editor'),
53
+ });
43
54
  </script>
44
55
  ```
package/dist/index.cjs CHANGED
@@ -11,7 +11,7 @@ var view = require('@codemirror/view');
11
11
  // This file was generated by lezer-generator. You probably shouldn't edit it.
12
12
  const parser = lr.LRParser.deserialize({
13
13
  version: 14,
14
- states: "$nQVQPOOO!QQQO'#ChO!VQPO'#CjO!^QPO'#CmOOQO'#Cs'#CsOOQO'#Cn'#CnQVQPOOO!eQQO,59SOOQO,59U,59UO!jQPO,59UOOQO,59X,59XO!rQPO,59XOOQO-E6l-E6lOVQPO1G.nOVQPO'#CoO!yQPO1G.pOOQO1G.p1G.pOOQO1G.s1G.sO#RQPO7+$YOOQO,59Z,59ZOOQO-E6m-E6mOOQO7+$[7+$[OOQO<<Gt<<GtO#ZQQO<<GtO#`QQOAN=`OVQPOG22zO#eQPOLD(fOOQO!$'LQ!$'LQ",
14
+ states: "$nQVQPOOO!QQQO'#ChO!VQPO'#CjO!^QPO'#CmOOQO'#Cs'#CsOOQO'#Cn'#CnQVQPOOO!eQQO,59SOOQO,59U,59UO!jQQO,59UOOQO,59X,59XO!rQPO,59XOOQO-E6l-E6lOVQPO1G.nOVQPO'#CoO!yQQO1G.pOOQO1G.p1G.pOOQO1G.s1G.sO#RQQO7+$YOOQO,59Z,59ZOOQO-E6m-E6mOOQO7+$[7+$[OOQO<<Gt<<GtO#ZQQO<<GtO#`QQOAN=`OVQPOG22zO#eQPOLD(fOOQO!$'LQ!$'LQ",
15
15
  stateData: "#r~OfOS~OQSORSOSSOTSOUSOVSOWSOXSOYSOZSO`ROiPOmQO~O]VO~OlWO~PVO_YO~PVOj]O~Ok^Ol`O~O_aO~PVOk^OleO~OhfOkgO~O]hO~OjiO~OhkO~OQUTXWRW~",
16
16
  goto: "!ghPPPPPPPPPPPPiPiPPis}PPP!TaSOQRUZ]^iQUOQZRT[UZQ_XRd_WTORUZQXQQb]Qc^Rji",
17
17
  nodeNames: "⚠ Program Number Identifier String Boolean Null Operator OperatorKeyword Punctuation NullSafe NullCoalescing Object ObjectKey Array ClosingBracket OpeningBracket Application",
@@ -22,7 +22,7 @@ const parser = lr.LRParser.deserialize({
22
22
  ],
23
23
  skippedNodes: [0],
24
24
  repeatNodeCount: 2,
25
- tokenData: "By~R!QXY$XYZ$X]^$Xpq$Xqr$jrs%Puv$zvw&{wx'Txy(xyz(}z{)S{|$z|})[}!O$z!O!P)a!P!Q$z!Q![*r![!],R!^!_$r!_!`,Y!`!a$r!a!b,`!c!},u!}#O-Y#P#Q-_#Q#R$z#R#S,u#T#U-d#U#V,u#V#W.}#W#X,u#X#Y2q#Y#Z5e#Z#],u#]#^8P#^#a,u#a#b8j#b#c;Y#c#d>s#d#g,u#g#h?^#h#iAc#i#o,u#o#pBg#p#qBl#q#rBt#r#s$z~$^Sf~XY$XYZ$X]^$Xpq$X~$oPV~!_!`$r~$wPV~!_!`$z~%POV~R%SXOr%Prs%os#O%P#O#P%v#P;'S%P;'S;=`&u<%l~%P~O%P~~%oR%vO]QSPR%yRO;'S%P;'S;=`&S;=`O%PR&VYOr%Prs%os#O%P#O#P%v#P;'S%P;'S;=`&u;=`<%l%P<%l~%P~O%P~~%oR&xP;=`<%l%P~'QPV~vw$zR'WXOw'Twx%ox#O'T#O#P's#P;'S'T;'S;=`(r<%l~'T~O'T~~%oR'vRO;'S'T;'S;=`(P;=`O'TR(SYOw'Twx%ox#O'T#O#P's#P;'S'T;'S;=`(r;=`<%l'T<%l~'T~O'T~~%oR(uP;=`<%l'T~(}O`~~)SO_~~)XPV~z{$z~)aOk~~)fQXP!O!P$z!Q![)l~)qSQ~!Q![)l!g!h)}#R#S*l#X#Y)}~*QR{|*Z}!O*Z!Q![*a~*^P!Q![*a~*fQQ~!Q![*a#R#S*Z~*oP!Q![)l~*wTQ~!O!P+W!Q![*r!g!h)}#R#S+{#X#Y)}~+ZSO!O+g!P;'S+g;'S;=`+u<%lO+g~+lRQ~!Q![)l!g!h)}#X#Y)}~+xP;=`<%l+g~,OP!Q![*rR,YOjQXP~,]P!_!`$r~,eQXP!O!P,k!a!b,p~,pOY~~,uOZ~R,|S]QRP!Q![,u!c!},u#R#S,u#T#o,u~-_Om~~-dOl~R-kU]QRP!Q![,u!c!},u#R#S,u#T#b,u#b#c-}#c#o,uR.UU]QRP!Q![,u!c!},u#R#S,u#T#W,u#W#X.h#X#o,uR.qS]QWPRP!Q![,u!c!},u#R#S,u#T#o,uR/UU]QRP!Q![,u!c!},u#R#S,u#T#c,u#c#d/h#d#o,uR/oU]QRP!Q![,u!c!},u#R#S,u#T#b,u#b#c0R#c#o,uR0YU]QRP!Q![,u!c!},u#R#S,u#T#h,u#h#i0l#i#o,uR0sT]QRP!Q![,u!c!},u#R#S,u#T#U1S#U#o,uR1ZU]QRP!Q![,u!c!},u#R#S,u#T#],u#]#^1m#^#o,uR1tU]QRP!Q![,u!c!},u#R#S,u#T#b,u#b#c2W#c#o,uR2_U]QRP!Q![,u!c!},u#R#S,u#T#g,u#g#h.h#h#o,uR2xU]QRP!Q![,u!c!},u#R#S,u#T#b,u#b#c3[#c#o,uR3cU]QRP!Q![,u!c!},u#R#S,u#T#W,u#W#X3u#X#o,uR3|U]QRP!Q![,u!c!},u#R#S,u#T#g,u#g#h4`#h#o,uR4gT]QRPpq4v!Q![,u!c!},u#R#S,u#T#o,uP4yP#k#l4|P5PP#]#^5SP5VP#h#i5YP5]P#[#]5`P5eOWPR5lT]QRP!Q![,u!c!},u#R#S,u#T#U5{#U#o,uR6SU]QRP!Q![,u!c!},u#R#S,u#T#`,u#`#a6f#a#o,uR6mU]QRP!Q![,u!c!},u#R#S,u#T#g,u#g#h7P#h#o,uR7WU]QRP!Q![,u!c!},u#R#S,u#T#X,u#X#Y7j#Y#o,uR7sS]QTPRP!Q![,u!c!},u#R#S,u#T#o,uR8WU]QRP!Q![,u!c!},u#R#S,u#T#b,u#b#c.h#c#o,uR8qT]QRP!Q![,u!c!},u#R#S,u#T#U9Q#U#o,uR9XU]QRP!Q![,u!c!},u#R#S,u#T#h,u#h#i9k#i#o,uR9rU]QRP!Q![,u!c!},u#R#S,u#T#V,u#V#W:U#W#o,uR:]U]QRP!Q![,u!c!},u#R#S,u#T#[,u#[#]:o#]#o,uR:vU]QRP!Q![,u!c!},u#R#S,u#T#X,u#X#Y2W#Y#o,uR;aW]QRP!Q![,u!c!},u#R#S,u#T#c,u#c#d;y#d#i,u#i#j=Y#j#o,uR<QU]QRP!Q![,u!c!},u#R#S,u#T#h,u#h#i<d#i#o,uR<mT]QWPRPpq<|!Q![,u!c!},u#R#S,u#T#o,uP=PP#]#^=SP=VP#b#c5`R=aU]QRP!Q![,u!c!},u#R#S,u#T#`,u#`#a=s#a#o,uR=zU]QRP!Q![,u!c!},u#R#S,u#T#`,u#`#a>^#a#o,uR>gS]QUPRP!Q![,u!c!},u#R#S,u#T#o,uR>zU]QRP!Q![,u!c!},u#R#S,u#T#f,u#f#g.h#g#o,uR?eU]QRP!Q![,u!c!},u#R#S,u#T#h,u#h#i?w#i#o,uR@OT]QRP!Q![,u!c!},u#R#S,u#T#U@_#U#o,uR@fU]QRP!Q![,u!c!},u#R#S,u#T#f,u#f#g@x#g#o,uRAPU]QRP!Q![,u!c!},u#R#S,u#T#h,u#h#i3u#i#o,uRAjU]QRP!Q![,u!c!},u#R#S,u#T#f,u#f#gA|#g#o,uRBTU]QRP!Q![,u!c!},u#R#S,u#T#i,u#i#j7P#j#o,u~BlOi~~BqPV~#p#q$z~ByOh~",
25
+ tokenData: "B{~R!QXY$XYZ$X]^$Xpq$Xqr$jrs%Puv$zvw&{wx'Txy(xyz(}z{)S{|$z|})[}!O$z!O!P)c!P!Q$z!Q![*t![!],T!^!_$r!_!`,[!`!a$r!a!b,b!c!},w!}#O-[#P#Q-a#Q#R$z#R#S,w#T#U-f#U#V,w#V#W/P#W#X,w#X#Y2s#Y#Z5g#Z#],w#]#^8R#^#a,w#a#b8l#b#c;[#c#d>u#d#g,w#g#h?`#h#iAe#i#o,w#o#pBi#p#qBn#q#rBv#r#s$z~$^Sf~XY$XYZ$X]^$Xpq$X~$oPV~!_!`$r~$wPV~!_!`$z~%POV~R%SXOr%Prs%os#O%P#O#P%v#P;'S%P;'S;=`&u<%l~%P~O%P~~%oR%vO]QSPR%yRO;'S%P;'S;=`&S;=`O%PR&VYOr%Prs%os#O%P#O#P%v#P;'S%P;'S;=`&u;=`<%l%P<%l~%P~O%P~~%oR&xP;=`<%l%P~'QPV~vw$zR'WXOw'Twx%ox#O'T#O#P's#P;'S'T;'S;=`(r<%l~'T~O'T~~%oR'vRO;'S'T;'S;=`(P;=`O'TR(SYOw'Twx%ox#O'T#O#P's#P;'S'T;'S;=`(r;=`<%l'T<%l~'T~O'T~~%oR(uP;=`<%l'T~(}O`~~)SO_~~)XPV~z{$zR)cOkQXP~)hQXP!O!P$z!Q![)n~)sSQ~!Q![)n!g!h*P#R#S*n#X#Y*P~*SR{|*]}!O*]!Q![*c~*`P!Q![*c~*hQQ~!Q![*c#R#S*]~*qP!Q![)n~*yTQ~!O!P+Y!Q![*t!g!h*P#R#S+}#X#Y*P~+]SO!O+i!P;'S+i;'S;=`+w<%lO+i~+nRQ~!Q![)n!g!h*P#X#Y*P~+zP;=`<%l+i~,QP!Q![*tR,[OjQXP~,_P!_!`$r~,gQXP!O!P,m!a!b,r~,rOY~~,wOZ~R-OS]QRP!Q![,w!c!},w#R#S,w#T#o,w~-aOm~~-fOl~R-mU]QRP!Q![,w!c!},w#R#S,w#T#b,w#b#c.P#c#o,wR.WU]QRP!Q![,w!c!},w#R#S,w#T#W,w#W#X.j#X#o,wR.sS]QWPRP!Q![,w!c!},w#R#S,w#T#o,wR/WU]QRP!Q![,w!c!},w#R#S,w#T#c,w#c#d/j#d#o,wR/qU]QRP!Q![,w!c!},w#R#S,w#T#b,w#b#c0T#c#o,wR0[U]QRP!Q![,w!c!},w#R#S,w#T#h,w#h#i0n#i#o,wR0uT]QRP!Q![,w!c!},w#R#S,w#T#U1U#U#o,wR1]U]QRP!Q![,w!c!},w#R#S,w#T#],w#]#^1o#^#o,wR1vU]QRP!Q![,w!c!},w#R#S,w#T#b,w#b#c2Y#c#o,wR2aU]QRP!Q![,w!c!},w#R#S,w#T#g,w#g#h.j#h#o,wR2zU]QRP!Q![,w!c!},w#R#S,w#T#b,w#b#c3^#c#o,wR3eU]QRP!Q![,w!c!},w#R#S,w#T#W,w#W#X3w#X#o,wR4OU]QRP!Q![,w!c!},w#R#S,w#T#g,w#g#h4b#h#o,wR4iT]QRPpq4x!Q![,w!c!},w#R#S,w#T#o,wP4{P#k#l5OP5RP#]#^5UP5XP#h#i5[P5_P#[#]5bP5gOWPR5nT]QRP!Q![,w!c!},w#R#S,w#T#U5}#U#o,wR6UU]QRP!Q![,w!c!},w#R#S,w#T#`,w#`#a6h#a#o,wR6oU]QRP!Q![,w!c!},w#R#S,w#T#g,w#g#h7R#h#o,wR7YU]QRP!Q![,w!c!},w#R#S,w#T#X,w#X#Y7l#Y#o,wR7uS]QTPRP!Q![,w!c!},w#R#S,w#T#o,wR8YU]QRP!Q![,w!c!},w#R#S,w#T#b,w#b#c.j#c#o,wR8sT]QRP!Q![,w!c!},w#R#S,w#T#U9S#U#o,wR9ZU]QRP!Q![,w!c!},w#R#S,w#T#h,w#h#i9m#i#o,wR9tU]QRP!Q![,w!c!},w#R#S,w#T#V,w#V#W:W#W#o,wR:_U]QRP!Q![,w!c!},w#R#S,w#T#[,w#[#]:q#]#o,wR:xU]QRP!Q![,w!c!},w#R#S,w#T#X,w#X#Y2Y#Y#o,wR;cW]QRP!Q![,w!c!},w#R#S,w#T#c,w#c#d;{#d#i,w#i#j=[#j#o,wR<SU]QRP!Q![,w!c!},w#R#S,w#T#h,w#h#i<f#i#o,wR<oT]QWPRPpq=O!Q![,w!c!},w#R#S,w#T#o,wP=RP#]#^=UP=XP#b#c5bR=cU]QRP!Q![,w!c!},w#R#S,w#T#`,w#`#a=u#a#o,wR=|U]QRP!Q![,w!c!},w#R#S,w#T#`,w#`#a>`#a#o,wR>iS]QUPRP!Q![,w!c!},w#R#S,w#T#o,wR>|U]QRP!Q![,w!c!},w#R#S,w#T#f,w#f#g.j#g#o,wR?gU]QRP!Q![,w!c!},w#R#S,w#T#h,w#h#i?y#i#o,wR@QT]QRP!Q![,w!c!},w#R#S,w#T#U@a#U#o,wR@hU]QRP!Q![,w!c!},w#R#S,w#T#f,w#f#g@z#g#o,wRARU]QRP!Q![,w!c!},w#R#S,w#T#h,w#h#i3w#i#o,wRAlU]QRP!Q![,w!c!},w#R#S,w#T#f,w#f#gBO#g#o,wRBVU]QRP!Q![,w!c!},w#R#S,w#T#i,w#i#j7R#j#o,w~BnOi~~BsPV~#p#q$z~B{Oh~",
26
26
  tokenizers: [0, 1],
27
27
  topRules: {"Program":[0,1]},
28
28
  tokenPrec: 118
@@ -33,8 +33,18 @@ const isFunction = (identifier, config) => { var _a; return (_a = config.functio
33
33
  const isVariable = (identifier, config) => { var _a; return (_a = config.identifiers) === null || _a === void 0 ? void 0 : _a.find(variable => variable.name === identifier); };
34
34
  const expressionLanguageLinter = (config) => lint.linter(view => {
35
35
  let diagnostics = [];
36
+ let previousNode = null;
36
37
  language.syntaxTree(view.state).cursor().iterate(node => {
38
+ var _a;
37
39
  if (node.name == "Identifier") {
40
+ if ((previousNode === null || previousNode === void 0 ? void 0 : previousNode.name) == "Identifier" && ((_a = node.node.parent) === null || _a === void 0 ? void 0 : _a.name) != 'Array') {
41
+ diagnostics.push({
42
+ from: node.from,
43
+ to: node.to,
44
+ severity: 'error',
45
+ message: `Unexpected identifier after another identifier`,
46
+ });
47
+ }
38
48
  const identifier = view.state.sliceDoc(node.from, node.to);
39
49
  if (!isFunction(identifier, config) && !isVariable(identifier, config)) {
40
50
  diagnostics.push({
@@ -45,6 +55,7 @@ const expressionLanguageLinter = (config) => lint.linter(view => {
45
55
  });
46
56
  }
47
57
  }
58
+ previousNode = node.node;
48
59
  });
49
60
  return diagnostics;
50
61
  });
@@ -104,48 +115,62 @@ const ELLanguage = language.LRLanguage.define({
104
115
  }),
105
116
  languageData: {}
106
117
  });
107
- function completeOperatorKeyword(state, config, tree, from, to) {
118
+ function completeOperatorKeyword(state, config, tree, from, to, explicit) {
108
119
  var _a, _b;
109
120
  const text = state.sliceDoc(from, to);
110
121
  return {
111
122
  from,
112
123
  to,
113
- options: (_b = (_a = config.operatorKeywords) === null || _a === void 0 ? void 0 : _a.filter(value => value.startsWith(text)).map(keyword => ({ label: keyword, type: "property" }))) !== null && _b !== void 0 ? _b : [],
114
- validFor: (text) => { var _a, _b; return (_b = (_a = config.operatorKeywords) === null || _a === void 0 ? void 0 : _a.some(value => value.startsWith(text))) !== null && _b !== void 0 ? _b : false; },
124
+ options: (_b = (_a = config.operatorKeywords) === null || _a === void 0 ? void 0 : _a.filter(({ name }) => explicit || name.startsWith(text)).map(({ name, info, detail }) => ({ label: name, apply: `${name} `, info, detail, type: "keyword" }))) !== null && _b !== void 0 ? _b : [],
125
+ validFor: (text) => { var _a, _b; return (_b = (_a = config.operatorKeywords) === null || _a === void 0 ? void 0 : _a.some(({ name }) => explicit || name.startsWith(text))) !== null && _b !== void 0 ? _b : false; },
115
126
  };
116
127
  }
117
- function completeIdentifier(state, config, tree, from, to) {
118
- var _a, _b, _c, _d, _e, _f;
128
+ function completeIdentifier(state, config, tree, from, to, explicit) {
129
+ var _a, _b, _c, _d, _e, _f, _g;
119
130
  const text = state.sliceDoc(from, to);
120
- const identifiers = (_b = (_a = config.identifiers) === null || _a === void 0 ? void 0 : _a.filter(({ name }) => name.startsWith(text))) !== null && _b !== void 0 ? _b : [];
121
- const functions = (_d = (_c = config.functions) === null || _c === void 0 ? void 0 : _c.filter(({ name }) => name.startsWith(text))) !== null && _d !== void 0 ? _d : [];
131
+ const identifiers = (_b = (_a = config.identifiers) === null || _a === void 0 ? void 0 : _a.filter(({ name }) => explicit || name.startsWith(text))) !== null && _b !== void 0 ? _b : [];
132
+ const functions = (_d = (_c = config.functions) === null || _c === void 0 ? void 0 : _c.filter(({ name }) => explicit || name.startsWith(text))) !== null && _d !== void 0 ? _d : [];
133
+ const prevName = (_e = tree.prevSibling) === null || _e === void 0 ? void 0 : _e.name;
134
+ const apply = (name) => !prevName || !['OpeningBracket', 'Operator', 'OperatorKeyword', 'Punctuation'].includes(prevName) ? `${name} ` : name;
122
135
  return {
123
136
  from,
124
137
  to,
125
138
  options: [
126
- ...((_e = identifiers.map(({ name, info, detail }) => ({ label: name, info, detail, type: 'variable' }))) !== null && _e !== void 0 ? _e : []),
127
- ...((_f = functions.map(({ name, args = [], info }) => ({ label: name, detail: `(${args.join(',')})`, apply: `${name}(${args.length == 0 ? ')' : ''}`, info, type: "function" }))) !== null && _f !== void 0 ? _f : []),
139
+ ...((_f = identifiers.map(({ name, info, detail }) => ({ label: name, apply: apply(name), info, detail, type: 'variable' }))) !== null && _f !== void 0 ? _f : []),
140
+ ...((_g = functions.map(({ name, args = [], info }) => ({ label: name, detail: `(${args.join(',')})`, apply: `${name}(${args.length == 0 ? ')' : ''}`, info, type: "function" }))) !== null && _g !== void 0 ? _g : []),
128
141
  ],
129
142
  validFor: identifier,
130
143
  };
131
144
  }
132
145
  function expressionLanguageCompletionFor(config, context) {
133
- let { state, pos } = context;
146
+ let { state, pos, explicit } = context;
134
147
  let tree = language.syntaxTree(state).resolveInner(pos, -1);
148
+ const isOperator = (node) => ['Operator', 'OperatorKeyword', 'Punctuation', 'NullSafe', 'NullCoalescing', 'OpeningBracket'].includes(node.name);
149
+ const isIdentifier = (node) => node.name === 'Identifier';
135
150
  if (tree.name == 'String') {
136
151
  return null;
137
152
  }
138
- if (tree.prevSibling && !['Operator', 'OperatorKeyword', 'Punctuation', 'NullSafe', 'NullCoalescing', 'OpeningBracket'].includes(tree.prevSibling.name)) {
139
- return completeOperatorKeyword(state, config, tree, tree.from, pos);
153
+ if (tree.prevSibling && !isOperator(tree.prevSibling) && (!explicit || !isOperator(tree.node))) {
154
+ return completeOperatorKeyword(state, config, tree, tree.from, pos, explicit);
140
155
  }
141
- if (tree.name == "Identifier") {
142
- return completeIdentifier(state, config, tree, tree.from, pos);
156
+ if ((!tree.prevSibling || !isIdentifier(tree.prevSibling) || isOperator(tree.node)) && (explicit || isIdentifier(tree.node))) {
157
+ return completeIdentifier(state, config, tree, isIdentifier(tree.node) ? tree.from : pos, pos, explicit);
143
158
  }
144
159
  return null;
145
160
  }
146
161
  function expressionLanguageCompletionSourceWith(config) {
147
162
  var _a;
148
- (_a = config.operatorKeywords) !== null && _a !== void 0 ? _a : (config.operatorKeywords = ['starts with', 'ends with', 'contains', 'matches', 'not in', 'in', 'not', 'or', 'and']);
163
+ (_a = config.operatorKeywords) !== null && _a !== void 0 ? _a : (config.operatorKeywords = [
164
+ { name: 'starts with' },
165
+ { name: 'ends with' },
166
+ { name: 'contains' },
167
+ { name: 'matches' },
168
+ { name: 'not in' },
169
+ { name: 'in' },
170
+ { name: 'not' },
171
+ { name: 'or' },
172
+ { name: 'and' },
173
+ ]);
149
174
  return (context) => expressionLanguageCompletionFor(config, context);
150
175
  }
151
176
  function expressionlanguage(config = {}, extensions = []) {
package/dist/index.d.cts CHANGED
@@ -10,7 +10,11 @@ interface ExpressionLanguageConfig {
10
10
  args: string[];
11
11
  info?: string;
12
12
  }[];
13
- operatorKeywords?: readonly string[];
13
+ operatorKeywords?: readonly {
14
+ name: string;
15
+ detail?: string;
16
+ info?: string;
17
+ }[];
14
18
  }
15
19
  declare const keywordTooltip: (config: ExpressionLanguageConfig) => import("@codemirror/state").Extension;
16
20
  declare const ELLanguage: LRLanguage;
package/dist/index.d.ts CHANGED
@@ -10,7 +10,11 @@ interface ExpressionLanguageConfig {
10
10
  args: string[];
11
11
  info?: string;
12
12
  }[];
13
- operatorKeywords?: readonly string[];
13
+ operatorKeywords?: readonly {
14
+ name: string;
15
+ detail?: string;
16
+ info?: string;
17
+ }[];
14
18
  }
15
19
  declare const keywordTooltip: (config: ExpressionLanguageConfig) => import("@codemirror/state").Extension;
16
20
  declare const ELLanguage: LRLanguage;
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import { hoverTooltip } from '@codemirror/view';
7
7
  // This file was generated by lezer-generator. You probably shouldn't edit it.
8
8
  const parser = LRParser.deserialize({
9
9
  version: 14,
10
- states: "$nQVQPOOO!QQQO'#ChO!VQPO'#CjO!^QPO'#CmOOQO'#Cs'#CsOOQO'#Cn'#CnQVQPOOO!eQQO,59SOOQO,59U,59UO!jQPO,59UOOQO,59X,59XO!rQPO,59XOOQO-E6l-E6lOVQPO1G.nOVQPO'#CoO!yQPO1G.pOOQO1G.p1G.pOOQO1G.s1G.sO#RQPO7+$YOOQO,59Z,59ZOOQO-E6m-E6mOOQO7+$[7+$[OOQO<<Gt<<GtO#ZQQO<<GtO#`QQOAN=`OVQPOG22zO#eQPOLD(fOOQO!$'LQ!$'LQ",
10
+ states: "$nQVQPOOO!QQQO'#ChO!VQPO'#CjO!^QPO'#CmOOQO'#Cs'#CsOOQO'#Cn'#CnQVQPOOO!eQQO,59SOOQO,59U,59UO!jQQO,59UOOQO,59X,59XO!rQPO,59XOOQO-E6l-E6lOVQPO1G.nOVQPO'#CoO!yQQO1G.pOOQO1G.p1G.pOOQO1G.s1G.sO#RQQO7+$YOOQO,59Z,59ZOOQO-E6m-E6mOOQO7+$[7+$[OOQO<<Gt<<GtO#ZQQO<<GtO#`QQOAN=`OVQPOG22zO#eQPOLD(fOOQO!$'LQ!$'LQ",
11
11
  stateData: "#r~OfOS~OQSORSOSSOTSOUSOVSOWSOXSOYSOZSO`ROiPOmQO~O]VO~OlWO~PVO_YO~PVOj]O~Ok^Ol`O~O_aO~PVOk^OleO~OhfOkgO~O]hO~OjiO~OhkO~OQUTXWRW~",
12
12
  goto: "!ghPPPPPPPPPPPPiPiPPis}PPP!TaSOQRUZ]^iQUOQZRT[UZQ_XRd_WTORUZQXQQb]Qc^Rji",
13
13
  nodeNames: "⚠ Program Number Identifier String Boolean Null Operator OperatorKeyword Punctuation NullSafe NullCoalescing Object ObjectKey Array ClosingBracket OpeningBracket Application",
@@ -18,7 +18,7 @@ const parser = LRParser.deserialize({
18
18
  ],
19
19
  skippedNodes: [0],
20
20
  repeatNodeCount: 2,
21
- tokenData: "By~R!QXY$XYZ$X]^$Xpq$Xqr$jrs%Puv$zvw&{wx'Txy(xyz(}z{)S{|$z|})[}!O$z!O!P)a!P!Q$z!Q![*r![!],R!^!_$r!_!`,Y!`!a$r!a!b,`!c!},u!}#O-Y#P#Q-_#Q#R$z#R#S,u#T#U-d#U#V,u#V#W.}#W#X,u#X#Y2q#Y#Z5e#Z#],u#]#^8P#^#a,u#a#b8j#b#c;Y#c#d>s#d#g,u#g#h?^#h#iAc#i#o,u#o#pBg#p#qBl#q#rBt#r#s$z~$^Sf~XY$XYZ$X]^$Xpq$X~$oPV~!_!`$r~$wPV~!_!`$z~%POV~R%SXOr%Prs%os#O%P#O#P%v#P;'S%P;'S;=`&u<%l~%P~O%P~~%oR%vO]QSPR%yRO;'S%P;'S;=`&S;=`O%PR&VYOr%Prs%os#O%P#O#P%v#P;'S%P;'S;=`&u;=`<%l%P<%l~%P~O%P~~%oR&xP;=`<%l%P~'QPV~vw$zR'WXOw'Twx%ox#O'T#O#P's#P;'S'T;'S;=`(r<%l~'T~O'T~~%oR'vRO;'S'T;'S;=`(P;=`O'TR(SYOw'Twx%ox#O'T#O#P's#P;'S'T;'S;=`(r;=`<%l'T<%l~'T~O'T~~%oR(uP;=`<%l'T~(}O`~~)SO_~~)XPV~z{$z~)aOk~~)fQXP!O!P$z!Q![)l~)qSQ~!Q![)l!g!h)}#R#S*l#X#Y)}~*QR{|*Z}!O*Z!Q![*a~*^P!Q![*a~*fQQ~!Q![*a#R#S*Z~*oP!Q![)l~*wTQ~!O!P+W!Q![*r!g!h)}#R#S+{#X#Y)}~+ZSO!O+g!P;'S+g;'S;=`+u<%lO+g~+lRQ~!Q![)l!g!h)}#X#Y)}~+xP;=`<%l+g~,OP!Q![*rR,YOjQXP~,]P!_!`$r~,eQXP!O!P,k!a!b,p~,pOY~~,uOZ~R,|S]QRP!Q![,u!c!},u#R#S,u#T#o,u~-_Om~~-dOl~R-kU]QRP!Q![,u!c!},u#R#S,u#T#b,u#b#c-}#c#o,uR.UU]QRP!Q![,u!c!},u#R#S,u#T#W,u#W#X.h#X#o,uR.qS]QWPRP!Q![,u!c!},u#R#S,u#T#o,uR/UU]QRP!Q![,u!c!},u#R#S,u#T#c,u#c#d/h#d#o,uR/oU]QRP!Q![,u!c!},u#R#S,u#T#b,u#b#c0R#c#o,uR0YU]QRP!Q![,u!c!},u#R#S,u#T#h,u#h#i0l#i#o,uR0sT]QRP!Q![,u!c!},u#R#S,u#T#U1S#U#o,uR1ZU]QRP!Q![,u!c!},u#R#S,u#T#],u#]#^1m#^#o,uR1tU]QRP!Q![,u!c!},u#R#S,u#T#b,u#b#c2W#c#o,uR2_U]QRP!Q![,u!c!},u#R#S,u#T#g,u#g#h.h#h#o,uR2xU]QRP!Q![,u!c!},u#R#S,u#T#b,u#b#c3[#c#o,uR3cU]QRP!Q![,u!c!},u#R#S,u#T#W,u#W#X3u#X#o,uR3|U]QRP!Q![,u!c!},u#R#S,u#T#g,u#g#h4`#h#o,uR4gT]QRPpq4v!Q![,u!c!},u#R#S,u#T#o,uP4yP#k#l4|P5PP#]#^5SP5VP#h#i5YP5]P#[#]5`P5eOWPR5lT]QRP!Q![,u!c!},u#R#S,u#T#U5{#U#o,uR6SU]QRP!Q![,u!c!},u#R#S,u#T#`,u#`#a6f#a#o,uR6mU]QRP!Q![,u!c!},u#R#S,u#T#g,u#g#h7P#h#o,uR7WU]QRP!Q![,u!c!},u#R#S,u#T#X,u#X#Y7j#Y#o,uR7sS]QTPRP!Q![,u!c!},u#R#S,u#T#o,uR8WU]QRP!Q![,u!c!},u#R#S,u#T#b,u#b#c.h#c#o,uR8qT]QRP!Q![,u!c!},u#R#S,u#T#U9Q#U#o,uR9XU]QRP!Q![,u!c!},u#R#S,u#T#h,u#h#i9k#i#o,uR9rU]QRP!Q![,u!c!},u#R#S,u#T#V,u#V#W:U#W#o,uR:]U]QRP!Q![,u!c!},u#R#S,u#T#[,u#[#]:o#]#o,uR:vU]QRP!Q![,u!c!},u#R#S,u#T#X,u#X#Y2W#Y#o,uR;aW]QRP!Q![,u!c!},u#R#S,u#T#c,u#c#d;y#d#i,u#i#j=Y#j#o,uR<QU]QRP!Q![,u!c!},u#R#S,u#T#h,u#h#i<d#i#o,uR<mT]QWPRPpq<|!Q![,u!c!},u#R#S,u#T#o,uP=PP#]#^=SP=VP#b#c5`R=aU]QRP!Q![,u!c!},u#R#S,u#T#`,u#`#a=s#a#o,uR=zU]QRP!Q![,u!c!},u#R#S,u#T#`,u#`#a>^#a#o,uR>gS]QUPRP!Q![,u!c!},u#R#S,u#T#o,uR>zU]QRP!Q![,u!c!},u#R#S,u#T#f,u#f#g.h#g#o,uR?eU]QRP!Q![,u!c!},u#R#S,u#T#h,u#h#i?w#i#o,uR@OT]QRP!Q![,u!c!},u#R#S,u#T#U@_#U#o,uR@fU]QRP!Q![,u!c!},u#R#S,u#T#f,u#f#g@x#g#o,uRAPU]QRP!Q![,u!c!},u#R#S,u#T#h,u#h#i3u#i#o,uRAjU]QRP!Q![,u!c!},u#R#S,u#T#f,u#f#gA|#g#o,uRBTU]QRP!Q![,u!c!},u#R#S,u#T#i,u#i#j7P#j#o,u~BlOi~~BqPV~#p#q$z~ByOh~",
21
+ tokenData: "B{~R!QXY$XYZ$X]^$Xpq$Xqr$jrs%Puv$zvw&{wx'Txy(xyz(}z{)S{|$z|})[}!O$z!O!P)c!P!Q$z!Q![*t![!],T!^!_$r!_!`,[!`!a$r!a!b,b!c!},w!}#O-[#P#Q-a#Q#R$z#R#S,w#T#U-f#U#V,w#V#W/P#W#X,w#X#Y2s#Y#Z5g#Z#],w#]#^8R#^#a,w#a#b8l#b#c;[#c#d>u#d#g,w#g#h?`#h#iAe#i#o,w#o#pBi#p#qBn#q#rBv#r#s$z~$^Sf~XY$XYZ$X]^$Xpq$X~$oPV~!_!`$r~$wPV~!_!`$z~%POV~R%SXOr%Prs%os#O%P#O#P%v#P;'S%P;'S;=`&u<%l~%P~O%P~~%oR%vO]QSPR%yRO;'S%P;'S;=`&S;=`O%PR&VYOr%Prs%os#O%P#O#P%v#P;'S%P;'S;=`&u;=`<%l%P<%l~%P~O%P~~%oR&xP;=`<%l%P~'QPV~vw$zR'WXOw'Twx%ox#O'T#O#P's#P;'S'T;'S;=`(r<%l~'T~O'T~~%oR'vRO;'S'T;'S;=`(P;=`O'TR(SYOw'Twx%ox#O'T#O#P's#P;'S'T;'S;=`(r;=`<%l'T<%l~'T~O'T~~%oR(uP;=`<%l'T~(}O`~~)SO_~~)XPV~z{$zR)cOkQXP~)hQXP!O!P$z!Q![)n~)sSQ~!Q![)n!g!h*P#R#S*n#X#Y*P~*SR{|*]}!O*]!Q![*c~*`P!Q![*c~*hQQ~!Q![*c#R#S*]~*qP!Q![)n~*yTQ~!O!P+Y!Q![*t!g!h*P#R#S+}#X#Y*P~+]SO!O+i!P;'S+i;'S;=`+w<%lO+i~+nRQ~!Q![)n!g!h*P#X#Y*P~+zP;=`<%l+i~,QP!Q![*tR,[OjQXP~,_P!_!`$r~,gQXP!O!P,m!a!b,r~,rOY~~,wOZ~R-OS]QRP!Q![,w!c!},w#R#S,w#T#o,w~-aOm~~-fOl~R-mU]QRP!Q![,w!c!},w#R#S,w#T#b,w#b#c.P#c#o,wR.WU]QRP!Q![,w!c!},w#R#S,w#T#W,w#W#X.j#X#o,wR.sS]QWPRP!Q![,w!c!},w#R#S,w#T#o,wR/WU]QRP!Q![,w!c!},w#R#S,w#T#c,w#c#d/j#d#o,wR/qU]QRP!Q![,w!c!},w#R#S,w#T#b,w#b#c0T#c#o,wR0[U]QRP!Q![,w!c!},w#R#S,w#T#h,w#h#i0n#i#o,wR0uT]QRP!Q![,w!c!},w#R#S,w#T#U1U#U#o,wR1]U]QRP!Q![,w!c!},w#R#S,w#T#],w#]#^1o#^#o,wR1vU]QRP!Q![,w!c!},w#R#S,w#T#b,w#b#c2Y#c#o,wR2aU]QRP!Q![,w!c!},w#R#S,w#T#g,w#g#h.j#h#o,wR2zU]QRP!Q![,w!c!},w#R#S,w#T#b,w#b#c3^#c#o,wR3eU]QRP!Q![,w!c!},w#R#S,w#T#W,w#W#X3w#X#o,wR4OU]QRP!Q![,w!c!},w#R#S,w#T#g,w#g#h4b#h#o,wR4iT]QRPpq4x!Q![,w!c!},w#R#S,w#T#o,wP4{P#k#l5OP5RP#]#^5UP5XP#h#i5[P5_P#[#]5bP5gOWPR5nT]QRP!Q![,w!c!},w#R#S,w#T#U5}#U#o,wR6UU]QRP!Q![,w!c!},w#R#S,w#T#`,w#`#a6h#a#o,wR6oU]QRP!Q![,w!c!},w#R#S,w#T#g,w#g#h7R#h#o,wR7YU]QRP!Q![,w!c!},w#R#S,w#T#X,w#X#Y7l#Y#o,wR7uS]QTPRP!Q![,w!c!},w#R#S,w#T#o,wR8YU]QRP!Q![,w!c!},w#R#S,w#T#b,w#b#c.j#c#o,wR8sT]QRP!Q![,w!c!},w#R#S,w#T#U9S#U#o,wR9ZU]QRP!Q![,w!c!},w#R#S,w#T#h,w#h#i9m#i#o,wR9tU]QRP!Q![,w!c!},w#R#S,w#T#V,w#V#W:W#W#o,wR:_U]QRP!Q![,w!c!},w#R#S,w#T#[,w#[#]:q#]#o,wR:xU]QRP!Q![,w!c!},w#R#S,w#T#X,w#X#Y2Y#Y#o,wR;cW]QRP!Q![,w!c!},w#R#S,w#T#c,w#c#d;{#d#i,w#i#j=[#j#o,wR<SU]QRP!Q![,w!c!},w#R#S,w#T#h,w#h#i<f#i#o,wR<oT]QWPRPpq=O!Q![,w!c!},w#R#S,w#T#o,wP=RP#]#^=UP=XP#b#c5bR=cU]QRP!Q![,w!c!},w#R#S,w#T#`,w#`#a=u#a#o,wR=|U]QRP!Q![,w!c!},w#R#S,w#T#`,w#`#a>`#a#o,wR>iS]QUPRP!Q![,w!c!},w#R#S,w#T#o,wR>|U]QRP!Q![,w!c!},w#R#S,w#T#f,w#f#g.j#g#o,wR?gU]QRP!Q![,w!c!},w#R#S,w#T#h,w#h#i?y#i#o,wR@QT]QRP!Q![,w!c!},w#R#S,w#T#U@a#U#o,wR@hU]QRP!Q![,w!c!},w#R#S,w#T#f,w#f#g@z#g#o,wRARU]QRP!Q![,w!c!},w#R#S,w#T#h,w#h#i3w#i#o,wRAlU]QRP!Q![,w!c!},w#R#S,w#T#f,w#f#gBO#g#o,wRBVU]QRP!Q![,w!c!},w#R#S,w#T#i,w#i#j7R#j#o,w~BnOi~~BsPV~#p#q$z~B{Oh~",
22
22
  tokenizers: [0, 1],
23
23
  topRules: {"Program":[0,1]},
24
24
  tokenPrec: 118
@@ -29,8 +29,18 @@ const isFunction = (identifier, config) => { var _a; return (_a = config.functio
29
29
  const isVariable = (identifier, config) => { var _a; return (_a = config.identifiers) === null || _a === void 0 ? void 0 : _a.find(variable => variable.name === identifier); };
30
30
  const expressionLanguageLinter = (config) => linter(view => {
31
31
  let diagnostics = [];
32
+ let previousNode = null;
32
33
  syntaxTree(view.state).cursor().iterate(node => {
34
+ var _a;
33
35
  if (node.name == "Identifier") {
36
+ if ((previousNode === null || previousNode === void 0 ? void 0 : previousNode.name) == "Identifier" && ((_a = node.node.parent) === null || _a === void 0 ? void 0 : _a.name) != 'Array') {
37
+ diagnostics.push({
38
+ from: node.from,
39
+ to: node.to,
40
+ severity: 'error',
41
+ message: `Unexpected identifier after another identifier`,
42
+ });
43
+ }
34
44
  const identifier = view.state.sliceDoc(node.from, node.to);
35
45
  if (!isFunction(identifier, config) && !isVariable(identifier, config)) {
36
46
  diagnostics.push({
@@ -41,6 +51,7 @@ const expressionLanguageLinter = (config) => linter(view => {
41
51
  });
42
52
  }
43
53
  }
54
+ previousNode = node.node;
44
55
  });
45
56
  return diagnostics;
46
57
  });
@@ -100,48 +111,62 @@ const ELLanguage = LRLanguage.define({
100
111
  }),
101
112
  languageData: {}
102
113
  });
103
- function completeOperatorKeyword(state, config, tree, from, to) {
114
+ function completeOperatorKeyword(state, config, tree, from, to, explicit) {
104
115
  var _a, _b;
105
116
  const text = state.sliceDoc(from, to);
106
117
  return {
107
118
  from,
108
119
  to,
109
- options: (_b = (_a = config.operatorKeywords) === null || _a === void 0 ? void 0 : _a.filter(value => value.startsWith(text)).map(keyword => ({ label: keyword, type: "property" }))) !== null && _b !== void 0 ? _b : [],
110
- validFor: (text) => { var _a, _b; return (_b = (_a = config.operatorKeywords) === null || _a === void 0 ? void 0 : _a.some(value => value.startsWith(text))) !== null && _b !== void 0 ? _b : false; },
120
+ options: (_b = (_a = config.operatorKeywords) === null || _a === void 0 ? void 0 : _a.filter(({ name }) => explicit || name.startsWith(text)).map(({ name, info, detail }) => ({ label: name, apply: `${name} `, info, detail, type: "keyword" }))) !== null && _b !== void 0 ? _b : [],
121
+ validFor: (text) => { var _a, _b; return (_b = (_a = config.operatorKeywords) === null || _a === void 0 ? void 0 : _a.some(({ name }) => explicit || name.startsWith(text))) !== null && _b !== void 0 ? _b : false; },
111
122
  };
112
123
  }
113
- function completeIdentifier(state, config, tree, from, to) {
114
- var _a, _b, _c, _d, _e, _f;
124
+ function completeIdentifier(state, config, tree, from, to, explicit) {
125
+ var _a, _b, _c, _d, _e, _f, _g;
115
126
  const text = state.sliceDoc(from, to);
116
- const identifiers = (_b = (_a = config.identifiers) === null || _a === void 0 ? void 0 : _a.filter(({ name }) => name.startsWith(text))) !== null && _b !== void 0 ? _b : [];
117
- const functions = (_d = (_c = config.functions) === null || _c === void 0 ? void 0 : _c.filter(({ name }) => name.startsWith(text))) !== null && _d !== void 0 ? _d : [];
127
+ const identifiers = (_b = (_a = config.identifiers) === null || _a === void 0 ? void 0 : _a.filter(({ name }) => explicit || name.startsWith(text))) !== null && _b !== void 0 ? _b : [];
128
+ const functions = (_d = (_c = config.functions) === null || _c === void 0 ? void 0 : _c.filter(({ name }) => explicit || name.startsWith(text))) !== null && _d !== void 0 ? _d : [];
129
+ const prevName = (_e = tree.prevSibling) === null || _e === void 0 ? void 0 : _e.name;
130
+ const apply = (name) => !prevName || !['OpeningBracket', 'Operator', 'OperatorKeyword', 'Punctuation'].includes(prevName) ? `${name} ` : name;
118
131
  return {
119
132
  from,
120
133
  to,
121
134
  options: [
122
- ...((_e = identifiers.map(({ name, info, detail }) => ({ label: name, info, detail, type: 'variable' }))) !== null && _e !== void 0 ? _e : []),
123
- ...((_f = functions.map(({ name, args = [], info }) => ({ label: name, detail: `(${args.join(',')})`, apply: `${name}(${args.length == 0 ? ')' : ''}`, info, type: "function" }))) !== null && _f !== void 0 ? _f : []),
135
+ ...((_f = identifiers.map(({ name, info, detail }) => ({ label: name, apply: apply(name), info, detail, type: 'variable' }))) !== null && _f !== void 0 ? _f : []),
136
+ ...((_g = functions.map(({ name, args = [], info }) => ({ label: name, detail: `(${args.join(',')})`, apply: `${name}(${args.length == 0 ? ')' : ''}`, info, type: "function" }))) !== null && _g !== void 0 ? _g : []),
124
137
  ],
125
138
  validFor: identifier,
126
139
  };
127
140
  }
128
141
  function expressionLanguageCompletionFor(config, context) {
129
- let { state, pos } = context;
142
+ let { state, pos, explicit } = context;
130
143
  let tree = syntaxTree(state).resolveInner(pos, -1);
144
+ const isOperator = (node) => ['Operator', 'OperatorKeyword', 'Punctuation', 'NullSafe', 'NullCoalescing', 'OpeningBracket'].includes(node.name);
145
+ const isIdentifier = (node) => node.name === 'Identifier';
131
146
  if (tree.name == 'String') {
132
147
  return null;
133
148
  }
134
- if (tree.prevSibling && !['Operator', 'OperatorKeyword', 'Punctuation', 'NullSafe', 'NullCoalescing', 'OpeningBracket'].includes(tree.prevSibling.name)) {
135
- return completeOperatorKeyword(state, config, tree, tree.from, pos);
149
+ if (tree.prevSibling && !isOperator(tree.prevSibling) && (!explicit || !isOperator(tree.node))) {
150
+ return completeOperatorKeyword(state, config, tree, tree.from, pos, explicit);
136
151
  }
137
- if (tree.name == "Identifier") {
138
- return completeIdentifier(state, config, tree, tree.from, pos);
152
+ if ((!tree.prevSibling || !isIdentifier(tree.prevSibling) || isOperator(tree.node)) && (explicit || isIdentifier(tree.node))) {
153
+ return completeIdentifier(state, config, tree, isIdentifier(tree.node) ? tree.from : pos, pos, explicit);
139
154
  }
140
155
  return null;
141
156
  }
142
157
  function expressionLanguageCompletionSourceWith(config) {
143
158
  var _a;
144
- (_a = config.operatorKeywords) !== null && _a !== void 0 ? _a : (config.operatorKeywords = ['starts with', 'ends with', 'contains', 'matches', 'not in', 'in', 'not', 'or', 'and']);
159
+ (_a = config.operatorKeywords) !== null && _a !== void 0 ? _a : (config.operatorKeywords = [
160
+ { name: 'starts with' },
161
+ { name: 'ends with' },
162
+ { name: 'contains' },
163
+ { name: 'matches' },
164
+ { name: 'not in' },
165
+ { name: 'in' },
166
+ { name: 'not' },
167
+ { name: 'or' },
168
+ { name: 'and' },
169
+ ]);
145
170
  return (context) => expressionLanguageCompletionFor(config, context);
146
171
  }
147
172
  function expressionlanguage(config = {}, extensions = []) {
package/package.json CHANGED
@@ -41,5 +41,5 @@
41
41
  "access": "public",
42
42
  "registry": "https://registry.npmjs.org/"
43
43
  },
44
- "version": "0.2.3"
44
+ "version": "0.3.0"
45
45
  }