497 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			497 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import { parser } from '@lezer/javascript';
 | |
| import { syntaxTree, LRLanguage, indentNodeProp, continuedIndent, flatIndent, delimitedIndent, foldNodeProp, foldInside, sublanguageProp, LanguageSupport, defineLanguageFacet } from '@codemirror/language';
 | |
| import { EditorSelection } from '@codemirror/state';
 | |
| import { EditorView } from '@codemirror/view';
 | |
| import { snippetCompletion, ifNotIn, completeFromList } from '@codemirror/autocomplete';
 | |
| import { IterMode, NodeWeakMap } from '@lezer/common';
 | |
| 
 | |
| /**
 | |
| A collection of JavaScript-related
 | |
| [snippets](https://codemirror.net/6/docs/ref/#autocomplete.snippet).
 | |
| */
 | |
| const snippets = [
 | |
|     /*@__PURE__*/snippetCompletion("function ${name}(${params}) {\n\t${}\n}", {
 | |
|         label: "function",
 | |
|         detail: "definition",
 | |
|         type: "keyword"
 | |
|     }),
 | |
|     /*@__PURE__*/snippetCompletion("for (let ${index} = 0; ${index} < ${bound}; ${index}++) {\n\t${}\n}", {
 | |
|         label: "for",
 | |
|         detail: "loop",
 | |
|         type: "keyword"
 | |
|     }),
 | |
|     /*@__PURE__*/snippetCompletion("for (let ${name} of ${collection}) {\n\t${}\n}", {
 | |
|         label: "for",
 | |
|         detail: "of loop",
 | |
|         type: "keyword"
 | |
|     }),
 | |
|     /*@__PURE__*/snippetCompletion("do {\n\t${}\n} while (${})", {
 | |
|         label: "do",
 | |
|         detail: "loop",
 | |
|         type: "keyword"
 | |
|     }),
 | |
|     /*@__PURE__*/snippetCompletion("while (${}) {\n\t${}\n}", {
 | |
|         label: "while",
 | |
|         detail: "loop",
 | |
|         type: "keyword"
 | |
|     }),
 | |
|     /*@__PURE__*/snippetCompletion("try {\n\t${}\n} catch (${error}) {\n\t${}\n}", {
 | |
|         label: "try",
 | |
|         detail: "/ catch block",
 | |
|         type: "keyword"
 | |
|     }),
 | |
|     /*@__PURE__*/snippetCompletion("if (${}) {\n\t${}\n}", {
 | |
|         label: "if",
 | |
|         detail: "block",
 | |
|         type: "keyword"
 | |
|     }),
 | |
|     /*@__PURE__*/snippetCompletion("if (${}) {\n\t${}\n} else {\n\t${}\n}", {
 | |
|         label: "if",
 | |
|         detail: "/ else block",
 | |
|         type: "keyword"
 | |
|     }),
 | |
|     /*@__PURE__*/snippetCompletion("class ${name} {\n\tconstructor(${params}) {\n\t\t${}\n\t}\n}", {
 | |
|         label: "class",
 | |
|         detail: "definition",
 | |
|         type: "keyword"
 | |
|     }),
 | |
|     /*@__PURE__*/snippetCompletion("import {${names}} from \"${module}\"\n${}", {
 | |
|         label: "import",
 | |
|         detail: "named",
 | |
|         type: "keyword"
 | |
|     }),
 | |
|     /*@__PURE__*/snippetCompletion("import ${name} from \"${module}\"\n${}", {
 | |
|         label: "import",
 | |
|         detail: "default",
 | |
|         type: "keyword"
 | |
|     })
 | |
| ];
 | |
| /**
 | |
| A collection of snippet completions for TypeScript. Includes the
 | |
| JavaScript [snippets](https://codemirror.net/6/docs/ref/#lang-javascript.snippets).
 | |
| */
 | |
| const typescriptSnippets = /*@__PURE__*/snippets.concat([
 | |
|     /*@__PURE__*/snippetCompletion("interface ${name} {\n\t${}\n}", {
 | |
|         label: "interface",
 | |
|         detail: "definition",
 | |
|         type: "keyword"
 | |
|     }),
 | |
|     /*@__PURE__*/snippetCompletion("type ${name} = ${type}", {
 | |
|         label: "type",
 | |
|         detail: "definition",
 | |
|         type: "keyword"
 | |
|     }),
 | |
|     /*@__PURE__*/snippetCompletion("enum ${name} {\n\t${}\n}", {
 | |
|         label: "enum",
 | |
|         detail: "definition",
 | |
|         type: "keyword"
 | |
|     })
 | |
| ]);
 | |
