Premier commit déjà bien avancé

This commit is contained in:
2025-11-10 18:33:24 +01:00
commit db4f0508cb
652 changed files with 440521 additions and 0 deletions

View File

@ -0,0 +1,16 @@
name: Trigger CI
on: push
jobs:
build:
name: Dispatch to main repo
runs-on: ubuntu-latest
steps:
- name: Emit repository_dispatch
uses: mvasigh/dispatch-action@main
with:
# You should create a personal access token and store it in your repository
token: ${{ secrets.DISPATCH_AUTH }}
repo: dev
owner: codemirror
event_type: push

View File

@ -0,0 +1,198 @@
## 6.2.4 (2025-05-14)
### Bug fixes
Fix a crash in the `esLint` helper when a rule's `meta.docs` isn't defined.
Properly dedent lines starting with an opening curly brace below composite statements like `for`/`while`.
## 6.2.3 (2025-02-12)
### Bug fixes
Disable JavaScript completions in JSX context.
## 6.2.2 (2024-02-20)
### Bug fixes
Fix a bug that would cause self-closing JSX tags to have another closing tag inserted when typing the final '>'.
## 6.2.1 (2023-08-28)
### Bug fixes
`autoCloseTags` now generates two separate transactions, so that the completion can be undone separately.
## 6.2.0 (2023-08-26)
### New features
Export a `typescriptSnippets` array and include TypeScript keyword completions in the default support extension when in TypeScript mode.
## 6.1.9 (2023-06-02)
### Bug fixes
Make sure `scopeCompletionSource` doesn't try to complete property names that aren't simple identifier (such as numeric indices).
## 6.1.8 (2023-05-13)
### Bug fixes
Stop completing keywords after `.` tokens.
## 6.1.7 (2023-04-19)
### Bug fixes
Fix overeager JSX tag closing inside attribute values and in self-closing tags.
## 6.1.6 (2023-04-13)
### Bug fixes
Fix a bug that allowed `autoCloseTags` to close JSX tags in JavaScript context.
## 6.1.5 (2023-04-04)
### Bug fixes
Make TypeScript object type syntax foldable.
## 6.1.4 (2023-02-13)
### Bug fixes
Make sure code in JSX context can be commented correctly.
## 6.1.3 (2023-02-02)
### Bug fixes
Fix auto-closing of JSX fragments.
## 6.1.2 (2022-12-07)
### Bug fixes
Automatic tag closing in JSX now works for namespaced and member-expression tag names.
## 6.1.1 (2022-10-24)
### Bug fixes
Make `completionPath` handle `?.` syntax.
## 6.1.0 (2022-09-20)
### New features
The `completionPath` helper can now be used to find the object path to complete at a given position.
`scopeCompletionSource` provides a completion source based on a scope object.
## 6.0.2 (2022-07-21)
### Bug fixes
Fix the `source` field in ESLint diagnostics to properly hold `"eslint"`.
Fix (non-)auto indentation in template strings and comments.
## 6.0.1 (2022-06-29)
### Bug fixes
Avoid completing variables/keywords in property or definition positions.
Fix a bug that broke local variable completion if JavaScript was parsed an overlay in an outer language.
## 6.0.0 (2022-06-08)
### Breaking changes
Update dependencies to 6.0.0
## 0.20.1 (2022-06-01)
### New features
`localCompletionSource` (included in the support extensions returned from `javascript`) now provides a way to complete locally-defined names.
## 0.20.0 (2022-04-20)
### New features
The new `autoCloseTags` extension (included by default in the `javascript` language extension when `jsx` is configured) finishes JSX closing tags when you type a `>` or `/` character.
## 0.19.7 (2022-01-28)
## 0.19.6 (2022-01-11)
### Bug fixes
Remove accidentally released unfinished changes.
## 0.19.5 (2022-01-11)
### Bug fixes
Add the `function` highlight modifier to variables used in tagged template expressions.
## 0.19.4 (2022-01-03)
### Bug fixes
Fix highlighting of TypeScript private/public/protected keywords.
## 0.19.3 (2021-11-12)
### Bug fixes
Add styling for private properties.
## 0.19.2 (2021-09-23)
### New features
Use more specific highlighting tags for JSX attribute names and values.
## 0.19.1 (2021-08-11)
### Bug fixes
Fix incorrect versions for @lezer dependencies.
## 0.19.0 (2021-08-11)
### Breaking changes
Update dependencies to 0.19.0
## 0.18.0 (2021-03-03)
### Bug fixes
Extend `indentOnInput` expression to cover closing JSX tags.
## 0.17.2 (2021-02-15)
### Bug fixes
Improve highlighting tag specificity of defined function and class names. Add indentation information for JSX constructs
Support smart indent for JSX syntax.
## 0.17.1 (2021-01-06)
### New features
The package now also exports a CommonJS module.
## 0.17.0 (2020-12-29)
### Breaking changes
First numbered release.

