@valtzu/codemirror-lang-el 1.3.0 → 1.4.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 CHANGED
@@ -1,6 +1,13 @@
1
1
  CHANGELOG
2
2
  =========
3
3
 
4
+ 1.4
5
+ ---
6
+
7
+ * Improve support for typed arrays
8
+ * Add support for null-safe array access
9
+ * Minor bugfixes & adjustments to autocomplete & linting
10
+
4
11
  1.3
5
12
  ---
6
13
 
package/dist/index.cjs CHANGED
@@ -14,25 +14,25 @@ const t = {
14
14
  };
15
15
 
16
16
  // This file was generated by lezer-generator. You probably shouldn't edit it.
17
- const spec_word = {__proto__:null,true:90, TRUE:92, false:94, FALSE:96, null:98, NULL:100, starts:110, with:112, ends:114, contains:116, matches:118, not:120, in:122, and:124, or:126, xor:128};
18
- const spec_Operator = {__proto__:null,"?":109, "!":131, "~":133, "+":135, "-":137};
17
+ const spec_word = {__proto__:null,true:92, TRUE:94, false:96, FALSE:98, null:100, NULL:102, starts:114, with:116, ends:118, contains:120, matches:122, not:124, in:126, and:128, or:130, xor:132};
18
+ const spec_Operator = {__proto__:null,"?":113, "!":135, "~":137, "+":139, "-":141};
19
19
  const parser = lr.LRParser.deserialize({
20
20
  version: 14,
21
- states: ")YOYQPOOP!aOPOOQ!fQPOOO#dQPO'#CeO$wQPO'#CmO%OQPO'#CnOYQPO'#CtOYQPO'#CvOOQO'#DR'#DRO%VQPO'#CdOOQO'#Ck'#CkOOQO'#Cl'#ClOOQO'#Cu'#CuP%[OQO'#C]POOO)C>q)C>qO%gQPO,58yOYQPO,58}OYQPO,59^OYQPO,59[O%lQPO'#CsOOQO'#Cs'#CsO%qQPO'#CsO&{QPO,59XOOQO,59X,59XO'SQPO'#DXO'aQPO,59YO'fQPO,59`O'|QPO,59bO(TQPO'#CfOOQO,59O,59OPOOO'#Cw'#CwP([OQO,58wPOOO,58w,58wO(gQPO'#CbOOQO1G.e1G.eOOQO1G.m1G.mO)zQPO1G.iO*RQPO1G.xO*iQPO1G.vOOQO,59_,59_OYQPO1G.sOYQPO'#CxO*pQPO,59sOOQO1G.t1G.tOOQO1G.|1G.|O*{QPO,59QPOOO-E6u-E6uPOOO1G.c1G.cOOQO7+$T7+$TOYQPO7+$bO+QQPO7+$_O+[QPO,59dOOQO-E6v-E6vOOQO1G.l1G.lO+iQPO<<G|OYQPO'#CyO,PQPO<<GyOOQO<<Gy<<GyO,XQPO,59eOOQO-E6w-E6wOOQOAN=eAN=eOYQPO1G/PO,`QPO7+$k",
22
- stateData: ",r~OpOSqPQ~O]WO^WOvROxTOzVO}YO!OYO!PYO!QYO!RZO!SZO!USO!^[O!c[O!d[O!e[O!f[O~Oq]O~OS_OT_OeaOx`O!WbO!XcO!ZcO![dO!]dO!^eO!_dO!`dO!adO!bdO~OScXTcXecXncXxcXzXX!WcX!XcX!ZcX![cX!]cX!^cX!_cX!`cX!acX!bcX!VcXwcX|cXycX!TcX~O!TgO~PYOw{P~PYOzlO~OrnOsnOtpO~OvqO~O!YwO~O!_wO]gX^gXvgXxgXzgX}gX!OgX!PgX!QgX!RgX!SgX!UgX!^gX!cgX!dgX!egX!fgX~O!VxO~P!fO|yOw{Xy{X~P!fOw{O~Onha!Vhawha|hayha!Tha~P!fOy|O~P!fOy{P~PYOrnOsnOt!PO~OSUXTUXeUXnUXxUXz[X!WUX!XUX!ZUX![UX!]UX!^UX!_UX!`UX!aUX!bUX!VUXwUX|UXyUX!TUX~Ow!QO~P!fOnfi!Vfiwfi|fiyfi!Tfi~P!fO!V!RO~P!fO|yOw{ay{a~Oy!VO~O|!XO!T!ZO~P!fOwla|layla~P!fOndy!Vdywdy|dyydy!Tdy~P!fO|!XO!T!^O~O!V!_O~P!fO|mq!Tmq~P!fO^TeS]vS~",
23
- goto: "%O|P}P!QPP!b!Q!Q!e!u!e!xPP!Q!Q!Q!Q!Q!QP!Q!{!Q#[!Q#l#r#xPPPPPPP$OPPPPP$xR^PmWOSTUV`ablxy!R!X!_Rr_mXOSTUV`ablxy!R!X!_RmXRs_kaQfhjktuv!S!T!W![!`mUOSTUV`ablxy!R!X!_Qo]R!OoQzhR!UzQ!Y!SR!]!YQQOQfSShTlQjUQkVQt`QuaQvbQ!SxQ!TyQ!W!RQ![!XR!`!_QiTR}l",
24
- nodeNames: "⚠ BlockComment Expression PropertyAccess MemberOf NullSafeMemberOf Property ArrayAccess Call Function Arguments MethodAccess Method Number String Boolean Null Object Array Variable TernaryExpression Operator BinaryExpression OperatorKeyword UnaryExpression UnaryOperator Application",
25
- maxTerm: 68,
21
+ states: ")YOYQPOOP!aOPOOQ!fQQOOO#gQQO'#CgO$}QPO'#CoO%UQPO'#CpOYQPO'#CvOYQPO'#CxOOQO'#DT'#DTO%]QPO'#CfOOQO'#Cm'#CmOOQO'#Cn'#CnOOQO'#Cw'#CwP%bOSO'#C]POOO)C>s)C>sO%mQPO,58yOYQPO,58}OYQPO,59`OYQPO,59^O%rQPO'#CuOOQO'#Cu'#CuO%wQPO'#CuO'RQQO,59ZOOQO,59Z,59ZO'YQQO'#DYO'gQPO,59[O'lQQO,59bO(SQQO,59dO(ZQPO'#ChOOQO,59Q,59QPOOO'#Cy'#CyP(bOSO,58wPOOO,58w,58wO(mQQO'#CbOOQO1G.e1G.eOOQO1G.o1G.oO*TQQO1G.iO*[QQO1G.zO*rQQO1G.xOOQO,59a,59aOYQPO1G.uOYQPO'#CzO*yQPO,59tOOQO1G.v1G.vOOQO1G/O1G/OO+UQPO,59SPOOO-E6w-E6wPOOO1G.c1G.cOOQO7+$T7+$TOYQPO7+$dO+ZQQO7+$aO+eQQO,59fOOQO-E6x-E6xOOQO1G.n1G.nO+rQQO<<HOOYQPO'#C{O,YQPO<<G{OOQO<<G{<<G{O,bQQO,59gOOQO-E6y-E6yOOQOAN=gAN=gOYQPO1G/RO,iQQO7+$m",
22
+ stateData: ",{~OrOSsPQ~O_WO`WOxRO{VO!OYO!PYO!QYO!RYO!SZO!TZO!VSO!XTO!`[O!e[O!f[O!g[O!h[O~Os]O~OS_OT_OW`OX`OgaO!YbO!ZcO!]cO!^dO!_dO!`eO!adO!bdO!cdO!ddO~OSeXTeXWeXXeXgeXpeX{ZX!YeX!ZeX!]eX!^eX!_eX!`eX!aeX!beX!ceX!deX!WeXyeX}eXzeX!UeX~O!UgO~PYOy|P~PYO{lO~OtnOunOvpO~OxqO~O![wO~O!awO_iX`iXxiX{iX!OiX!PiX!QiX!RiX!SiX!TiX!ViX!XiX!`iX!eiX!fiX!giX!hiX~O!WxO~P!fO}yOy|Xz|X~P!fOy{O~Opja!Wjayja}jazja!Uja~P!fOz|O~P!fOz|P~PYOtnOunOv!PO~OSUXTUXWUXXUXgUXpUX{^X!YUX!ZUX!]UX!^UX!_UX!`UX!aUX!bUX!cUX!dUX!WUXyUX}UXzUX!UUX~Oy!QO~P!fOphi!Whiyhi}hizhi!Uhi~P!fO!W!RO~P!fO}yOy|az|a~Oz!VO~O}!XO!U!ZO~P!fOyna}nazna~P!fOpfy!Wfyyfy}fyzfy!Ufy~P!fO}!XO!U!^O~O!W!_O~P!fO}oq!Uoq~P!fO`TgS_xS~",
23
+ goto: "%P}P!OP!RPP!c!RPP!R!f!v!f!yPP!R!R!R!R!R!RP!R!|!R#]!R#m#s#yPPPPPPP$PPPPP$yR^PmWOSTUV`ablxy!R!X!_Rr_mXOSTUV`ablxy!R!X!_RmXRs_kaQfhjktuv!S!T!W![!`mUOSTUV`ablxy!R!X!_Qo]R!OoQzhR!UzQ!Y!SR!]!YQQOQfSShTlQjUQkVQt`QuaQvbQ!SxQ!TyQ!W!RQ![!XR!`!_QiTR}l",
24
+ nodeNames: "⚠ BlockComment Expression PropertyAccess MemberOf NullSafeMemberOf Property ArrayAccess ArrayAccessor NullSafeArrayAccessor Call Function Arguments MethodAccess Method Number String Boolean Null Object Array Variable TernaryExpression Operator BinaryExpression OperatorKeyword UnaryExpression UnaryOperator Application",
25
+ maxTerm: 70,
26
26
  nodeProps: [
27
- [t, 13,"number",14,"string",15,"bool",16,"null",17,"object",18,"array"]
27
+ [t, 15,"number",16,"string",17,"bool",18,"null",19,"object",20,"array"]
28
28
  ],
29
- skippedNodes: [0,1,27],
29
+ skippedNodes: [0,1,29],
30
30
  repeatNodeCount: 3,
31
- 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#{~#_Sp~XY#YYZ#Y]^#Ypq#Y~#pPe~!_!`#s~#xPe~!_!`#{~$QOe~~$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~&PPe~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~'|Oz~~(ROy~~(WPe~z{#{~(`O|~~(ePS~!O!P#{~(mPe~z{(p~(uOq~~(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!V~~+fQe~!^!_#{!_!`#{~+oP!_!`#s~+wQe~!_!`#{!`!a#{~,SRe~!O!P,]![!]#{!a!b#{~,bOT~~,gSv~!Q![,b!c!},b#R#S,b#T#o,b~,xOx~~,}Ow~~-SO!U~~-XPe~#p#q#{~-aO!T~",
32
- tokenizers: [1, new lr.LocalTokenGroup("j~RQYZXz{^~^Os~~aP!P!Qd~iOt~~", 25, 34)],
31
+ tokenData: "-k~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!},j!}#O,{#P#Q-S#Q#R#{#R#S,j#T#o,j#o#p-X#p#q-^#q#r-f#r#s#{~#_Sr~XY#YYZ#Y]^#Ypq#Y~#pPg~!_!`#s~#xPg~!_!`#{~$QOg~~$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~&PPg~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~~(WPg~z{#{~(`O}~~(ePS~!O!P#{~(mPg~z{(p~(uOs~~(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~~+fQg~!^!_#{!_!`#{~+oP!_!`#s~+wQg~!_!`#{!`!a#{~,SRg~!O!P,]![!]#{!a!b#{~,bPT~!}#O,e~,jOX~~,oSx~!Q![,j!c!},j#R#S,j#T#o,jU-SO!XQWS~-XOy~~-^O!V~~-cPg~#p#q#{~-kO!U~",
32
+ tokenizers: [1, 2, new lr.LocalTokenGroup("j~RQYZXz{^~^Ou~~aP!P!Qd~iOv~~", 25, 36)],
33
33
  topRules: {"Expression":[0,2]},
34
- specialized: [{term: 38, get: (value) => spec_word[value] || -1},{term: 21, get: (value) => spec_Operator[value] || -1}],
35
- tokenPrec: 532
34
+ specialized: [{term: 40, get: (value) => spec_word[value] || -1},{term: 23, get: (value) => spec_Operator[value] || -1}],
35
+ tokenPrec: 541
36
36
  });
