@valtzu/codemirror-lang-el 0.9.0 → 1.0.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 +12 -0
- package/CONFIGURATION.md +108 -0
- package/README.md +5 -3
- package/dist/index.cjs +74 -52
- package/dist/index.d.cts +39 -17
- package/dist/index.d.ts +39 -17
- package/dist/index.js +75 -53
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
package/CONFIGURATION.md
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
|
|
2
|
+
## Enum
|
|
3
|
+
|
|
4
|
+
- [ELScalar](#elscalar)
|
|
5
|
+
|
|
6
|
+
### ELScalar
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
| Property | Type | Description |
|
|
11
|
+
| ---------- | ---------- | ---------- |
|
|
12
|
+
| `Bool` | `'bool'` | Equivalent to PHP `bool` |
|
|
13
|
+
| `Number` | `'number'` | Equivalent to PHP `int` or `float` |
|
|
14
|
+
| `String` | `'string'` | Equivalent to PHP `string` |
|
|
15
|
+
| `Null` | `'null'` | Equivalent to PHP `null` |
|
|
16
|
+
| `Any` | `'any'` | Equivalent to PHP `mixed` |
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
## Interfaces
|
|
20
|
+
|
|
21
|
+
- [ExpressionLanguageConfig](#expressionlanguageconfig)
|
|
22
|
+
- [ELType](#eltype)
|
|
23
|
+
- [ELIdentifier](#elidentifier)
|
|
24
|
+
- [ELFunction](#elfunction)
|
|
25
|
+
- [ELParameter](#elparameter)
|
|
26
|
+
- [ELKeyword](#elkeyword)
|
|
27
|
+
|
|
28
|
+
### ExpressionLanguageConfig
|
|
29
|
+
|
|
30
|
+
The configuration object that is passed to `expressionlanguage` function
|
|
31
|
+
|
|
32
|
+
| Property | Type | Description |
|
|
33
|
+
| ---------- | ---------- | ---------- |
|
|
34
|
+
| `types` | `{ [key: string]: ELType; } or undefined` | Type definitions used in `identifiers` and `functions` |
|
|
35
|
+
| `identifiers` | `ELIdentifier[] or undefined` | Top-level variables |
|
|
36
|
+
| `functions` | `ELFunction[] or undefined` | Top-level functions |
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
### ELType
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
| Property | Type | Description |
|
|
44
|
+
| ---------- | ---------- | ---------- |
|
|
45
|
+
| `identifiers` | `ELIdentifier[] or undefined` | Properties of the object |
|
|
46
|
+
| `functions` | `ELFunction[] or undefined` | Methods of the object |
|
|
47
|
+
| `info` | `string or undefined` | |
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
### ELIdentifier
|
|
51
|
+
|
|
52
|
+
Represents a variable or a property of an object
|
|
53
|
+
|
|
54
|
+
| Property | Type | Description |
|
|
55
|
+
| ---------- | ---------- | ---------- |
|
|
56
|
+
| `name` | `string` | |
|
|
57
|
+
| `detail` | `string or undefined` | If set, this is shown instead of `type` |
|
|
58
|
+
| `info` | `string or undefined` | Text to show in hover tooltip, autocomplete etc. |
|
|
59
|
+
| `type` | `string[] or undefined` | All possible types for this identifier |
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
### ELFunction
|
|
63
|
+
|
|
64
|
+
Represents a function or a method of an object
|
|
65
|
+
|
|
66
|
+
| Property | Type | Description |
|
|
67
|
+
| ---------- | ---------- | ---------- |
|
|
68
|
+
| `name` | `string` | |
|
|
69
|
+
| `args` | `ELParameter[] or undefined` | |
|
|
70
|
+
| `info` | `string or undefined` | |
|
|
71
|
+
| `returnType` | `string[] or undefined` | |
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
### ELParameter
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
| Property | Type | Description |
|
|
79
|
+
| ---------- | ---------- | ---------- |
|
|
80
|
+
| `name` | `string` | |
|
|
81
|
+
| `type` | `string[] or undefined` | |
|
|
82
|
+
| `info` | `string or undefined` | |
|
|
83
|
+
| `optional` | `boolean or undefined` | |
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
### ELKeyword
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
| Property | Type | Description |
|
|
91
|
+
| ---------- | ---------- | ---------- |
|
|
92
|
+
| `name` | `string` | |
|
|
93
|
+
| `detail` | `string or undefined` | |
|
|
94
|
+
| `info` | `string or undefined` | |
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
## Types
|
|
98
|
+
|
|
99
|
+
- [ELTypeName](#eltypename)
|
|
100
|
+
|
|
101
|
+
### ELTypeName
|
|
102
|
+
|
|
103
|
+
One of predefined types (`ELScalar`) or a custom type from `ExpressionLanguageConfig.types`
|
|
104
|
+
|
|
105
|
+
| Type | Type |
|
|
106
|
+
| ---------- | ---------- |
|
|
107
|
+
| `ELTypeName` | `ELScalar or string` |
|
|
108
|
+
|
package/README.md
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
## Symfony Expression Language support for CodeMirror 6
|
|
2
2
|
|
|
3
|
-
> :warning: **This is unstable**: Expect breaking changes until v1 is out.
|
|
4
|
-
|
|
5
3
|
### Features
|
|
6
4
|
|
|
7
5
|
#### Linting
|
|
@@ -10,7 +8,7 @@
|
|
|
10
8
|
|
|
11
9
|
1. Lint variable & function names
|
|
12
10
|
1. Lint object properties & methods, even on expression result
|
|
13
|
-
1. Lint argument count
|
|
11
|
+
1. Lint argument count
|
|
14
12
|
1. Lint argument types
|
|
15
13
|
|
|
16
14
|
#### Autocompletion
|
|
@@ -58,6 +56,10 @@ yarn add @valtzu/codemirror-lang-el
|
|
|
58
56
|
|
|
59
57
|
---
|
|
60
58
|
|
|
59
|
+
### Configuration
|
|
60
|
+
|
|
61
|
+
See [CONFIGURATION.md](CONFIGURATION.md)
|
|
62
|
+
|
|
61
63
|
### Example
|
|
62
64
|
|
|
63
65
|
[Live demo](https://jsfiddle.net/turse2xq/)
|
package/dist/index.cjs
CHANGED
|
@@ -35,12 +35,18 @@ const parser = lr.LRParser.deserialize({
|
|
|
35
35
|
tokenPrec: 532
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
+
// generate CONFIGURATION.md from this file by running "tsdoc --src=src/types.ts --dest=CONFIGURATION.md --noemoji --types"
|
|
38
39
|
exports.ELScalar = void 0;
|
|
39
40
|
(function (ELScalar) {
|
|
41
|
+
/** Equivalent to PHP `bool` */
|
|
40
42
|
ELScalar["Bool"] = "bool";
|
|
43
|
+
/** Equivalent to PHP `int` or `float` */
|
|
41
44
|
ELScalar["Number"] = "number";
|
|
45
|
+
/** Equivalent to PHP `string` */
|
|
42
46
|
ELScalar["String"] = "string";
|
|
47
|
+
/** Equivalent to PHP `null` */
|
|
43
48
|
ELScalar["Null"] = "null";
|
|
49
|
+
/** Equivalent to PHP `mixed` */
|
|
44
50
|
ELScalar["Any"] = "any";
|
|
45
51
|
})(exports.ELScalar || (exports.ELScalar = {}));
|
|
46
52
|
|
|
@@ -70,6 +76,11 @@ const createInfoElement = (html) => {
|
|
|
70
76
|
dom.className = 'cm-diagnostic';
|
|
71
77
|
return dom;
|
|
72
78
|
};
|
|
79
|
+
const createCompletionInfoElement = (html) => {
|
|
80
|
+
const dom = document.createElement("div");
|
|
81
|
+
dom.innerHTML = html;
|
|
82
|
+
return dom;
|
|
83
|
+
};
|
|
73
84
|
function resolveFunctionDefinition(node, state, config) {
|
|
74
85
|
var _a;
|
|
75
86
|
if (!node) {
|
|
@@ -77,17 +88,17 @@ function resolveFunctionDefinition(node, state, config) {
|
|
|
77
88
|
}
|
|
78
89
|
let identifier;
|
|
79
90
|
if ((node.type.is(PropertyAccess) || node.type.is(MethodAccess)) && node.lastChild) {
|
|
80
|
-
const leftArgument = (_a = node.firstChild) === null || _a ===
|
|
91
|
+
const leftArgument = (_a = node.firstChild) === null || _a === void 0 ? void 0 : _a.node;
|
|
81
92
|
const types = Array.from(resolveTypes(state, leftArgument, config));
|
|
82
93
|
identifier = state.sliceDoc(node.lastChild.from, node.lastChild.to);
|
|
83
|
-
return types.map(type => { var _a; return resolveCallable(identifier, (_a = config.types) === null || _a ===
|
|
94
|
+
return types.map(type => { var _a; return resolveCallable(identifier, (_a = config.types) === null || _a === void 0 ? void 0 : _a[type]); }).find(x => x);
|
|
84
95
|
}
|
|
85
96
|
else if (node.type.is(Function)) {
|
|
86
97
|
identifier = state.sliceDoc(node.from, node.node.firstChild ? node.node.firstChild.from - 1 : node.to);
|
|
87
98
|
return resolveCallable(identifier, config);
|
|
88
99
|
}
|
|
89
100
|
}
|
|
90
|
-
const resolveCallable = (identifier, config) => { var _a; return (_a = config === null || config ===
|
|
101
|
+
const resolveCallable = (identifier, config) => { var _a; return (_a = config === null || config === void 0 ? void 0 : config.functions) === null || _a === void 0 ? void 0 : _a.find(x => x.name === identifier); };
|
|
91
102
|
const resolveIdentifier = (nodeTypeId, identifier, config) => {
|
|
92
103
|
var _a;
|
|
93
104
|
switch (nodeTypeId) {
|
|
@@ -96,7 +107,7 @@ const resolveIdentifier = (nodeTypeId, identifier, config) => {
|
|
|
96
107
|
return resolveCallable(identifier, config);
|
|
97
108
|
case Property:
|
|
98
109
|
case Variable:
|
|
99
|
-
return (_a = config === null || config ===
|
|
110
|
+
return (_a = config === null || config === void 0 ? void 0 : config.identifiers) === null || _a === void 0 ? void 0 : _a.find(x => x.name === identifier);
|
|
100
111
|
}
|
|
101
112
|
};
|
|
102
113
|
function resolveTypes(state, node, config) {
|
|
@@ -115,27 +126,27 @@ function resolveTypes(state, node, config) {
|
|
|
115
126
|
else if (node.type.is(Variable)) {
|
|
116
127
|
const varName = state.sliceDoc(node.from, node.to) || '';
|
|
117
128
|
// @ts-ignore
|
|
118
|
-
(_b = (_a = resolveIdentifier(node.type.id, varName, config)) === null || _a ===
|
|
129
|
+
(_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));
|
|
119
130
|
}
|
|
120
131
|
else if (node.type.is(Function)) {
|
|
121
132
|
const varName = state.sliceDoc(node.from, node.to) || '';
|
|
122
133
|
// @ts-ignore
|
|
123
|
-
(_d = (_c = resolveIdentifier(node.type.id, varName, config)) === null || _c ===
|
|
134
|
+
(_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));
|
|
124
135
|
}
|
|
125
|
-
else if (node.type.is(PropertyAccess) && node.firstChild && ((_e = node.lastChild) === null || _e ===
|
|
136
|
+
else if (node.type.is(PropertyAccess) && node.firstChild && ((_e = node.lastChild) === null || _e === void 0 ? void 0 : _e.type.is(Property))) {
|
|
126
137
|
const varName = state.sliceDoc(node.lastChild.from, node.lastChild.to) || '';
|
|
127
|
-
(_f = resolveTypes(state, node.firstChild, config)) === null || _f ===
|
|
138
|
+
(_f = resolveTypes(state, node.firstChild, config)) === null || _f === void 0 ? void 0 : _f.forEach(baseType => {
|
|
128
139
|
var _a, _b, _c, _d;
|
|
129
140
|
// @ts-ignore
|
|
130
|
-
(_d = (_c = resolveIdentifier((_a = node.lastChild) === null || _a ===
|
|
141
|
+
(_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));
|
|
131
142
|
});
|
|
132
143
|
}
|
|
133
|
-
else if (node.type.is(MethodAccess) && node.firstChild && ((_g = node.lastChild) === null || _g ===
|
|
144
|
+
else if (node.type.is(MethodAccess) && node.firstChild && ((_g = node.lastChild) === null || _g === void 0 ? void 0 : _g.type.is(Method))) {
|
|
134
145
|
const varName = state.sliceDoc(node.lastChild.from, node.lastChild.to) || '';
|
|
135
|
-
(_h = resolveTypes(state, node.firstChild, config)) === null || _h ===
|
|
146
|
+
(_h = resolveTypes(state, node.firstChild, config)) === null || _h === void 0 ? void 0 : _h.forEach(baseType => {
|
|
136
147
|
var _a, _b, _c, _d;
|
|
137
148
|
// @ts-ignore
|
|
138
|
-
(_d = (_c = resolveIdentifier((_a = node.lastChild) === null || _a ===
|
|
149
|
+
(_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));
|
|
139
150
|
});
|
|
140
151
|
}
|
|
141
152
|
else if (node.type.is(Application) && node.firstChild) {
|
|
@@ -145,7 +156,7 @@ function resolveTypes(state, node, config) {
|
|
|
145
156
|
resolveTypes(state, node.firstChild.nextSibling, config).forEach(x => types.add(x));
|
|
146
157
|
resolveTypes(state, node.firstChild.nextSibling.nextSibling, config).forEach(x => types.add(x));
|
|
147
158
|
}
|
|
148
|
-
else if (node.type.is(BinaryExpression) && ((_j = node.firstChild) === null || _j ===
|
|
159
|
+
else if (node.type.is(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)) {
|
|
149
160
|
const operator = state.sliceDoc(node.firstChild.nextSibling.from, node.firstChild.nextSibling.to);
|
|
150
161
|
if (operator == '?:' || operator == '??' || operator == '?') {
|
|
151
162
|
if (operator == '?:' || operator == '??') {
|
|
@@ -192,6 +203,7 @@ const keywords = [
|
|
|
192
203
|
|
|
193
204
|
var utils = /*#__PURE__*/Object.freeze({
|
|
194
205
|
__proto__: null,
|
|
206
|
+
createCompletionInfoElement: createCompletionInfoElement,
|
|
195
207
|
createInfoElement: createInfoElement,
|
|
196
208
|
getExpressionLanguageConfig: getExpressionLanguageConfig,
|
|
197
209
|
keywords: keywords,
|
|
@@ -218,7 +230,7 @@ const expressionLanguageLinterSource = (state) => {
|
|
|
218
230
|
}
|
|
219
231
|
identifier = state.sliceDoc(from, to);
|
|
220
232
|
if (identifier.length === 0) {
|
|
221
|
-
diagnostics.push({ from, to: (_c = (_b = (_a = node.node.parent) === null || _a ===
|
|
233
|
+
diagnostics.push({ from, to: (_c = (_b = (_a = node.node.parent) === null || _a === void 0 ? void 0 : _a.parent) === null || _b === void 0 ? void 0 : _b.to) !== null && _c !== void 0 ? _c : to, severity: 'error', message: `Expression expected` });
|
|
222
234
|
}
|
|
223
235
|
else {
|
|
224
236
|
const type = /^[a-zA-Z_]+[a-zA-Z_0-9]*$/.test(identifier) ? 'identifier' : 'operator';
|
|
@@ -227,16 +239,20 @@ const expressionLanguageLinterSource = (state) => {
|
|
|
227
239
|
return;
|
|
228
240
|
case Arguments:
|
|
229
241
|
const fn = resolveFunctionDefinition(node.node.prevSibling, state, config);
|
|
230
|
-
const args = fn === null || fn ===
|
|
242
|
+
const args = fn === null || fn === void 0 ? void 0 : fn.args;
|
|
231
243
|
if (!args) {
|
|
232
244
|
return;
|
|
233
245
|
}
|
|
234
|
-
|
|
246
|
+
const argCountMin = args.reduce((count, arg) => count + Number(!arg.optional), 0);
|
|
247
|
+
const argCountMax = args.length;
|
|
248
|
+
const argumentCountHintFn = () => `<code>${fn.name}</code> takes ${argCountMin == argCountMax ? `exactly ${argCountMax}` : `${argCountMin}–${argCountMax}`} argument${argCountMax == 1 ? '' : 's'}`;
|
|
249
|
+
let i = 0;
|
|
250
|
+
for (let n = node.node.firstChild; n != null; n = n.nextSibling) {
|
|
235
251
|
if (n.type.is(BlockComment)) {
|
|
236
252
|
continue;
|
|
237
253
|
}
|
|
238
|
-
if (i >
|
|
239
|
-
diagnostics.push({ from: n.from, to: n.to, severity: 'warning', message: `Unexpected argument –
|
|
254
|
+
if (i > argCountMax - 1) {
|
|
255
|
+
diagnostics.push({ from: n.from, to: n.to, severity: 'warning', message: `Unexpected argument – ${argumentCountHintFn()}` });
|
|
240
256
|
continue;
|
|
241
257
|
}
|
|
242
258
|
const typesUsed = Array.from(resolveTypes(state, n, config));
|
|
@@ -246,13 +262,16 @@ const expressionLanguageLinterSource = (state) => {
|
|
|
246
262
|
}
|
|
247
263
|
i++;
|
|
248
264
|
}
|
|
265
|
+
if (i < argCountMin) {
|
|
266
|
+
diagnostics.push({ from: node.from, to: node.to, severity: 'error', message: `Too few arguments – ${argumentCountHintFn()}` });
|
|
267
|
+
}
|
|
249
268
|
break;
|
|
250
269
|
case Property:
|
|
251
270
|
case Method:
|
|
252
|
-
const leftArgument = (_e = (_d = node.node.parent) === null || _d ===
|
|
271
|
+
const leftArgument = (_e = (_d = node.node.parent) === null || _d === void 0 ? void 0 : _d.firstChild) === null || _e === void 0 ? void 0 : _e.node;
|
|
253
272
|
const types = Array.from(resolveTypes(state, leftArgument, config));
|
|
254
273
|
identifier = state.sliceDoc(from, to);
|
|
255
|
-
if (!types.find(type => { var _a; return resolveIdentifier(id, identifier, (_a = config.types) === null || _a ===
|
|
274
|
+
if (!types.find(type => { var _a; return resolveIdentifier(id, identifier, (_a = config.types) === null || _a === void 0 ? void 0 : _a[type]); })) {
|
|
256
275
|
diagnostics.push({ from, to, severity: 'error', message: `${node.name} <code>${identifier}</code> not found in <code>${types.join('|')}</code>` });
|
|
257
276
|
}
|
|
258
277
|
break;
|
|
@@ -264,7 +283,7 @@ const expressionLanguageLinterSource = (state) => {
|
|
|
264
283
|
}
|
|
265
284
|
break;
|
|
266
285
|
}
|
|
267
|
-
if (identifier && ((_f = node.node.parent) === null || _f ===
|
|
286
|
+
if (identifier && ((_f = node.node.parent) === null || _f === void 0 ? void 0 : _f.type.isError)) {
|
|
268
287
|
diagnostics.push({ from, to, severity: 'error', message: `Unexpected identifier <code>${identifier}</code>` });
|
|
269
288
|
}
|
|
270
289
|
});
|
|
@@ -288,13 +307,13 @@ var linter = /*#__PURE__*/Object.freeze({
|
|
|
288
307
|
const autocompleteFunction = (x) => {
|
|
289
308
|
var _a, _b, _c;
|
|
290
309
|
return ({
|
|
291
|
-
label: `${x.name}(${((_b = (_a = x.args) === null || _a ===
|
|
310
|
+
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(',')) || ''})`,
|
|
292
311
|
apply: (view, completion, from, to) => {
|
|
293
312
|
var _a, _b;
|
|
294
|
-
view.dispatch(Object.assign(Object.assign({}, autocomplete.insertCompletionText(view.state, `${x.name}()`, from, to)), { selection: { anchor: from + x.name.length + (((_b = (_a = x.args) === null || _a ===
|
|
313
|
+
view.dispatch(Object.assign(Object.assign({}, autocomplete.insertCompletionText(view.state, `${x.name}()`, from, to)), { selection: { anchor: from + x.name.length + (((_b = (_a = x.args) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > 0 ? 1 : 2) } }));
|
|
295
314
|
},
|
|
296
|
-
detail: (_c = x.returnType) === null || _c ===
|
|
297
|
-
info: x.info,
|
|
315
|
+
detail: (_c = x.returnType) === null || _c === void 0 ? void 0 : _c.join('|'),
|
|
316
|
+
info: () => ({ dom: createCompletionInfoElement(x.info) }),
|
|
298
317
|
type: "function",
|
|
299
318
|
});
|
|
300
319
|
};
|
|
@@ -303,8 +322,8 @@ const autocompleteIdentifier = (x) => {
|
|
|
303
322
|
return ({
|
|
304
323
|
label: x.name,
|
|
305
324
|
apply: x.name,
|
|
306
|
-
info: x.info,
|
|
307
|
-
detail: x.detail || ((_a = x.type) === null || _a ===
|
|
325
|
+
info: () => ({ dom: createCompletionInfoElement(x.info) }),
|
|
326
|
+
detail: x.detail || ((_a = x.type) === null || _a === void 0 ? void 0 : _a.join('|')),
|
|
308
327
|
type: 'variable',
|
|
309
328
|
});
|
|
310
329
|
};
|
|
@@ -316,17 +335,17 @@ function completeOperatorKeyword(state, config, tree, from, to, explicit) {
|
|
|
316
335
|
options: (_a = keywords.map(({ name, info, detail }) => ({
|
|
317
336
|
label: name,
|
|
318
337
|
apply: `${name} `,
|
|
319
|
-
info: info,
|
|
338
|
+
info: () => ({ dom: createCompletionInfoElement(info) }),
|
|
320
339
|
detail,
|
|
321
340
|
type: "keyword"
|
|
322
|
-
}))) !== null && _a !==
|
|
323
|
-
validFor: (text) => { var _a; return (_a = keywords.some(({ name }) => explicit || name.includes(text))) !== null && _a !==
|
|
341
|
+
}))) !== null && _a !== void 0 ? _a : [],
|
|
342
|
+
validFor: (text) => { var _a; return (_a = keywords.some(({ name }) => explicit || name.includes(text))) !== null && _a !== void 0 ? _a : false; },
|
|
324
343
|
};
|
|
325
344
|
}
|
|
326
345
|
function completeIdentifier(state, config, tree, from, to) {
|
|
327
346
|
var _a, _b;
|
|
328
|
-
const identifiers = (_a = config.identifiers) !== null && _a !==
|
|
329
|
-
const functions = (_b = config.functions) !== null && _b !==
|
|
347
|
+
const identifiers = (_a = config.identifiers) !== null && _a !== void 0 ? _a : []; //?.filter(({ name }) => explicit || name.toLowerCase().startsWith(text)) ?? [];
|
|
348
|
+
const functions = (_b = config.functions) !== null && _b !== void 0 ? _b : []; //?.filter(({ name }) => explicit || name.toLowerCase().startsWith(text)) ?? [];
|
|
330
349
|
return {
|
|
331
350
|
from,
|
|
332
351
|
to,
|
|
@@ -336,17 +355,17 @@ function completeIdentifier(state, config, tree, from, to) {
|
|
|
336
355
|
}
|
|
337
356
|
function completeMember(state, config, tree, from, to, explicit) {
|
|
338
357
|
var _a, _b, _c, _d, _e, _f;
|
|
339
|
-
if (!(((_a = tree.parent) === null || _a ===
|
|
358
|
+
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)) {
|
|
340
359
|
return null;
|
|
341
360
|
}
|
|
342
361
|
const types = resolveTypes(state, tree.parent.firstChild.node, config);
|
|
343
|
-
if (!(types === null || types ===
|
|
362
|
+
if (!(types === null || types === void 0 ? void 0 : types.size)) {
|
|
344
363
|
return null;
|
|
345
364
|
}
|
|
346
365
|
let options = [];
|
|
347
366
|
for (const type of types) {
|
|
348
|
-
const typeDeclaration = (_d = config.types) === null || _d ===
|
|
349
|
-
options.push(...(((_e = typeDeclaration === null || typeDeclaration ===
|
|
367
|
+
const typeDeclaration = (_d = config.types) === null || _d === void 0 ? void 0 : _d[type];
|
|
368
|
+
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)) || []));
|
|
350
369
|
}
|
|
351
370
|
return {
|
|
352
371
|
from,
|
|
@@ -362,22 +381,22 @@ function expressionLanguageCompletion(context) {
|
|
|
362
381
|
const lastChar = state.sliceDoc(pos - 1, pos);
|
|
363
382
|
const prevNode = tree.resolveInner(pos, lastChar === ')' ? 0 : -1);
|
|
364
383
|
const config = getExpressionLanguageConfig(state);
|
|
365
|
-
const isIdentifier = (node) => (node === null || node ===
|
|
366
|
-
const isMember = (node) => (node === null || node ===
|
|
384
|
+
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));
|
|
385
|
+
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));
|
|
367
386
|
if (prevNode.type.is(String) || prevNode.type.is(BlockComment)) {
|
|
368
387
|
return null;
|
|
369
388
|
}
|
|
370
|
-
if ((((_a = prevNode.parent) === null || _a ===
|
|
389
|
+
if ((((_a = prevNode.parent) === null || _a === void 0 ? void 0 : _a.type.is(PropertyAccess)) || ((_b = prevNode.parent) === null || _b === void 0 ? void 0 : _b.type.is(MethodAccess))) && [PropertyAccess, MethodAccess, ArrayAccess, Variable, Call, Application].includes((_c = prevNode.parent.firstChild) === null || _c === void 0 ? void 0 : _c.type.id)) {
|
|
371
390
|
return completeMember(state, config, prevNode, isIdentifier(prevNode) || isMember(prevNode) ? prevNode.from : pos, pos);
|
|
372
391
|
}
|
|
373
|
-
if (/^[\sa-z]*$/.test(lastChar) && ([Expression, UnaryExpression, BinaryExpression, TernaryExpression].includes(prevNode.type.id) && prevNode.lastChild && !((_d = prevNode.lastChild) === null || _d ===
|
|
374
|
-
|| [Arguments, Array$1].includes(prevNode.type.id) && prevNode.lastChild && !((_e = prevNode.lastChild) === null || _e ===
|
|
375
|
-
|| [Expression, UnaryExpression, BinaryExpression, TernaryExpression].includes((_f = prevNode.parent) === null || _f ===
|
|
376
|
-
|| [Variable, Function].includes((_g = prevNode.parent) === null || _g ===
|
|
392
|
+
if (/^[\sa-z]*$/.test(lastChar) && ([Expression, UnaryExpression, BinaryExpression, TernaryExpression].includes(prevNode.type.id) && prevNode.lastChild && !((_d = prevNode.lastChild) === null || _d === void 0 ? void 0 : _d.type.isError)
|
|
393
|
+
|| [Arguments, Array$1].includes(prevNode.type.id) && prevNode.lastChild && !((_e = prevNode.lastChild) === null || _e === void 0 ? void 0 : _e.type.isError)
|
|
394
|
+
|| [Expression, UnaryExpression, BinaryExpression, TernaryExpression].includes((_f = prevNode.parent) === null || _f === void 0 ? void 0 : _f.type.id) && prevNode.type.isError
|
|
395
|
+
|| [Variable, Function].includes((_g = prevNode.parent) === null || _g === void 0 ? void 0 : _g.type.id) && prevNode.type.isError)) {
|
|
377
396
|
return completeOperatorKeyword(state, config, prevNode, ![Expression, UnaryExpression, BinaryExpression, TernaryExpression, Arguments].includes(prevNode.type.id) ? prevNode.from : pos, pos, explicit);
|
|
378
397
|
}
|
|
379
|
-
if (!/[0-9]/.test(lastChar) && !prevNode.type.is(OperatorKeyword) && ([Expression, UnaryExpression, BinaryExpression, TernaryExpression].includes(prevNode.type.id) && ((_h = prevNode.lastChild) === null || _h ===
|
|
380
|
-
|| [Expression, UnaryExpression, BinaryExpression, TernaryExpression, Arguments].includes((_k = (_j = prevNode.parent) === null || _j ===
|
|
398
|
+
if (!/[0-9]/.test(lastChar) && !prevNode.type.is(OperatorKeyword) && ([Expression, UnaryExpression, BinaryExpression, TernaryExpression].includes(prevNode.type.id) && ((_h = prevNode.lastChild) === null || _h === void 0 ? void 0 : _h.type.isError)
|
|
399
|
+
|| [Expression, UnaryExpression, BinaryExpression, TernaryExpression, Arguments].includes((_k = (_j = prevNode.parent) === null || _j === void 0 ? void 0 : _j.type.id) !== null && _k !== void 0 ? _k : -1) && !prevNode.type.isError
|
|
381
400
|
|| prevNode.type.is(Arguments) || prevNode.type.is(Array$1))) {
|
|
382
401
|
return completeIdentifier(state, config, prevNode, isIdentifier(prevNode) ? prevNode.from : pos, pos);
|
|
383
402
|
}
|
|
@@ -421,7 +440,7 @@ function getCursorTooltips(state) {
|
|
|
421
440
|
return null;
|
|
422
441
|
}
|
|
423
442
|
const n = args.childAfter(range.from - 1);
|
|
424
|
-
const argName = (_b = (_a = fn.args) === null || _a ===
|
|
443
|
+
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;
|
|
425
444
|
if (n && n.from !== range.from || !argName) {
|
|
426
445
|
return null;
|
|
427
446
|
}
|
|
@@ -455,7 +474,7 @@ const keywordTooltip = view.hoverTooltip((view, pos, side) => {
|
|
|
455
474
|
const tree = language.syntaxTree(view.state).resolveInner(pos, side);
|
|
456
475
|
if (tree.type.is(OperatorKeyword)) {
|
|
457
476
|
const name = view.state.sliceDoc(tree.from, tree.to);
|
|
458
|
-
const info = (_a = keywords.find(x => x.name === name)) === null || _a ===
|
|
477
|
+
const info = (_a = keywords.find(x => x.name === name)) === null || _a === void 0 ? void 0 : _a.info;
|
|
459
478
|
if (info) {
|
|
460
479
|
return {
|
|
461
480
|
pos: tree.from,
|
|
@@ -470,20 +489,20 @@ const keywordTooltip = view.hoverTooltip((view, pos, side) => {
|
|
|
470
489
|
}
|
|
471
490
|
const skipEmpty = (x) => x;
|
|
472
491
|
let info;
|
|
473
|
-
if (((_b = tree.parent) === null || _b ===
|
|
492
|
+
if (((_b = tree.parent) === null || _b === void 0 ? void 0 : _b.firstChild) && (((_c = tree.parent) === null || _c === void 0 ? void 0 : _c.type.is(PropertyAccess)) || ((_d = tree.parent) === null || _d === void 0 ? void 0 : _d.type.is(MethodAccess))) && tree.prevSibling) {
|
|
474
493
|
const node = tree.parent.firstChild;
|
|
475
494
|
const types = Array.from(resolveTypes(view.state, node, config));
|
|
476
495
|
const name = view.state.sliceDoc(tree.from, tree.to);
|
|
477
496
|
info = [
|
|
478
|
-
...types.map(type => { var _a, _b, _c, _d; return (_d = (_c = (_b = (_a = config.types) === null || _a ===
|
|
479
|
-
...types.map(type => { var _a, _b, _c, _d; return (_d = (_c = (_b = (_a = config.types) === null || _a ===
|
|
497
|
+
...types.map(type => { var _a, _b, _c, _d; return (_d = (_c = (_b = (_a = config.types) === null || _a === void 0 ? void 0 : _a[type]) === null || _b === void 0 ? void 0 : _b.identifiers) === null || _c === void 0 ? void 0 : _c.find(x => x.name === name)) === null || _d === void 0 ? void 0 : _d.info; }).filter(skipEmpty),
|
|
498
|
+
...types.map(type => { var _a, _b, _c, _d; return (_d = (_c = (_b = (_a = config.types) === null || _a === void 0 ? void 0 : _a[type]) === null || _b === void 0 ? void 0 : _b.functions) === null || _c === void 0 ? void 0 : _c.find(x => x.name === name)) === null || _d === void 0 ? void 0 : _d.info; }).filter(skipEmpty),
|
|
480
499
|
].join('\n');
|
|
481
500
|
}
|
|
482
501
|
else {
|
|
483
502
|
const name = view.state.sliceDoc(tree.from, tree.to);
|
|
484
503
|
info = [
|
|
485
|
-
...[(_f = (_e = config.identifiers) === null || _e ===
|
|
486
|
-
...[(_h = (_g = config.functions) === null || _g ===
|
|
504
|
+
...[(_f = (_e = config.identifiers) === null || _e === void 0 ? void 0 : _e.find(x => x.name === name)) === null || _f === void 0 ? void 0 : _f.info].filter(skipEmpty),
|
|
505
|
+
...[(_h = (_g = config.functions) === null || _g === void 0 ? void 0 : _g.find(x => x.name === name)) === null || _h === void 0 ? void 0 : _h.info].filter(skipEmpty),
|
|
487
506
|
].join('\n');
|
|
488
507
|
}
|
|
489
508
|
if (!info) {
|
|
@@ -529,6 +548,9 @@ const baseTheme = view.EditorView.baseTheme({
|
|
|
529
548
|
fontSize: ".8em",
|
|
530
549
|
fontStyle: "monospace",
|
|
531
550
|
backgroundColor: "rgba(127, 127, 127, .3)",
|
|
551
|
+
display: 'inline-block',
|
|
552
|
+
padding: '2px 4px',
|
|
553
|
+
borderRadius: '3px',
|
|
532
554
|
},
|
|
533
555
|
});
|
|
534
556
|
|
package/dist/index.d.cts
CHANGED
|
@@ -5,14 +5,37 @@ import { CompletionContext, CompletionResult } from '@codemirror/autocomplete';
|
|
|
5
5
|
import { SyntaxNode } from '@lezer/common';
|
|
6
6
|
import { Tooltip } from '@codemirror/view';
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* The configuration object that is passed to `expressionlanguage` function
|
|
10
|
+
*/
|
|
11
|
+
interface ExpressionLanguageConfig {
|
|
12
|
+
/** Type definitions used in `identifiers` & `functions` */
|
|
13
|
+
types?: {
|
|
14
|
+
[key: string]: ELType;
|
|
15
|
+
};
|
|
16
|
+
/** Top-level variables */
|
|
17
|
+
identifiers?: ELIdentifier[];
|
|
18
|
+
/** Top-level functions */
|
|
19
|
+
functions?: ELFunction[];
|
|
20
|
+
}
|
|
21
|
+
interface ELType {
|
|
22
|
+
/** Properties of the object */
|
|
23
|
+
identifiers?: ELIdentifier[];
|
|
24
|
+
/** Methods of the object */
|
|
25
|
+
functions?: ELFunction[];
|
|
26
|
+
info?: string;
|
|
27
|
+
}
|
|
8
28
|
/**
|
|
9
29
|
* Represents a variable or a property of an object
|
|
10
30
|
*/
|
|
11
31
|
interface ELIdentifier {
|
|
12
32
|
name: string;
|
|
33
|
+
/** If set, this is shown instead of `type` */
|
|
13
34
|
detail?: string;
|
|
35
|
+
/** Text to show in hover tooltip, autocomplete etc. */
|
|
14
36
|
info?: string;
|
|
15
|
-
|
|
37
|
+
/** All possible types for this identifier */
|
|
38
|
+
type?: ELTypeName[];
|
|
16
39
|
}
|
|
17
40
|
/**
|
|
18
41
|
* Represents a function or a method of an object
|
|
@@ -21,38 +44,35 @@ interface ELFunction {
|
|
|
21
44
|
name: string;
|
|
22
45
|
args?: ELParameter[];
|
|
23
46
|
info?: string;
|
|
24
|
-
returnType?:
|
|
47
|
+
returnType?: ELTypeName[];
|
|
25
48
|
}
|
|
26
49
|
interface ELParameter {
|
|
27
50
|
name: string;
|
|
28
|
-
type?:
|
|
51
|
+
type?: ELTypeName[];
|
|
29
52
|
info?: string;
|
|
30
53
|
optional?: boolean;
|
|
31
54
|
}
|
|
32
|
-
interface ELType {
|
|
33
|
-
identifiers?: ELIdentifier[];
|
|
34
|
-
functions?: ELFunction[];
|
|
35
|
-
info?: string;
|
|
36
|
-
}
|
|
37
|
-
interface ExpressionLanguageConfig {
|
|
38
|
-
types?: {
|
|
39
|
-
[key: string]: ELType;
|
|
40
|
-
};
|
|
41
|
-
identifiers?: ELIdentifier[];
|
|
42
|
-
functions?: ELFunction[];
|
|
43
|
-
}
|
|
44
55
|
interface ELKeyword {
|
|
45
56
|
name: string;
|
|
46
57
|
detail?: string;
|
|
47
58
|
info?: string;
|
|
48
59
|
}
|
|
49
60
|
declare enum ELScalar {
|
|
61
|
+
/** Equivalent to PHP `bool` */
|
|
50
62
|
Bool = "bool",
|
|
63
|
+
/** Equivalent to PHP `int` or `float` */
|
|
51
64
|
Number = "number",
|
|
65
|
+
/** Equivalent to PHP `string` */
|
|
52
66
|
String = "string",
|
|
67
|
+
/** Equivalent to PHP `null` */
|
|
53
68
|
Null = "null",
|
|
69
|
+
/** Equivalent to PHP `mixed` */
|
|
54
70
|
Any = "any"
|
|
55
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* One of predefined types (`ELScalar`) or a custom type from `ExpressionLanguageConfig.types`
|
|
74
|
+
*/
|
|
75
|
+
type ELTypeName = ELScalar | string;
|
|
56
76
|
|
|
57
77
|
declare function expressionLanguageCompletion(context: CompletionContext): CompletionResult | null;
|
|
58
78
|
|
|
@@ -74,6 +94,7 @@ declare const Property: number;
|
|
|
74
94
|
declare const Variable: number;
|
|
75
95
|
|
|
76
96
|
declare const createInfoElement: (html: string) => HTMLDivElement;
|
|
97
|
+
declare const createCompletionInfoElement: (html: string) => HTMLDivElement;
|
|
77
98
|
declare function resolveFunctionDefinition(node: SyntaxNode | null, state: EditorState, config: ExpressionLanguageConfig): ELFunction | undefined;
|
|
78
99
|
declare const resolveIdentifier: (nodeTypeId: typeof Method | typeof Property | typeof Function | typeof Variable, identifier?: string, config?: {
|
|
79
100
|
identifiers?: ELIdentifier[];
|
|
@@ -83,6 +104,7 @@ declare function resolveTypes(state: EditorState, node: SyntaxNode | undefined |
|
|
|
83
104
|
declare function getExpressionLanguageConfig(state: EditorState): ExpressionLanguageConfig;
|
|
84
105
|
declare const keywords: ELKeyword[];
|
|
85
106
|
|
|
107
|
+
declare const utils_d_createCompletionInfoElement: typeof createCompletionInfoElement;
|
|
86
108
|
declare const utils_d_createInfoElement: typeof createInfoElement;
|
|
87
109
|
declare const utils_d_getExpressionLanguageConfig: typeof getExpressionLanguageConfig;
|
|
88
110
|
declare const utils_d_keywords: typeof keywords;
|
|
@@ -90,7 +112,7 @@ declare const utils_d_resolveFunctionDefinition: typeof resolveFunctionDefinitio
|
|
|
90
112
|
declare const utils_d_resolveIdentifier: typeof resolveIdentifier;
|
|
91
113
|
declare const utils_d_resolveTypes: typeof resolveTypes;
|
|
92
114
|
declare namespace utils_d {
|
|
93
|
-
export { utils_d_createInfoElement as createInfoElement, utils_d_getExpressionLanguageConfig as getExpressionLanguageConfig, utils_d_keywords as keywords, utils_d_resolveFunctionDefinition as resolveFunctionDefinition, utils_d_resolveIdentifier as resolveIdentifier, utils_d_resolveTypes as resolveTypes };
|
|
115
|
+
export { utils_d_createCompletionInfoElement as createCompletionInfoElement, utils_d_createInfoElement as createInfoElement, utils_d_getExpressionLanguageConfig as getExpressionLanguageConfig, utils_d_keywords as keywords, utils_d_resolveFunctionDefinition as resolveFunctionDefinition, utils_d_resolveIdentifier as resolveIdentifier, utils_d_resolveTypes as resolveTypes };
|
|
94
116
|
}
|
|
95
117
|
|
|
96
118
|
declare const cursorTooltipField: StateField<readonly Tooltip[]>;
|
|
@@ -107,4 +129,4 @@ declare namespace tooltip_d {
|
|
|
107
129
|
declare const ELLanguage: LRLanguage;
|
|
108
130
|
declare function expressionlanguage(config?: ExpressionLanguageConfig, extensions?: Extension[]): LanguageSupport;
|
|
109
131
|
|
|
110
|
-
export { type ELFunction, type ELIdentifier, type ELKeyword, ELLanguage, type ELParameter, ELScalar, type ELType, type ExpressionLanguageConfig, complete_d as _complete, linter_d as _linter, tooltip_d as _tooltip, utils_d as _utils, expressionlanguage };
|
|
132
|
+
export { type ELFunction, type ELIdentifier, type ELKeyword, ELLanguage, type ELParameter, ELScalar, type ELType, type ELTypeName, type ExpressionLanguageConfig, complete_d as _complete, linter_d as _linter, tooltip_d as _tooltip, utils_d as _utils, expressionlanguage };
|
package/dist/index.d.ts
CHANGED
|
@@ -5,14 +5,37 @@ import { CompletionContext, CompletionResult } from '@codemirror/autocomplete';
|
|
|
5
5
|
import { SyntaxNode } from '@lezer/common';
|
|
6
6
|
import { Tooltip } from '@codemirror/view';
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* The configuration object that is passed to `expressionlanguage` function
|
|
10
|
+
*/
|
|
11
|
+
interface ExpressionLanguageConfig {
|
|
12
|
+
/** Type definitions used in `identifiers` & `functions` */
|
|
13
|
+
types?: {
|
|
14
|
+
[key: string]: ELType;
|
|
15
|
+
};
|
|
16
|
+
/** Top-level variables */
|
|
17
|
+
identifiers?: ELIdentifier[];
|
|
18
|
+
/** Top-level functions */
|
|
19
|
+
functions?: ELFunction[];
|
|
20
|
+
}
|
|
21
|
+
interface ELType {
|
|
22
|
+
/** Properties of the object */
|
|
23
|
+
identifiers?: ELIdentifier[];
|
|
24
|
+
/** Methods of the object */
|
|
25
|
+
functions?: ELFunction[];
|
|
26
|
+
info?: string;
|
|
27
|
+
}
|
|
8
28
|
/**
|
|
9
29
|
* Represents a variable or a property of an object
|
|
10
30
|
*/
|
|
11
31
|
interface ELIdentifier {
|
|
12
32
|
name: string;
|
|
33
|
+
/** If set, this is shown instead of `type` */
|
|
13
34
|
detail?: string;
|
|
35
|
+
/** Text to show in hover tooltip, autocomplete etc. */
|
|
14
36
|
info?: string;
|
|
15
|
-
|
|
37
|
+
/** All possible types for this identifier */
|
|
38
|
+
type?: ELTypeName[];
|
|
16
39
|
}
|
|
17
40
|
/**
|
|
18
41
|
* Represents a function or a method of an object
|
|
@@ -21,38 +44,35 @@ interface ELFunction {
|
|
|
21
44
|
name: string;
|
|
22
45
|
args?: ELParameter[];
|
|
23
46
|
info?: string;
|
|
24
|
-
returnType?:
|
|
47
|
+
returnType?: ELTypeName[];
|
|
25
48
|
}
|
|
26
49
|
interface ELParameter {
|
|
27
50
|
name: string;
|
|
28
|
-
type?:
|
|
51
|
+
type?: ELTypeName[];
|
|
29
52
|
info?: string;
|
|
30
53
|
optional?: boolean;
|
|
31
54
|
}
|
|
32
|
-
interface ELType {
|
|
33
|
-
identifiers?: ELIdentifier[];
|
|
34
|
-
functions?: ELFunction[];
|
|
35
|
-
info?: string;
|
|
36
|
-
}
|
|
37
|
-
interface ExpressionLanguageConfig {
|
|
38
|
-
types?: {
|
|
39
|
-
[key: string]: ELType;
|
|
40
|
-
};
|
|
41
|
-
identifiers?: ELIdentifier[];
|
|
42
|
-
functions?: ELFunction[];
|
|
43
|
-
}
|
|
44
55
|
interface ELKeyword {
|
|
45
56
|
name: string;
|
|
46
57
|
detail?: string;
|
|
47
58
|
info?: string;
|
|
48
59
|
}
|
|
49
60
|
declare enum ELScalar {
|
|
61
|
+
/** Equivalent to PHP `bool` */
|
|
50
62
|
Bool = "bool",
|
|
63
|
+
/** Equivalent to PHP `int` or `float` */
|
|
51
64
|
Number = "number",
|
|
65
|
+
/** Equivalent to PHP `string` */
|
|
52
66
|
String = "string",
|
|
67
|
+
/** Equivalent to PHP `null` */
|
|
53
68
|
Null = "null",
|
|
69
|
+
/** Equivalent to PHP `mixed` */
|
|
54
70
|
Any = "any"
|
|
55
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* One of predefined types (`ELScalar`) or a custom type from `ExpressionLanguageConfig.types`
|
|
74
|
+
*/
|
|
75
|
+
type ELTypeName = ELScalar | string;
|
|
56
76
|
|
|
57
77
|
declare function expressionLanguageCompletion(context: CompletionContext): CompletionResult | null;
|
|
58
78
|
|
|
@@ -74,6 +94,7 @@ declare const Property: number;
|
|
|
74
94
|
declare const Variable: number;
|
|
75
95
|
|
|
76
96
|
declare const createInfoElement: (html: string) => HTMLDivElement;
|
|
97
|
+
declare const createCompletionInfoElement: (html: string) => HTMLDivElement;
|
|
77
98
|
declare function resolveFunctionDefinition(node: SyntaxNode | null, state: EditorState, config: ExpressionLanguageConfig): ELFunction | undefined;
|
|
78
99
|
declare const resolveIdentifier: (nodeTypeId: typeof Method | typeof Property | typeof Function | typeof Variable, identifier?: string, config?: {
|
|
79
100
|
identifiers?: ELIdentifier[];
|
|
@@ -83,6 +104,7 @@ declare function resolveTypes(state: EditorState, node: SyntaxNode | undefined |
|
|
|
83
104
|
declare function getExpressionLanguageConfig(state: EditorState): ExpressionLanguageConfig;
|
|
84
105
|
declare const keywords: ELKeyword[];
|
|
85
106
|
|
|
107
|
+
declare const utils_d_createCompletionInfoElement: typeof createCompletionInfoElement;
|
|
86
108
|
declare const utils_d_createInfoElement: typeof createInfoElement;
|
|
87
109
|
declare const utils_d_getExpressionLanguageConfig: typeof getExpressionLanguageConfig;
|
|
88
110
|
declare const utils_d_keywords: typeof keywords;
|
|
@@ -90,7 +112,7 @@ declare const utils_d_resolveFunctionDefinition: typeof resolveFunctionDefinitio
|
|
|
90
112
|
declare const utils_d_resolveIdentifier: typeof resolveIdentifier;
|
|
91
113
|
declare const utils_d_resolveTypes: typeof resolveTypes;
|
|
92
114
|
declare namespace utils_d {
|
|
93
|
-
export { utils_d_createInfoElement as createInfoElement, utils_d_getExpressionLanguageConfig as getExpressionLanguageConfig, utils_d_keywords as keywords, utils_d_resolveFunctionDefinition as resolveFunctionDefinition, utils_d_resolveIdentifier as resolveIdentifier, utils_d_resolveTypes as resolveTypes };
|
|
115
|
+
export { utils_d_createCompletionInfoElement as createCompletionInfoElement, utils_d_createInfoElement as createInfoElement, utils_d_getExpressionLanguageConfig as getExpressionLanguageConfig, utils_d_keywords as keywords, utils_d_resolveFunctionDefinition as resolveFunctionDefinition, utils_d_resolveIdentifier as resolveIdentifier, utils_d_resolveTypes as resolveTypes };
|
|
94
116
|
}
|
|
95
117
|
|
|
96
118
|
declare const cursorTooltipField: StateField<readonly Tooltip[]>;
|
|
@@ -107,4 +129,4 @@ declare namespace tooltip_d {
|
|
|
107
129
|
declare const ELLanguage: LRLanguage;
|
|
108
130
|
declare function expressionlanguage(config?: ExpressionLanguageConfig, extensions?: Extension[]): LanguageSupport;
|
|
109
131
|
|
|
110
|
-
export { type ELFunction, type ELIdentifier, type ELKeyword, ELLanguage, type ELParameter, ELScalar, type ELType, type ExpressionLanguageConfig, complete_d as _complete, linter_d as _linter, tooltip_d as _tooltip, utils_d as _utils, expressionlanguage };
|
|
132
|
+
export { type ELFunction, type ELIdentifier, type ELKeyword, ELLanguage, type ELParameter, ELScalar, type ELType, type ELTypeName, type ExpressionLanguageConfig, complete_d as _complete, linter_d as _linter, tooltip_d as _tooltip, utils_d as _utils, expressionlanguage };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LRParser, LocalTokenGroup } from '@lezer/lr';
|
|
2
|
-
import { syntaxTree, LRLanguage, indentNodeProp,
|
|
2
|
+
import { syntaxTree, LRLanguage, indentNodeProp, foldNodeProp, delimitedIndent, LanguageSupport } from '@codemirror/language';
|
|
3
3
|
import { styleTags, tags } from '@lezer/highlight';
|
|
4
4
|
import { linter as linter$1 } from '@codemirror/lint';
|
|
5
5
|
import { insertCompletionText } from '@codemirror/autocomplete';
|
|
@@ -33,11 +33,17 @@ const parser = /*@__PURE__*/LRParser.deserialize({
|
|
|
33
33
|
tokenPrec: 532
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
+
// generate CONFIGURATION.md from this file by running "tsdoc --src=src/types.ts --dest=CONFIGURATION.md --noemoji --types"
|
|
36
37
|
var ELScalar = /*@__PURE__*/(function (ELScalar) {
|
|
38
|
+
/** Equivalent to PHP `bool` */
|
|
37
39
|
ELScalar["Bool"] = "bool";
|
|
40
|
+
/** Equivalent to PHP `int` or `float` */
|
|
38
41
|
ELScalar["Number"] = "number";
|
|
42
|
+
/** Equivalent to PHP `string` */
|
|
39
43
|
ELScalar["String"] = "string";
|
|
44
|
+
/** Equivalent to PHP `null` */
|
|
40
45
|
ELScalar["Null"] = "null";
|
|
46
|
+
/** Equivalent to PHP `mixed` */
|
|
41
47
|
ELScalar["Any"] = "any";
|
|
42
48
|
return ELScalar})(ELScalar || (ELScalar = {}));
|
|
43
49
|
|
|
@@ -67,6 +73,11 @@ const createInfoElement = (html) => {
|
|
|
67
73
|
dom.className = 'cm-diagnostic';
|
|
68
74
|
return dom;
|
|
69
75
|
};
|
|
76
|
+
const createCompletionInfoElement = (html) => {
|
|
77
|
+
const dom = document.createElement("div");
|
|
78
|
+
dom.innerHTML = html;
|
|
79
|
+
return dom;
|
|
80
|
+
};
|
|
70
81
|
function resolveFunctionDefinition(node, state, config) {
|
|
71
82
|
var _a;
|
|
72
83
|
if (!node) {
|
|
@@ -74,17 +85,17 @@ function resolveFunctionDefinition(node, state, config) {
|
|
|
74
85
|
}
|
|
75
86
|
let identifier;
|
|
76
87
|
if ((node.type.is(PropertyAccess) || node.type.is(MethodAccess)) && node.lastChild) {
|
|
77
|
-
const leftArgument = (_a = node.firstChild) === null || _a ===
|
|
88
|
+
const leftArgument = (_a = node.firstChild) === null || _a === void 0 ? void 0 : _a.node;
|
|
78
89
|
const types = Array.from(resolveTypes(state, leftArgument, config));
|
|
79
90
|
identifier = state.sliceDoc(node.lastChild.from, node.lastChild.to);
|
|
80
|
-
return types.map(type => { var _a; return resolveCallable(identifier, (_a = config.types) === null || _a ===
|
|
91
|
+
return types.map(type => { var _a; return resolveCallable(identifier, (_a = config.types) === null || _a === void 0 ? void 0 : _a[type]); }).find(x => x);
|
|
81
92
|
}
|
|
82
93
|
else if (node.type.is(Function)) {
|
|
83
94
|
identifier = state.sliceDoc(node.from, node.node.firstChild ? node.node.firstChild.from - 1 : node.to);
|
|
84
95
|
return resolveCallable(identifier, config);
|
|
85
96
|
}
|
|
86
97
|
}
|
|
87
|
-
const resolveCallable = (identifier, config) => { var _a; return (_a = config === null || config ===
|
|
98
|
+
const resolveCallable = (identifier, config) => { var _a; return (_a = config === null || config === void 0 ? void 0 : config.functions) === null || _a === void 0 ? void 0 : _a.find(x => x.name === identifier); };
|
|
88
99
|
const resolveIdentifier = (nodeTypeId, identifier, config) => {
|
|
89
100
|
var _a;
|
|
90
101
|
switch (nodeTypeId) {
|
|
@@ -93,7 +104,7 @@ const resolveIdentifier = (nodeTypeId, identifier, config) => {
|
|
|
93
104
|
return resolveCallable(identifier, config);
|
|
94
105
|
case Property:
|
|
95
106
|
case Variable:
|
|
96
|
-
return (_a = config === null || config ===
|
|
107
|
+
return (_a = config === null || config === void 0 ? void 0 : config.identifiers) === null || _a === void 0 ? void 0 : _a.find(x => x.name === identifier);
|
|
97
108
|
}
|
|
98
109
|
};
|
|
99
110
|
function resolveTypes(state, node, config) {
|
|
@@ -112,27 +123,27 @@ function resolveTypes(state, node, config) {
|
|
|
112
123
|
else if (node.type.is(Variable)) {
|
|
113
124
|
const varName = state.sliceDoc(node.from, node.to) || '';
|
|
114
125
|
// @ts-ignore
|
|
115
|
-
(_b = (_a = resolveIdentifier(node.type.id, varName, config)) === null || _a ===
|
|
126
|
+
(_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));
|
|
116
127
|
}
|
|
117
128
|
else if (node.type.is(Function)) {
|
|
118
129
|
const varName = state.sliceDoc(node.from, node.to) || '';
|
|
119
130
|
// @ts-ignore
|
|
120
|
-
(_d = (_c = resolveIdentifier(node.type.id, varName, config)) === null || _c ===
|
|
131
|
+
(_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));
|
|
121
132
|
}
|
|
122
|
-
else if (node.type.is(PropertyAccess) && node.firstChild && ((_e = node.lastChild) === null || _e ===
|
|
133
|
+
else if (node.type.is(PropertyAccess) && node.firstChild && ((_e = node.lastChild) === null || _e === void 0 ? void 0 : _e.type.is(Property))) {
|
|
123
134
|
const varName = state.sliceDoc(node.lastChild.from, node.lastChild.to) || '';
|
|
124
|
-
(_f = resolveTypes(state, node.firstChild, config)) === null || _f ===
|
|
135
|
+
(_f = resolveTypes(state, node.firstChild, config)) === null || _f === void 0 ? void 0 : _f.forEach(baseType => {
|
|
125
136
|
var _a, _b, _c, _d;
|
|
126
137
|
// @ts-ignore
|
|
127
|
-
(_d = (_c = resolveIdentifier((_a = node.lastChild) === null || _a ===
|
|
138
|
+
(_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));
|
|
128
139
|
});
|
|
129
140
|
}
|
|
130
|
-
else if (node.type.is(MethodAccess) && node.firstChild && ((_g = node.lastChild) === null || _g ===
|
|
141
|
+
else if (node.type.is(MethodAccess) && node.firstChild && ((_g = node.lastChild) === null || _g === void 0 ? void 0 : _g.type.is(Method))) {
|
|
131
142
|
const varName = state.sliceDoc(node.lastChild.from, node.lastChild.to) || '';
|
|
132
|
-
(_h = resolveTypes(state, node.firstChild, config)) === null || _h ===
|
|
143
|
+
(_h = resolveTypes(state, node.firstChild, config)) === null || _h === void 0 ? void 0 : _h.forEach(baseType => {
|
|
133
144
|
var _a, _b, _c, _d;
|
|
134
145
|
// @ts-ignore
|
|
135
|
-
(_d = (_c = resolveIdentifier((_a = node.lastChild) === null || _a ===
|
|
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.returnType) === null || _d === void 0 ? void 0 : _d.forEach((x) => types.add(x));
|
|
136
147
|
});
|
|
137
148
|
}
|
|
138
149
|
else if (node.type.is(Application) && node.firstChild) {
|
|
@@ -142,7 +153,7 @@ function resolveTypes(state, node, config) {
|
|
|
142
153
|
resolveTypes(state, node.firstChild.nextSibling, config).forEach(x => types.add(x));
|
|
143
154
|
resolveTypes(state, node.firstChild.nextSibling.nextSibling, config).forEach(x => types.add(x));
|
|
144
155
|
}
|
|
145
|
-
else if (node.type.is(BinaryExpression) && ((_j = node.firstChild) === null || _j ===
|
|
156
|
+
else if (node.type.is(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)) {
|
|
146
157
|
const operator = state.sliceDoc(node.firstChild.nextSibling.from, node.firstChild.nextSibling.to);
|
|
147
158
|
if (operator == '?:' || operator == '??' || operator == '?') {
|
|
148
159
|
if (operator == '?:' || operator == '??') {
|
|
@@ -189,6 +200,7 @@ const keywords = [
|
|
|
189
200
|
|
|
190
201
|
var utils = /*#__PURE__*//*@__PURE__*/Object.freeze({
|
|
191
202
|
__proto__: null,
|
|
203
|
+
createCompletionInfoElement: createCompletionInfoElement,
|
|
192
204
|
createInfoElement: createInfoElement,
|
|
193
205
|
getExpressionLanguageConfig: getExpressionLanguageConfig,
|
|
194
206
|
keywords: keywords,
|
|
@@ -215,7 +227,7 @@ const expressionLanguageLinterSource = (state) => {
|
|
|
215
227
|
}
|
|
216
228
|
identifier = state.sliceDoc(from, to);
|
|
217
229
|
if (identifier.length === 0) {
|
|
218
|
-
diagnostics.push({ from, to: (_c = (_b = (_a = node.node.parent) === null || _a ===
|
|
230
|
+
diagnostics.push({ from, to: (_c = (_b = (_a = node.node.parent) === null || _a === void 0 ? void 0 : _a.parent) === null || _b === void 0 ? void 0 : _b.to) !== null && _c !== void 0 ? _c : to, severity: 'error', message: `Expression expected` });
|
|
219
231
|
}
|
|
220
232
|
else {
|
|
221
233
|
const type = /^[a-zA-Z_]+[a-zA-Z_0-9]*$/.test(identifier) ? 'identifier' : 'operator';
|
|
@@ -224,16 +236,20 @@ const expressionLanguageLinterSource = (state) => {
|
|
|
224
236
|
return;
|
|
225
237
|
case Arguments:
|
|
226
238
|
const fn = resolveFunctionDefinition(node.node.prevSibling, state, config);
|
|
227
|
-
const args = fn === null || fn ===
|
|
239
|
+
const args = fn === null || fn === void 0 ? void 0 : fn.args;
|
|
228
240
|
if (!args) {
|
|
229
241
|
return;
|
|
230
242
|
}
|
|
231
|
-
|
|
243
|
+
const argCountMin = args.reduce((count, arg) => count + Number(!arg.optional), 0);
|
|
244
|
+
const argCountMax = args.length;
|
|
245
|
+
const argumentCountHintFn = () => `<code>${fn.name}</code> takes ${argCountMin == argCountMax ? `exactly ${argCountMax}` : `${argCountMin}–${argCountMax}`} argument${argCountMax == 1 ? '' : 's'}`;
|
|
246
|
+
let i = 0;
|
|
247
|
+
for (let n = node.node.firstChild; n != null; n = n.nextSibling) {
|
|
232
248
|
if (n.type.is(BlockComment)) {
|
|
233
249
|
continue;
|
|
234
250
|
}
|
|
235
|
-
if (i >
|
|
236
|
-
diagnostics.push({ from: n.from, to: n.to, severity: 'warning', message: `Unexpected argument –
|
|
251
|
+
if (i > argCountMax - 1) {
|
|
252
|
+
diagnostics.push({ from: n.from, to: n.to, severity: 'warning', message: `Unexpected argument – ${argumentCountHintFn()}` });
|
|
237
253
|
continue;
|
|
238
254
|
}
|
|
239
255
|
const typesUsed = Array.from(resolveTypes(state, n, config));
|
|
@@ -243,13 +259,16 @@ const expressionLanguageLinterSource = (state) => {
|
|
|
243
259
|
}
|
|
244
260
|
i++;
|
|
245
261
|
}
|
|
262
|
+
if (i < argCountMin) {
|
|
263
|
+
diagnostics.push({ from: node.from, to: node.to, severity: 'error', message: `Too few arguments – ${argumentCountHintFn()}` });
|
|
264
|
+
}
|
|
246
265
|
break;
|
|
247
266
|
case Property:
|
|
248
267
|
case Method:
|
|
249
|
-
const leftArgument = (_e = (_d = node.node.parent) === null || _d ===
|
|
268
|
+
const leftArgument = (_e = (_d = node.node.parent) === null || _d === void 0 ? void 0 : _d.firstChild) === null || _e === void 0 ? void 0 : _e.node;
|
|
250
269
|
const types = Array.from(resolveTypes(state, leftArgument, config));
|
|
251
270
|
identifier = state.sliceDoc(from, to);
|
|
252
|
-
if (!types.find(type => { var _a; return resolveIdentifier(id, identifier, (_a = config.types) === null || _a ===
|
|
271
|
+
if (!types.find(type => { var _a; return resolveIdentifier(id, identifier, (_a = config.types) === null || _a === void 0 ? void 0 : _a[type]); })) {
|
|
253
272
|
diagnostics.push({ from, to, severity: 'error', message: `${node.name} <code>${identifier}</code> not found in <code>${types.join('|')}</code>` });
|
|
254
273
|
}
|
|
255
274
|
break;
|
|
@@ -261,7 +280,7 @@ const expressionLanguageLinterSource = (state) => {
|
|
|
261
280
|
}
|
|
262
281
|
break;
|
|
263
282
|
}
|
|
264
|
-
if (identifier && ((_f = node.node.parent) === null || _f ===
|
|
283
|
+
if (identifier && ((_f = node.node.parent) === null || _f === void 0 ? void 0 : _f.type.isError)) {
|
|
265
284
|
diagnostics.push({ from, to, severity: 'error', message: `Unexpected identifier <code>${identifier}</code>` });
|
|
266
285
|
}
|
|
267
286
|
});
|
|
@@ -285,13 +304,13 @@ var linter = /*#__PURE__*//*@__PURE__*/Object.freeze({
|
|
|
285
304
|
const autocompleteFunction = (x) => {
|
|
286
305
|
var _a, _b, _c;
|
|
287
306
|
return ({
|
|
288
|
-
label: `${x.name}(${((_b = (_a = x.args) === null || _a ===
|
|
307
|
+
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(',')) || ''})`,
|
|
289
308
|
apply: (view, completion, from, to) => {
|
|
290
309
|
var _a, _b;
|
|
291
|
-
view.dispatch(Object.assign(Object.assign({}, insertCompletionText(view.state, `${x.name}()`, from, to)), { selection: { anchor: from + x.name.length + (((_b = (_a = x.args) === null || _a ===
|
|
310
|
+
view.dispatch(Object.assign(Object.assign({}, insertCompletionText(view.state, `${x.name}()`, from, to)), { selection: { anchor: from + x.name.length + (((_b = (_a = x.args) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > 0 ? 1 : 2) } }));
|
|
292
311
|
},
|
|
293
|
-
detail: (_c = x.returnType) === null || _c ===
|
|
294
|
-
info: x.info,
|
|
312
|
+
detail: (_c = x.returnType) === null || _c === void 0 ? void 0 : _c.join('|'),
|
|
313
|
+
info: () => ({ dom: createCompletionInfoElement(x.info) }),
|
|
295
314
|
type: "function",
|
|
296
315
|
});
|
|
297
316
|
};
|
|
@@ -300,8 +319,8 @@ const autocompleteIdentifier = (x) => {
|
|
|
300
319
|
return ({
|
|
301
320
|
label: x.name,
|
|
302
321
|
apply: x.name,
|
|
303
|
-
info: x.info,
|
|
304
|
-
detail: x.detail || ((_a = x.type) === null || _a ===
|
|
322
|
+
info: () => ({ dom: createCompletionInfoElement(x.info) }),
|
|
323
|
+
detail: x.detail || ((_a = x.type) === null || _a === void 0 ? void 0 : _a.join('|')),
|
|
305
324
|
type: 'variable',
|
|
306
325
|
});
|
|
307
326
|
};
|
|
@@ -313,17 +332,17 @@ function completeOperatorKeyword(state, config, tree, from, to, explicit) {
|
|
|
313
332
|
options: (_a = keywords.map(({ name, info, detail }) => ({
|
|
314
333
|
label: name,
|
|
315
334
|
apply: `${name} `,
|
|
316
|
-
info: info,
|
|
335
|
+
info: () => ({ dom: createCompletionInfoElement(info) }),
|
|
317
336
|
detail,
|
|
318
337
|
type: "keyword"
|
|
319
|
-
}))) !== null && _a !==
|
|
320
|
-
validFor: (text) => { var _a; return (_a = keywords.some(({ name }) => explicit || name.includes(text))) !== null && _a !==
|
|
338
|
+
}))) !== null && _a !== void 0 ? _a : [],
|
|
339
|
+
validFor: (text) => { var _a; return (_a = keywords.some(({ name }) => explicit || name.includes(text))) !== null && _a !== void 0 ? _a : false; },
|
|
321
340
|
};
|
|
322
341
|
}
|
|
323
342
|
function completeIdentifier(state, config, tree, from, to) {
|
|
324
343
|
var _a, _b;
|
|
325
|
-
const identifiers = (_a = config.identifiers) !== null && _a !==
|
|
326
|
-
const functions = (_b = config.functions) !== null && _b !==
|
|
344
|
+
const identifiers = (_a = config.identifiers) !== null && _a !== void 0 ? _a : []; //?.filter(({ name }) => explicit || name.toLowerCase().startsWith(text)) ?? [];
|
|
345
|
+
const functions = (_b = config.functions) !== null && _b !== void 0 ? _b : []; //?.filter(({ name }) => explicit || name.toLowerCase().startsWith(text)) ?? [];
|
|
327
346
|
return {
|
|
328
347
|
from,
|
|
329
348
|
to,
|
|
@@ -333,17 +352,17 @@ function completeIdentifier(state, config, tree, from, to) {
|
|
|
333
352
|
}
|
|
334
353
|
function completeMember(state, config, tree, from, to, explicit) {
|
|
335
354
|
var _a, _b, _c, _d, _e, _f;
|
|
336
|
-
if (!(((_a = tree.parent) === null || _a ===
|
|
355
|
+
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)) {
|
|
337
356
|
return null;
|
|
338
357
|
}
|
|
339
358
|
const types = resolveTypes(state, tree.parent.firstChild.node, config);
|
|
340
|
-
if (!(types === null || types ===
|
|
359
|
+
if (!(types === null || types === void 0 ? void 0 : types.size)) {
|
|
341
360
|
return null;
|
|
342
361
|
}
|
|
343
362
|
let options = [];
|
|
344
363
|
for (const type of types) {
|
|
345
|
-
const typeDeclaration = (_d = config.types) === null || _d ===
|
|
346
|
-
options.push(...(((_e = typeDeclaration === null || typeDeclaration ===
|
|
364
|
+
const typeDeclaration = (_d = config.types) === null || _d === void 0 ? void 0 : _d[type];
|
|
365
|
+
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)) || []));
|
|
347
366
|
}
|
|
348
367
|
return {
|
|
349
368
|
from,
|
|
@@ -359,22 +378,22 @@ function expressionLanguageCompletion(context) {
|
|
|
359
378
|
const lastChar = state.sliceDoc(pos - 1, pos);
|
|
360
379
|
const prevNode = tree.resolveInner(pos, lastChar === ')' ? 0 : -1);
|
|
361
380
|
const config = getExpressionLanguageConfig(state);
|
|
362
|
-
const isIdentifier = (node) => (node === null || node ===
|
|
363
|
-
const isMember = (node) => (node === null || node ===
|
|
381
|
+
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));
|
|
382
|
+
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));
|
|
364
383
|
if (prevNode.type.is(String) || prevNode.type.is(BlockComment)) {
|
|
365
384
|
return null;
|
|
366
385
|
}
|
|
367
|
-
if ((((_a = prevNode.parent) === null || _a ===
|
|
386
|
+
if ((((_a = prevNode.parent) === null || _a === void 0 ? void 0 : _a.type.is(PropertyAccess)) || ((_b = prevNode.parent) === null || _b === void 0 ? void 0 : _b.type.is(MethodAccess))) && [PropertyAccess, MethodAccess, ArrayAccess, Variable, Call, Application].includes((_c = prevNode.parent.firstChild) === null || _c === void 0 ? void 0 : _c.type.id)) {
|
|
368
387
|
return completeMember(state, config, prevNode, isIdentifier(prevNode) || isMember(prevNode) ? prevNode.from : pos, pos);
|
|
369
388
|
}
|
|
370
|
-
if (/^[\sa-z]*$/.test(lastChar) && ([Expression, UnaryExpression, BinaryExpression, TernaryExpression].includes(prevNode.type.id) && prevNode.lastChild && !((_d = prevNode.lastChild) === null || _d ===
|
|
371
|
-
|| [Arguments, Array$1].includes(prevNode.type.id) && prevNode.lastChild && !((_e = prevNode.lastChild) === null || _e ===
|
|
372
|
-
|| [Expression, UnaryExpression, BinaryExpression, TernaryExpression].includes((_f = prevNode.parent) === null || _f ===
|
|
373
|
-
|| [Variable, Function].includes((_g = prevNode.parent) === null || _g ===
|
|
389
|
+
if (/^[\sa-z]*$/.test(lastChar) && ([Expression, UnaryExpression, BinaryExpression, TernaryExpression].includes(prevNode.type.id) && prevNode.lastChild && !((_d = prevNode.lastChild) === null || _d === void 0 ? void 0 : _d.type.isError)
|
|
390
|
+
|| [Arguments, Array$1].includes(prevNode.type.id) && prevNode.lastChild && !((_e = prevNode.lastChild) === null || _e === void 0 ? void 0 : _e.type.isError)
|
|
391
|
+
|| [Expression, UnaryExpression, BinaryExpression, TernaryExpression].includes((_f = prevNode.parent) === null || _f === void 0 ? void 0 : _f.type.id) && prevNode.type.isError
|
|
392
|
+
|| [Variable, Function].includes((_g = prevNode.parent) === null || _g === void 0 ? void 0 : _g.type.id) && prevNode.type.isError)) {
|
|
374
393
|
return completeOperatorKeyword(state, config, prevNode, ![Expression, UnaryExpression, BinaryExpression, TernaryExpression, Arguments].includes(prevNode.type.id) ? prevNode.from : pos, pos, explicit);
|
|
375
394
|
}
|
|
376
|
-
if (!/[0-9]/.test(lastChar) && !prevNode.type.is(OperatorKeyword) && ([Expression, UnaryExpression, BinaryExpression, TernaryExpression].includes(prevNode.type.id) && ((_h = prevNode.lastChild) === null || _h ===
|
|
377
|
-
|| [Expression, UnaryExpression, BinaryExpression, TernaryExpression, Arguments].includes((_k = (_j = prevNode.parent) === null || _j ===
|
|
395
|
+
if (!/[0-9]/.test(lastChar) && !prevNode.type.is(OperatorKeyword) && ([Expression, UnaryExpression, BinaryExpression, TernaryExpression].includes(prevNode.type.id) && ((_h = prevNode.lastChild) === null || _h === void 0 ? void 0 : _h.type.isError)
|
|
396
|
+
|| [Expression, UnaryExpression, BinaryExpression, TernaryExpression, Arguments].includes((_k = (_j = prevNode.parent) === null || _j === void 0 ? void 0 : _j.type.id) !== null && _k !== void 0 ? _k : -1) && !prevNode.type.isError
|
|
378
397
|
|| prevNode.type.is(Arguments) || prevNode.type.is(Array$1))) {
|
|
379
398
|
return completeIdentifier(state, config, prevNode, isIdentifier(prevNode) ? prevNode.from : pos, pos);
|
|
380
399
|
}
|
|
@@ -418,7 +437,7 @@ function getCursorTooltips(state) {
|
|
|
418
437
|
return null;
|
|
419
438
|
}
|
|
420
439
|
const n = args.childAfter(range.from - 1);
|
|
421
|
-
const argName = (_b = (_a = fn.args) === null || _a ===
|
|
440
|
+
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;
|
|
422
441
|
if (n && n.from !== range.from || !argName) {
|
|
423
442
|
return null;
|
|
424
443
|
}
|
|
@@ -452,7 +471,7 @@ const keywordTooltip = /*@__PURE__*/hoverTooltip((view, pos, side) => {
|
|
|
452
471
|
const tree = syntaxTree(view.state).resolveInner(pos, side);
|
|
453
472
|
if (tree.type.is(OperatorKeyword)) {
|
|
454
473
|
const name = view.state.sliceDoc(tree.from, tree.to);
|
|
455
|
-
const info = (_a = keywords.find(x => x.name === name)) === null || _a ===
|
|
474
|
+
const info = (_a = keywords.find(x => x.name === name)) === null || _a === void 0 ? void 0 : _a.info;
|
|
456
475
|
if (info) {
|
|
457
476
|
return {
|
|
458
477
|
pos: tree.from,
|
|
@@ -467,20 +486,20 @@ const keywordTooltip = /*@__PURE__*/hoverTooltip((view, pos, side) => {
|
|
|
467
486
|
}
|
|
468
487
|
const skipEmpty = (x) => x;
|
|
469
488
|
let info;
|
|
470
|
-
if (((_b = tree.parent) === null || _b ===
|
|
489
|
+
if (((_b = tree.parent) === null || _b === void 0 ? void 0 : _b.firstChild) && (((_c = tree.parent) === null || _c === void 0 ? void 0 : _c.type.is(PropertyAccess)) || ((_d = tree.parent) === null || _d === void 0 ? void 0 : _d.type.is(MethodAccess))) && tree.prevSibling) {
|
|
471
490
|
const node = tree.parent.firstChild;
|
|
472
491
|
const types = Array.from(resolveTypes(view.state, node, config));
|
|
473
492
|
const name = view.state.sliceDoc(tree.from, tree.to);
|
|
474
493
|
info = [
|
|
475
|
-
...types.map(type => { var _a, _b, _c, _d; return (_d = (_c = (_b = (_a = config.types) === null || _a ===
|
|
476
|
-
...types.map(type => { var _a, _b, _c, _d; return (_d = (_c = (_b = (_a = config.types) === null || _a ===
|
|
494
|
+
...types.map(type => { var _a, _b, _c, _d; return (_d = (_c = (_b = (_a = config.types) === null || _a === void 0 ? void 0 : _a[type]) === null || _b === void 0 ? void 0 : _b.identifiers) === null || _c === void 0 ? void 0 : _c.find(x => x.name === name)) === null || _d === void 0 ? void 0 : _d.info; }).filter(skipEmpty),
|
|
495
|
+
...types.map(type => { var _a, _b, _c, _d; return (_d = (_c = (_b = (_a = config.types) === null || _a === void 0 ? void 0 : _a[type]) === null || _b === void 0 ? void 0 : _b.functions) === null || _c === void 0 ? void 0 : _c.find(x => x.name === name)) === null || _d === void 0 ? void 0 : _d.info; }).filter(skipEmpty),
|
|
477
496
|
].join('\n');
|
|
478
497
|
}
|
|
479
498
|
else {
|
|
480
499
|
const name = view.state.sliceDoc(tree.from, tree.to);
|
|
481
500
|
info = [
|
|
482
|
-
...[(_f = (_e = config.identifiers) === null || _e ===
|
|
483
|
-
...[(_h = (_g = config.functions) === null || _g ===
|
|
501
|
+
...[(_f = (_e = config.identifiers) === null || _e === void 0 ? void 0 : _e.find(x => x.name === name)) === null || _f === void 0 ? void 0 : _f.info].filter(skipEmpty),
|
|
502
|
+
...[(_h = (_g = config.functions) === null || _g === void 0 ? void 0 : _g.find(x => x.name === name)) === null || _h === void 0 ? void 0 : _h.info].filter(skipEmpty),
|
|
484
503
|
].join('\n');
|
|
485
504
|
}
|
|
486
505
|
if (!info) {
|
|
@@ -526,6 +545,9 @@ const baseTheme = /*@__PURE__*/EditorView.baseTheme({
|
|
|
526
545
|
fontSize: ".8em",
|
|
527
546
|
fontStyle: "monospace",
|
|
528
547
|
backgroundColor: "rgba(127, 127, 127, .3)",
|
|
548
|
+
display: 'inline-block',
|
|
549
|
+
padding: '2px 4px',
|
|
550
|
+
borderRadius: '3px',
|
|
529
551
|
},
|
|
530
552
|
});
|
|
531
553
|
|
package/package.json
CHANGED
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@codemirror/buildhelper": "^1.0.0",
|
|
29
29
|
"@types/mocha": "^10.0.10",
|
|
30
|
-
"@types/node": "^22.10.5"
|
|
30
|
+
"@types/node": "^22.10.5",
|
|
31
|
+
"tsdoc-markdown": "^1.1.1"
|
|
31
32
|
},
|
|
32
33
|
"license": "MIT",
|
|
33
34
|
"repository": {
|
|
@@ -38,5 +39,5 @@
|
|
|
38
39
|
"access": "public",
|
|
39
40
|
"registry": "https://registry.npmjs.org/"
|
|
40
41
|
},
|
|
41
|
-
"version": "0.
|
|
42
|
+
"version": "1.0.0"
|
|
42
43
|
}
|