View File

@ -0,0 +1,21 @@
MIT License
Copyright (C) 2018-2021 by Marijn Haverbeke <marijn@haverbeke.berlin> and others
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,125 @@
<!-- NOTE: README.md is generated from src/README.md -->
# @codemirror/lang-javascript [![NPM version](https://img.shields.io/npm/v/@codemirror/lang-javascript.svg)](https://www.npmjs.org/package/@codemirror/lang-javascript)
[ [**WEBSITE**](https://codemirror.net/) | [**ISSUES**](https://github.com/codemirror/dev/issues) | [**FORUM**](https://discuss.codemirror.net/c/next/) | [**CHANGELOG**](https://github.com/codemirror/lang-javascript/blob/main/CHANGELOG.md) ]
This package implements JavaScript language support for the
[CodeMirror](https://codemirror.net/) code editor.
The [project page](https://codemirror.net/) has more information, a
number of [examples](https://codemirror.net/examples/) and the
[documentation](https://codemirror.net/docs/).
This code is released under an
[MIT license](https://github.com/codemirror/lang-javascript/tree/main/LICENSE).
We aim to be an inclusive, welcoming community. To make that explicit,
we have a [code of
conduct](http://contributor-covenant.org/version/1/1/0/) that applies
to communication around the project.
## Usage
```javascript
import {EditorView, basicSetup} from "codemirror"
import {javascript} from "@codemirror/lang-javascript"
const view = new EditorView({
parent: document.body,
doc: `console.log("Hello world")`,
extensions: [basicSetup, javascript()]
})
```
## API Reference
<dl>
<dt id="user-content-javascript">
<code><strong><a href="#user-content-javascript">javascript</a></strong>(<a id="user-content-javascript^config" href="#user-content-javascript^config">config</a>&#8288;?: {jsx&#8288;?: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean">boolean</a>, typescript&#8288;?: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean">boolean</a>} = {}) → <a href="https://codemirror.net/docs/ref#language.LanguageSupport">LanguageSupport</a></code></dt>
<dd><p>JavaScript support. Includes <a href="#user-content-snippets">snippet</a>
and local variable completion.</p>
</dd>
<dt id="user-content-javascriptlanguage">
<code><strong><a href="#user-content-javascriptlanguage">javascriptLanguage</a></strong>: <a href="https://codemirror.net/docs/ref#language.LRLanguage">LRLanguage</a></code></dt>
<dd><p>A language provider based on the <a href="https://github.com/lezer-parser/javascript">Lezer JavaScript
parser</a>, extended with
highlighting and indentation information.</p>
</dd>
<dt id="user-content-typescriptlanguage">
<code><strong><a href="#user-content-typescriptlanguage">typescriptLanguage</a></strong>: <a href="https://codemirror.net/docs/ref#language.LRLanguage">LRLanguage</a></code></dt>
<dd><p>A language provider for TypeScript.</p>
</dd>
<dt id="user-content-jsxlanguage">
<code><strong><a href="#user-content-jsxlanguage">jsxLanguage</a></strong>: <a href="https://codemirror.net/docs/ref#language.LRLanguage">LRLanguage</a></code></dt>
<dd><p>Language provider for JSX.</p>
</dd>
<dt id="user-content-tsxlanguage">
<code><strong><a href="#user-content-tsxlanguage">tsxLanguage</a></strong>: <a href="https://codemirror.net/docs/ref#language.LRLanguage">LRLanguage</a></code></dt>
<dd><p>Language provider for JSX + TypeScript.</p>
</dd>
<dt id="user-content-autoclosetags">
<code><strong><a href="#user-content-autoclosetags">autoCloseTags</a></strong>: <a href="https://codemirror.net/docs/ref#state.Extension">Extension</a></code></dt>
<dd><p>Extension that will automatically insert JSX close tags when a <code>&gt;</code> or
<code>/</code> is typed.</p>
</dd>
<dt id="user-content-snippets">
<code><strong><a href="#user-content-snippets">snippets</a></strong>: readonly <a href="https://codemirror.net/docs/ref#autocomplete.Completion">Completion</a>[]</code></dt>
<dd><p>A collection of JavaScript-related
<a href="https://codemirror.net/docs/ref/#autocomplete.snippet">snippets</a>.</p>
</dd>
<dt id="user-content-typescriptsnippets">
<code><strong><a href="#user-content-typescriptsnippets">typescriptSnippets</a></strong>: <a href="https://codemirror.net/docs/ref#autocomplete.Completion">Completion</a>[]</code></dt>
<dd><p>A collection of snippet completions for TypeScript. Includes the
JavaScript <a href="#user-content-snippets">snippets</a>.</p>
</dd>
<dt id="user-content-localcompletionsource">
<code><strong><a href="#user-content-localcompletionsource">localCompletionSource</a></strong>(<a id="user-content-localcompletionsource^context" href="#user-content-localcompletionsource^context">context</a>: <a href="https://codemirror.net/docs/ref#autocomplete.CompletionContext">CompletionContext</a>) → <a href="https://codemirror.net/docs/ref#autocomplete.CompletionResult">CompletionResult</a> | <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null">null</a></code></dt>
<dd><p>Completion source that looks up locally defined names in
JavaScript code.</p>
</dd>
<dt id="user-content-completionpath">
<code><strong><a href="#user-content-completionpath">completionPath</a></strong>(<a id="user-content-completionpath^context" href="#user-content-completionpath^context">context</a>: <a href="https://codemirror.net/docs/ref#autocomplete.CompletionContext">CompletionContext</a>) → {path: readonly <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String">string</a>[], name: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String">string</a>} | <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null">null</a></code></dt>
<dd><p>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 <code>a.b.c</code> it will
return <code>{path: [&quot;a&quot;, &quot;b&quot;], name: &quot;c&quot;}</code>. When completing after <code>x</code>
it will return <code>{path: [], name: &quot;x&quot;}</code>. When not in a property or
name, it will return null if <code>context.explicit</code> is false, and
<code>{path: [], name: &quot;&quot;}</code> otherwise.</p>
</dd>
<dt id="user-content-scopecompletionsource">
<code><strong><a href="#user-content-scopecompletionsource">scopeCompletionSource</a></strong>(<a id="user-content-scopecompletionsource^scope" href="#user-content-scopecompletionsource^scope">scope</a>: any) → <a href="https://codemirror.net/docs/ref#autocomplete.CompletionSource">CompletionSource</a></code></dt>
<dd><p>Defines a <a href="https://codemirror.net/docs/ref/#autocomplete.CompletionSource">completion source</a> that
completes from the given scope object (for example <code>globalThis</code>).
Will enter properties of the object when completing properties on
a directly-named path.</p>
</dd>
<dt id="user-content-eslint">
<code><strong><a href="#user-content-eslint">esLint</a></strong>(<a id="user-content-eslint^eslint" href="#user-content-eslint^eslint">eslint</a>: any, <a id="user-content-eslint^config" href="#user-content-eslint^config">config</a>&#8288;?: any) → fn(<a id="user-content-eslint^returns^view" href="#user-content-eslint^returns^view">view</a>: <a href="https://codemirror.net/docs/ref#view.EditorView">EditorView</a>) → <a href="https://codemirror.net/docs/ref#lint.Diagnostic">Diagnostic</a>[]</code></dt>
<dd><p>Connects an <a href="https://eslint.org/">ESLint</a> linter to CodeMirror's
<a href="https://codemirror.net/docs/ref/#lint">lint</a> integration. <code>eslint</code> should be an instance of the
<a href="https://eslint.org/docs/developer-guide/nodejs-api#linter"><code>Linter</code></a>
class, and <code>config</code> an optional ESLint configuration. The return
value of this function can be passed to <a href="https://codemirror.net/docs/ref/#lint.linter"><code>linter</code></a>
to create a JavaScript linting extension.</p>
<p>Note that ESLint targets node, and is tricky to run in the
browser. The
<a href="https://github.com/UziTech/eslint-linter-browserify">eslint-linter-browserify</a>
package may help with that (see
<a href="https://github.com/UziTech/eslint-linter-browserify/blob/master/example/script.js">example</a>).</p>
</dd>
</dl>

View File

@ -0,0 +1,511 @@
'use strict';
var javascript$1 = require('@lezer/javascript');
var language = require('@codemirror/language');
var state = require('@codemirror/state');
var view = require('@codemirror/view');
var autocomplete = require('@codemirror/autocomplete');
var common = require('@lezer/common');
/**
A collection of JavaScript-related
[snippets](https://codemirror.net/6/docs/ref/#autocomplete.snippet).
*/
const snippets = [
autocomplete.snippetCompletion("function ${name}(${params}) {\n\t${}\n}", {
label: "function",
detail: "definition",
type: "keyword"
}),
autocomplete.snippetCompletion("for (let ${index} = 0; ${index} < ${bound}; ${index}++) {\n\t${}\n}", {
label: "for",
detail: "loop",
type: "keyword"
}),
autocomplete.snippetCompletion("for (let ${name} of ${collection}) {\n\t${}\n}", {
label: "for",
detail: "of loop",
type: "keyword"
}),
autocomplete.snippetCompletion("do {\n\t${}\n} while (${})", {
label: "do",
detail: "loop",
type: "keyword"
}),
autocomplete.snippetCompletion("while (${}) {\n\t${}\n}", {
label: "while",
detail: "loop",
type: "keyword"
}),
autocomplete.snippetCompletion("try {\n\t${}\n} catch (${error}) {\n\t${}\n}", {
label: "try",
detail: "/ catch block",
type: "keyword"
}),
autocomplete.snippetCompletion("if (${}) {\n\t${}\n}", {
label: "if",
detail: "block",
type: "keyword"
}),
autocomplete.snippetCompletion("if (${}) {\n\t${}\n} else {\n\t${}\n}", {
label: "if",
detail: "/ else block",
type: "keyword"
}),
autocomplete.snippetCompletion("class ${name} {\n\tconstructor(${params}) {\n\t\t${}\n\t}\n}", {
label: "class",
detail: "definition",
type: "keyword"
}),
autocomplete.snippetCompletion("import {${names}} from \"${module}\"\n${}", {
label: "import",
detail: "named",
type: "keyword"
}),
autocomplete.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 = snippets.concat([
autocomplete.snippetCompletion("interface ${name} {\n\t${}\n}", {
label: "interface",
detail: "definition",
type: "keyword"
}),
autocomplete.snippetCompletion("type ${name} = ${type}", {
label: "type",
detail: "definition",
type: "keyword"
}),
autocomplete.snippetCompletion("enum ${name} {\n\t${}\n}", {
label: "enum",
detail: "definition",
type: "keyword"
})
]);
const cache = new common.NodeWeakMap();
const ScopeNodes = 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: defID("function"),
ClassDeclaration: defID("class"),
ClassExpression: () => true,
EnumDeclaration: defID("constant"),
TypeAliasDeclaration: defID("type"),
NamespaceDeclaration: 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(common.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",
"JSXText", "JSXAttributeValue", "JSXOpenTag", "JSXCloseTag", "JSXSelfClosingTag",
".", "?."
];
/**
Completion source that looks up locally defined names in
JavaScript code.
*/
function localCompletionSource(context) {
let inner = language.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 = language.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 = language.LRLanguage.define({
name: "javascript",
parser: javascript$1.parser.configure({
props: [
language.indentNodeProp.add({
IfStatement: language.continuedIndent({ except: /^\s*({|else\b)/ }),
TryStatement: language.continuedIndent({ except: /^\s*({|catch\b|finally\b)/ }),
LabeledStatement: language.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: language.delimitedIndent({ closing: "}" }),
ArrowFunction: cx => cx.baseIndent + cx.unit,
"TemplateString BlockComment": () => null,
"Statement Property": language.continuedIndent({ except: /^\s*{/ }),
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;
}
}),
language.foldNodeProp.add({
"Block ClassBody SwitchBody EnumBody ObjectExpression ArrayExpression ObjectType": language.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: language.defineLanguageFacet({ commentTokens: { block: { open: "{/*", close: "*/}" } } })
};
/**
A language provider for TypeScript.
*/
const typescriptLanguage = javascriptLanguage.configure({ dialect: "ts" }, "typescript");
/**
Language provider for JSX.
*/
const jsxLanguage = javascriptLanguage.configure({
dialect: "jsx",
props: [language.sublanguageProp.add(n => n.isTop ? [jsxSublanguage] : undefined)]
});
/**
Language provider for JSX + TypeScript.
*/
const tsxLanguage = javascriptLanguage.configure({
dialect: "jsx ts",
props: [language.sublanguageProp.add(n => n.isTop ? [jsxSublanguage] : undefined)]
}, "typescript");
let kwCompletion = (name) => ({ label: name, type: "keyword" });
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);
const typescriptKeywords = keywords.concat(["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 language.LanguageSupport(lang, [
javascriptLanguage.data.of({
autocomplete: autocomplete.ifNotIn(dontComplete, autocomplete.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" && /Android\b/.test(navigator.userAgent);
/**
Extension that will automatically insert JSX close tags when a `>` or
`/` is typed.
*/
const autoCloseTags = view.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: state$1 } = base;
let closeTags = state$1.changeByRange(range => {
var _a;
let { head } = range, around = language.syntaxTree(state$1).resolveInner(head - 1, -1), name;
if (around.name == "JSXStartTag")
around = around.parent;
if (state$1.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$1.doc, base.firstChild, head)) || ((_a = base.firstChild) === null || _a === void 0 ? void 0 : _a.name) == "JSXFragmentTag")) {
let insert = `${name}>`;
return { range: state.EditorSelection.cursor(head + insert.length, -1), changes: { from: head, insert } };
}
}
else if (text == ">") {
let openTag = findOpenTag(around);
if (openTag && openTag.name == "JSXOpenTag" &&
!/^\/?>|^<\//.test(state$1.doc.sliceString(head, head + 2)) &&
(name = elementName(state$1.doc, openTag, head)))
return { range, changes: { from: head, insert: `</${name}>` } };
}
return { range };
});
if (closeTags.changes.empty)
return false;
view.dispatch([
base,
state$1.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) => {
var _a;
if ((_a = desc.meta.docs) === null || _a === void 0 ? void 0 : _a.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;
}
exports.autoCloseTags = autoCloseTags;
exports.completionPath = completionPath;
exports.esLint = esLint;
exports.javascript = javascript;
exports.javascriptLanguage = javascriptLanguage;
exports.jsxLanguage = jsxLanguage;
exports.localCompletionSource = localCompletionSource;
exports.scopeCompletionSource = scopeCompletionSource;
exports.snippets = snippets;
exports.tsxLanguage = tsxLanguage;
exports.typescriptLanguage = typescriptLanguage;
exports.typescriptSnippets = typescriptSnippets;

View File

@ -0,0 +1,93 @@
import * as _codemirror_state from '@codemirror/state';
import { LRLanguage, LanguageSupport } from '@codemirror/language';
import { Completion, CompletionContext, CompletionResult, CompletionSource } from '@codemirror/autocomplete';
import { Diagnostic } from '@codemirror/lint';
import { EditorView } from '@codemirror/view';
/**
A language provider based on the [Lezer JavaScript
parser](https://github.com/lezer-parser/javascript), extended with
highlighting and indentation information.
*/
declare const javascriptLanguage: LRLanguage;
/**
A language provider for TypeScript.
*/
declare const typescriptLanguage: LRLanguage;
/**
Language provider for JSX.
*/
declare const jsxLanguage: LRLanguage;
/**
Language provider for JSX + TypeScript.
*/
declare const tsxLanguage: LRLanguage;
/**
JavaScript support. Includes [snippet](https://codemirror.net/6/docs/ref/#lang-javascript.snippets)
and local variable completion.
*/
declare function javascript(config?: {
jsx?: boolean;
typescript?: boolean;
}): LanguageSupport;
/**
Extension that will automatically insert JSX close tags when a `>` or
`/` is typed.
*/
declare const autoCloseTags: _codemirror_state.Extension;
/**
A collection of JavaScript-related
[snippets](https://codemirror.net/6/docs/ref/#autocomplete.snippet).
*/
declare const snippets: readonly Completion[];
/**
A collection of snippet completions for TypeScript. Includes the
JavaScript [snippets](https://codemirror.net/6/docs/ref/#lang-javascript.snippets).
*/
declare const typescriptSnippets: Completion[];
/**
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)).
*/
declare function esLint(eslint: any, config?: any): (view: EditorView) => Diagnostic[];
/**
Completion source that looks up locally defined names in
JavaScript code.
*/
declare function localCompletionSource(context: CompletionContext): CompletionResult | 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.
*/
declare function completionPath(context: CompletionContext): {
path: readonly string[];
name: string;
} | null;
/**
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.
*/
declare function scopeCompletionSource(scope: any): CompletionSource;
export { autoCloseTags, completionPath, esLint, javascript, javascriptLanguage, jsxLanguage, localCompletionSource, scopeCompletionSource, snippets, tsxLanguage, typescriptLanguage, typescriptSnippets };

View File

@ -0,0 +1,93 @@
import * as _codemirror_state from '@codemirror/state';
import { LRLanguage, LanguageSupport } from '@codemirror/language';
import { Completion, CompletionContext, CompletionResult, CompletionSource } from '@codemirror/autocomplete';
import { Diagnostic } from '@codemirror/lint';
import { EditorView } from '@codemirror/view';
/**
A language provider based on the [Lezer JavaScript
parser](https://github.com/lezer-parser/javascript), extended with
highlighting and indentation information.
*/
declare const javascriptLanguage: LRLanguage;
/**
A language provider for TypeScript.
*/
declare const typescriptLanguage: LRLanguage;
/**
Language provider for JSX.
*/
declare const jsxLanguage: LRLanguage;
/**
Language provider for JSX + TypeScript.
*/
declare const tsxLanguage: LRLanguage;
/**
JavaScript support. Includes [snippet](https://codemirror.net/6/docs/ref/#lang-javascript.snippets)
and local variable completion.
*/
declare function javascript(config?: {
jsx?: boolean;
typescript?: boolean;
}): LanguageSupport;
/**
Extension that will automatically insert JSX close tags when a `>` or
`/` is typed.
*/
declare const autoCloseTags: _codemirror_state.Extension;
/**
A collection of JavaScript-related
[snippets](https://codemirror.net/6/docs/ref/#autocomplete.snippet).
*/
declare const snippets: readonly Completion[];
/**
A collection of snippet completions for TypeScript. Includes the
JavaScript [snippets](https://codemirror.net/6/docs/ref/#lang-javascript.snippets).
*/
declare const typescriptSnippets: Completion[];
/**
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)).
*/
declare function esLint(eslint: any, config?: any): (view: EditorView) => Diagnostic[];
/**
Completion source that looks up locally defined names in
JavaScript code.
*/
declare function localCompletionSource(context: CompletionContext): CompletionResult | 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.
*/
declare function completionPath(context: CompletionContext): {
path: readonly string[];
name: string;
} | null;
/**
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.
*/
declare function scopeCompletionSource(scope: any): CompletionSource;
export { autoCloseTags, completionPath, esLint, javascript, javascriptLanguage, jsxLanguage, localCompletionSource, scopeCompletionSource, snippets, tsxLanguage, typescriptLanguage, typescriptSnippets };

View File

@ -0,0 +1,498 @@
import { parser } from '@lezer/javascript';
import { syntaxTree, LRLanguage, indentNodeProp, continuedIndent, flatIndent, delimitedIndent, foldNodeProp, foldInside, defineLanguageFacet, sublanguageProp, LanguageSupport } from '@codemirror/language';
import { EditorSelection } from '@codemirror/state';
import { EditorView } from '@codemirror/view';
import { snippetCompletion, ifNotIn, completeFromList } from '@codemirror/autocomplete';
import { NodeWeakMap, IterMode } 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",
"JSXText", "JSXAttributeValue", "JSXOpenTag", "JSXCloseTag", "JSXSelfClosingTag",
".", "?."
];
/**
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: /^\s*{/ }),
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) => {
var _a;
if ((_a = desc.meta.docs) === null || _a === void 0 ? void 0 : _a.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 };

View File

@ -0,0 +1,45 @@
{
"name": "@codemirror/lang-javascript",
"version": "6.2.4",
"description": "JavaScript language support for the CodeMirror code editor",
"scripts": {
"test": "cm-runtests",
"prepare": "cm-buildhelper src/index.ts"
},
"keywords": [
"editor",
"code"
],
"author": {
"name": "Marijn Haverbeke",
"email": "marijn@haverbeke.berlin",
"url": "http://marijnhaverbeke.nl"
},
"type": "module",
"main": "dist/index.cjs",
"exports": {
"import": "./dist/index.js",
"require": "./dist/index.cjs"
},
"types": "dist/index.d.ts",
"module": "dist/index.js",
"sideEffects": false,
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
"@codemirror/language": "^6.6.0",
"@codemirror/lint": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.17.0",
"@lezer/common": "^1.0.0",
"@lezer/javascript": "^1.0.0"
},
"devDependencies": {
"@codemirror/buildhelper": "^1.0.0",
"@lezer/lr": "^1.0.0"
},
"repository": {
"type": "git",
"url": "https://github.com/codemirror/lang-javascript.git"
}
}