37
37
 
38
38
  // generate CONFIGURATION.md from this file by running "tsdoc --src=src/types.ts --dest=CONFIGURATION.md --noemoji --types"
@@ -56,21 +56,23 @@ exports.ELScalar = void 0;
56
56
  const BlockComment = 1,
57
57
  Expression = 2,
58
58
  PropertyAccess = 3,
59
+ NullSafeMemberOf = 5,
59
60
  Property = 6,
60
61
  ArrayAccess = 7,
61
- Call = 8,
62
- Function = 9,
63
- Arguments = 10,
64
- MethodAccess = 11,
65
- Method = 12,
66
- String = 14,
67
- Array$1 = 18,
68
- Variable = 19,
69
- TernaryExpression = 20,
70
- BinaryExpression = 22,
71
- OperatorKeyword = 23,
72
- UnaryExpression = 24,
73
- Application = 26;
62
+ NullSafeArrayAccessor = 9,
63
+ Call = 10,
64
+ Function = 11,
65
+ Arguments = 12,
66
+ MethodAccess = 13,
67
+ Method = 14,
68
+ String = 16,
69
+ Array$1 = 20,
70
+ Variable = 21,
71
+ TernaryExpression = 22,
72
+ BinaryExpression = 24,
73
+ OperatorKeyword = 25,
74
+ UnaryExpression = 26,
75
+ Application = 28;
74
76
 
