@valtzu/codemirror-lang-el 1.2.0 → 1.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/CHANGELOG.md +7 -0
- package/dist/index.cjs +47 -21
- package/dist/index.js +47 -21
- package/package.json +8 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
CHANGELOG
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
|
+
1.3
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
* Lint left- and right-side arguments of `contains`, `starts with`, `ends with` and `matches` operators
|
|
8
|
+
* Add eslint to make contributing/review easier
|
|
9
|
+
* Add type checking for left-side argument in `in` expression
|
|
10
|
+
|
|
4
11
|
1.2
|
|
5
12
|
---
|
|
6
13
|
|
package/dist/index.cjs
CHANGED
|
@@ -8,7 +8,7 @@ var autocomplete = require('@codemirror/autocomplete');
|
|
|
8
8
|
var state = require('@codemirror/state');
|
|
9
9
|
var view = require('@codemirror/view');
|
|
10
10
|
|
|
11
|
-
// @ts-
|
|
11
|
+
// @ts-expect-error TS2739
|
|
12
12
|
const t = {
|
|
13
13
|
deserialize: (str) => str,
|
|
14
14
|
};
|
|
@@ -117,7 +117,7 @@ const resolveIdentifier = (nodeTypeId, identifier, config) => {
|
|
|
117
117
|
};
|
|
118
118
|
function resolveTypes(state, node, config) {
|
|
119
119
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
120
|
-
|
|
120
|
+
const types = new Set();
|
|
121
121
|
if (!node) {
|
|
122
122
|
return types;
|
|
123
123
|
}
|
|
@@ -130,19 +130,19 @@ function resolveTypes(state, node, config) {
|
|
|
130
130
|
}
|
|
131
131
|
else if (node.type.is(Variable)) {
|
|
132
132
|
const varName = state.sliceDoc(node.from, node.to) || '';
|
|
133
|
-
// @ts-
|
|
133
|
+
// @ts-expect-error TS2339
|
|
134
134
|
(_b = (_a = resolveIdentifier(node.type.id, varName, config)) === null || _a === void 0 ? void 0 : _a.type) === null || _b === void 0 ? void 0 : _b.forEach((x) => types.add(x));
|
|
135
135
|
}
|
|
136
136
|
else if (node.type.is(Function)) {
|
|
137
137
|
const varName = state.sliceDoc(node.from, node.to) || '';
|
|
138
|
-
// @ts-
|
|
138
|
+
// @ts-expect-error TS2339
|
|
139
139
|
(_d = (_c = resolveIdentifier(node.type.id, varName, config)) === null || _c === void 0 ? void 0 : _c.returnType) === null || _d === void 0 ? void 0 : _d.forEach((x) => types.add(x));
|
|
140
140
|
}
|
|
141
141
|
else if (node.type.is(PropertyAccess) && node.firstChild && ((_e = node.lastChild) === null || _e === void 0 ? void 0 : _e.type.is(Property))) {
|
|
142
142
|
const varName = state.sliceDoc(node.lastChild.from, node.lastChild.to) || '';
|
|
143
143
|
(_f = resolveTypes(state, node.firstChild, config)) === null || _f === void 0 ? void 0 : _f.forEach(baseType => {
|
|
144
144
|
var _a, _b, _c, _d;
|
|
145
|
-
// @ts-
|
|
145
|
+
// @ts-expect-error TS2339
|
|
146
146
|
(_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
147
|
});
|
|
148
148
|
}
|
|
@@ -150,7 +150,7 @@ function resolveTypes(state, node, config) {
|
|
|
150
150
|
const varName = state.sliceDoc(node.lastChild.from, node.lastChild.to) || '';
|
|
151
151
|
(_h = resolveTypes(state, node.firstChild, config)) === null || _h === void 0 ? void 0 : _h.forEach(baseType => {
|
|
152
152
|
var _a, _b, _c, _d;
|
|
153
|
-
// @ts-
|
|
153
|
+
// @ts-expect-error TS2339
|
|
154
154
|
(_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
155
|
});
|
|
156
156
|
}
|
|
@@ -234,13 +234,13 @@ var utils = /*#__PURE__*/Object.freeze({
|
|
|
234
234
|
*/
|
|
235
235
|
const expressionLanguageLinterSource = (state) => {
|
|
236
236
|
const config = getExpressionLanguageConfig(state);
|
|
237
|
-
|
|
237
|
+
const diagnostics = [];
|
|
238
238
|
language.syntaxTree(state).cursor().iterate(node => {
|
|
239
239
|
var _a, _b, _c, _d, _e, _f;
|
|
240
240
|
const { from, to, type: { id } } = node;
|
|
241
241
|
let identifier;
|
|
242
242
|
switch (id) {
|
|
243
|
-
case 0:
|
|
243
|
+
case 0: {
|
|
244
244
|
if (state.doc.length === 0 || from === 0) {
|
|
245
245
|
// Don't show error on empty doc (even though it is an error)
|
|
246
246
|
return;
|
|
@@ -254,7 +254,8 @@ const expressionLanguageLinterSource = (state) => {
|
|
|
254
254
|
diagnostics.push({ from, to, severity: 'error', message: `Unexpected ${type} <code>${identifier}</code>` });
|
|
255
255
|
}
|
|
256
256
|
return;
|
|
257
|
-
|
|
257
|
+
}
|
|
258
|
+
case Arguments: {
|
|
258
259
|
const fn = resolveFunctionDefinition(node.node.prevSibling, state, config);
|
|
259
260
|
const args = fn === null || fn === void 0 ? void 0 : fn.args;
|
|
260
261
|
if (!args) {
|
|
@@ -275,7 +276,12 @@ const expressionLanguageLinterSource = (state) => {
|
|
|
275
276
|
const typesUsed = Array.from(resolveTypes(state, n, config));
|
|
276
277
|
const typesExpected = args[i].type;
|
|
277
278
|
if (typesExpected && !typesExpected.includes(exports.ELScalar.Any) && !typesUsed.some(x => typesExpected.includes(x))) {
|
|
278
|
-
diagnostics.push({
|
|
279
|
+
diagnostics.push({
|
|
280
|
+
from: n.from,
|
|
281
|
+
to: n.to,
|
|
282
|
+
severity: 'error',
|
|
283
|
+
message: `<code>${typesExpected.join('|')}</code> expected, got <code>${typesUsed.join('|')}</code>`
|
|
284
|
+
});
|
|
279
285
|
}
|
|
280
286
|
i++;
|
|
281
287
|
}
|
|
@@ -283,8 +289,9 @@ const expressionLanguageLinterSource = (state) => {
|
|
|
283
289
|
diagnostics.push({ from: node.from, to: node.to, severity: 'error', message: `Too few arguments – ${argumentCountHintFn()}` });
|
|
284
290
|
}
|
|
285
291
|
break;
|
|
292
|
+
}
|
|
286
293
|
case Property:
|
|
287
|
-
case Method:
|
|
294
|
+
case Method: {
|
|
288
295
|
const leftArgument = (_e = (_d = node.node.parent) === null || _d === void 0 ? void 0 : _d.firstChild) === null || _e === void 0 ? void 0 : _e.node;
|
|
289
296
|
const types = Array.from(resolveTypes(state, leftArgument, config));
|
|
290
297
|
identifier = state.sliceDoc(from, to);
|
|
@@ -292,26 +299,46 @@ const expressionLanguageLinterSource = (state) => {
|
|
|
292
299
|
diagnostics.push({ from, to, severity: 'error', message: `${node.name} <code>${identifier}</code> not found in <code>${types.join('|')}</code>` });
|
|
293
300
|
}
|
|
294
301
|
break;
|
|
302
|
+
}
|
|
295
303
|
case Variable:
|
|
296
|
-
case Function:
|
|
304
|
+
case Function: {
|
|
297
305
|
identifier = state.sliceDoc(from, node.node.firstChild ? node.node.firstChild.from - 1 : to);
|
|
298
306
|
if (!resolveIdentifier(id, identifier, config)) {
|
|
299
307
|
diagnostics.push({ from, to, severity: 'error', message: `${node.node.name} <code>${identifier}</code> not found` });
|
|
300
308
|
}
|
|
301
309
|
break;
|
|
302
|
-
|
|
310
|
+
}
|
|
311
|
+
case BinaryExpression: {
|
|
303
312
|
const operatorNode = node.node.getChild(OperatorKeyword);
|
|
304
313
|
if (operatorNode) {
|
|
305
314
|
const operator = state.sliceDoc(operatorNode.from, operatorNode.to);
|
|
315
|
+
const leftArgument = node.node.firstChild;
|
|
316
|
+
const rightArgument = node.node.lastChild;
|
|
306
317
|
if (operator === 'in') {
|
|
307
|
-
const
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
318
|
+
const leftTypes = resolveTypes(state, leftArgument, config);
|
|
319
|
+
const rightTypes = resolveTypes(state, rightArgument, config);
|
|
320
|
+
const allowsAny = rightTypes.has(exports.ELScalar.Array) || rightTypes.has(exports.ELScalar.Any);
|
|
321
|
+
if (!allowsAny && ![...rightTypes].some(x => x.endsWith('[]'))) {
|
|
322
|
+
diagnostics.push({ from: rightArgument.from, to: rightArgument.to, severity: 'error', message: `<code>${exports.ELScalar.Array}</code> expected, got <code>${[...rightTypes].join('|')}</code>` });
|
|
323
|
+
}
|
|
324
|
+
else if (!allowsAny && !rightTypes.has(`${exports.ELScalar.Any}[]`) && ![...leftTypes].some(type => rightTypes.has(`${type}[]`))) {
|
|
325
|
+
diagnostics.push({ from: leftArgument.from, to: rightArgument.to, severity: 'warning', message: `Expression is always <code>false</code> because <code>${[...leftTypes].join('|')}</code> not found in <code>${[...rightTypes].join('|')}</code>` });
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
else if (["contains", "starts with", "ends with", "matches"].includes(operator)) {
|
|
329
|
+
// Both sides must be string
|
|
330
|
+
const leftTypes = resolveTypes(state, leftArgument, config);
|
|
331
|
+
const rightTypes = resolveTypes(state, rightArgument, config);
|
|
332
|
+
if (!leftTypes.has(exports.ELScalar.String)) {
|
|
333
|
+
diagnostics.push({ from: leftArgument.from, to: leftArgument.to, severity: 'error', message: `<code>string</code> expected, got <code>${[...leftTypes].join('|')}</code>` });
|
|
334
|
+
}
|
|
335
|
+
if (!rightTypes.has(exports.ELScalar.String)) {
|
|
336
|
+
diagnostics.push({ from: rightArgument.from, to: rightArgument.to, severity: 'error', message: `<code>string</code> expected, got <code>${[...rightTypes].join('|')}</code>` });
|
|
311
337
|
}
|
|
312
338
|
}
|
|
313
339
|
}
|
|
314
340
|
break;
|
|
341
|
+
}
|
|
315
342
|
}
|
|
316
343
|
if (identifier && ((_f = node.node.parent) === null || _f === void 0 ? void 0 : _f.type.isError)) {
|
|
317
344
|
diagnostics.push({ from, to, severity: 'error', message: `Unexpected identifier <code>${identifier}</code>` });
|
|
@@ -383,7 +410,7 @@ function completeIdentifier(state, config, tree, from, to) {
|
|
|
383
410
|
validFor: /^[a-zA-Z_]+[a-zA-Z_0-9]*$/,
|
|
384
411
|
};
|
|
385
412
|
}
|
|
386
|
-
function completeMember(state, config, tree, from, to
|
|
413
|
+
function completeMember(state, config, tree, from, to) {
|
|
387
414
|
var _a, _b, _c, _d, _e, _f;
|
|
388
415
|
if (!(((_a = tree.parent) === null || _a === void 0 ? void 0 : _a.type.is(PropertyAccess)) || ((_b = tree.parent) === null || _b === void 0 ? void 0 : _b.type.is(MethodAccess))) || !((_c = tree.parent) === null || _c === void 0 ? void 0 : _c.firstChild)) {
|
|
389
416
|
return null;
|
|
@@ -392,7 +419,7 @@ function completeMember(state, config, tree, from, to, explicit) {
|
|
|
392
419
|
if (!(types === null || types === void 0 ? void 0 : types.size)) {
|
|
393
420
|
return null;
|
|
394
421
|
}
|
|
395
|
-
|
|
422
|
+
const options = [];
|
|
396
423
|
for (const type of types) {
|
|
397
424
|
const typeDeclaration = (_d = config.types) === null || _d === void 0 ? void 0 : _d[type];
|
|
398
425
|
options.push(...(((_e = typeDeclaration === null || typeDeclaration === void 0 ? void 0 : typeDeclaration.identifiers) === null || _e === void 0 ? void 0 : _e.map(autocompleteIdentifier)) || []), ...(((_f = typeDeclaration === null || typeDeclaration === void 0 ? void 0 : typeDeclaration.functions) === null || _f === void 0 ? void 0 : _f.map(autocompleteFunction)) || []));
|
|
@@ -454,7 +481,6 @@ function resolveArguments(node) {
|
|
|
454
481
|
}
|
|
455
482
|
function getCursorTooltips(state) {
|
|
456
483
|
const config = getExpressionLanguageConfig(state);
|
|
457
|
-
// @ts-ignore
|
|
458
484
|
return state.selection.ranges
|
|
459
485
|
.filter(range => range.empty)
|
|
460
486
|
.map(range => {
|
|
@@ -480,7 +506,7 @@ function getCursorTooltips(state) {
|
|
|
480
506
|
strictSide: false,
|
|
481
507
|
arrow: true,
|
|
482
508
|
create: () => {
|
|
483
|
-
|
|
509
|
+
const dom = document.createElement("div");
|
|
484
510
|
dom.className = "cm-tooltip-cursor";
|
|
485
511
|
dom.textContent = `${argName}`;
|
|
486
512
|
return { dom };
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ 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-
|
|
9
|
+
// @ts-expect-error TS2739
|
|
10
10
|
const t = {
|
|
11
11
|
deserialize: (str) => str,
|
|
12
12
|
};
|
|
@@ -114,7 +114,7 @@ const resolveIdentifier = (nodeTypeId, identifier, config) => {
|
|
|
114
114
|
};
|
|
115
115
|
function resolveTypes(state, node, config) {
|
|
116
116
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
117
|
-
|
|
117
|
+
const types = new Set();
|
|
118
118
|
if (!node) {
|
|
119
119
|
return types;
|
|
120
120
|
}
|
|
@@ -127,19 +127,19 @@ function resolveTypes(state, node, config) {
|
|
|
127
127
|
}
|
|
128
128
|
else if (node.type.is(Variable)) {
|
|
129
129
|
const varName = state.sliceDoc(node.from, node.to) || '';
|
|
130
|
-
// @ts-
|
|
130
|
+
// @ts-expect-error TS2339
|
|
131
131
|
(_b = (_a = resolveIdentifier(node.type.id, varName, config)) === null || _a === void 0 ? void 0 : _a.type) === null || _b === void 0 ? void 0 : _b.forEach((x) => types.add(x));
|
|
132
132
|
}
|
|
133
133
|
else if (node.type.is(Function)) {
|
|
134
134
|
const varName = state.sliceDoc(node.from, node.to) || '';
|
|
135
|
-
// @ts-
|
|
135
|
+
// @ts-expect-error TS2339
|
|
136
136
|
(_d = (_c = resolveIdentifier(node.type.id, varName, config)) === null || _c === void 0 ? void 0 : _c.returnType) === null || _d === void 0 ? void 0 : _d.forEach((x) => types.add(x));
|
|
137
137
|
}
|
|
138
138
|
else if (node.type.is(PropertyAccess) && node.firstChild && ((_e = node.lastChild) === null || _e === void 0 ? void 0 : _e.type.is(Property))) {
|
|
139
139
|
const varName = state.sliceDoc(node.lastChild.from, node.lastChild.to) || '';
|
|
140
140
|
(_f = resolveTypes(state, node.firstChild, config)) === null || _f === void 0 ? void 0 : _f.forEach(baseType => {
|
|
141
141
|
var _a, _b, _c, _d;
|
|
142
|
-
// @ts-
|
|
142
|
+
// @ts-expect-error TS2339
|
|
143
143
|
(_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
144
|
});
|
|
145
145
|
}
|
|
@@ -147,7 +147,7 @@ function resolveTypes(state, node, config) {
|
|
|
147
147
|
const varName = state.sliceDoc(node.lastChild.from, node.lastChild.to) || '';
|
|
148
148
|
(_h = resolveTypes(state, node.firstChild, config)) === null || _h === void 0 ? void 0 : _h.forEach(baseType => {
|
|
149
149
|
var _a, _b, _c, _d;
|
|
150
|
-
// @ts-
|
|
150
|
+
// @ts-expect-error TS2339
|
|
151
151
|
(_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
152
|
});
|
|
153
153
|
}
|
|
@@ -231,13 +231,13 @@ var utils = /*#__PURE__*//*@__PURE__*/Object.freeze({
|
|
|
231
231
|
*/
|
|
232
232
|
const expressionLanguageLinterSource = (state) => {
|
|
233
233
|
const config = getExpressionLanguageConfig(state);
|
|
234
|
-
|
|
234
|
+
const diagnostics = [];
|
|
235
235
|
syntaxTree(state).cursor().iterate(node => {
|
|
236
236
|
var _a, _b, _c, _d, _e, _f;
|
|
237
237
|
const { from, to, type: { id } } = node;
|
|
238
238
|
let identifier;
|
|
239
239
|
switch (id) {
|
|
240
|
-
case 0:
|
|
240
|
+
case 0: {
|
|
241
241
|
if (state.doc.length === 0 || from === 0) {
|
|
242
242
|
// Don't show error on empty doc (even though it is an error)
|
|
243
243
|
return;
|
|
@@ -251,7 +251,8 @@ const expressionLanguageLinterSource = (state) => {
|
|
|
251
251
|
diagnostics.push({ from, to, severity: 'error', message: `Unexpected ${type} <code>${identifier}</code>` });
|
|
252
252
|
}
|
|
253
253
|
return;
|
|
254
|
-
|
|
254
|
+
}
|
|
255
|
+
case Arguments: {
|
|
255
256
|
const fn = resolveFunctionDefinition(node.node.prevSibling, state, config);
|
|
256
257
|
const args = fn === null || fn === void 0 ? void 0 : fn.args;
|
|
257
258
|
if (!args) {
|
|
@@ -272,7 +273,12 @@ const expressionLanguageLinterSource = (state) => {
|
|
|
272
273
|
const typesUsed = Array.from(resolveTypes(state, n, config));
|
|
273
274
|
const typesExpected = args[i].type;
|
|
274
275
|
if (typesExpected && !typesExpected.includes(ELScalar.Any) && !typesUsed.some(x => typesExpected.includes(x))) {
|
|
275
|
-
diagnostics.push({
|
|
276
|
+
diagnostics.push({
|
|
277
|
+
from: n.from,
|
|
278
|
+
to: n.to,
|
|
279
|
+
severity: 'error',
|
|
280
|
+
message: `<code>${typesExpected.join('|')}</code> expected, got <code>${typesUsed.join('|')}</code>`
|
|
281
|
+
});
|
|
276
282
|
}
|
|
277
283
|
i++;
|
|
278
284
|
}
|
|
@@ -280,8 +286,9 @@ const expressionLanguageLinterSource = (state) => {
|
|
|
280
286
|
diagnostics.push({ from: node.from, to: node.to, severity: 'error', message: `Too few arguments – ${argumentCountHintFn()}` });
|
|
281
287
|
}
|
|
282
288
|
break;
|
|
289
|
+
}
|
|
283
290
|
case Property:
|
|
284
|
-
case Method:
|
|
291
|
+
case Method: {
|
|
285
292
|
const leftArgument = (_e = (_d = node.node.parent) === null || _d === void 0 ? void 0 : _d.firstChild) === null || _e === void 0 ? void 0 : _e.node;
|
|
286
293
|
const types = Array.from(resolveTypes(state, leftArgument, config));
|
|
287
294
|
identifier = state.sliceDoc(from, to);
|
|
@@ -289,26 +296,46 @@ const expressionLanguageLinterSource = (state) => {
|
|
|
289
296
|
diagnostics.push({ from, to, severity: 'error', message: `${node.name} <code>${identifier}</code> not found in <code>${types.join('|')}</code>` });
|
|
290
297
|
}
|
|
291
298
|
break;
|
|
299
|
+
}
|
|
292
300
|
case Variable:
|
|
293
|
-
case Function:
|
|
301
|
+
case Function: {
|
|
294
302
|
identifier = state.sliceDoc(from, node.node.firstChild ? node.node.firstChild.from - 1 : to);
|
|
295
303
|
if (!resolveIdentifier(id, identifier, config)) {
|
|
296
304
|
diagnostics.push({ from, to, severity: 'error', message: `${node.node.name} <code>${identifier}</code> not found` });
|
|
297
305
|
}
|
|
298
306
|
break;
|
|
299
|
-
|
|
307
|
+
}
|
|
308
|
+
case BinaryExpression: {
|
|
300
309
|
const operatorNode = node.node.getChild(OperatorKeyword);
|
|
301
310
|
if (operatorNode) {
|
|
302
311
|
const operator = state.sliceDoc(operatorNode.from, operatorNode.to);
|
|
312
|
+
const leftArgument = node.node.firstChild;
|
|
313
|
+
const rightArgument = node.node.lastChild;
|
|
303
314
|
if (operator === 'in') {
|
|
304
|
-
const
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
315
|
+
const leftTypes = resolveTypes(state, leftArgument, config);
|
|
316
|
+
const rightTypes = resolveTypes(state, rightArgument, config);
|
|
317
|
+
const allowsAny = rightTypes.has(ELScalar.Array) || rightTypes.has(ELScalar.Any);
|
|
318
|
+
if (!allowsAny && ![...rightTypes].some(x => x.endsWith('[]'))) {
|
|
319
|
+
diagnostics.push({ from: rightArgument.from, to: rightArgument.to, severity: 'error', message: `<code>${ELScalar.Array}</code> expected, got <code>${[...rightTypes].join('|')}</code>` });
|
|
320
|
+
}
|
|
321
|
+
else if (!allowsAny && !rightTypes.has(`${ELScalar.Any}[]`) && ![...leftTypes].some(type => rightTypes.has(`${type}[]`))) {
|
|
322
|
+
diagnostics.push({ from: leftArgument.from, to: rightArgument.to, severity: 'warning', message: `Expression is always <code>false</code> because <code>${[...leftTypes].join('|')}</code> not found in <code>${[...rightTypes].join('|')}</code>` });
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
else if (["contains", "starts with", "ends with", "matches"].includes(operator)) {
|
|
326
|
+
// Both sides must be string
|
|
327
|
+
const leftTypes = resolveTypes(state, leftArgument, config);
|
|
328
|
+
const rightTypes = resolveTypes(state, rightArgument, config);
|
|
329
|
+
if (!leftTypes.has(ELScalar.String)) {
|
|
330
|
+
diagnostics.push({ from: leftArgument.from, to: leftArgument.to, severity: 'error', message: `<code>string</code> expected, got <code>${[...leftTypes].join('|')}</code>` });
|
|
331
|
+
}
|
|
332
|
+
if (!rightTypes.has(ELScalar.String)) {
|
|
333
|
+
diagnostics.push({ from: rightArgument.from, to: rightArgument.to, severity: 'error', message: `<code>string</code> expected, got <code>${[...rightTypes].join('|')}</code>` });
|
|
308
334
|
}
|
|
309
335
|
}
|
|
310
336
|
}
|
|
311
337
|
break;
|
|
338
|
+
}
|
|
312
339
|
}
|
|
313
340
|
if (identifier && ((_f = node.node.parent) === null || _f === void 0 ? void 0 : _f.type.isError)) {
|
|
314
341
|
diagnostics.push({ from, to, severity: 'error', message: `Unexpected identifier <code>${identifier}</code>` });
|
|
@@ -380,7 +407,7 @@ function completeIdentifier(state, config, tree, from, to) {
|
|
|
380
407
|
validFor: /^[a-zA-Z_]+[a-zA-Z_0-9]*$/,
|
|
381
408
|
};
|
|
382
409
|
}
|
|
383
|
-
function completeMember(state, config, tree, from, to
|
|
410
|
+
function completeMember(state, config, tree, from, to) {
|
|
384
411
|
var _a, _b, _c, _d, _e, _f;
|
|
385
412
|
if (!(((_a = tree.parent) === null || _a === void 0 ? void 0 : _a.type.is(PropertyAccess)) || ((_b = tree.parent) === null || _b === void 0 ? void 0 : _b.type.is(MethodAccess))) || !((_c = tree.parent) === null || _c === void 0 ? void 0 : _c.firstChild)) {
|
|
386
413
|
return null;
|
|
@@ -389,7 +416,7 @@ function completeMember(state, config, tree, from, to, explicit) {
|
|
|
389
416
|
if (!(types === null || types === void 0 ? void 0 : types.size)) {
|
|
390
417
|
return null;
|
|
391
418
|
}
|
|
392
|
-
|
|
419
|
+
const options = [];
|
|
393
420
|
for (const type of types) {
|
|
394
421
|
const typeDeclaration = (_d = config.types) === null || _d === void 0 ? void 0 : _d[type];
|
|
395
422
|
options.push(...(((_e = typeDeclaration === null || typeDeclaration === void 0 ? void 0 : typeDeclaration.identifiers) === null || _e === void 0 ? void 0 : _e.map(autocompleteIdentifier)) || []), ...(((_f = typeDeclaration === null || typeDeclaration === void 0 ? void 0 : typeDeclaration.functions) === null || _f === void 0 ? void 0 : _f.map(autocompleteFunction)) || []));
|
|
@@ -451,7 +478,6 @@ function resolveArguments(node) {
|
|
|
451
478
|
}
|
|
452
479
|
function getCursorTooltips(state) {
|
|
453
480
|
const config = getExpressionLanguageConfig(state);
|
|
454
|
-
// @ts-ignore
|
|
455
481
|
return state.selection.ranges
|
|
456
482
|
.filter(range => range.empty)
|
|
457
483
|
.map(range => {
|
|
@@ -477,7 +503,7 @@ function getCursorTooltips(state) {
|
|
|
477
503
|
strictSide: false,
|
|
478
504
|
arrow: true,
|
|
479
505
|
create: () => {
|
|
480
|
-
|
|
506
|
+
const dom = document.createElement("div");
|
|
481
507
|
dom.className = "cm-tooltip-cursor";
|
|
482
508
|
dom.textContent = `${argName}`;
|
|
483
509
|
return { dom };
|
package/package.json
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
"scripts": {
|
|
5
5
|
"pretest": "npm run-script prepare",
|
|
6
6
|
"test": "cm-runtests",
|
|
7
|
-
"prepare": "cm-buildhelper src/index.ts"
|
|
7
|
+
"prepare": "cm-buildhelper src/index.ts",
|
|
8
|
+
"lint-fix": "eslint . --fix --ext .ts,.js",
|
|
9
|
+
"lint": "eslint . --ext .ts,.js"
|
|
8
10
|
},
|
|
9
11
|
"type": "module",
|
|
10
12
|
"main": "dist/index.cjs",
|
|
@@ -28,7 +30,10 @@
|
|
|
28
30
|
"@codemirror/buildhelper": "^1.0.0",
|
|
29
31
|
"@types/mocha": "^10.0.10",
|
|
30
32
|
"@types/node": "^22.10.5",
|
|
31
|
-
"tsdoc-markdown": "^1.1.1"
|
|
33
|
+
"tsdoc-markdown": "^1.1.1",
|
|
34
|
+
"eslint": "^8.48.0",
|
|
35
|
+
"@typescript-eslint/parser": "^6.5.0",
|
|
36
|
+
"@typescript-eslint/eslint-plugin": "^6.5.0"
|
|
32
37
|
},
|
|
33
38
|
"license": "MIT",
|
|
34
39
|
"repository": {
|
|
@@ -39,5 +44,5 @@
|
|
|
39
44
|
"access": "public",
|
|
40
45
|
"registry": "https://registry.npmjs.org/"
|
|
41
46
|
},
|
|
42
|
-
"version": "1.
|
|
47
|
+
"version": "1.3.0"
|
|
43
48
|
}
|