| 
 | |
| const cache = /*@__PURE__*/new NodeWeakMap();
 | |
| const ScopeNodes = /*@__PURE__*/new Set([
 | |
|     "Script", "Block",
 | |
|     "FunctionExpression", "FunctionDeclaration", "ArrowFunction", "MethodDeclaration",
 | |
|     "ForStatement"
 | |
| ]);
 | |
| function defID(type) {
 | |
|     return (node, def) => {
 | |
|         let id = node.node.getChild("VariableDefinition");
 | |
|         if (id)
 | |
|             def(id, type);
 | |
|         return true;
 | |
|     };
 | |
| }
 | |
| const functionContext = ["FunctionDeclaration"];
 | |
| const gatherCompletions = {
 | |
|     FunctionDeclaration: /*@__PURE__*/defID("function"),
 | |
|     ClassDeclaration: /*@__PURE__*/defID("class"),
 | |
|     ClassExpression: () => true,
 | |
|     EnumDeclaration: /*@__PURE__*/defID("constant"),
 | |
|     TypeAliasDeclaration: /*@__PURE__*/defID("type"),
 | |
|     NamespaceDeclaration: /*@__PURE__*/defID("namespace"),
 | |
|     VariableDefinition(node, def) { if (!node.matchContext(functionContext))
 | |
|         def(node, "variable"); },
 | |
|     TypeDefinition(node, def) { def(node, "type"); },
 | |
|     __proto__: null
 | |
| };
 | |
| function getScope(doc, node) {
 | |
|     let cached = cache.get(node);
 | |
|     if (cached)
 | |
|         return cached;
 | |
|     let completions = [], top = true;
 | |
|     function def(node, type) {
 | |
|         let name = doc.sliceString(node.from, node.to);
 | |
|         completions.push({ label: name, type });
 | |
|     }
 | |
|     node.cursor(IterMode.IncludeAnonymous).iterate(node => {
 | |
|         if (top) {
 | |
|             top = false;
 | |
|         }
 | |
|         else if (node.name) {
 | |
|             let gather = gatherCompletions[node.name];
 | |
|             if (gather && gather(node, def) || ScopeNodes.has(node.name))
 | |
|                 return false;
 | |
|         }
 | |
|         else if (node.to - node.from > 8192) {
 | |
|             // Allow caching for bigger internal nodes
 | |
|             for (let c of getScope(doc, node.node))
 | |
|                 completions.push(c);
 | |
|             return false;
 | |
|         }
 | |
|     });
 | |
|     cache.set(node, completions);
 | |
|     return completions;
 | |
| }
 | |
| const Identifier = /^[\w$\xa1-\uffff][\w$\d\xa1-\uffff]*$/;
 | |
| const dontComplete = [
 | |
|     "TemplateString", "String", "RegExp",
 | |
|     "LineComment", "BlockComment",
 | |
|     "VariableDefinition", "TypeDefinition", "Label",
 | |
|     "PropertyDefinition", "PropertyName",
 | |
|     "PrivatePropertyDefinition", "PrivatePropertyName",
 | |
|     ".", "?."
 | |
| ];
 | |
| /**
 | |
| Completion source that looks up locally defined names in
 | |
| JavaScript code.
 | |
| */
 | |
| function localCompletionSource(context) {
 | |
|     let inner = syntaxTree(context.state).resolveInner(context.pos, -1);
 | |
|     if (dontComplete.indexOf(inner.name) > -1)
 | |
|         return null;
 | |
|     let isWord = inner.name == "VariableName" ||
 | |
|         inner.to - inner.from < 20 && Identifier.test(context.state.sliceDoc(inner.from, inner.to));
 | |
|     if (!isWord && !context.explicit)
 | |
|         return null;
 | |
|     let options = [];
 | |
|     for (let pos = inner; pos; pos = pos.parent) {
 | |
|         if (ScopeNodes.has(pos.name))
 | |
|             options = options.concat(getScope(context.state.doc, pos));
 | |
|     }
 | |
|     return {
 | |
|         options,
 | |
|         from: isWord ? inner.from : context.pos,
 | |
|         validFor: Identifier
 | |
|     };
 | |
| }
 | |