75
77
  const createInfoElement = (html) => {
76
78
  const dom = document.createElement("div");
@@ -94,7 +96,7 @@ function resolveFunctionDefinition(node, state, config) {
94
96
  let identifier;
95
97
  if ((node.type.is(PropertyAccess) || node.type.is(MethodAccess)) && node.lastChild) {
96
98
  const leftArgument = (_a = node.firstChild) === null || _a === void 0 ? void 0 : _a.node;
97
- const types = Array.from(resolveTypes(state, leftArgument, config));
99
+ const types = window.Array.from(resolveTypes(state, leftArgument, config));
98
100
  identifier = state.sliceDoc(node.lastChild.from, node.lastChild.to);
99
101
  return types.map(type => { var _a; return resolveCallable(identifier, (_a = config.types) === null || _a === void 0 ? void 0 : _a[type]); }).find(x => x);
100
102
  }
@@ -123,7 +125,29 @@ function resolveTypes(state, node, config) {
123
125
  }
124
126
  let type;
125
127
  if (typeof (type = node.type.prop(t)) !== "undefined") {
126
- types.add(type);
128
+ if (type === exports.ELScalar.Array) {
129
+ // For array literals, infer element types from array contents
130
+ const elementTypes = new Set();
131
+ for (let child = node.firstChild; child; child = child.nextSibling) {
132
+ if (!child.type.isError) {
133
+ resolveTypes(state, child, config).forEach(elementType => {
134
+ elementTypes.add(elementType);
135
+ });
136
+ }
137
+ }
138
+ if (elementTypes.size > 0) {
139
+ // Build typed array notation (e.g., "string[]")
140
+ elementTypes.forEach(elementType => {
141
+ types.add(`${elementType}[]`);
142
+ });
143
+ }
144
+ else {
145
+ types.add(type);
146
+ }
147
+ }
148
+ else {
149
+ types.add(type);
150
+ }
127
151
  }
128
152
  else if (node.type.is(Call) && node.firstChild && node.lastChild) {
129
153
  resolveTypes(state, node.firstChild, config).forEach(x => types.add(x));
@@ -145,6 +169,9 @@ function resolveTypes(state, node, config) {
145
169
  // @ts-expect-error TS2339
146
170
  (_d = (_c = resolveIdentifier((_a = node.lastChild) === null || _a === void 0 ? void 0 : _a.type.id, 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));
147
171
  });
172
+ if (node.getChild(NullSafeMemberOf)) {
173
+ types.add(exports.ELScalar.Null);
174
+ }
148
175
  }
149
176
  else if (node.type.is(MethodAccess) && node.firstChild && ((_g = node.lastChild) === null || _g === void 0 ? void 0 : _g.type.is(Method))) {
150
177
  const varName = state.sliceDoc(node.lastChild.from, node.lastChild.to) || '';
@@ -153,6 +180,9 @@ function resolveTypes(state, node, config) {
153
180
  // @ts-expect-error TS2339
154
181
  (_d = (_c = resolveIdentifier((_a = node.lastChild) === null || _a === void 0 ? void 0 : _a.type.id, 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));
155
182
  });
183
+ if (node.getChild(NullSafeMemberOf)) {
184
+ types.add(exports.ELScalar.Null);
185
+ }
156
186
  }
157
187
  // Array indexing: for typed arrays (e.g. Foo[]) return element type, for generic arrays return any
158
188
  else if (node.type.is(ArrayAccess) && node.firstChild) {
@@ -165,6 +195,9 @@ function resolveTypes(state, node, config) {
165
195
  types.add(exports.ELScalar.Any);
166
196
  }
167
197
  });
198
+ if (node.getChild(NullSafeArrayAccessor)) {
199
+ types.add(exports.ELScalar.Null);
200
+ }
168
201
  }
