jexl-lang-cm 0.0.1
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/.github/workflows/dispatch.yml +16 -0
- package/CHANGELOG.md +198 -0
- package/LICENSE +21 -0
- package/README.md +125 -0
- package/dist/index.cjs +511 -0
- package/dist/index.d.cts +93 -0
- package/dist/index.d.ts +93 -0
- package/dist/index.js +498 -0
- package/package.json +35 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var javascript$1 = require('@lezer/javascript');
|
|
4
|
+
var language = require('@codemirror/language');
|
|
5
|
+
var state = require('@codemirror/state');
|
|
6
|
+
var view = require('@codemirror/view');
|
|
7
|
+
var autocomplete = require('@codemirror/autocomplete');
|
|
8
|
+
var common = require('@lezer/common');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
A collection of JavaScript-related
|
|
12
|
+
[snippets](https://codemirror.net/6/docs/ref/#autocomplete.snippet).
|
|
13
|
+
*/
|
|
14
|
+
const snippets = [
|
|
15
|
+
autocomplete.snippetCompletion("function ${name}(${params}) {\n\t${}\n}", {
|
|
16
|
+
label: "function",
|
|
17
|
+
detail: "definition",
|
|
18
|
+
type: "keyword"
|
|
19
|
+
}),
|
|
20
|
+
autocomplete.snippetCompletion("for (let ${index} = 0; ${index} < ${bound}; ${index}++) {\n\t${}\n}", {
|
|
21
|
+
label: "for",
|
|
22
|
+
detail: "loop",
|
|
23
|
+
type: "keyword"
|
|
24
|
+
}),
|
|
25
|
+
autocomplete.snippetCompletion("for (let ${name} of ${collection}) {\n\t${}\n}", {
|
|
26
|
+
label: "for",
|
|
27
|
+
detail: "of loop",
|
|
28
|
+
type: "keyword"
|
|
29
|
+
}),
|
|
30
|
+
autocomplete.snippetCompletion("do {\n\t${}\n} while (${})", {
|
|
31
|
+
label: "do",
|
|
32
|
+
detail: "loop",
|
|
33
|
+
type: "keyword"
|
|
34
|
+
}),
|
|
35
|
+
autocomplete.snippetCompletion("while (${}) {\n\t${}\n}", {
|
|
36
|
+
label: "while",
|
|
37
|
+
detail: "loop",
|
|
38
|
+
type: "keyword"
|
|
39
|
+
}),
|
|
40
|
+
autocomplete.snippetCompletion("try {\n\t${}\n} catch (${error}) {\n\t${}\n}", {
|
|
41
|
+
label: "try",
|
|
42
|
+
detail: "/ catch block",
|
|
43
|
+
type: "keyword"
|
|
44
|
+
}),
|
|
45
|
+
autocomplete.snippetCompletion("if (${}) {\n\t${}\n}", {
|
|
46
|
+
label: "if",
|
|
47
|
+
detail: "block",
|
|
48
|
+
type: "keyword"
|
|
49
|
+
}),
|
|
50
|
+
autocomplete.snippetCompletion("if (${}) {\n\t${}\n} else {\n\t${}\n}", {
|
|
51
|
+
label: "if",
|
|
52
|
+
detail: "/ else block",
|
|
53
|
+
type: "keyword"
|
|
54
|
+
}),
|
|
55
|
+
autocomplete.snippetCompletion("class ${name} {\n\tconstructor(${params}) {\n\t\t${}\n\t}\n}", {
|
|
56
|
+
label: "class",
|
|
57
|
+
detail: "definition",
|
|
58
|
+
type: "keyword"
|
|
59
|
+
}),
|
|
60
|
+
autocomplete.snippetCompletion("import {${names}} from \"${module}\"\n${}", {
|
|
61
|
+
label: "import",
|
|
62
|
+
detail: "named",
|
|
63
|
+
type: "keyword"
|
|
64
|
+
}),
|
|
65
|
+
autocomplete.snippetCompletion("import ${name} from \"${module}\"\n${}", {
|
|
66
|
+
label: "import",
|
|
67
|
+
detail: "default",
|
|
68
|
+
type: "keyword"
|
|
69
|
+
})
|
|
70
|
+
];
|
|
71
|
+
/**
|
|
72
|
+
A collection of snippet completions for TypeScript. Includes the
|
|
73
|
+
JavaScript [snippets](https://codemirror.net/6/docs/ref/#lang-javascript.snippets).
|
|
74
|
+
*/
|
|
75
|
+
const typescriptSnippets = snippets.concat([
|
|
76
|
+
autocomplete.snippetCompletion("interface ${name} {\n\t${}\n}", {
|
|
77
|
+
label: "interface",
|
|
78
|
+
detail: "definition",
|
|
79
|
+
type: "keyword"
|
|
80
|
+
}),
|
|
81
|
+
autocomplete.snippetCompletion("type ${name} = ${type}", {
|
|
82
|
+
label: "type",
|
|
83
|
+
detail: "definition",
|
|
84
|
+
type: "keyword"
|
|
85
|
+
}),
|
|
86
|
+
autocomplete.snippetCompletion("enum ${name} {\n\t${}\n}", {
|
|
87
|
+
label: "enum",
|
|
88
|
+
detail: "definition",
|
|
89
|
+
type: "keyword"
|
|
90
|
+
})
|
|
91
|
+
]);
|
|
92
|
+
|
|
93
|
+
const cache = new common.NodeWeakMap();
|
|
94
|
+
const ScopeNodes = new Set([
|
|
95
|
+
"Script", "Block",
|
|
96
|
+
"FunctionExpression", "FunctionDeclaration", "ArrowFunction", "MethodDeclaration",
|
|
97
|
+
"ForStatement"
|
|
98
|
+
]);
|
|
99
|
+
function defID(type) {
|
|
100
|
+
return (node, def) => {
|
|
101
|
+
let id = node.node.getChild("VariableDefinition");
|
|
102
|
+
if (id)
|
|
103
|
+
def(id, type);
|
|
104
|
+
return true;
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
const functionContext = ["FunctionDeclaration"];
|
|
108
|
+
const gatherCompletions = {
|
|
109
|
+
FunctionDeclaration: defID("function"),
|
|
110
|
+
ClassDeclaration: defID("class"),
|
|
111
|
+
ClassExpression: () => true,
|
|
112
|
+
EnumDeclaration: defID("constant"),
|
|
113
|
+
TypeAliasDeclaration: defID("type"),
|
|
114
|
+
NamespaceDeclaration: defID("namespace"),
|
|
115
|
+
VariableDefinition(node, def) { if (!node.matchContext(functionContext))
|
|
116
|
+
def(node, "variable"); },
|
|
117
|
+
TypeDefinition(node, def) { def(node, "type"); },
|
|
118
|
+
__proto__: null
|
|
119
|
+
};
|
|
120
|
+
function getScope(doc, node) {
|
|
121
|
+
let cached = cache.get(node);
|
|
122
|
+
if (cached)
|
|
123
|
+
return cached;
|
|
124
|
+
let completions = [], top = true;
|
|
125
|
+
function def(node, type) {
|
|
126
|
+
let name = doc.sliceString(node.from, node.to);
|
|
127
|
+
completions.push({ label: name, type });
|
|
128
|
+
}
|
|
129
|
+
node.cursor(common.IterMode.IncludeAnonymous).iterate(node => {
|
|
130
|
+
if (top) {
|
|
131
|
+
top = false;
|
|
132
|
+
}
|
|
133
|
+
else if (node.name) {
|
|
134
|
+
let gather = gatherCompletions[node.name];
|
|
135
|
+
if (gather && gather(node, def) || ScopeNodes.has(node.name))
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
else if (node.to - node.from > 8192) {
|
|
139
|
+
// Allow caching for bigger internal nodes
|
|
140
|
+
for (let c of getScope(doc, node.node))
|
|
141
|
+
completions.push(c);
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
cache.set(node, completions);
|
|
146
|
+
return completions;
|
|
147
|
+
}
|
|
148
|
+
const Identifier = /^[\w$\xa1-\uffff][\w$\d\xa1-\uffff]*$/;
|
|
149
|
+
const dontComplete = [
|
|
150
|
+
"TemplateString", "String", "RegExp",
|
|
151
|
+
"LineComment", "BlockComment",
|
|
152
|
+
"VariableDefinition", "TypeDefinition", "Label",
|
|
153
|
+
"PropertyDefinition", "PropertyName",
|
|
154
|
+
"PrivatePropertyDefinition", "PrivatePropertyName",
|
|
155
|
+
"JSXText", "JSXAttributeValue", "JSXOpenTag", "JSXCloseTag", "JSXSelfClosingTag",
|
|
156
|
+
".", "?."
|
|
157
|
+
];
|
|
158
|
+
/**
|
|
159
|
+
Completion source that looks up locally defined names in
|
|
160
|
+
JavaScript code.
|
|
161
|
+
*/
|
|
162
|
+
function localCompletionSource(context) {
|
|
163
|
+
let inner = language.syntaxTree(context.state).resolveInner(context.pos, -1);
|
|
164
|
+
if (dontComplete.indexOf(inner.name) > -1)
|
|
165
|
+
return null;
|
|
166
|
+
let isWord = inner.name == "VariableName" ||
|
|
167
|
+
inner.to - inner.from < 20 && Identifier.test(context.state.sliceDoc(inner.from, inner.to));
|
|
168
|
+
if (!isWord && !context.explicit)
|
|
169
|
+
return null;
|
|
170
|
+
let options = [];
|
|
171
|
+
for (let pos = inner; pos; pos = pos.parent) {
|
|
172
|
+
if (ScopeNodes.has(pos.name))
|
|
173
|
+
options = options.concat(getScope(context.state.doc, pos));
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
options,
|
|
177
|
+
from: isWord ? inner.from : context.pos,
|
|
178
|
+
validFor: Identifier
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
function pathFor(read, member, name) {
|
|
182
|
+
var _a;
|
|
183
|
+
let path = [];
|
|
184
|
+
for (;;) {
|
|
185
|
+
let obj = member.firstChild, prop;
|
|
186
|
+
if ((obj === null || obj === void 0 ? void 0 : obj.name) == "VariableName") {
|
|
187
|
+
path.push(read(obj));
|
|
188
|
+
return { path: path.reverse(), name };
|
|
189
|
+
}
|
|
190
|
+
else if ((obj === null || obj === void 0 ? void 0 : obj.name) == "MemberExpression" && ((_a = (prop = obj.lastChild)) === null || _a === void 0 ? void 0 : _a.name) == "PropertyName") {
|
|
191
|
+
path.push(read(prop));
|
|
192
|
+
member = obj;
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
Helper function for defining JavaScript completion sources. It
|
|
201
|
+
returns the completable name and object path for a completion
|
|
202
|
+
context, or null if no name/property completion should happen at
|
|
203
|
+
that position. For example, when completing after `a.b.c` it will
|
|
204
|
+
return `{path: ["a", "b"], name: "c"}`. When completing after `x`
|
|
205
|
+
it will return `{path: [], name: "x"}`. When not in a property or
|
|
206
|
+
name, it will return null if `context.explicit` is false, and
|
|
207
|
+
`{path: [], name: ""}` otherwise.
|
|
208
|
+
*/
|
|
209
|
+
function completionPath(context) {
|
|
210
|
+
let read = (node) => context.state.doc.sliceString(node.from, node.to);
|
|
211
|
+
let inner = language.syntaxTree(context.state).resolveInner(context.pos, -1);
|
|
212
|
+
if (inner.name == "PropertyName") {
|
|
213
|
+
return pathFor(read, inner.parent, read(inner));
|
|
214
|
+
}
|
|
215
|
+
else if ((inner.name == "." || inner.name == "?.") && inner.parent.name == "MemberExpression") {
|
|
216
|
+
return pathFor(read, inner.parent, "");
|
|
217
|
+
}
|
|
218
|
+
else if (dontComplete.indexOf(inner.name) > -1) {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
else if (inner.name == "VariableName" || inner.to - inner.from < 20 && Identifier.test(read(inner))) {
|
|
222
|
+
return { path: [], name: read(inner) };
|
|
223
|
+
}
|
|
224
|
+
else if (inner.name == "MemberExpression") {
|
|
225
|
+
return pathFor(read, inner, "");
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
return context.explicit ? { path: [], name: "" } : null;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
function enumeratePropertyCompletions(obj, top) {
|
|
232
|
+
let options = [], seen = new Set;
|
|
233
|
+
for (let depth = 0;; depth++) {
|
|
234
|
+
for (let name of (Object.getOwnPropertyNames || Object.keys)(obj)) {
|
|
235
|
+
if (!/^[a-zA-Z_$\xaa-\uffdc][\w$\xaa-\uffdc]*$/.test(name) || seen.has(name))
|
|
236
|
+
continue;
|
|
237
|
+
seen.add(name);
|
|
238
|
+
let value;
|
|
239
|
+
try {
|
|
240
|
+
value = obj[name];
|
|
241
|
+
}
|
|
242
|
+
catch (_) {
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
options.push({
|
|
246
|
+
label: name,
|
|
247
|
+
type: typeof value == "function" ? (/^[A-Z]/.test(name) ? "class" : top ? "function" : "method")
|
|
248
|
+
: top ? "variable" : "property",
|
|
249
|
+
boost: -depth
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
let next = Object.getPrototypeOf(obj);
|
|
253
|
+
if (!next)
|
|
254
|
+
return options;
|
|
255
|
+
obj = next;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
Defines a [completion source](https://codemirror.net/6/docs/ref/#autocomplete.CompletionSource) that
|
|
260
|
+
completes from the given scope object (for example `globalThis`).
|
|
261
|
+
Will enter properties of the object when completing properties on
|
|
262
|
+
a directly-named path.
|
|
263
|
+
*/
|
|
264
|
+
function scopeCompletionSource(scope) {
|
|
265
|
+
let cache = new Map;
|
|
266
|
+
return (context) => {
|
|
267
|
+
let path = completionPath(context);
|
|
268
|
+
if (!path)
|
|
269
|
+
return null;
|
|
270
|
+
let target = scope;
|
|
271
|
+
for (let step of path.path) {
|
|
272
|
+
target = target[step];
|
|
273
|
+
if (!target)
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
let options = cache.get(target);
|
|
277
|
+
if (!options)
|
|
278
|
+
cache.set(target, options = enumeratePropertyCompletions(target, !path.path.length));
|
|
279
|
+
return {
|
|
280
|
+
from: context.pos - path.name.length,
|
|
281
|
+
options,
|
|
282
|
+
validFor: Identifier
|
|
283
|
+
};
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
A language provider based on the [Lezer JavaScript
|
|
289
|
+
parser](https://github.com/lezer-parser/javascript), extended with
|
|
290
|
+
highlighting and indentation information.
|
|
291
|
+
*/
|
|
292
|
+
const javascriptLanguage = language.LRLanguage.define({
|
|
293
|
+
name: "javascript",
|
|
294
|
+
parser: javascript$1.parser.configure({
|
|
295
|
+
props: [
|
|
296
|
+
language.indentNodeProp.add({
|
|
297
|
+
IfStatement: language.continuedIndent({ except: /^\s*({|else\b)/ }),
|
|
298
|
+
TryStatement: language.continuedIndent({ except: /^\s*({|catch\b|finally\b)/ }),
|
|
299
|
+
LabeledStatement: language.flatIndent,
|
|
300
|
+
SwitchBody: context => {
|
|
301
|
+
let after = context.textAfter, closed = /^\s*\}/.test(after), isCase = /^\s*(case|default)\b/.test(after);
|
|
302
|
+
return context.baseIndent + (closed ? 0 : isCase ? 1 : 2) * context.unit;
|
|
303
|
+
},
|
|
304
|
+
Block: language.delimitedIndent({ closing: "}" }),
|
|
305
|
+
ArrowFunction: cx => cx.baseIndent + cx.unit,
|
|
306
|
+
"TemplateString BlockComment": () => null,
|
|
307
|
+
"Statement Property": language.continuedIndent({ except: /^\s*{/ }),
|
|
308
|
+
JSXElement(context) {
|
|
309
|
+
let closed = /^\s*<\//.test(context.textAfter);
|
|
310
|
+
return context.lineIndent(context.node.from) + (closed ? 0 : context.unit);
|
|
311
|
+
},
|
|
312
|
+
JSXEscape(context) {
|
|
313
|
+
let closed = /\s*\}/.test(context.textAfter);
|
|
314
|
+
return context.lineIndent(context.node.from) + (closed ? 0 : context.unit);
|
|
315
|
+
},
|
|
316
|
+
"JSXOpenTag JSXSelfClosingTag"(context) {
|
|
317
|
+
return context.column(context.node.from) + context.unit;
|
|
318
|
+
}
|
|
319
|
+
}),
|
|
320
|
+
language.foldNodeProp.add({
|
|
321
|
+
"Block ClassBody SwitchBody EnumBody ObjectExpression ArrayExpression ObjectType": language.foldInside,
|
|
322
|
+
BlockComment(tree) { return { from: tree.from + 2, to: tree.to - 2 }; }
|
|
323
|
+
})
|
|
324
|
+
]
|
|
325
|
+
}),
|
|
326
|
+
languageData: {
|
|
327
|
+
closeBrackets: { brackets: ["(", "[", "{", "'", '"', "`"] },
|
|
328
|
+
commentTokens: { line: "//", block: { open: "/*", close: "*/" } },
|
|
329
|
+
indentOnInput: /^\s*(?:case |default:|\{|\}|<\/)$/,
|
|
330
|
+
wordChars: "$"
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
const jsxSublanguage = {
|
|
334
|
+
test: node => /^JSX/.test(node.name),
|
|
335
|
+
facet: language.defineLanguageFacet({ commentTokens: { block: { open: "{/*", close: "*/}" } } })
|
|
336
|
+
};
|
|
337
|
+
/**
|
|
338
|
+
A language provider for TypeScript.
|
|
339
|
+
*/
|
|
340
|
+
const typescriptLanguage = javascriptLanguage.configure({ dialect: "ts" }, "typescript");
|
|
341
|
+
/**
|
|
342
|
+
Language provider for JSX.
|
|
343
|
+
*/
|
|
344
|
+
const jsxLanguage = javascriptLanguage.configure({
|
|
345
|
+
dialect: "jsx",
|
|
346
|
+
props: [language.sublanguageProp.add(n => n.isTop ? [jsxSublanguage] : undefined)]
|
|
347
|
+
});
|
|
348
|
+
/**
|
|
349
|
+
Language provider for JSX + TypeScript.
|
|
350
|
+
*/
|
|
351
|
+
const tsxLanguage = javascriptLanguage.configure({
|
|
352
|
+
dialect: "jsx ts",
|
|
353
|
+
props: [language.sublanguageProp.add(n => n.isTop ? [jsxSublanguage] : undefined)]
|
|
354
|
+
}, "typescript");
|
|
355
|
+
let kwCompletion = (name) => ({ label: name, type: "keyword" });
|
|
356
|
+
const keywords = "break case const continue default delete export extends false finally in instanceof let new return static super switch this throw true typeof var yield".split(" ").map(kwCompletion);
|
|
357
|
+
const typescriptKeywords = keywords.concat(["declare", "implements", "private", "protected", "public"].map(kwCompletion));
|
|
358
|
+
/**
|
|
359
|
+
JavaScript support. Includes [snippet](https://codemirror.net/6/docs/ref/#lang-javascript.snippets)
|
|
360
|
+
and local variable completion.
|
|
361
|
+
*/
|
|
362
|
+
function javascript(config = {}) {
|
|
363
|
+
let lang = config.jsx ? (config.typescript ? tsxLanguage : jsxLanguage)
|
|
364
|
+
: config.typescript ? typescriptLanguage : javascriptLanguage;
|
|
365
|
+
let completions = config.typescript ? typescriptSnippets.concat(typescriptKeywords) : snippets.concat(keywords);
|
|
366
|
+
return new language.LanguageSupport(lang, [
|
|
367
|
+
javascriptLanguage.data.of({
|
|
368
|
+
autocomplete: autocomplete.ifNotIn(dontComplete, autocomplete.completeFromList(completions))
|
|
369
|
+
}),
|
|
370
|
+
javascriptLanguage.data.of({
|
|
371
|
+
autocomplete: localCompletionSource
|
|
372
|
+
}),
|
|
373
|
+
config.jsx ? autoCloseTags : [],
|
|
374
|
+
]);
|
|
375
|
+
}
|
|
376
|
+
function findOpenTag(node) {
|
|
377
|
+
for (;;) {
|
|
378
|
+
if (node.name == "JSXOpenTag" || node.name == "JSXSelfClosingTag" || node.name == "JSXFragmentTag")
|
|
379
|
+
return node;
|
|
380
|
+
if (node.name == "JSXEscape" || !node.parent)
|
|
381
|
+
return null;
|
|
382
|
+
node = node.parent;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
function elementName(doc, tree, max = doc.length) {
|
|
386
|
+
for (let ch = tree === null || tree === void 0 ? void 0 : tree.firstChild; ch; ch = ch.nextSibling) {
|
|
387
|
+
if (ch.name == "JSXIdentifier" || ch.name == "JSXBuiltin" || ch.name == "JSXNamespacedName" ||
|
|
388
|
+
ch.name == "JSXMemberExpression")
|
|
389
|
+
return doc.sliceString(ch.from, Math.min(ch.to, max));
|
|
390
|
+
}
|
|
391
|
+
return "";
|
|
392
|
+
}
|
|
393
|
+
const android = typeof navigator == "object" && /Android\b/.test(navigator.userAgent);
|
|
394
|
+
/**
|
|
395
|
+
Extension that will automatically insert JSX close tags when a `>` or
|
|
396
|
+
`/` is typed.
|
|
397
|
+
*/
|
|
398
|
+
const autoCloseTags = view.EditorView.inputHandler.of((view, from, to, text, defaultInsert) => {
|
|
399
|
+
if ((android ? view.composing : view.compositionStarted) || view.state.readOnly ||
|
|
400
|
+
from != to || (text != ">" && text != "/") ||
|
|
401
|
+
!javascriptLanguage.isActiveAt(view.state, from, -1))
|
|
402
|
+
return false;
|
|
403
|
+
let base = defaultInsert(), { state: state$1 } = base;
|
|
404
|
+
let closeTags = state$1.changeByRange(range => {
|
|
405
|
+
var _a;
|
|
406
|
+
let { head } = range, around = language.syntaxTree(state$1).resolveInner(head - 1, -1), name;
|
|
407
|
+
if (around.name == "JSXStartTag")
|
|
408
|
+
around = around.parent;
|
|
409
|
+
if (state$1.doc.sliceString(head - 1, head) != text || around.name == "JSXAttributeValue" && around.to > head) ;
|
|
410
|
+
else if (text == ">" && around.name == "JSXFragmentTag") {
|
|
411
|
+
return { range, changes: { from: head, insert: `</>` } };
|
|
412
|
+
}
|
|
413
|
+
else if (text == "/" && around.name == "JSXStartCloseTag") {
|
|
414
|
+
let empty = around.parent, base = empty.parent;
|
|
415
|
+
if (base && empty.from == head - 2 &&
|
|
416
|
+
((name = elementName(state$1.doc, base.firstChild, head)) || ((_a = base.firstChild) === null || _a === void 0 ? void 0 : _a.name) == "JSXFragmentTag")) {
|
|
417
|
+
let insert = `${name}>`;
|
|
418
|
+
return { range: state.EditorSelection.cursor(head + insert.length, -1), changes: { from: head, insert } };
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
else if (text == ">") {
|
|
422
|
+
let openTag = findOpenTag(around);
|
|
423
|
+
if (openTag && openTag.name == "JSXOpenTag" &&
|
|
424
|
+
!/^\/?>|^<\//.test(state$1.doc.sliceString(head, head + 2)) &&
|
|
425
|
+
(name = elementName(state$1.doc, openTag, head)))
|
|
426
|
+
return { range, changes: { from: head, insert: `</${name}>` } };
|
|
427
|
+
}
|
|
428
|
+
return { range };
|
|
429
|
+
});
|
|
430
|
+
if (closeTags.changes.empty)
|
|
431
|
+
return false;
|
|
432
|
+
view.dispatch([
|
|
433
|
+
base,
|
|
434
|
+
state$1.update(closeTags, { userEvent: "input.complete", scrollIntoView: true })
|
|
435
|
+
]);
|
|
436
|
+
return true;
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
Connects an [ESLint](https://eslint.org/) linter to CodeMirror's
|
|
441
|
+
[lint](https://codemirror.net/6/docs/ref/#lint) integration. `eslint` should be an instance of the
|
|
442
|
+
[`Linter`](https://eslint.org/docs/developer-guide/nodejs-api#linter)
|
|
443
|
+
class, and `config` an optional ESLint configuration. The return
|
|
444
|
+
value of this function can be passed to [`linter`](https://codemirror.net/6/docs/ref/#lint.linter)
|
|
445
|
+
to create a JavaScript linting extension.
|
|
446
|
+
|
|
447
|
+
Note that ESLint targets node, and is tricky to run in the
|
|
448
|
+
browser. The
|
|
449
|
+
[eslint-linter-browserify](https://github.com/UziTech/eslint-linter-browserify)
|
|
450
|
+
package may help with that (see
|
|
451
|
+
[example](https://github.com/UziTech/eslint-linter-browserify/blob/master/example/script.js)).
|
|
452
|
+
*/
|
|
453
|
+
function esLint(eslint, config) {
|
|
454
|
+
if (!config) {
|
|
455
|
+
config = {
|
|
456
|
+
parserOptions: { ecmaVersion: 2019, sourceType: "module" },
|
|
457
|
+
env: { browser: true, node: true, es6: true, es2015: true, es2017: true, es2020: true },
|
|
458
|
+
rules: {}
|
|
459
|
+
};
|
|
460
|
+
eslint.getRules().forEach((desc, name) => {
|
|
461
|
+
var _a;
|
|
462
|
+
if ((_a = desc.meta.docs) === null || _a === void 0 ? void 0 : _a.recommended)
|
|
463
|
+
config.rules[name] = 2;
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
return (view) => {
|
|
467
|
+
let { state } = view, found = [];
|
|
468
|
+
for (let { from, to } of javascriptLanguage.findRegions(state)) {
|
|
469
|
+
let fromLine = state.doc.lineAt(from), offset = { line: fromLine.number - 1, col: from - fromLine.from, pos: from };
|
|
470
|
+
for (let d of eslint.verify(state.sliceDoc(from, to), config))
|
|
471
|
+
found.push(translateDiagnostic(d, state.doc, offset));
|
|
472
|
+
}
|
|
473
|
+
return found;
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
function mapPos(line, col, doc, offset) {
|
|
477
|
+
return doc.line(line + offset.line).from + col + (line == 1 ? offset.col - 1 : -1);
|
|
478
|
+
}
|
|
479
|
+
function translateDiagnostic(input, doc, offset) {
|
|
480
|
+
let start = mapPos(input.line, input.column, doc, offset);
|
|
481
|
+
let result = {
|
|
482
|
+
from: start,
|
|
483
|
+
to: input.endLine != null && input.endColumn != 1 ? mapPos(input.endLine, input.endColumn, doc, offset) : start,
|
|
484
|
+
message: input.message,
|
|
485
|
+
source: input.ruleId ? "eslint:" + input.ruleId : "eslint",
|
|
486
|
+
severity: input.severity == 1 ? "warning" : "error",
|
|
487
|
+
};
|
|
488
|
+
if (input.fix) {
|
|
489
|
+
let { range, text } = input.fix, from = range[0] + offset.pos - start, to = range[1] + offset.pos - start;
|
|
490
|
+
result.actions = [{
|
|
491
|
+
name: "fix",
|
|
492
|
+
apply(view, start) {
|
|
493
|
+
view.dispatch({ changes: { from: start + from, to: start + to, insert: text }, scrollIntoView: true });
|
|
494
|
+
}
|
|
495
|
+
}];
|
|
496
|
+
}
|
|
497
|
+
return result;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
exports.autoCloseTags = autoCloseTags;
|
|
501
|
+
exports.completionPath = completionPath;
|
|
502
|
+
exports.esLint = esLint;
|
|
503
|
+
exports.javascript = javascript;
|
|
504
|
+
exports.javascriptLanguage = javascriptLanguage;
|
|
505
|
+
exports.jsxLanguage = jsxLanguage;
|
|
506
|
+
exports.localCompletionSource = localCompletionSource;
|
|
507
|
+
exports.scopeCompletionSource = scopeCompletionSource;
|
|
508
|
+
exports.snippets = snippets;
|
|
509
|
+
exports.tsxLanguage = tsxLanguage;
|
|
510
|
+
exports.typescriptLanguage = typescriptLanguage;
|
|
511
|
+
exports.typescriptSnippets = typescriptSnippets;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import * as _codemirror_state from '@codemirror/state';
|
|
2
|
+
import { LRLanguage, LanguageSupport } from '@codemirror/language';
|
|
3
|
+
import { Completion, CompletionContext, CompletionResult, CompletionSource } from '@codemirror/autocomplete';
|
|
4
|
+
import { Diagnostic } from '@codemirror/lint';
|
|
5
|
+
import { EditorView } from '@codemirror/view';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
A language provider based on the [Lezer JavaScript
|
|
9
|
+
parser](https://github.com/lezer-parser/javascript), extended with
|
|
10
|
+
highlighting and indentation information.
|
|
11
|
+
*/
|
|
12
|
+
declare const javascriptLanguage: LRLanguage;
|
|
13
|
+
/**
|
|
14
|
+
A language provider for TypeScript.
|
|
15
|
+
*/
|
|
16
|
+
declare const typescriptLanguage: LRLanguage;
|
|
17
|
+
/**
|
|
18
|
+
Language provider for JSX.
|
|
19
|
+
*/
|
|
20
|
+
declare const jsxLanguage: LRLanguage;
|
|
21
|
+
/**
|
|
22
|
+
Language provider for JSX + TypeScript.
|
|
23
|
+
*/
|
|
24
|
+
declare const tsxLanguage: LRLanguage;
|
|
25
|
+
/**
|
|
26
|
+
JavaScript support. Includes [snippet](https://codemirror.net/6/docs/ref/#lang-javascript.snippets)
|
|
27
|
+
and local variable completion.
|
|
28
|
+
*/
|
|
29
|
+
declare function javascript(config?: {
|
|
30
|
+
jsx?: boolean;
|
|
31
|
+
typescript?: boolean;
|
|
32
|
+
}): LanguageSupport;
|
|
33
|
+
/**
|
|
34
|
+
Extension that will automatically insert JSX close tags when a `>` or
|
|
35
|
+
`/` is typed.
|
|
36
|
+
*/
|
|
37
|
+
declare const autoCloseTags: _codemirror_state.Extension;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
A collection of JavaScript-related
|
|
41
|
+
[snippets](https://codemirror.net/6/docs/ref/#autocomplete.snippet).
|
|
42
|
+
*/
|
|
43
|
+
declare const snippets: readonly Completion[];
|
|
44
|
+
/**
|
|
45
|
+
A collection of snippet completions for TypeScript. Includes the
|
|
46
|
+
JavaScript [snippets](https://codemirror.net/6/docs/ref/#lang-javascript.snippets).
|
|
47
|
+
*/
|
|
48
|
+
declare const typescriptSnippets: Completion[];
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
Connects an [ESLint](https://eslint.org/) linter to CodeMirror's
|
|
52
|
+
[lint](https://codemirror.net/6/docs/ref/#lint) integration. `eslint` should be an instance of the
|
|
53
|
+
[`Linter`](https://eslint.org/docs/developer-guide/nodejs-api#linter)
|
|
54
|
+
class, and `config` an optional ESLint configuration. The return
|
|
55
|
+
value of this function can be passed to [`linter`](https://codemirror.net/6/docs/ref/#lint.linter)
|
|
56
|
+
to create a JavaScript linting extension.
|
|
57
|
+
|
|
58
|
+
Note that ESLint targets node, and is tricky to run in the
|
|
59
|
+
browser. The
|
|
60
|
+
[eslint-linter-browserify](https://github.com/UziTech/eslint-linter-browserify)
|
|
61
|
+
package may help with that (see
|
|
62
|
+
[example](https://github.com/UziTech/eslint-linter-browserify/blob/master/example/script.js)).
|
|
63
|
+
*/
|
|
64
|
+
declare function esLint(eslint: any, config?: any): (view: EditorView) => Diagnostic[];
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
Completion source that looks up locally defined names in
|
|
68
|
+
JavaScript code.
|
|
69
|
+
*/
|
|
70
|
+
declare function localCompletionSource(context: CompletionContext): CompletionResult | null;
|
|
71
|
+
/**
|
|
72
|
+
Helper function for defining JavaScript completion sources. It
|
|
73
|
+
returns the completable name and object path for a completion
|
|
74
|
+
context, or null if no name/property completion should happen at
|
|
75
|
+
that position. For example, when completing after `a.b.c` it will
|
|
76
|
+
return `{path: ["a", "b"], name: "c"}`. When completing after `x`
|
|
77
|
+
it will return `{path: [], name: "x"}`. When not in a property or
|
|
78
|
+
name, it will return null if `context.explicit` is false, and
|
|
79
|
+
`{path: [], name: ""}` otherwise.
|
|
80
|
+
*/
|
|
81
|
+
declare function completionPath(context: CompletionContext): {
|
|
82
|
+
path: readonly string[];
|
|
83
|
+
name: string;
|
|
84
|
+
} | null;
|
|
85
|
+
/**
|
|
86
|
+
Defines a [completion source](https://codemirror.net/6/docs/ref/#autocomplete.CompletionSource) that
|
|
87
|
+
completes from the given scope object (for example `globalThis`).
|
|
88
|
+
Will enter properties of the object when completing properties on
|
|
89
|
+
a directly-named path.
|
|
90
|
+
*/
|
|
91
|
+
declare function scopeCompletionSource(scope: any): CompletionSource;
|
|
92
|
+
|
|
93
|
+
export { autoCloseTags, completionPath, esLint, javascript, javascriptLanguage, jsxLanguage, localCompletionSource, scopeCompletionSource, snippets, tsxLanguage, typescriptLanguage, typescriptSnippets };
|