| function pathFor(read, member, name) {
 | |
|     var _a;
 | |
|     let path = [];
 | |
|     for (;;) {
 | |
|         let obj = member.firstChild, prop;
 | |
|         if ((obj === null || obj === void 0 ? void 0 : obj.name) == "VariableName") {
 | |
|             path.push(read(obj));
 | |
|             return { path: path.reverse(), name };
 | |
|         }
 | |
|         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") {
 | |
|             path.push(read(prop));
 | |
|             member = obj;
 | |
|         }
 | |
|         else {
 | |
|             return null;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| /**
 | |
| Helper function for defining JavaScript completion sources. It
 | |
| returns the completable name and object path for a completion
 | |
| context, or null if no name/property completion should happen at
 | |
| that position. For example, when completing after `a.b.c` it will
 | |
| return `{path: ["a", "b"], name: "c"}`. When completing after `x`
 | |
| it will return `{path: [], name: "x"}`. When not in a property or
 | |
| name, it will return null if `context.explicit` is false, and
 | |
| `{path: [], name: ""}` otherwise.
 | |
| */
 | |
| function completionPath(context) {
 | |
|     let read = (node) => context.state.doc.sliceString(node.from, node.to);
 | |
|     let inner = syntaxTree(context.state).resolveInner(context.pos, -1);
 | |
|     if (inner.name == "PropertyName") {
 | |
|         return pathFor(read, inner.parent, read(inner));
 | |
|     }
 | |
|     else if ((inner.name == "." || inner.name == "?.") && inner.parent.name == "MemberExpression") {
 | |
|         return pathFor(read, inner.parent, "");
 | |
|     }
 | |
|     else if (dontComplete.indexOf(inner.name) > -1) {
 | |
|         return null;
 | |
|     }
 | |
|     else if (inner.name == "VariableName" || inner.to - inner.from < 20 && Identifier.test(read(inner))) {
 | |
|         return { path: [], name: read(inner) };
 | |
|     }
 | |
|     else if (inner.name == "MemberExpression") {
 | |
|         return pathFor(read, inner, "");
 | |
|     }
 | |
|     else {
 | |
|         return context.explicit ? { path: [], name: "" } : null;
 | |
|     }
 | |
| }
 | |
| function enumeratePropertyCompletions(obj, top) {
 | |
|     let options = [], seen = new Set;
 | |
|     for (let depth = 0;; depth++) {
 | |
|         for (let name of (Object.getOwnPropertyNames || Object.keys)(obj)) {
 | |
|             if (!/^[a-zA-Z_$\xaa-\uffdc][\w$\xaa-\uffdc]*$/.test(name) || seen.has(name))
 | |
|                 continue;
 | |
|             seen.add(name);
 | |
|             let value;
 | |
|             try {
 | |
|                 value = obj[name];
 | |
|             }
 | |
|             catch (_) {
 | |
|                 continue;
 | |
|             }
 | |
|             options.push({
 | |
|                 label: name,
 | |
|                 type: typeof value == "function" ? (/^[A-Z]/.test(name) ? "class" : top ? "function" : "method")
 | |
|                     : top ? "variable" : "property",
 | |
|                 boost: -depth
 | |
|             });
 | |
|         }
 | |
|         let next = Object.getPrototypeOf(obj);
 | |
|         if (!next)
 | |
|             return options;
 | |
|         obj = next;
 | |
|     }
 | |
| }
 | |
| /**
 | |
| Defines a [completion source](https://codemirror.net/6/docs/ref/#autocomplete.CompletionSource) that
 | |
| completes from the given scope object (for example `globalThis`).
 | |
| Will enter properties of the object when completing properties on
 | |
| a directly-named path.
 | |
| */
 | |
| function scopeCompletionSource(scope) {
 | |
|     let cache = new Map;
 | |
|     return (context) => {
 | |
|         let path = completionPath(context);
 | |
|         if (!path)
 | |
|             return null;
 | |
|         let target = scope;
 | |
|         for (let step of path.path) {
 | |
|             target = target[step];
 | |
|             if (!target)
 | |
|                 return null;
 | |
|         }
 | |
|         let options = cache.get(target);
 | |
|         if (!options)
 | |
|             cache.set(target, options = enumeratePropertyCompletions(target, !path.path.length));
 | |
|         return {
 | |
|             from: context.pos - path.name.length,
 | |
|             options,
 | |
|             validFor: Identifier
 | |
|         };
 | |
|     };
 | |
| }
 | |
| 
 | |
| /**
 | |
| A language provider based on the [Lezer JavaScript
 | |
| parser](https://github.com/lezer-parser/javascript), extended with
 | |
| highlighting and indentation information.
 | |
| */
 | |
| const javascriptLanguage = /*@__PURE__*/LRLanguage.define({
 | |
|     name: "javascript",
 | |
|     parser: /*@__PURE__*/parser.configure({
 | |
|         props: [
 | |
|             /*@__PURE__*/indentNodeProp.add({
 | |
|                 IfStatement: /*@__PURE__*/continuedIndent({ except: /^\s*({|else\b)/ }),
 | |
|                 TryStatement: /*@__PURE__*/continuedIndent({ except: /^\s*({|catch\b|finally\b)/ }),
 | |
|                 LabeledStatement: flatIndent,
 | |
|                 SwitchBody: context => {
 | |
|                     let after = context.textAfter, closed = /^\s*\}/.test(after), isCase = /^\s*(case|default)\b/.test(after);
 | |
|                     return context.baseIndent + (closed ? 0 : isCase ? 1 : 2) * context.unit;
 | |
|                 },
 | |
|                 Block: /*@__PURE__*/delimitedIndent({ closing: "}" }),
 | |
|                 ArrowFunction: cx => cx.baseIndent + cx.unit,
 | |
|                 "TemplateString BlockComment": () => null,
 | |
|                 "Statement Property": /*@__PURE__*/continuedIndent({ except: /^{/ }),
 | |
|                 JSXElement(context) {
 | |
|                     let closed = /^\s*<\//.test(context.textAfter);
 | |
|                     return context.lineIndent(context.node.from) + (closed ? 0 : context.unit);
 | |
|                 },
 | |
|                 JSXEscape(context) {
 | |
|                     let closed = /\s*\}/.test(context.textAfter);
 | |
|                     return context.lineIndent(context.node.from) + (closed ? 0 : context.unit);
 | |
|                 },
 | |
|                 "JSXOpenTag JSXSelfClosingTag"(context) {
 | |
|                     return context.column(context.node.from) + context.unit;
 | |
|                 }
 | |
|             }),
 | |
|             /*@__PURE__*/foldNodeProp.add({
 | |
|                 "Block ClassBody SwitchBody EnumBody ObjectExpression ArrayExpression ObjectType": foldInside,
 | |
|                 BlockComment(tree) { return { from: tree.from + 2, to: tree.to - 2 }; }
 | |
|             })
 | |
|         ]
 | |
|     }),
 | |
|     languageData: {
 | |
|         closeBrackets: { brackets: ["(", "[", "{", "'", '"', "`"] },
 | |
|         commentTokens: { line: "//", block: { open: "/*", close: "*/" } },
 | |
|         indentOnInput: /^\s*(?:case |default:|\{|\}|<\/)$/,
 | |
|         wordChars: "$"
 | |
|     }
 | |
| });
 | |
| const jsxSublanguage = {
 | |
|     test: node => /^JSX/.test(node.name),
 | |
|     facet: /*@__PURE__*/defineLanguageFacet({ commentTokens: { block: { open: "{/*", close: "*/}" } } })
 | |
| };
 | |
| /**
 | |
| A language provider for TypeScript.
 | |
| */
 | |
| const typescriptLanguage = /*@__PURE__*/javascriptLanguage.configure({ dialect: "ts" }, "typescript");
 | |
| /**
 | |
| Language provider for JSX.
 | |
| */
 | |
| const jsxLanguage = /*@__PURE__*/javascriptLanguage.configure({
 | |
|     dialect: "jsx",
 | |
|     props: [/*@__PURE__*/sublanguageProp.add(n => n.isTop ? [jsxSublanguage] : undefined)]
 | |
| });
 | |
| /**
 | |
| Language provider for JSX + TypeScript.
 | |
| */
 | |
| const tsxLanguage = /*@__PURE__*/javascriptLanguage.configure({
 | |
|     dialect: "jsx ts",
 | |
|     props: [/*@__PURE__*/sublanguageProp.add(n => n.isTop ? [jsxSublanguage] : undefined)]
 | |
| }, "typescript");
 | |
| let kwCompletion = (name) => ({ label: name, type: "keyword" });
 | |
| const keywords = /*@__PURE__*/"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);
 | |
| const typescriptKeywords = /*@__PURE__*/keywords.concat(/*@__PURE__*/["declare", "implements", "private", "protected", "public"].map(kwCompletion));
 | |
| /**
 | |
| JavaScript support. Includes [snippet](https://codemirror.net/6/docs/ref/#lang-javascript.snippets)
 | |
| and local variable completion.
 | |
| */
 | |
| function javascript(config = {}) {
 | |
|     let lang = config.jsx ? (config.typescript ? tsxLanguage : jsxLanguage)
 | |
|         : config.typescript ? typescriptLanguage : javascriptLanguage;
 | |
|     let completions = config.typescript ? typescriptSnippets.concat(typescriptKeywords) : snippets.concat(keywords);
 | |
|     return new LanguageSupport(lang, [
 | |
|         javascriptLanguage.data.of({
 | |
|             autocomplete: ifNotIn(dontComplete, completeFromList(completions))
 | |
|         }),
 | |
|         javascriptLanguage.data.of({
 | |
|             autocomplete: localCompletionSource
 | |
|         }),
 | |
|         config.jsx ? autoCloseTags : [],
 | |
|     ]);
 | |
| }
 | |
| function findOpenTag(node) {
 | |
|     for (;;) {
 | |
|         if (node.name == "JSXOpenTag" || node.name == "JSXSelfClosingTag" || node.name == "JSXFragmentTag")
 | |
|             return node;
 | |
|         if (node.name == "JSXEscape" || !node.parent)
 | |
|             return null;
 | |
|         node = node.parent;
 | |
|     }
 | |
| }
 | |
| function elementName(doc, tree, max = doc.length) {
 | |
|     for (let ch = tree === null || tree === void 0 ? void 0 : tree.firstChild; ch; ch = ch.nextSibling) {
 | |
|         if (ch.name == "JSXIdentifier" || ch.name == "JSXBuiltin" || ch.name == "JSXNamespacedName" ||
 | |
|             ch.name == "JSXMemberExpression")
 | |
|             return doc.sliceString(ch.from, Math.min(ch.to, max));
 | |
|     }
 | |
|     return "";
 | |
| }
 | |
| const android = typeof navigator == "object" && /*@__PURE__*//Android\b/.test(navigator.userAgent);
 | |
| /**
 | |
| Extension that will automatically insert JSX close tags when a `>` or
 | |
| `/` is typed.
 | |
| */
 | |
| const autoCloseTags = /*@__PURE__*/EditorView.inputHandler.of((view, from, to, text, defaultInsert) => {
 | |
|     if ((android ? view.composing : view.compositionStarted) || view.state.readOnly ||
 | |
|         from != to || (text != ">" && text != "/") ||
 | |
|         !javascriptLanguage.isActiveAt(view.state, from, -1))
 | |
|         return false;
 | |
|     let base = defaultInsert(), { state } = base;
 | |
|     let closeTags = state.changeByRange(range => {
 | |
|         var _a;
 | |
|         let { head } = range, around = syntaxTree(state).resolveInner(head - 1, -1), name;
 | |
|         if (around.name == "JSXStartTag")
 | |
|             around = around.parent;
 | |
|         if (state.doc.sliceString(head - 1, head) != text || around.name == "JSXAttributeValue" && around.to > head) ;
 | |
|         else if (text == ">" && around.name == "JSXFragmentTag") {
 | |
|             return { range, changes: { from: head, insert: `</>` } };
 | |
|         }
 | |
|         else if (text == "/" && around.name == "JSXStartCloseTag") {
 | |
|             let empty = around.parent, base = empty.parent;
 | |
|             if (base && empty.from == head - 2 &&
 | |
|                 ((name = elementName(state.doc, base.firstChild, head)) || ((_a = base.firstChild) === null || _a === void 0 ? void 0 : _a.name) == "JSXFragmentTag")) {
 | |
|                 let insert = `${name}>`;
 | |
|                 return { range: EditorSelection.cursor(head + insert.length, -1), changes: { from: head, insert } };
 | |
|             }
 | |
|         }
 | |
|         else if (text == ">") {
 | |
|             let openTag = findOpenTag(around);
 | |
|             if (openTag && openTag.name == "JSXOpenTag" &&
 | |
|                 !/^\/?>|^<\//.test(state.doc.sliceString(head, head + 2)) &&
 | |
|                 (name = elementName(state.doc, openTag, head)))
 | |
|                 return { range, changes: { from: head, insert: `</${name}>` } };
 | |
|         }
 | |
|         return { range };
 | |
|     });
 | |
|     if (closeTags.changes.empty)
 | |
|         return false;
 | |
|     view.dispatch([
 | |
|         base,
 | |
|         state.update(closeTags, { userEvent: "input.complete", scrollIntoView: true })
 | |
|     ]);
 | |
|     return true;
 | |
| });
 | |
| 
 | |
| /**
 | |
| Connects an [ESLint](https://eslint.org/) linter to CodeMirror's
 | |
| [lint](https://codemirror.net/6/docs/ref/#lint) integration. `eslint` should be an instance of the
 | |
| [`Linter`](https://eslint.org/docs/developer-guide/nodejs-api#linter)
 | |
| class, and `config` an optional ESLint configuration. The return
 | |
| value of this function can be passed to [`linter`](https://codemirror.net/6/docs/ref/#lint.linter)
 | |
| to create a JavaScript linting extension.
 | |
| 
 | |
| Note that ESLint targets node, and is tricky to run in the
 | |
| browser. The
 | |
| [eslint-linter-browserify](https://github.com/UziTech/eslint-linter-browserify)
 | |
| package may help with that (see
 | |
| [example](https://github.com/UziTech/eslint-linter-browserify/blob/master/example/script.js)).
 | |
| */
 | |
| function esLint(eslint, config) {
 | |
|     if (!config) {
 | |
|         config = {
 | |
|             parserOptions: { ecmaVersion: 2019, sourceType: "module" },
 | |
|             env: { browser: true, node: true, es6: true, es2015: true, es2017: true, es2020: true },
 | |
|             rules: {}
 | |
|         };
 | |
|         eslint.getRules().forEach((desc, name) => {
 | |
|             if (desc.meta.docs.recommended)
 | |
|                 config.rules[name] = 2;
 | |
|         });
 | |
|     }
 | |
|     return (view) => {
 | |
|         let { state } = view, found = [];
 | |
|         for (let { from, to } of javascriptLanguage.findRegions(state)) {
 | |
|             let fromLine = state.doc.lineAt(from), offset = { line: fromLine.number - 1, col: from - fromLine.from, pos: from };
 | |
|             for (let d of eslint.verify(state.sliceDoc(from, to), config))
 | |
|                 found.push(translateDiagnostic(d, state.doc, offset));
 | |
|         }
 | |
|         return found;
 | |
|     };
 | |
| }
 | |
| function mapPos(line, col, doc, offset) {
 | |
|     return doc.line(line + offset.line).from + col + (line == 1 ? offset.col - 1 : -1);
 | |
| }
 | |
| function translateDiagnostic(input, doc, offset) {
 | |
|     let start = mapPos(input.line, input.column, doc, offset);
 | |
|     let result = {
 | |
|         from: start,
 | |
|         to: input.endLine != null && input.endColumn != 1 ? mapPos(input.endLine, input.endColumn, doc, offset) : start,
 | |
|         message: input.message,
 | |
|         source: input.ruleId ? "eslint:" + input.ruleId : "eslint",
 | |
|         severity: input.severity == 1 ? "warning" : "error",
 | |
|     };
 | |
|     if (input.fix) {
 | |
|         let { range, text } = input.fix, from = range[0] + offset.pos - start, to = range[1] + offset.pos - start;
 | |
|         result.actions = [{
 | |
|                 name: "fix",
 | |
|                 apply(view, start) {
 | |
|                     view.dispatch({ changes: { from: start + from, to: start + to, insert: text }, scrollIntoView: true });
 | |
|                 }
 | |
|             }];
 | |
|     }
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| export { autoCloseTags, completionPath, esLint, javascript, javascriptLanguage, jsxLanguage, localCompletionSource, scopeCompletionSource, snippets, tsxLanguage, typescriptLanguage, typescriptSnippets };
 |