169
202
  else if (node.type.is(Application) && node.firstChild) {
170
203
  resolveTypes(state, node.firstChild, config).forEach(x => types.add(x));
@@ -236,7 +269,7 @@ const expressionLanguageLinterSource = (state) => {
236
269
  const config = getExpressionLanguageConfig(state);
237
270
  const diagnostics = [];
238
271
  language.syntaxTree(state).cursor().iterate(node => {
239
- var _a, _b, _c, _d, _e, _f;
272
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
240
273
  const { from, to, type: { id } } = node;
241
274
  let identifier;
242
275
  switch (id) {
@@ -292,7 +325,19 @@ const expressionLanguageLinterSource = (state) => {
292
325
  }
293
326
  case Property:
294
327
  case Method: {
295
- const leftArgument = (_e = (_d = node.node.parent) === null || _d === void 0 ? void 0 : _d.firstChild) === null || _e === void 0 ? void 0 : _e.node;
328
+ const parent = node.node.parent;
329
+ const isPropertyAccess = parent === null || parent === void 0 ? void 0 : parent.type.is(PropertyAccess);
330
+ const isMethodAccess = parent === null || parent === void 0 ? void 0 : parent.type.is(MethodAccess);
331
+ // Skip validation if this is part of a PropertyAccess/MethodAccess on array type
332
+ // (the PropertyAccess/MethodAccess case will handle the error)
333
+ if ((isPropertyAccess || isMethodAccess) && (parent === null || parent === void 0 ? void 0 : parent.firstChild)) {
334
+ const types = Array.from(resolveTypes(state, parent.firstChild.node, config));
335
+ const hasArrayType = types.includes(exports.ELScalar.Array) || types.some(x => x.endsWith('[]'));
336
+ if (hasArrayType && !types.includes(exports.ELScalar.Any)) {
337
+ break; // Skip property validation, error will be reported by PropertyAccess/MethodAccess case
338
+ }
339
+ }
340
+ const leftArgument = (_d = parent === null || parent === void 0 ? void 0 : parent.firstChild) === null || _d === void 0 ? void 0 : _d.node;
296
341
  const types = Array.from(resolveTypes(state, leftArgument, config));
297
342
  identifier = state.sliceDoc(from, to);
298
343
  if (!types.find(type => { var _a; return resolveIdentifier(id, identifier, (_a = config.types) === null || _a === void 0 ? void 0 : _a[type]); })) {
@@ -300,6 +345,29 @@ const expressionLanguageLinterSource = (state) => {
300
345
  }
301
346
  break;
302
347
  }
348
+ case PropertyAccess:
349
+ case MethodAccess: {
350
+ const leftArgument = (_e = node.node.firstChild) === null || _e === void 0 ? void 0 : _e.node;
351
+ const types = Array.from(resolveTypes(state, leftArgument, config));
352
+ const hasArrayType = types.includes(exports.ELScalar.Array) || types.some(x => x.endsWith('[]'));
353
+ if (hasArrayType && !types.includes(exports.ELScalar.Any)) {
354
+ const propertyOrMethod = node.node.lastChild;
355
+ const errorFrom = (_f = propertyOrMethod === null || propertyOrMethod === void 0 ? void 0 : propertyOrMethod.from) !== null && _f !== void 0 ? _f : from;
356
+ const errorTo = (_g = propertyOrMethod === null || propertyOrMethod === void 0 ? void 0 : propertyOrMethod.to) !== null && _g !== void 0 ? _g : to;
357
+ diagnostics.push({ from: errorFrom, to: errorTo, severity: 'error', message: `Unexpected object access on <code>${types.join('|')}</code>` });
358
+ }
359
+ break;
360
+ }
361
+ case ArrayAccess: {
362
+ const leftArgument = (_h = node.node.firstChild) === null || _h === void 0 ? void 0 : _h.node;
363
+ const arrayAccessor = leftArgument.nextSibling;
364
+ const types = Array.from(resolveTypes(state, leftArgument, config));
365
+ const allowsAny = types.includes(exports.ELScalar.Array) || types.includes(exports.ELScalar.Any);
366
+ if (!allowsAny && ![...types].some(x => x.endsWith('[]'))) {
367
+ diagnostics.push({ from: arrayAccessor.from, to, severity: 'error', message: `Unexpected array access on <code>${types.join('|')}</code>` });
368
+ }
369
+ break;
370
+ }
303
371
  case Variable:
304
372
  case Function: {
305
373
  identifier = state.sliceDoc(from, node.node.firstChild ? node.node.firstChild.from - 1 : to);
@@ -340,7 +408,7 @@ const expressionLanguageLinterSource = (state) => {
340
408
  break;
341
409
  }
342
410
  }
343
- if (identifier && ((_f = node.node.parent) === null || _f === void 0 ? void 0 : _f.type.isError)) {
411
+ if (identifier && ((_j = node.node.parent) === null || _j === void 0 ? void 0 : _j.type.isError)) {
344
412
  diagnostics.push({ from, to, severity: 'error', message: `Unexpected identifier <code>${identifier}</code>` });
345
413
  }
346
414
  });
@@ -436,7 +504,7 @@ function expressionLanguageCompletion(context) {
436
504
  const { state, pos, explicit } = context;
437
505
  const tree = language.syntaxTree(state);
438
506
  const lastChar = state.sliceDoc(pos - 1, pos);
439
- const prevNode = tree.resolveInner(pos, lastChar === ')' ? 0 : -1);
507
+ const prevNode = tree.resolveInner(pos, (lastChar === ')' || lastChar === ']') ? 0 : -1);
440
508
  const config = getExpressionLanguageConfig(state);
441
509
  const isIdentifier = (node) => (node === null || node === void 0 ? void 0 : node.type.is(Variable)) || (node === null || node === void 0 ? void 0 : node.type.is(Function));
442
510
  const isMember = (node) => (node === null || node === void 0 ? void 0 : node.type.is(Property)) || (node === null || node === void 0 ? void 0 : node.type.is(Method));
package/dist/index.js CHANGED
@@ -12,25 +12,25 @@ const t = {
12
12
  };
13
13
 
14
14
  // This file was generated by lezer-generator. You probably shouldn't edit it.
15
- const spec_word = {__proto__:null,true:90, TRUE:92, false:94, FALSE:96, null:98, NULL:100, starts:110, with:112, ends:114, contains:116, matches:118, not:120, in:122, and:124, or:126, xor:128};
16
- const spec_Operator = {__proto__:null,"?":109, "!":131, "~":133, "+":135, "-":137};
15
+ const spec_word = {__proto__:null,true:92, TRUE:94, false:96, FALSE:98, null:100, NULL:102, starts:114, with:116, ends:118, contains:120, matches:122, not:124, in:126, and:128, or:130, xor:132};
16
+ const spec_Operator = {__proto__:null,"?":113, "!":135, "~":137, "+":139, "-":141};
17
17
  const parser = /*@__PURE__*/LRParser.deserialize({
18
18
  version: 14,
19
- states: ")YOYQPOOP!aOPOOQ!fQPOOO#dQPO'#CeO$wQPO'#CmO%OQPO'#CnOYQPO'#CtOYQPO'#CvOOQO'#DR'#DRO%VQPO'#CdOOQO'#Ck'#CkOOQO'#Cl'#ClOOQO'#Cu'#CuP%[OQO'#C]POOO)C>q)C>qO%gQPO,58yOYQPO,58}OYQPO,59^OYQPO,59[O%lQPO'#CsOOQO'#Cs'#CsO%qQPO'#CsO&{QPO,59XOOQO,59X,59XO'SQPO'#DXO'aQPO,59YO'fQPO,59`O'|QPO,59bO(TQPO'#CfOOQO,59O,59OPOOO'#Cw'#CwP([OQO,58wPOOO,58w,58wO(gQPO'#CbOOQO1G.e1G.eOOQO1G.m1G.mO)zQPO1G.iO*RQPO1G.xO*iQPO1G.vOOQO,59_,59_OYQPO1G.sOYQPO'#CxO*pQPO,59sOOQO1G.t1G.tOOQO1G.|1G.|O*{QPO,59QPOOO-E6u-E6uPOOO1G.c1G.cOOQO7+$T7+$TOYQPO7+$bO+QQPO7+$_O+[QPO,59dOOQO-E6v-E6vOOQO1G.l1G.lO+iQPO<<G|OYQPO'#CyO,PQPO<<GyOOQO<<Gy<<GyO,XQPO,59eOOQO-E6w-E6wOOQOAN=eAN=eOYQPO1G/PO,`QPO7+$k",
20
- stateData: ",r~OpOSqPQ~O]WO^WOvROxTOzVO}YO!OYO!PYO!QYO!RZO!SZO!USO!^[O!c[O!d[O!e[O!f[O~Oq]O~OS_OT_OeaOx`O!WbO!XcO!ZcO![dO!]dO!^eO!_dO!`dO!adO!bdO~OScXTcXecXncXxcXzXX!WcX!XcX!ZcX![cX!]cX!^cX!_cX!`cX!acX!bcX!VcXwcX|cXycX!TcX~O!TgO~PYOw{P~PYOzlO~OrnOsnOtpO~OvqO~O!YwO~O!_wO]gX^gXvgXxgXzgX}gX!OgX!PgX!QgX!RgX!SgX!UgX!^gX!cgX!dgX!egX!fgX~O!VxO~P!fO|yOw{Xy{X~P!fOw{O~Onha!Vhawha|hayha!Tha~P!fOy|O~P!fOy{P~PYOrnOsnOt!PO~OSUXTUXeUXnUXxUXz[X!WUX!XUX!ZUX![UX!]UX!^UX!_UX!`UX!aUX!bUX!VUXwUX|UXyUX!TUX~Ow!QO~P!fOnfi!Vfiwfi|fiyfi!Tfi~P!fO!V!RO~P!fO|yOw{ay{a~Oy!VO~O|!XO!T!ZO~P!fOwla|layla~P!fOndy!Vdywdy|dyydy!Tdy~P!fO|!XO!T!^O~O!V!_O~P!fO|mq!Tmq~P!fO^TeS]vS~",
21
- goto: "%O|P}P!QPP!b!Q!Q!e!u!e!xPP!Q!Q!Q!Q!Q!QP!Q!{!Q#[!Q#l#r#xPPPPPPP$OPPPPP$xR^PmWOSTUV`ablxy!R!X!_Rr_mXOSTUV`ablxy!R!X!_RmXRs_kaQfhjktuv!S!T!W![!`mUOSTUV`ablxy!R!X!_Qo]R!OoQzhR!UzQ!Y!SR!]!YQQOQfSShTlQjUQkVQt`QuaQvbQ!SxQ!TyQ!W!RQ![!XR!`!_QiTR}l",
22
- nodeNames: "⚠ BlockComment Expression PropertyAccess MemberOf NullSafeMemberOf Property ArrayAccess Call Function Arguments MethodAccess Method Number String Boolean Null Object Array Variable TernaryExpression Operator BinaryExpression OperatorKeyword UnaryExpression UnaryOperator Application",
23
- maxTerm: 68,
19
+ states: ")YOYQPOOP!aOPOOQ!fQQOOO#gQQO'#CgO$}QPO'#CoO%UQPO'#CpOYQPO'#CvOYQPO'#CxOOQO'#DT'#DTO%]QPO'#CfOOQO'#Cm'#CmOOQO'#Cn'#CnOOQO'#Cw'#CwP%bOSO'#C]POOO)C>s)C>sO%mQPO,58yOYQPO,58}OYQPO,59`OYQPO,59^O%rQPO'#CuOOQO'#Cu'#CuO%wQPO'#CuO'RQQO,59ZOOQO,59Z,59ZO'YQQO'#DYO'gQPO,59[O'lQQO,59bO(SQQO,59dO(ZQPO'#ChOOQO,59Q,59QPOOO'#Cy'#CyP(bOSO,58wPOOO,58w,58wO(mQQO'#CbOOQO1G.e1G.eOOQO1G.o1G.oO*TQQO1G.iO*[QQO1G.zO*rQQO1G.xOOQO,59a,59aOYQPO1G.uOYQPO'#CzO*yQPO,59tOOQO1G.v1G.vOOQO1G/O1G/OO+UQPO,59SPOOO-E6w-E6wPOOO1G.c1G.cOOQO7+$T7+$TOYQPO7+$dO+ZQQO7+$aO+eQQO,59fOOQO-E6x-E6xOOQO1G.n1G.nO+rQQO<<HOOYQPO'#C{O,YQPO<<G{OOQO<<G{<<G{O,bQQO,59gOOQO-E6y-E6yOOQOAN=gAN=gOYQPO1G/RO,iQQO7+$m",
20
+ stateData: ",{~OrOSsPQ~O_WO`WOxRO{VO!OYO!PYO!QYO!RYO!SZO!TZO!VSO!XTO!`[O!e[O!f[O!g[O!h[O~Os]O~OS_OT_OW`OX`OgaO!YbO!ZcO!]cO!^dO!_dO!`eO!adO!bdO!cdO!ddO~OSeXTeXWeXXeXgeXpeX{ZX!YeX!ZeX!]eX!^eX!_eX!`eX!aeX!beX!ceX!deX!WeXyeX}eXzeX!UeX~O!UgO~PYOy|P~PYO{lO~OtnOunOvpO~OxqO~O![wO~O!awO_iX`iXxiX{iX!OiX!PiX!QiX!RiX!SiX!TiX!ViX!XiX!`iX!eiX!fiX!giX!hiX~O!WxO~P!fO}yOy|Xz|X~P!fOy{O~Opja!Wjayja}jazja!Uja~P!fOz|O~P!fOz|P~PYOtnOunOv!PO~OSUXTUXWUXXUXgUXpUX{^X!YUX!ZUX!]UX!^UX!_UX!`UX!aUX!bUX!cUX!dUX!WUXyUX}UXzUX!UUX~Oy!QO~P!fOphi!Whiyhi}hizhi!Uhi~P!fO!W!RO~P!fO}yOy|az|a~Oz!VO~O}!XO!U!ZO~P!fOyna}nazna~P!fOpfy!Wfyyfy}fyzfy!Ufy~P!fO}!XO!U!^O~O!W!_O~P!fO}oq!Uoq~P!fO`TgS_xS~",
21
+ goto: "%P}P!OP!RPP!c!RPP!R!f!v!f!yPP!R!R!R!R!R!RP!R!|!R#]!R#m#s#yPPPPPPP$PPPPP$yR^PmWOSTUV`ablxy!R!X!_Rr_mXOSTUV`ablxy!R!X!_RmXRs_kaQfhjktuv!S!T!W![!`mUOSTUV`ablxy!R!X!_Qo]R!OoQzhR!UzQ!Y!SR!]!YQQOQfSShTlQjUQkVQt`QuaQvbQ!SxQ!TyQ!W!RQ![!XR!`!_QiTR}l",
22
+ nodeNames: "⚠ BlockComment Expression PropertyAccess MemberOf NullSafeMemberOf Property ArrayAccess ArrayAccessor NullSafeArrayAccessor Call Function Arguments MethodAccess Method Number String Boolean Null Object Array Variable TernaryExpression Operator BinaryExpression OperatorKeyword UnaryExpression UnaryOperator Application",
23
+ maxTerm: 70,
24
24
  nodeProps: [
25
- [t, 13,"number",14,"string",15,"bool",16,"null",17,"object",18,"array"]
25
+ [t, 15,"number",16,"string",17,"bool",18,"null",19,"object",20,"array"]
26
26
  ],
27
- skippedNodes: [0,1,27],
27
+ skippedNodes: [0,1,29],
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#{~#_Sp~XY#YYZ#Y]^#Ypq#Y~#pPe~!_!`#s~#xPe~!_!`#{~$QOe~~$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~&PPe~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~'|Oz~~(ROy~~(WPe~z{#{~(`O|~~(ePS~!O!P#{~(mPe~z{(p~(uOq~~(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!V~~+fQe~!^!_#{!_!`#{~+oP!_!`#s~+wQe~!_!`#{!`!a#{~,SRe~!O!P,]![!]#{!a!b#{~,bOT~~,gSv~!Q![,b!c!},b#R#S,b#T#o,b~,xOx~~,}Ow~~-SO!U~~-XPe~#p#q#{~-aO!T~",
30
- tokenizers: [1, /*@__PURE__*/new LocalTokenGroup("j~RQYZXz{^~^Os~~aP!P!Qd~iOt~~", 25, 34)],
29
+ tokenData: "-k~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!},j!}#O,{#P#Q-S#Q#R#{#R#S,j#T#o,j#o#p-X#p#q-^#q#r-f#r#s#{~#_Sr~XY#YYZ#Y]^#Ypq#Y~#pPg~!_!`#s~#xPg~!_!`#{~$QOg~~$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~&PPg~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~~(WPg~z{#{~(`O}~~(ePS~!O!P#{~(mPg~z{(p~(uOs~~(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~~+fQg~!^!_#{!_!`#{~+oP!_!`#s~+wQg~!_!`#{!`!a#{~,SRg~!O!P,]![!]#{!a!b#{~,bPT~!}#O,e~,jOX~~,oSx~!Q![,j!c!},j#R#S,j#T#o,jU-SO!XQWS~-XOy~~-^O!V~~-cPg~#p#q#{~-kO!U~",
30
+ tokenizers: [1, 2, /*@__PURE__*/new LocalTokenGroup("j~RQYZXz{^~^Ou~~aP!P!Qd~iOv~~", 25, 36)],
31
31
  topRules: {"Expression":[0,2]},
32
- specialized: [{term: 38, get: (value) => spec_word[value] || -1},{term: 21, get: (value) => spec_Operator[value] || -1}],
33
- tokenPrec: 532
32
+ specialized: [{term: 40, get: (value) => spec_word[value] || -1},{term: 23, get: (value) => spec_Operator[value] || -1}],
33
+ tokenPrec: 541
34
34
  });
35
35
 
36
36
  // generate CONFIGURATION.md from this file by running "tsdoc --src=src/types.ts --dest=CONFIGURATION.md --noemoji --types"
@@ -53,21 +53,23 @@ return ELScalar})(ELScalar || (ELScalar = {}));
53
53
  const BlockComment = 1,
54
54
  Expression = 2,
55
55
  PropertyAccess = 3,
56
+ NullSafeMemberOf = 5,
56
57
  Property = 6,
57
58
  ArrayAccess = 7,
58
- Call = 8,
59
- Function = 9,
60
- Arguments = 10,
61
- MethodAccess = 11,
62
- Method = 12,
63
- String = 14,
64
- Array$1 = 18,
65
- Variable = 19,
66
- TernaryExpression = 20,
67
- BinaryExpression = 22,
68
- OperatorKeyword = 23,
69
- UnaryExpression = 24,
70
- Application = 26;
59
+ NullSafeArrayAccessor = 9,
60
+ Call = 10,
61
+ Function = 11,
62
+ Arguments = 12,
63
+ MethodAccess = 13,
64
+ Method = 14,
65
+ String = 16,
66
+ Array$1 = 20,
67
+ Variable = 21,
68
+ TernaryExpression = 22,
69
+ BinaryExpression = 24,
70
+ OperatorKeyword = 25,
71
+ UnaryExpression = 26,
72
+ Application = 28;
71
73
 
72
74
  const createInfoElement = (html) => {
73
75
  const dom = document.createElement("div");
@@ -91,7 +93,7 @@ function resolveFunctionDefinition(node, state, config) {
91
93
  let identifier;
92
94
  if ((node.type.is(PropertyAccess) || node.type.is(MethodAccess)) && node.lastChild) {
93
95
  const leftArgument = (_a = node.firstChild) === null || _a === void 0 ? void 0 : _a.node;
94
- const types = Array.from(resolveTypes(state, leftArgument, config));
96
+ const types = window.Array.from(resolveTypes(state, leftArgument, config));
95
97
  identifier = state.sliceDoc(node.lastChild.from, node.lastChild.to);
96
98
  return types.map(type => { var _a; return resolveCallable(identifier, (_a = config.types) === null || _a === void 0 ? void 0 : _a[type]); }).find(x => x);
97
99
  }
@@ -120,7 +122,29 @@ function resolveTypes(state, node, config) {
120
122
  }
121
123
  let type;
122
124
  if (typeof (type = node.type.prop(t)) !== "undefined") {
123
- types.add(type);
125
+ if (type === ELScalar.Array) {
126
+ // For array literals, infer element types from array contents
127
+ const elementTypes = new Set();
128
+ for (let child = node.firstChild; child; child = child.nextSibling) {
129
+ if (!child.type.isError) {
130
+ resolveTypes(state, child, config).forEach(elementType => {
131
+ elementTypes.add(elementType);
132
+ });
133
+ }
134
+ }
135
+ if (elementTypes.size > 0) {
136
+ // Build typed array notation (e.g., "string[]")
137
+ elementTypes.forEach(elementType => {
138
+ types.add(`${elementType}[]`);
139
+ });
140
+ }
141
+ else {
142
+ types.add(type);
143
+ }
144
+ }
145
+ else {
146
+ types.add(type);
147
+ }
124
148
  }
125
149
  else if (node.type.is(Call) && node.firstChild && node.lastChild) {
126
150
  resolveTypes(state, node.firstChild, config).forEach(x => types.add(x));
@@ -142,6 +166,9 @@ function resolveTypes(state, node, config) {
142
166
  // @ts-expect-error TS2339
143
167
  (_d = (_c = resolveIdentifier((_a = node.lastChild) === null || _a === void 0 ? void 0 : _a.type.id, 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));
144
168
  });
169
+ if (node.getChild(NullSafeMemberOf)) {
170
+ types.add(ELScalar.Null);
171
+ }
145
172
  }
146
173
  else if (node.type.is(MethodAccess) && node.firstChild && ((_g = node.lastChild) === null || _g === void 0 ? void 0 : _g.type.is(Method))) {
147
174
  const varName = state.sliceDoc(node.lastChild.from, node.lastChild.to) || '';
@@ -150,6 +177,9 @@ function resolveTypes(state, node, config) {
150
177
  // @ts-expect-error TS2339
151
178
  (_d = (_c = resolveIdentifier((_a = node.lastChild) === null || _a === void 0 ? void 0 : _a.type.id, 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));
152
179
  });
180
+ if (node.getChild(NullSafeMemberOf)) {
181
+ types.add(ELScalar.Null);
182
+ }
153
183
  }
154
184
  // Array indexing: for typed arrays (e.g. Foo[]) return element type, for generic arrays return any
155
185
  else if (node.type.is(ArrayAccess) && node.firstChild) {
@@ -162,6 +192,9 @@ function resolveTypes(state, node, config) {
162
192
  types.add(ELScalar.Any);
163
193
  }
164
194
  });
195
+ if (node.getChild(NullSafeArrayAccessor)) {
196
+ types.add(ELScalar.Null);
197
+ }
165
198
  }
166
199
  else if (node.type.is(Application) && node.firstChild) {
167
200
  resolveTypes(state, node.firstChild, config).forEach(x => types.add(x));
@@ -233,7 +266,7 @@ const expressionLanguageLinterSource = (state) => {
233
266
  const config = getExpressionLanguageConfig(state);
234
267
  const diagnostics = [];
235
268
  syntaxTree(state).cursor().iterate(node => {
236
- var _a, _b, _c, _d, _e, _f;
269
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
237
270
  const { from, to, type: { id } } = node;
238
271
  let identifier;
239
272
  switch (id) {
@@ -289,7 +322,19 @@ const expressionLanguageLinterSource = (state) => {
289
322
  }
290
323
  case Property:
291
324
  case Method: {
292
- const leftArgument = (_e = (_d = node.node.parent) === null || _d === void 0 ? void 0 : _d.firstChild) === null || _e === void 0 ? void 0 : _e.node;
325
+ const parent = node.node.parent;
326
+ const isPropertyAccess = parent === null || parent === void 0 ? void 0 : parent.type.is(PropertyAccess);
327
+ const isMethodAccess = parent === null || parent === void 0 ? void 0 : parent.type.is(MethodAccess);
328
+ // Skip validation if this is part of a PropertyAccess/MethodAccess on array type
329
+ // (the PropertyAccess/MethodAccess case will handle the error)
330
+ if ((isPropertyAccess || isMethodAccess) && (parent === null || parent === void 0 ? void 0 : parent.firstChild)) {
331
+ const types = Array.from(resolveTypes(state, parent.firstChild.node, config));
332
+ const hasArrayType = types.includes(ELScalar.Array) || types.some(x => x.endsWith('[]'));
333
+ if (hasArrayType && !types.includes(ELScalar.Any)) {
334
+ break; // Skip property validation, error will be reported by PropertyAccess/MethodAccess case
335
+ }
336
+ }
337
+ const leftArgument = (_d = parent === null || parent === void 0 ? void 0 : parent.firstChild) === null || _d === void 0 ? void 0 : _d.node;
293
338
  const types = Array.from(resolveTypes(state, leftArgument, config));
294
339
  identifier = state.sliceDoc(from, to);
295
340
  if (!types.find(type => { var _a; return resolveIdentifier(id, identifier, (_a = config.types) === null || _a === void 0 ? void 0 : _a[type]); })) {
@@ -297,6 +342,29 @@ const expressionLanguageLinterSource = (state) => {
297
342
  }
298
343
  break;
299
344
  }
345
+ case PropertyAccess:
346
+ case MethodAccess: {
347
+ const leftArgument = (_e = node.node.firstChild) === null || _e === void 0 ? void 0 : _e.node;
348
+ const types = Array.from(resolveTypes(state, leftArgument, config));
349
+ const hasArrayType = types.includes(ELScalar.Array) || types.some(x => x.endsWith('[]'));
350
+ if (hasArrayType && !types.includes(ELScalar.Any)) {
351
+ const propertyOrMethod = node.node.lastChild;
352
+ const errorFrom = (_f = propertyOrMethod === null || propertyOrMethod === void 0 ? void 0 : propertyOrMethod.from) !== null && _f !== void 0 ? _f : from;
353
+ const errorTo = (_g = propertyOrMethod === null || propertyOrMethod === void 0 ? void 0 : propertyOrMethod.to) !== null && _g !== void 0 ? _g : to;
354
+ diagnostics.push({ from: errorFrom, to: errorTo, severity: 'error', message: `Unexpected object access on <code>${types.join('|')}</code>` });
355
+ }
356
+ break;
357
+ }
358
+ case ArrayAccess: {
359
+ const leftArgument = (_h = node.node.firstChild) === null || _h === void 0 ? void 0 : _h.node;
360
+ const arrayAccessor = leftArgument.nextSibling;
361
+ const types = Array.from(resolveTypes(state, leftArgument, config));
362
+ const allowsAny = types.includes(ELScalar.Array) || types.includes(ELScalar.Any);
363
+ if (!allowsAny && ![...types].some(x => x.endsWith('[]'))) {
364
+ diagnostics.push({ from: arrayAccessor.from, to, severity: 'error', message: `Unexpected array access on <code>${types.join('|')}</code>` });
365
+ }
366
+ break;
367
+ }
300
368
  case Variable:
301
369
  case Function: {
302
370
  identifier = state.sliceDoc(from, node.node.firstChild ? node.node.firstChild.from - 1 : to);
@@ -337,7 +405,7 @@ const expressionLanguageLinterSource = (state) => {
337
405
  break;
338
406
  }
339
407
  }
340
- if (identifier && ((_f = node.node.parent) === null || _f === void 0 ? void 0 : _f.type.isError)) {
408
+ if (identifier && ((_j = node.node.parent) === null || _j === void 0 ? void 0 : _j.type.isError)) {
341
409
  diagnostics.push({ from, to, severity: 'error', message: `Unexpected identifier <code>${identifier}</code>` });
342
410
  }
343
411
  });
@@ -433,7 +501,7 @@ function expressionLanguageCompletion(context) {
433
501
  const { state, pos, explicit } = context;
434
502
  const tree = syntaxTree(state);
435
503
  const lastChar = state.sliceDoc(pos - 1, pos);
436
- const prevNode = tree.resolveInner(pos, lastChar === ')' ? 0 : -1);
504
+ const prevNode = tree.resolveInner(pos, (lastChar === ')' || lastChar === ']') ? 0 : -1);
437
505
  const config = getExpressionLanguageConfig(state);
438
506
  const isIdentifier = (node) => (node === null || node === void 0 ? void 0 : node.type.is(Variable)) || (node === null || node === void 0 ? void 0 : node.type.is(Function));
439
507
  const isMember = (node) => (node === null || node === void 0 ? void 0 : node.type.is(Property)) || (node === null || node === void 0 ? void 0 : node.type.is(Method));
package/package.json CHANGED
@@ -44,5 +44,5 @@
44
44
  "access": "public",
45
45
  "registry": "https://registry.npmjs.org/"
46
46
  },
47
- "version": "1.3.0"
47
+ "version": "1.4.0"
48
48
  }