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

300
frontend/node_modules/@codemirror/lint/CHANGELOG.md generated vendored Normal file
View File

@ -0,0 +1,300 @@
## 6.9.2 (2025-11-03)
### Bug fixes
Fix an infinite loop that would occur when a diagnostic pointed beyond the end of the document.
## 6.9.1 (2025-10-23)
### Bug fixes
Properly display diagnostics that just cover multiple newlines as widgets.
## 6.9.0 (2025-10-02)
### Bug fixes
Multiple configurations to `linter` will now be merged without raising an error.
### New features
The new `markClass` option to actions makes it possible to style action buttons.
## 6.8.5 (2025-03-26)
### Bug fixes
Fix a regression (since 6.8.4) that broke the `markerFilter` option.
## 6.8.4 (2024-11-28)
### Bug fixes
Don't create overlapping decorations when diagnostics overlap.
Fix an issue where block widgets could cause the lint gutter to show diagnostics multiple times.
## 6.8.3 (2024-11-21)
### Bug fixes
Fix an issue that prevented tooltips in the lint gutter from being displayed.
## 6.8.2 (2024-09-24)
### Bug fixes
Show lint markers for code replaced by a block widget.
When multiple linters are installed, start displaying results from ones that return quickly even if others are slow to return.
## 6.8.1 (2024-06-19)
### Bug fixes
Make lint markers non-inclusive again, since having them that way causes more issues than it solves.
## 6.8.0 (2024-05-23)
### New features
The new `autoPanel` option can be used to make the panel automatically appear when diagnostics are added and close when no diagnostics are left.
## 6.7.1 (2024-05-15)
### Bug fixes
Don't perform an additional superfluous timed lint run after `forceLinting` has been called.
## 6.7.0 (2024-04-30)
### New features
The `renderMessage` function is now called with the editor view as first argument.
## 6.6.0 (2024-04-29)
### New features
The new `hideOn` configuration option can be used to control in what circumstances lint tooltips get hidden by state changes.
## 6.5.0 (2024-01-30)
### Bug fixes
Make lint mark decorations inclusive, so that they are applied even if the marked content is replaced by a widget decoration.
### New features
`linter` can now be called with null as source to only provide a configuration.
`markerFilter` and `tooltipFilter` function now get passed the current editor state.
## 6.4.2 (2023-09-14)
### Bug fixes
Make sure scrolling diagnostic into view in the panel works when the editor is scaled.
## 6.4.1 (2023-08-26)
### Bug fixes
Fix a crash that could occur when a view was reconfigured in a way that removed the lint extension.
## 6.4.0 (2023-07-03)
### New features
Diagnostics can now use `"hint"` as a severity level.
Diagnostics can now set a `markClass` property to add an additional CSS class to the text marked by the diagnostic.
## 6.3.0 (2023-06-23)
### New features
A new `previousDiagnostic` command can be used to move back through the active diagnostics.
## 6.2.2 (2023-06-05)
### Bug fixes
Make sure lint gutter tooltips are properly closed when the content of their line changes.
## 6.2.1 (2023-04-13)
### Bug fixes
The `linter` function now eagerly includes all lint-related extensions, rather than appending them to the configuration as-needed, so that turning off linting by clearing the compartment that contains it works properly.
## 6.2.0 (2023-02-27)
### New features
The new `needsRefresh` option to `linter` makes it possible to cause linting to be recalculated for non-document state changes.
## 6.1.1 (2023-02-15)
### Bug fixes
Give lint action buttons a pointer cursor style.
Fix a bug that caused diagnostic action callbacks to be called twice when their button was clicked.
## 6.1.0 (2022-11-15)
### New features
The new `forEachDiagnostic` function can be used to iterate over the diagnostics in an editor state.
## 6.0.0 (2022-06-08)
### Breaking changes
Update dependencies to 6.0.0
## 0.20.3 (2022-05-25)
### New features
Diagnostic objects may now have a `renderMessage` method to render their message to the DOM.
## 0.20.2 (2022-05-02)
### New features
The package now exports the `LintSource` function type.
The new `markerFilter` and `tooltipFilter` options to `linter` and `lintGutter` allow more control over which diagnostics are visible and which have tooltips.
## 0.20.1 (2022-04-22)
### Bug fixes
Hide lint tooltips when the document is changed.
## 0.20.0 (2022-04-20)
### Breaking changes
Update dependencies to 0.20.0
## 0.19.6 (2022-03-04)
### Bug fixes
Fix a bug where hovering over the icons in the lint gutter would sometimes fail to show a tooltip or show the tooltip for another line.
## 0.19.5 (2022-02-25)
### Bug fixes
Make sure the lint gutter tooltips are positioned under their icon, even when the line is wrapped.
## 0.19.4 (2022-02-25)
### Bug fixes
Fix an issue where an outdated marker could stick around on the lint gutter after all diagnostics were removed.
### New features
Add a `hoverTime` option to the lint gutter. Change default hover time to 300
## 0.19.3 (2021-11-09)
### New features
Export a function `lintGutter` which returns an extension that installs a gutter marking lines with diagnostics.
The package now exports the effect used to update the diagnostics (`setDiagnosticsEffect`).
## 0.19.2 (2021-09-29)
### Bug fixes
Fix a bug where reconfiguring the lint source didn't restart linting.
## 0.19.1 (2021-09-17)
### Bug fixes
Prevent decorations that cover just a line break from being invisible by showing a widget instead of range for them.
### New features
The `diagnosticCount` method can now be used to determine whether there are active diagnostics.
## 0.19.0 (2021-08-11)
### Breaking changes
Update dependencies to 0.19.0
## 0.18.6 (2021-08-08)
### Bug fixes
Fix a crash in the key handler of the lint panel when no diagnostics are available.
## 0.18.5 (2021-08-07)
### Bug fixes
Fix an issue that caused `openLintPanel` to not actually open the panel when ran before the editor had any lint state loaded.
### New features
The package now exports a `forceLinting` function that forces pending lint queries to run immediately.
## 0.18.4 (2021-06-07)
### Bug fixes
Multiple `linter` extensions can now be added to an editor without disrupting each other.
Fix poor layout on lint tooltips due to changes in @codemirror/tooltip.
## 0.18.3 (2021-05-10)
### Bug fixes
Fix a regression where using `setDiagnostics` when linting hadn't been abled yet ignored the first set of diagnostics.
## 0.18.2 (2021-04-16)
### Bug fixes
Newlines in line messages are now shown as line breaks to the user.
### New features
You can now pass a delay option to `linter` to configure how long it waits before calling the linter.
## 0.18.1 (2021-03-15)
### Bug fixes
Adjust to current @codemirror/panel and @codemirror/tooltip interfaces.
## 0.18.0 (2021-03-03)
### Bug fixes
Make sure action access keys are discoverable for screen reader users.
Selection in the lint panel should now be properly visible to screen readers.
## 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.

21
frontend/node_modules/@codemirror/lint/LICENSE generated vendored Normal file
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.

18
frontend/node_modules/@codemirror/lint/README.md generated vendored Normal file
View File

@ -0,0 +1,18 @@
# @codemirror/lint [![NPM version](https://img.shields.io/npm/v/@codemirror/lint.svg)](https://www.npmjs.org/package/@codemirror/lint)
[ [**WEBSITE**](https://codemirror.net/) | [**DOCS**](https://codemirror.net/docs/ref/#lint) | [**ISSUES**](https://github.com/codemirror/dev/issues) | [**FORUM**](https://discuss.codemirror.net/c/next/) | [**CHANGELOG**](https://github.com/codemirror/lint/blob/main/CHANGELOG.md) ]
This package implements linting 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/lint/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.

950
frontend/node_modules/@codemirror/lint/dist/index.cjs generated vendored Normal file
View File

@ -0,0 +1,950 @@
'use strict';
var view = require('@codemirror/view');
var state = require('@codemirror/state');
var elt = require('crelt');
class SelectedDiagnostic {
constructor(from, to, diagnostic) {
this.from = from;
this.to = to;
this.diagnostic = diagnostic;
}
}
class LintState {
constructor(diagnostics, panel, selected) {
this.diagnostics = diagnostics;
this.panel = panel;
this.selected = selected;
}
static init(diagnostics, panel, state$1) {
// Filter the list of diagnostics for which to create markers
let diagnosticFilter = state$1.facet(lintConfig).markerFilter;
if (diagnosticFilter)
diagnostics = diagnosticFilter(diagnostics, state$1);
let sorted = diagnostics.slice().sort((a, b) => a.from - b.from || a.to - b.to);
let deco = new state.RangeSetBuilder(), active = [], pos = 0;
let scan = state$1.doc.iter(), scanPos = 0, docLen = state$1.doc.length;
for (let i = 0;;) {
let next = i == sorted.length ? null : sorted[i];
if (!next && !active.length)
break;
let from, to;
if (active.length) {
from = pos;
to = active.reduce((p, d) => Math.min(p, d.to), next && next.from > from ? next.from : 1e8);
}
else {
from = next.from;
if (from > docLen)
break;
to = next.to;
active.push(next);
i++;
}
while (i < sorted.length) {
let next = sorted[i];
if (next.from == from && (next.to > next.from || next.to == from)) {
active.push(next);
i++;
to = Math.min(next.to, to);
}
else {
to = Math.min(next.from, to);
break;
}
}
to = Math.min(to, docLen);
let widget = false;
if (active.some(d => d.from == from && (d.to == to || to == docLen))) {
widget = from == to;
if (!widget && to - from < 10) {
let behind = from - (scanPos + scan.value.length);
if (behind > 0) {
scan.next(behind);
scanPos = from;
}
for (let check = from;;) {
if (check >= to) {
widget = true;
break;
}
if (!scan.lineBreak && scanPos + scan.value.length > check)
break;
check = scanPos + scan.value.length;
scanPos += scan.value.length;
scan.next();
}
}
}
let sev = maxSeverity(active);
if (widget) {
deco.add(from, from, view.Decoration.widget({
widget: new DiagnosticWidget(sev),
diagnostics: active.slice()
}));
}
else {
let markClass = active.reduce((c, d) => d.markClass ? c + " " + d.markClass : c, "");
deco.add(from, to, view.Decoration.mark({
class: "cm-lintRange cm-lintRange-" + sev + markClass,
diagnostics: active.slice(),
inclusiveEnd: active.some(a => a.to > to)
}));
}
pos = to;
if (pos == docLen)
break;
for (let i = 0; i < active.length; i++)
if (active[i].to <= pos)
active.splice(i--, 1);
}
let set = deco.finish();
return new LintState(set, panel, findDiagnostic(set));
}
}
function findDiagnostic(diagnostics, diagnostic = null, after = 0) {
let found = null;
diagnostics.between(after, 1e9, (from, to, { spec }) => {
if (diagnostic && spec.diagnostics.indexOf(diagnostic) < 0)
return;
if (!found)
found = new SelectedDiagnostic(from, to, diagnostic || spec.diagnostics[0]);
else if (spec.diagnostics.indexOf(found.diagnostic) < 0)
return false;
else
found = new SelectedDiagnostic(found.from, to, found.diagnostic);
});
return found;
}
function hideTooltip(tr, tooltip) {
let from = tooltip.pos, to = tooltip.end || from;
let result = tr.state.facet(lintConfig).hideOn(tr, from, to);
if (result != null)
return result;
let line = tr.startState.doc.lineAt(tooltip.pos);
return !!(tr.effects.some(e => e.is(setDiagnosticsEffect)) || tr.changes.touchesRange(line.from, Math.max(line.to, to)));
}
function maybeEnableLint(state$1, effects) {
return state$1.field(lintState, false) ? effects : effects.concat(state.StateEffect.appendConfig.of(lintExtensions));
}
/**
Returns a transaction spec which updates the current set of
diagnostics, and enables the lint extension if if wasn't already
active.
*/
function setDiagnostics(state, diagnostics) {
return {
effects: maybeEnableLint(state, [setDiagnosticsEffect.of(diagnostics)])
};
}
/**
The state effect that updates the set of active diagnostics. Can
be useful when writing an extension that needs to track these.
*/
const setDiagnosticsEffect = state.StateEffect.define();
const togglePanel = state.StateEffect.define();
const movePanelSelection = state.StateEffect.define();
const lintState = state.StateField.define({
create() {
return new LintState(view.Decoration.none, null, null);
},
update(value, tr) {
if (tr.docChanged && value.diagnostics.size) {
let mapped = value.diagnostics.map(tr.changes), selected = null, panel = value.panel;
if (value.selected) {
let selPos = tr.changes.mapPos(value.selected.from, 1);
selected = findDiagnostic(mapped, value.selected.diagnostic, selPos) || findDiagnostic(mapped, null, selPos);
}
if (!mapped.size && panel && tr.state.facet(lintConfig).autoPanel)
panel = null;
value = new LintState(mapped, panel, selected);
}
for (let effect of tr.effects) {
if (effect.is(setDiagnosticsEffect)) {
let panel = !tr.state.facet(lintConfig).autoPanel ? value.panel : effect.value.length ? LintPanel.open : null;
value = LintState.init(effect.value, panel, tr.state);
}
else if (effect.is(togglePanel)) {
value = new LintState(value.diagnostics, effect.value ? LintPanel.open : null, value.selected);
}
else if (effect.is(movePanelSelection)) {
value = new LintState(value.diagnostics, value.panel, effect.value);
}
}
return value;
},
provide: f => [view.showPanel.from(f, val => val.panel),
view.EditorView.decorations.from(f, s => s.diagnostics)]
});
/**
Returns the number of active lint diagnostics in the given state.
*/
function diagnosticCount(state) {
let lint = state.field(lintState, false);
return lint ? lint.diagnostics.size : 0;
}
const activeMark = view.Decoration.mark({ class: "cm-lintRange cm-lintRange-active" });
function lintTooltip(view, pos, side) {
let { diagnostics } = view.state.field(lintState);
let found, start = -1, end = -1;
diagnostics.between(pos - (side < 0 ? 1 : 0), pos + (side > 0 ? 1 : 0), (from, to, { spec }) => {
if (pos >= from && pos <= to &&
(from == to || ((pos > from || side > 0) && (pos < to || side < 0)))) {
found = spec.diagnostics;
start = from;
end = to;
return false;
}
});
let diagnosticFilter = view.state.facet(lintConfig).tooltipFilter;
if (found && diagnosticFilter)
found = diagnosticFilter(found, view.state);
if (!found)
return null;
return {
pos: start,
end: end,
above: view.state.doc.lineAt(start).to < end,
create() {
return { dom: diagnosticsTooltip(view, found) };
}
};
}
function diagnosticsTooltip(view, diagnostics) {
return elt("ul", { class: "cm-tooltip-lint" }, diagnostics.map(d => renderDiagnostic(view, d, false)));
}
/**
Command to open and focus the lint panel.
*/
const openLintPanel = (view$1) => {
let field = view$1.state.field(lintState, false);
if (!field || !field.panel)
view$1.dispatch({ effects: maybeEnableLint(view$1.state, [togglePanel.of(true)]) });
let panel = view.getPanel(view$1, LintPanel.open);
if (panel)
panel.dom.querySelector(".cm-panel-lint ul").focus();
return true;
};
/**
Command to close the lint panel, when open.
*/
const closeLintPanel = (view) => {
let field = view.state.field(lintState, false);
if (!field || !field.panel)
return false;
view.dispatch({ effects: togglePanel.of(false) });
return true;
};
/**
Move the selection to the next diagnostic.
*/
const nextDiagnostic = (view) => {
let field = view.state.field(lintState, false);
if (!field)
return false;
let sel = view.state.selection.main, next = field.diagnostics.iter(sel.to + 1);
if (!next.value) {
next = field.diagnostics.iter(0);
if (!next.value || next.from == sel.from && next.to == sel.to)
return false;
}
view.dispatch({ selection: { anchor: next.from, head: next.to }, scrollIntoView: true });
return true;
};
/**
Move the selection to the previous diagnostic.
*/
const previousDiagnostic = (view) => {
let { state } = view, field = state.field(lintState, false);
if (!field)
return false;
let sel = state.selection.main;
let prevFrom, prevTo, lastFrom, lastTo;
field.diagnostics.between(0, state.doc.length, (from, to) => {
if (to < sel.to && (prevFrom == null || prevFrom < from)) {
prevFrom = from;
prevTo = to;
}
if (lastFrom == null || from > lastFrom) {
lastFrom = from;
lastTo = to;
}
});
if (lastFrom == null || prevFrom == null && lastFrom == sel.from)
return false;
view.dispatch({ selection: { anchor: prevFrom !== null && prevFrom !== void 0 ? prevFrom : lastFrom, head: prevTo !== null && prevTo !== void 0 ? prevTo : lastTo }, scrollIntoView: true });
return true;
};
/**
A set of default key bindings for the lint functionality.
- Ctrl-Shift-m (Cmd-Shift-m on macOS): [`openLintPanel`](https://codemirror.net/6/docs/ref/#lint.openLintPanel)
- F8: [`nextDiagnostic`](https://codemirror.net/6/docs/ref/#lint.nextDiagnostic)
*/
const lintKeymap = [
{ key: "Mod-Shift-m", run: openLintPanel, preventDefault: true },
{ key: "F8", run: nextDiagnostic }
];
const lintPlugin = view.ViewPlugin.fromClass(class {
constructor(view) {
this.view = view;
this.timeout = -1;
this.set = true;
let { delay } = view.state.facet(lintConfig);
this.lintTime = Date.now() + delay;
this.run = this.run.bind(this);
this.timeout = setTimeout(this.run, delay);
}
run() {
clearTimeout(this.timeout);
let now = Date.now();
if (now < this.lintTime - 10) {
this.timeout = setTimeout(this.run, this.lintTime - now);
}
else {
this.set = false;
let { state } = this.view, { sources } = state.facet(lintConfig);
if (sources.length)
batchResults(sources.map(s => Promise.resolve(s(this.view))), annotations => {
if (this.view.state.doc == state.doc)
this.view.dispatch(setDiagnostics(this.view.state, annotations.reduce((a, b) => a.concat(b))));
}, error => { view.logException(this.view.state, error); });
}
}
update(update) {
let config = update.state.facet(lintConfig);
if (update.docChanged || config != update.startState.facet(lintConfig) ||
config.needsRefresh && config.needsRefresh(update)) {
this.lintTime = Date.now() + config.delay;
if (!this.set) {
this.set = true;
this.timeout = setTimeout(this.run, config.delay);
}
}
}
force() {
if (this.set) {
this.lintTime = Date.now();
this.run();
}
}
destroy() {
clearTimeout(this.timeout);
}
});
function batchResults(promises, sink, error) {
let collected = [], timeout = -1;
for (let p of promises)
p.then(value => {
collected.push(value);
clearTimeout(timeout);
if (collected.length == promises.length)
sink(collected);
else
timeout = setTimeout(() => sink(collected), 200);
}, error);
}
const lintConfig = state.Facet.define({
combine(input) {
return {
sources: input.map(i => i.source).filter(x => x != null),
...state.combineConfig(input.map(i => i.config), {
delay: 750,
markerFilter: null,
tooltipFilter: null,
needsRefresh: null,
hideOn: () => null,
}, {
delay: Math.max,
markerFilter: combineFilter,
tooltipFilter: combineFilter,
needsRefresh: (a, b) => !a ? b : !b ? a : u => a(u) || b(u),
hideOn: (a, b) => !a ? b : !b ? a : (t, x, y) => a(t, x, y) || b(t, x, y),
autoPanel: (a, b) => a || b
})
};
}
});
function combineFilter(a, b) {
return !a ? b : !b ? a : (d, s) => b(a(d, s), s);
}
/**
Given a diagnostic source, this function returns an extension that
enables linting with that source. It will be called whenever the
editor is idle (after its content changed).
Note that settings given here will apply to all linters active in
the editor. If `null` is given as source, this only configures the
lint extension.
*/
function linter(source, config = {}) {
return [
lintConfig.of({ source, config }),
lintPlugin,
lintExtensions
];
}
/**
Forces any linters [configured](https://codemirror.net/6/docs/ref/#lint.linter) to run when the
editor is idle to run right away.
*/
function forceLinting(view) {
let plugin = view.plugin(lintPlugin);
if (plugin)
plugin.force();
}
function assignKeys(actions) {
let assigned = [];
if (actions)
actions: for (let { name } of actions) {
for (let i = 0; i < name.length; i++) {
let ch = name[i];
if (/[a-zA-Z]/.test(ch) && !assigned.some(c => c.toLowerCase() == ch.toLowerCase())) {
assigned.push(ch);
continue actions;
}
}
assigned.push("");
}
return assigned;
}
function renderDiagnostic(view, diagnostic, inPanel) {
var _a;
let keys = inPanel ? assignKeys(diagnostic.actions) : [];
return elt("li", { class: "cm-diagnostic cm-diagnostic-" + diagnostic.severity }, elt("span", { class: "cm-diagnosticText" }, diagnostic.renderMessage ? diagnostic.renderMessage(view) : diagnostic.message), (_a = diagnostic.actions) === null || _a === void 0 ? void 0 : _a.map((action, i) => {
let fired = false, click = (e) => {
e.preventDefault();
if (fired)
return;
fired = true;
let found = findDiagnostic(view.state.field(lintState).diagnostics, diagnostic);
if (found)
action.apply(view, found.from, found.to);
};
let { name } = action, keyIndex = keys[i] ? name.indexOf(keys[i]) : -1;
let nameElt = keyIndex < 0 ? name : [name.slice(0, keyIndex),
elt("u", name.slice(keyIndex, keyIndex + 1)),
name.slice(keyIndex + 1)];
let markClass = action.markClass ? " " + action.markClass : "";
return elt("button", {
type: "button",
class: "cm-diagnosticAction" + markClass,
onclick: click,
onmousedown: click,
"aria-label": ` Action: ${name}${keyIndex < 0 ? "" : ` (access key "${keys[i]})"`}.`
}, nameElt);
}), diagnostic.source && elt("div", { class: "cm-diagnosticSource" }, diagnostic.source));
}
class DiagnosticWidget extends view.WidgetType {
constructor(sev) {
super();
this.sev = sev;
}
eq(other) { return other.sev == this.sev; }
toDOM() {
return elt("span", { class: "cm-lintPoint cm-lintPoint-" + this.sev });
}
}
class PanelItem {
constructor(view, diagnostic) {
this.diagnostic = diagnostic;
this.id = "item_" + Math.floor(Math.random() * 0xffffffff).toString(16);
this.dom = renderDiagnostic(view, diagnostic, true);
this.dom.id = this.id;
this.dom.setAttribute("role", "option");
}
}
class LintPanel {
constructor(view) {
this.view = view;
this.items = [];
let onkeydown = (event) => {
if (event.keyCode == 27) { // Escape
closeLintPanel(this.view);
this.view.focus();
}
else if (event.keyCode == 38 || event.keyCode == 33) { // ArrowUp, PageUp
this.moveSelection((this.selectedIndex - 1 + this.items.length) % this.items.length);
}
else if (event.keyCode == 40 || event.keyCode == 34) { // ArrowDown, PageDown
this.moveSelection((this.selectedIndex + 1) % this.items.length);
}
else if (event.keyCode == 36) { // Home
this.moveSelection(0);
}
else if (event.keyCode == 35) { // End
this.moveSelection(this.items.length - 1);
}
else if (event.keyCode == 13) { // Enter
this.view.focus();
}
else if (event.keyCode >= 65 && event.keyCode <= 90 && this.selectedIndex >= 0) { // A-Z
let { diagnostic } = this.items[this.selectedIndex], keys = assignKeys(diagnostic.actions);
for (let i = 0; i < keys.length; i++)
if (keys[i].toUpperCase().charCodeAt(0) == event.keyCode) {
let found = findDiagnostic(this.view.state.field(lintState).diagnostics, diagnostic);
if (found)
diagnostic.actions[i].apply(view, found.from, found.to);
}
}
else {
return;
}
event.preventDefault();
};
let onclick = (event) => {
for (let i = 0; i < this.items.length; i++) {
if (this.items[i].dom.contains(event.target))
this.moveSelection(i);
}
};
this.list = elt("ul", {
tabIndex: 0,
role: "listbox",
"aria-label": this.view.state.phrase("Diagnostics"),
onkeydown,
onclick
});
this.dom = elt("div", { class: "cm-panel-lint" }, this.list, elt("button", {
type: "button",
name: "close",
"aria-label": this.view.state.phrase("close"),
onclick: () => closeLintPanel(this.view)
}, "×"));
this.update();
}
get selectedIndex() {
let selected = this.view.state.field(lintState).selected;
if (!selected)
return -1;
for (let i = 0; i < this.items.length; i++)
if (this.items[i].diagnostic == selected.diagnostic)
return i;
return -1;
}
update() {
let { diagnostics, selected } = this.view.state.field(lintState);
let i = 0, needsSync = false, newSelectedItem = null;
let seen = new Set();
diagnostics.between(0, this.view.state.doc.length, (_start, _end, { spec }) => {
for (let diagnostic of spec.diagnostics) {
if (seen.has(diagnostic))
continue;
seen.add(diagnostic);
let found = -1, item;
for (let j = i; j < this.items.length; j++)
if (this.items[j].diagnostic == diagnostic) {
found = j;
break;
}
if (found < 0) {
item = new PanelItem(this.view, diagnostic);
this.items.splice(i, 0, item);
needsSync = true;
}
else {
item = this.items[found];
if (found > i) {
this.items.splice(i, found - i);
needsSync = true;
}
}
if (selected && item.diagnostic == selected.diagnostic) {
if (!item.dom.hasAttribute("aria-selected")) {
item.dom.setAttribute("aria-selected", "true");
newSelectedItem = item;
}
}
else if (item.dom.hasAttribute("aria-selected")) {
item.dom.removeAttribute("aria-selected");
}
i++;
}
});
while (i < this.items.length && !(this.items.length == 1 && this.items[0].diagnostic.from < 0)) {
needsSync = true;
this.items.pop();
}
if (this.items.length == 0) {
this.items.push(new PanelItem(this.view, {
from: -1, to: -1,
severity: "info",
message: this.view.state.phrase("No diagnostics")
}));
needsSync = true;
}
if (newSelectedItem) {
this.list.setAttribute("aria-activedescendant", newSelectedItem.id);
this.view.requestMeasure({
key: this,
read: () => ({ sel: newSelectedItem.dom.getBoundingClientRect(), panel: this.list.getBoundingClientRect() }),
write: ({ sel, panel }) => {
let scaleY = panel.height / this.list.offsetHeight;
if (sel.top < panel.top)
this.list.scrollTop -= (panel.top - sel.top) / scaleY;
else if (sel.bottom > panel.bottom)
this.list.scrollTop += (sel.bottom - panel.bottom) / scaleY;
}
});
}
else if (this.selectedIndex < 0) {
this.list.removeAttribute("aria-activedescendant");
}
if (needsSync)
this.sync();
}
sync() {
let domPos = this.list.firstChild;
function rm() {
let prev = domPos;
domPos = prev.nextSibling;
prev.remove();
}
for (let item of this.items) {
if (item.dom.parentNode == this.list) {
while (domPos != item.dom)
rm();
domPos = item.dom.nextSibling;
}
else {
this.list.insertBefore(item.dom, domPos);
}
}
while (domPos)
rm();
}
moveSelection(selectedIndex) {
if (this.selectedIndex < 0)
return;
let field = this.view.state.field(lintState);
let selection = findDiagnostic(field.diagnostics, this.items[selectedIndex].diagnostic);
if (!selection)
return;
this.view.dispatch({
selection: { anchor: selection.from, head: selection.to },
scrollIntoView: true,
effects: movePanelSelection.of(selection)
});
}
static open(view) { return new LintPanel(view); }
}
function svg(content, attrs = `viewBox="0 0 40 40"`) {
return `url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" ${attrs}>${encodeURIComponent(content)}</svg>')`;
}
function underline(color) {
return svg(`<path d="m0 2.5 l2 -1.5 l1 0 l2 1.5 l1 0" stroke="${color}" fill="none" stroke-width=".7"/>`, `width="6" height="3"`);
}
const baseTheme = view.EditorView.baseTheme({
".cm-diagnostic": {
padding: "3px 6px 3px 8px",
marginLeft: "-1px",
display: "block",
whiteSpace: "pre-wrap"
},
".cm-diagnostic-error": { borderLeft: "5px solid #d11" },
".cm-diagnostic-warning": { borderLeft: "5px solid orange" },
".cm-diagnostic-info": { borderLeft: "5px solid #999" },
".cm-diagnostic-hint": { borderLeft: "5px solid #66d" },
".cm-diagnosticAction": {
font: "inherit",
border: "none",
padding: "2px 4px",
backgroundColor: "#444",
color: "white",
borderRadius: "3px",
marginLeft: "8px",
cursor: "pointer"
},
".cm-diagnosticSource": {
fontSize: "70%",
opacity: .7
},
".cm-lintRange": {
backgroundPosition: "left bottom",
backgroundRepeat: "repeat-x",
paddingBottom: "0.7px",
},
".cm-lintRange-error": { backgroundImage: underline("#d11") },
".cm-lintRange-warning": { backgroundImage: underline("orange") },
".cm-lintRange-info": { backgroundImage: underline("#999") },
".cm-lintRange-hint": { backgroundImage: underline("#66d") },
".cm-lintRange-active": { backgroundColor: "#ffdd9980" },
".cm-tooltip-lint": {
padding: 0,
margin: 0
},
".cm-lintPoint": {
position: "relative",
"&:after": {
content: '""',
position: "absolute",
bottom: 0,
left: "-2px",
borderLeft: "3px solid transparent",
borderRight: "3px solid transparent",
borderBottom: "4px solid #d11"
}
},
".cm-lintPoint-warning": {
"&:after": { borderBottomColor: "orange" }
},
".cm-lintPoint-info": {
"&:after": { borderBottomColor: "#999" }
},
".cm-lintPoint-hint": {
"&:after": { borderBottomColor: "#66d" }
},
".cm-panel.cm-panel-lint": {
position: "relative",
"& ul": {
maxHeight: "100px",
overflowY: "auto",
"& [aria-selected]": {
backgroundColor: "#ddd",
"& u": { textDecoration: "underline" }
},
"&:focus [aria-selected]": {
background_fallback: "#bdf",
backgroundColor: "Highlight",
color_fallback: "white",
color: "HighlightText"
},
"& u": { textDecoration: "none" },
padding: 0,
margin: 0
},
"& [name=close]": {
position: "absolute",
top: "0",
right: "2px",
background: "inherit",
border: "none",
font: "inherit",
padding: 0,
margin: 0
}
}
});
function severityWeight(sev) {
return sev == "error" ? 4 : sev == "warning" ? 3 : sev == "info" ? 2 : 1;
}
function maxSeverity(diagnostics) {
let sev = "hint", weight = 1;
for (let d of diagnostics) {
let w = severityWeight(d.severity);
if (w > weight) {
weight = w;
sev = d.severity;
}
}
return sev;
}
class LintGutterMarker extends view.GutterMarker {
constructor(diagnostics) {
super();
this.diagnostics = diagnostics;
this.severity = maxSeverity(diagnostics);
}
toDOM(view) {
let elt = document.createElement("div");
elt.className = "cm-lint-marker cm-lint-marker-" + this.severity;
let diagnostics = this.diagnostics;
let diagnosticsFilter = view.state.facet(lintGutterConfig).tooltipFilter;
if (diagnosticsFilter)
diagnostics = diagnosticsFilter(diagnostics, view.state);
if (diagnostics.length)
elt.onmouseover = () => gutterMarkerMouseOver(view, elt, diagnostics);
return elt;
}
}
function trackHoverOn(view, marker) {
let mousemove = (event) => {
let rect = marker.getBoundingClientRect();
if (event.clientX > rect.left - 10 /* Hover.Margin */ && event.clientX < rect.right + 10 /* Hover.Margin */ &&
event.clientY > rect.top - 10 /* Hover.Margin */ && event.clientY < rect.bottom + 10 /* Hover.Margin */)
return;
for (let target = event.target; target; target = target.parentNode) {
if (target.nodeType == 1 && target.classList.contains("cm-tooltip-lint"))
return;
}
window.removeEventListener("mousemove", mousemove);
if (view.state.field(lintGutterTooltip))
view.dispatch({ effects: setLintGutterTooltip.of(null) });
};
window.addEventListener("mousemove", mousemove);
}
function gutterMarkerMouseOver(view, marker, diagnostics) {
function hovered() {
let line = view.elementAtHeight(marker.getBoundingClientRect().top + 5 - view.documentTop);
const linePos = view.coordsAtPos(line.from);
if (linePos) {
view.dispatch({ effects: setLintGutterTooltip.of({
pos: line.from,
above: false,
clip: false,
create() {
return {
dom: diagnosticsTooltip(view, diagnostics),
getCoords: () => marker.getBoundingClientRect()
};
}
}) });
}
marker.onmouseout = marker.onmousemove = null;
trackHoverOn(view, marker);
}
let { hoverTime } = view.state.facet(lintGutterConfig);
let hoverTimeout = setTimeout(hovered, hoverTime);
marker.onmouseout = () => {
clearTimeout(hoverTimeout);
marker.onmouseout = marker.onmousemove = null;
};
marker.onmousemove = () => {
clearTimeout(hoverTimeout);
hoverTimeout = setTimeout(hovered, hoverTime);
};
}
function markersForDiagnostics(doc, diagnostics) {
let byLine = Object.create(null);
for (let diagnostic of diagnostics) {
let line = doc.lineAt(diagnostic.from);
(byLine[line.from] || (byLine[line.from] = [])).push(diagnostic);
}
let markers = [];
for (let line in byLine) {
markers.push(new LintGutterMarker(byLine[line]).range(+line));
}
return state.RangeSet.of(markers, true);
}
const lintGutterExtension = view.gutter({
class: "cm-gutter-lint",
markers: view => view.state.field(lintGutterMarkers),
widgetMarker: (view, widget, block) => {
let diagnostics = [];
view.state.field(lintGutterMarkers).between(block.from, block.to, (from, to, value) => {
if (from > block.from && from < block.to)
diagnostics.push(...value.diagnostics);
});
return diagnostics.length ? new LintGutterMarker(diagnostics) : null;
}
});
const lintGutterMarkers = state.StateField.define({
create() {
return state.RangeSet.empty;
},
update(markers, tr) {
markers = markers.map(tr.changes);
let diagnosticFilter = tr.state.facet(lintGutterConfig).markerFilter;
for (let effect of tr.effects) {
if (effect.is(setDiagnosticsEffect)) {
let diagnostics = effect.value;
if (diagnosticFilter)
diagnostics = diagnosticFilter(diagnostics || [], tr.state);
markers = markersForDiagnostics(tr.state.doc, diagnostics.slice(0));
}
}
return markers;
}
});
const setLintGutterTooltip = state.StateEffect.define();
const lintGutterTooltip = state.StateField.define({
create() { return null; },
update(tooltip, tr) {
if (tooltip && tr.docChanged)
tooltip = hideTooltip(tr, tooltip) ? null : { ...tooltip, pos: tr.changes.mapPos(tooltip.pos) };
return tr.effects.reduce((t, e) => e.is(setLintGutterTooltip) ? e.value : t, tooltip);
},
provide: field => view.showTooltip.from(field)
});
const lintGutterTheme = view.EditorView.baseTheme({
".cm-gutter-lint": {
width: "1.4em",
"& .cm-gutterElement": {
padding: ".2em"
}
},
".cm-lint-marker": {
width: "1em",
height: "1em"
},
".cm-lint-marker-info": {
content: svg(`<path fill="#aaf" stroke="#77e" stroke-width="6" stroke-linejoin="round" d="M5 5L35 5L35 35L5 35Z"/>`)
},
".cm-lint-marker-warning": {
content: svg(`<path fill="#fe8" stroke="#fd7" stroke-width="6" stroke-linejoin="round" d="M20 6L37 35L3 35Z"/>`),
},
".cm-lint-marker-error": {
content: svg(`<circle cx="20" cy="20" r="15" fill="#f87" stroke="#f43" stroke-width="6"/>`)
},
});
const lintExtensions = [
lintState,
view.EditorView.decorations.compute([lintState], state => {
let { selected, panel } = state.field(lintState);
return !selected || !panel || selected.from == selected.to ? view.Decoration.none : view.Decoration.set([
activeMark.range(selected.from, selected.to)
]);
}),
view.hoverTooltip(lintTooltip, { hideOn: hideTooltip }),
baseTheme
];
const lintGutterConfig = state.Facet.define({
combine(configs) {
return state.combineConfig(configs, {
hoverTime: 300 /* Hover.Time */,
markerFilter: null,
tooltipFilter: null
});
}
});
/**
Returns an extension that installs a gutter showing markers for
each line that has diagnostics, which can be hovered over to see
the diagnostics.
*/
function lintGutter(config = {}) {
return [lintGutterConfig.of(config), lintGutterMarkers, lintGutterExtension, lintGutterTheme, lintGutterTooltip];
}
/**
Iterate over the marked diagnostics for the given editor state,
calling `f` for each of them. Note that, if the document changed
since the diagnostics were created, the `Diagnostic` object will
hold the original outdated position, whereas the `to` and `from`
arguments hold the diagnostic's current position.
*/
function forEachDiagnostic(state$1, f) {
let lState = state$1.field(lintState, false);
if (lState && lState.diagnostics.size) {
let pending = [], pendingStart = [], lastEnd = -1;
for (let iter = state.RangeSet.iter([lState.diagnostics]);; iter.next()) {
for (let i = 0; i < pending.length; i++)
if (!iter.value || iter.value.spec.diagnostics.indexOf(pending[i]) < 0) {
f(pending[i], pendingStart[i], lastEnd);
pending.splice(i, 1);
pendingStart.splice(i--, 1);
}
if (!iter.value)
break;
for (let d of iter.value.spec.diagnostics)
if (pending.indexOf(d) < 0) {
pending.push(d);
pendingStart.push(iter.from);
}
lastEnd = iter.to;
}
}
}
exports.closeLintPanel = closeLintPanel;
exports.diagnosticCount = diagnosticCount;
exports.forEachDiagnostic = forEachDiagnostic;
exports.forceLinting = forceLinting;
exports.lintGutter = lintGutter;
exports.lintKeymap = lintKeymap;
exports.linter = linter;
exports.nextDiagnostic = nextDiagnostic;
exports.openLintPanel = openLintPanel;
exports.previousDiagnostic = previousDiagnostic;
exports.setDiagnostics = setDiagnostics;
exports.setDiagnosticsEffect = setDiagnosticsEffect;

195
frontend/node_modules/@codemirror/lint/dist/index.d.cts generated vendored Normal file
View File

@ -0,0 +1,195 @@
import * as _codemirror_state from '@codemirror/state';
import { EditorState, TransactionSpec, Extension, Transaction } from '@codemirror/state';
import { EditorView, Command, KeyBinding, ViewUpdate } from '@codemirror/view';
type Severity = "hint" | "info" | "warning" | "error";
/**
Describes a problem or hint for a piece of code.
*/
interface Diagnostic {
/**
The start position of the relevant text.
*/
from: number;
/**
The end position. May be equal to `from`, though actually
covering text is preferable.
*/
to: number;
/**
The severity of the problem. This will influence how it is
displayed.
*/
severity: Severity;
/**
When given, add an extra CSS class to parts of the code that
this diagnostic applies to.
*/
markClass?: string;
/**
An optional source string indicating where the diagnostic is
coming from. You can put the name of your linter here, if
applicable.
*/
source?: string;
/**
The message associated with this diagnostic.
*/
message: string;
/**
An optional custom rendering function that displays the message
as a DOM node.
*/
renderMessage?: (view: EditorView) => Node;
/**
An optional array of actions that can be taken on this
diagnostic.
*/
actions?: readonly Action[];
}
/**
An action associated with a diagnostic.
*/
interface Action {
/**
The label to show to the user. Should be relatively short.
*/
name: string;
/**
When given, add an extra CSS class to the action button.
*/
markClass?: string;
/**
The function to call when the user activates this action. Is
given the diagnostic's _current_ position, which may have
changed since the creation of the diagnostic, due to editing.
*/
apply: (view: EditorView, from: number, to: number) => void;
}
type DiagnosticFilter = (diagnostics: readonly Diagnostic[], state: EditorState) => Diagnostic[];
interface LintConfig {
/**
Time to wait (in milliseconds) after a change before running
the linter. Defaults to 750ms.
*/
delay?: number;
/**
Optional predicate that can be used to indicate when diagnostics
need to be recomputed. Linting is always re-done on document
changes.
*/
needsRefresh?: null | ((update: ViewUpdate) => boolean);
/**
Optional filter to determine which diagnostics produce markers
in the content.
*/
markerFilter?: null | DiagnosticFilter;
/**
Filter applied to a set of diagnostics shown in a tooltip. No
tooltip will appear if the empty set is returned.
*/
tooltipFilter?: null | DiagnosticFilter;
/**
Can be used to control what kind of transactions cause lint
hover tooltips associated with the given document range to be
hidden. By default any transactions that changes the line
around the range will hide it. Returning null falls back to this
behavior.
*/
hideOn?: (tr: Transaction, from: number, to: number) => boolean | null;
/**
When enabled (defaults to off), this will cause the lint panel
to automatically open when diagnostics are found, and close when
all diagnostics are resolved or removed.
*/
autoPanel?: boolean;
}
interface LintGutterConfig {
/**
The delay before showing a tooltip when hovering over a lint gutter marker.
*/
hoverTime?: number;
/**
Optional filter determining which diagnostics show a marker in
the gutter.
*/
markerFilter?: null | DiagnosticFilter;
/**
Optional filter for diagnostics displayed in a tooltip, which
can also be used to prevent a tooltip appearing.
*/
tooltipFilter?: null | DiagnosticFilter;
}
/**
Returns a transaction spec which updates the current set of
diagnostics, and enables the lint extension if if wasn't already
active.
*/
declare function setDiagnostics(state: EditorState, diagnostics: readonly Diagnostic[]): TransactionSpec;
/**
The state effect that updates the set of active diagnostics. Can
be useful when writing an extension that needs to track these.
*/
declare const setDiagnosticsEffect: _codemirror_state.StateEffectType<readonly Diagnostic[]>;
/**
Returns the number of active lint diagnostics in the given state.
*/
declare function diagnosticCount(state: EditorState): number;
/**
Command to open and focus the lint panel.
*/
declare const openLintPanel: Command;
/**
Command to close the lint panel, when open.
*/
declare const closeLintPanel: Command;
/**
Move the selection to the next diagnostic.
*/
declare const nextDiagnostic: Command;
/**
Move the selection to the previous diagnostic.
*/
declare const previousDiagnostic: Command;
/**
A set of default key bindings for the lint functionality.
- Ctrl-Shift-m (Cmd-Shift-m on macOS): [`openLintPanel`](https://codemirror.net/6/docs/ref/#lint.openLintPanel)
- F8: [`nextDiagnostic`](https://codemirror.net/6/docs/ref/#lint.nextDiagnostic)
*/
declare const lintKeymap: readonly KeyBinding[];
/**
The type of a function that produces diagnostics.
*/
type LintSource = (view: EditorView) => readonly Diagnostic[] | Promise<readonly Diagnostic[]>;
/**
Given a diagnostic source, this function returns an extension that
enables linting with that source. It will be called whenever the
editor is idle (after its content changed).
Note that settings given here will apply to all linters active in
the editor. If `null` is given as source, this only configures the
lint extension.
*/
declare function linter(source: LintSource | null, config?: LintConfig): Extension;
/**
Forces any linters [configured](https://codemirror.net/6/docs/ref/#lint.linter) to run when the
editor is idle to run right away.
*/
declare function forceLinting(view: EditorView): void;
/**
Returns an extension that installs a gutter showing markers for
each line that has diagnostics, which can be hovered over to see
the diagnostics.
*/
declare function lintGutter(config?: LintGutterConfig): Extension;
/**
Iterate over the marked diagnostics for the given editor state,
calling `f` for each of them. Note that, if the document changed
since the diagnostics were created, the `Diagnostic` object will
hold the original outdated position, whereas the `to` and `from`
arguments hold the diagnostic's current position.
*/
declare function forEachDiagnostic(state: EditorState, f: (d: Diagnostic, from: number, to: number) => void): void;
export { type Action, type Diagnostic, type LintSource, closeLintPanel, diagnosticCount, forEachDiagnostic, forceLinting, lintGutter, lintKeymap, linter, nextDiagnostic, openLintPanel, previousDiagnostic, setDiagnostics, setDiagnosticsEffect };

195
frontend/node_modules/@codemirror/lint/dist/index.d.ts generated vendored Normal file
View File

@ -0,0 +1,195 @@
import * as _codemirror_state from '@codemirror/state';
import { EditorState, TransactionSpec, Extension, Transaction } from '@codemirror/state';
import { EditorView, Command, KeyBinding, ViewUpdate } from '@codemirror/view';
type Severity = "hint" | "info" | "warning" | "error";
/**
Describes a problem or hint for a piece of code.
*/
interface Diagnostic {
/**
The start position of the relevant text.
*/
from: number;
/**
The end position. May be equal to `from`, though actually
covering text is preferable.
*/
to: number;
/**
The severity of the problem. This will influence how it is
displayed.
*/
severity: Severity;
/**
When given, add an extra CSS class to parts of the code that
this diagnostic applies to.
*/
markClass?: string;
/**
An optional source string indicating where the diagnostic is
coming from. You can put the name of your linter here, if
applicable.
*/
source?: string;
/**
The message associated with this diagnostic.
*/
message: string;
/**
An optional custom rendering function that displays the message
as a DOM node.
*/
renderMessage?: (view: EditorView) => Node;
/**
An optional array of actions that can be taken on this
diagnostic.
*/
actions?: readonly Action[];
}
/**
An action associated with a diagnostic.
*/
interface Action {
/**
The label to show to the user. Should be relatively short.
*/
name: string;
/**
When given, add an extra CSS class to the action button.
*/
markClass?: string;
/**
The function to call when the user activates this action. Is
given the diagnostic's _current_ position, which may have
changed since the creation of the diagnostic, due to editing.
*/
apply: (view: EditorView, from: number, to: number) => void;
}
type DiagnosticFilter = (diagnostics: readonly Diagnostic[], state: EditorState) => Diagnostic[];
interface LintConfig {
/**
Time to wait (in milliseconds) after a change before running
the linter. Defaults to 750ms.
*/
delay?: number;
/**
Optional predicate that can be used to indicate when diagnostics
need to be recomputed. Linting is always re-done on document
changes.
*/
needsRefresh?: null | ((update: ViewUpdate) => boolean);
/**
Optional filter to determine which diagnostics produce markers
in the content.
*/
markerFilter?: null | DiagnosticFilter;
/**
Filter applied to a set of diagnostics shown in a tooltip. No
tooltip will appear if the empty set is returned.
*/
tooltipFilter?: null | DiagnosticFilter;
/**
Can be used to control what kind of transactions cause lint
hover tooltips associated with the given document range to be
hidden. By default any transactions that changes the line
around the range will hide it. Returning null falls back to this
behavior.
*/
hideOn?: (tr: Transaction, from: number, to: number) => boolean | null;
/**
When enabled (defaults to off), this will cause the lint panel
to automatically open when diagnostics are found, and close when
all diagnostics are resolved or removed.
*/
autoPanel?: boolean;
}
interface LintGutterConfig {
/**
The delay before showing a tooltip when hovering over a lint gutter marker.
*/
hoverTime?: number;
/**
Optional filter determining which diagnostics show a marker in
the gutter.
*/
markerFilter?: null | DiagnosticFilter;
/**
Optional filter for diagnostics displayed in a tooltip, which
can also be used to prevent a tooltip appearing.
*/
tooltipFilter?: null | DiagnosticFilter;
}
/**
Returns a transaction spec which updates the current set of
diagnostics, and enables the lint extension if if wasn't already
active.
*/
declare function setDiagnostics(state: EditorState, diagnostics: readonly Diagnostic[]): TransactionSpec;
/**
The state effect that updates the set of active diagnostics. Can
be useful when writing an extension that needs to track these.
*/
declare const setDiagnosticsEffect: _codemirror_state.StateEffectType<readonly Diagnostic[]>;
/**
Returns the number of active lint diagnostics in the given state.
*/
declare function diagnosticCount(state: EditorState): number;
/**
Command to open and focus the lint panel.
*/
declare const openLintPanel: Command;
/**
Command to close the lint panel, when open.
*/
declare const closeLintPanel: Command;
/**
Move the selection to the next diagnostic.
*/
declare const nextDiagnostic: Command;
/**
Move the selection to the previous diagnostic.
*/
declare const previousDiagnostic: Command;
/**
A set of default key bindings for the lint functionality.
- Ctrl-Shift-m (Cmd-Shift-m on macOS): [`openLintPanel`](https://codemirror.net/6/docs/ref/#lint.openLintPanel)
- F8: [`nextDiagnostic`](https://codemirror.net/6/docs/ref/#lint.nextDiagnostic)
*/
declare const lintKeymap: readonly KeyBinding[];
/**
The type of a function that produces diagnostics.
*/
type LintSource = (view: EditorView) => readonly Diagnostic[] | Promise<readonly Diagnostic[]>;
/**
Given a diagnostic source, this function returns an extension that
enables linting with that source. It will be called whenever the
editor is idle (after its content changed).
Note that settings given here will apply to all linters active in
the editor. If `null` is given as source, this only configures the
lint extension.
*/
declare function linter(source: LintSource | null, config?: LintConfig): Extension;
/**
Forces any linters [configured](https://codemirror.net/6/docs/ref/#lint.linter) to run when the
editor is idle to run right away.
*/
declare function forceLinting(view: EditorView): void;
/**
Returns an extension that installs a gutter showing markers for
each line that has diagnostics, which can be hovered over to see
the diagnostics.
*/
declare function lintGutter(config?: LintGutterConfig): Extension;
/**
Iterate over the marked diagnostics for the given editor state,
calling `f` for each of them. Note that, if the document changed
since the diagnostics were created, the `Diagnostic` object will
hold the original outdated position, whereas the `to` and `from`
arguments hold the diagnostic's current position.
*/
declare function forEachDiagnostic(state: EditorState, f: (d: Diagnostic, from: number, to: number) => void): void;
export { type Action, type Diagnostic, type LintSource, closeLintPanel, diagnosticCount, forEachDiagnostic, forceLinting, lintGutter, lintKeymap, linter, nextDiagnostic, openLintPanel, previousDiagnostic, setDiagnostics, setDiagnosticsEffect };

937
frontend/node_modules/@codemirror/lint/dist/index.js generated vendored Normal file
View File

@ -0,0 +1,937 @@
import { Decoration, showPanel, EditorView, ViewPlugin, gutter, showTooltip, hoverTooltip, getPanel, logException, WidgetType, GutterMarker } from '@codemirror/view';
import { StateEffect, StateField, Facet, combineConfig, RangeSet, RangeSetBuilder } from '@codemirror/state';
import elt from 'crelt';
class SelectedDiagnostic {
constructor(from, to, diagnostic) {
this.from = from;
this.to = to;
this.diagnostic = diagnostic;
}
}
class LintState {
constructor(diagnostics, panel, selected) {
this.diagnostics = diagnostics;
this.panel = panel;
this.selected = selected;
}
static init(diagnostics, panel, state) {
// Filter the list of diagnostics for which to create markers
let diagnosticFilter = state.facet(lintConfig).markerFilter;
if (diagnosticFilter)
diagnostics = diagnosticFilter(diagnostics, state);
let sorted = diagnostics.slice().sort((a, b) => a.from - b.from || a.to - b.to);
let deco = new RangeSetBuilder(), active = [], pos = 0;
let scan = state.doc.iter(), scanPos = 0, docLen = state.doc.length;
for (let i = 0;;) {
let next = i == sorted.length ? null : sorted[i];
if (!next && !active.length)
break;
let from, to;
if (active.length) {
from = pos;
to = active.reduce((p, d) => Math.min(p, d.to), next && next.from > from ? next.from : 1e8);
}
else {
from = next.from;
if (from > docLen)
break;
to = next.to;
active.push(next);
i++;
}
while (i < sorted.length) {
let next = sorted[i];
if (next.from == from && (next.to > next.from || next.to == from)) {
active.push(next);
i++;
to = Math.min(next.to, to);
}
else {
to = Math.min(next.from, to);
break;
}
}
to = Math.min(to, docLen);
let widget = false;
if (active.some(d => d.from == from && (d.to == to || to == docLen))) {
widget = from == to;
if (!widget && to - from < 10) {
let behind = from - (scanPos + scan.value.length);
if (behind > 0) {
scan.next(behind);
scanPos = from;
}
for (let check = from;;) {
if (check >= to) {
widget = true;
break;
}
if (!scan.lineBreak && scanPos + scan.value.length > check)
break;
check = scanPos + scan.value.length;
scanPos += scan.value.length;
scan.next();
}
}
}
let sev = maxSeverity(active);
if (widget) {
deco.add(from, from, Decoration.widget({
widget: new DiagnosticWidget(sev),
diagnostics: active.slice()
}));
}
else {
let markClass = active.reduce((c, d) => d.markClass ? c + " " + d.markClass : c, "");
deco.add(from, to, Decoration.mark({
class: "cm-lintRange cm-lintRange-" + sev + markClass,
diagnostics: active.slice(),
inclusiveEnd: active.some(a => a.to > to)
}));
}
pos = to;
if (pos == docLen)
break;
for (let i = 0; i < active.length; i++)
if (active[i].to <= pos)
active.splice(i--, 1);
}
let set = deco.finish();
return new LintState(set, panel, findDiagnostic(set));
}
}
function findDiagnostic(diagnostics, diagnostic = null, after = 0) {
let found = null;
diagnostics.between(after, 1e9, (from, to, { spec }) => {
if (diagnostic && spec.diagnostics.indexOf(diagnostic) < 0)
return;
if (!found)
found = new SelectedDiagnostic(from, to, diagnostic || spec.diagnostics[0]);
else if (spec.diagnostics.indexOf(found.diagnostic) < 0)
return false;
else
found = new SelectedDiagnostic(found.from, to, found.diagnostic);
});
return found;
}
function hideTooltip(tr, tooltip) {
let from = tooltip.pos, to = tooltip.end || from;
let result = tr.state.facet(lintConfig).hideOn(tr, from, to);
if (result != null)
return result;
let line = tr.startState.doc.lineAt(tooltip.pos);
return !!(tr.effects.some(e => e.is(setDiagnosticsEffect)) || tr.changes.touchesRange(line.from, Math.max(line.to, to)));
}
function maybeEnableLint(state, effects) {
return state.field(lintState, false) ? effects : effects.concat(StateEffect.appendConfig.of(lintExtensions));
}
/**
Returns a transaction spec which updates the current set of
diagnostics, and enables the lint extension if if wasn't already
active.
*/
function setDiagnostics(state, diagnostics) {
return {
effects: maybeEnableLint(state, [setDiagnosticsEffect.of(diagnostics)])
};
}
/**
The state effect that updates the set of active diagnostics. Can
be useful when writing an extension that needs to track these.
*/
const setDiagnosticsEffect = /*@__PURE__*/StateEffect.define();
const togglePanel = /*@__PURE__*/StateEffect.define();
const movePanelSelection = /*@__PURE__*/StateEffect.define();
const lintState = /*@__PURE__*/StateField.define({
create() {
return new LintState(Decoration.none, null, null);
},
update(value, tr) {
if (tr.docChanged && value.diagnostics.size) {
let mapped = value.diagnostics.map(tr.changes), selected = null, panel = value.panel;
if (value.selected) {
let selPos = tr.changes.mapPos(value.selected.from, 1);
selected = findDiagnostic(mapped, value.selected.diagnostic, selPos) || findDiagnostic(mapped, null, selPos);
}
if (!mapped.size && panel && tr.state.facet(lintConfig).autoPanel)
panel = null;
value = new LintState(mapped, panel, selected);
}
for (let effect of tr.effects) {
if (effect.is(setDiagnosticsEffect)) {
let panel = !tr.state.facet(lintConfig).autoPanel ? value.panel : effect.value.length ? LintPanel.open : null;
value = LintState.init(effect.value, panel, tr.state);
}
else if (effect.is(togglePanel)) {
value = new LintState(value.diagnostics, effect.value ? LintPanel.open : null, value.selected);
}
else if (effect.is(movePanelSelection)) {
value = new LintState(value.diagnostics, value.panel, effect.value);
}
}
return value;
},
provide: f => [showPanel.from(f, val => val.panel),
EditorView.decorations.from(f, s => s.diagnostics)]
});
/**
Returns the number of active lint diagnostics in the given state.
*/
function diagnosticCount(state) {
let lint = state.field(lintState, false);
return lint ? lint.diagnostics.size : 0;
}
const activeMark = /*@__PURE__*/Decoration.mark({ class: "cm-lintRange cm-lintRange-active" });
function lintTooltip(view, pos, side) {
let { diagnostics } = view.state.field(lintState);
let found, start = -1, end = -1;
diagnostics.between(pos - (side < 0 ? 1 : 0), pos + (side > 0 ? 1 : 0), (from, to, { spec }) => {
if (pos >= from && pos <= to &&
(from == to || ((pos > from || side > 0) && (pos < to || side < 0)))) {
found = spec.diagnostics;
start = from;
end = to;
return false;
}
});
let diagnosticFilter = view.state.facet(lintConfig).tooltipFilter;
if (found && diagnosticFilter)
found = diagnosticFilter(found, view.state);
if (!found)
return null;
return {
pos: start,
end: end,
above: view.state.doc.lineAt(start).to < end,
create() {
return { dom: diagnosticsTooltip(view, found) };
}
};
}
function diagnosticsTooltip(view, diagnostics) {
return elt("ul", { class: "cm-tooltip-lint" }, diagnostics.map(d => renderDiagnostic(view, d, false)));
}
/**
Command to open and focus the lint panel.
*/
const openLintPanel = (view) => {
let field = view.state.field(lintState, false);
if (!field || !field.panel)
view.dispatch({ effects: maybeEnableLint(view.state, [togglePanel.of(true)]) });
let panel = getPanel(view, LintPanel.open);
if (panel)
panel.dom.querySelector(".cm-panel-lint ul").focus();
return true;
};
/**
Command to close the lint panel, when open.
*/
const closeLintPanel = (view) => {
let field = view.state.field(lintState, false);
if (!field || !field.panel)
return false;
view.dispatch({ effects: togglePanel.of(false) });
return true;
};
/**
Move the selection to the next diagnostic.
*/
const nextDiagnostic = (view) => {
let field = view.state.field(lintState, false);
if (!field)
return false;
let sel = view.state.selection.main, next = field.diagnostics.iter(sel.to + 1);
if (!next.value) {
next = field.diagnostics.iter(0);
if (!next.value || next.from == sel.from && next.to == sel.to)
return false;
}
view.dispatch({ selection: { anchor: next.from, head: next.to }, scrollIntoView: true });
return true;
};
/**
Move the selection to the previous diagnostic.
*/
const previousDiagnostic = (view) => {
let { state } = view, field = state.field(lintState, false);
if (!field)
return false;
let sel = state.selection.main;
let prevFrom, prevTo, lastFrom, lastTo;
field.diagnostics.between(0, state.doc.length, (from, to) => {
if (to < sel.to && (prevFrom == null || prevFrom < from)) {
prevFrom = from;
prevTo = to;
}
if (lastFrom == null || from > lastFrom) {
lastFrom = from;
lastTo = to;
}
});
if (lastFrom == null || prevFrom == null && lastFrom == sel.from)
return false;
view.dispatch({ selection: { anchor: prevFrom !== null && prevFrom !== void 0 ? prevFrom : lastFrom, head: prevTo !== null && prevTo !== void 0 ? prevTo : lastTo }, scrollIntoView: true });
return true;
};
/**
A set of default key bindings for the lint functionality.
- Ctrl-Shift-m (Cmd-Shift-m on macOS): [`openLintPanel`](https://codemirror.net/6/docs/ref/#lint.openLintPanel)
- F8: [`nextDiagnostic`](https://codemirror.net/6/docs/ref/#lint.nextDiagnostic)
*/
const lintKeymap = [
{ key: "Mod-Shift-m", run: openLintPanel, preventDefault: true },
{ key: "F8", run: nextDiagnostic }
];
const lintPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
constructor(view) {
this.view = view;
this.timeout = -1;
this.set = true;
let { delay } = view.state.facet(lintConfig);
this.lintTime = Date.now() + delay;
this.run = this.run.bind(this);
this.timeout = setTimeout(this.run, delay);
}
run() {
clearTimeout(this.timeout);
let now = Date.now();
if (now < this.lintTime - 10) {
this.timeout = setTimeout(this.run, this.lintTime - now);
}
else {
this.set = false;
let { state } = this.view, { sources } = state.facet(lintConfig);
if (sources.length)
batchResults(sources.map(s => Promise.resolve(s(this.view))), annotations => {
if (this.view.state.doc == state.doc)
this.view.dispatch(setDiagnostics(this.view.state, annotations.reduce((a, b) => a.concat(b))));
}, error => { logException(this.view.state, error); });
}
}
update(update) {
let config = update.state.facet(lintConfig);
if (update.docChanged || config != update.startState.facet(lintConfig) ||
config.needsRefresh && config.needsRefresh(update)) {
this.lintTime = Date.now() + config.delay;
if (!this.set) {
this.set = true;
this.timeout = setTimeout(this.run, config.delay);
}
}
}
force() {
if (this.set) {
this.lintTime = Date.now();
this.run();
}
}
destroy() {
clearTimeout(this.timeout);
}
});
function batchResults(promises, sink, error) {
let collected = [], timeout = -1;
for (let p of promises)
p.then(value => {
collected.push(value);
clearTimeout(timeout);
if (collected.length == promises.length)
sink(collected);
else
timeout = setTimeout(() => sink(collected), 200);
}, error);
}
const lintConfig = /*@__PURE__*/Facet.define({
combine(input) {
return {
sources: input.map(i => i.source).filter(x => x != null),
...combineConfig(input.map(i => i.config), {
delay: 750,
markerFilter: null,
tooltipFilter: null,
needsRefresh: null,
hideOn: () => null,
}, {
delay: Math.max,
markerFilter: combineFilter,
tooltipFilter: combineFilter,
needsRefresh: (a, b) => !a ? b : !b ? a : u => a(u) || b(u),
hideOn: (a, b) => !a ? b : !b ? a : (t, x, y) => a(t, x, y) || b(t, x, y),
autoPanel: (a, b) => a || b
})
};
}
});
function combineFilter(a, b) {
return !a ? b : !b ? a : (d, s) => b(a(d, s), s);
}
/**
Given a diagnostic source, this function returns an extension that
enables linting with that source. It will be called whenever the
editor is idle (after its content changed).
Note that settings given here will apply to all linters active in
the editor. If `null` is given as source, this only configures the
lint extension.
*/
function linter(source, config = {}) {
return [
lintConfig.of({ source, config }),
lintPlugin,
lintExtensions
];
}
/**
Forces any linters [configured](https://codemirror.net/6/docs/ref/#lint.linter) to run when the
editor is idle to run right away.
*/
function forceLinting(view) {
let plugin = view.plugin(lintPlugin);
if (plugin)
plugin.force();
}
function assignKeys(actions) {
let assigned = [];
if (actions)
actions: for (let { name } of actions) {
for (let i = 0; i < name.length; i++) {
let ch = name[i];
if (/[a-zA-Z]/.test(ch) && !assigned.some(c => c.toLowerCase() == ch.toLowerCase())) {
assigned.push(ch);
continue actions;
}
}
assigned.push("");
}
return assigned;
}
function renderDiagnostic(view, diagnostic, inPanel) {
var _a;
let keys = inPanel ? assignKeys(diagnostic.actions) : [];
return elt("li", { class: "cm-diagnostic cm-diagnostic-" + diagnostic.severity }, elt("span", { class: "cm-diagnosticText" }, diagnostic.renderMessage ? diagnostic.renderMessage(view) : diagnostic.message), (_a = diagnostic.actions) === null || _a === void 0 ? void 0 : _a.map((action, i) => {
let fired = false, click = (e) => {
e.preventDefault();
if (fired)
return;
fired = true;
let found = findDiagnostic(view.state.field(lintState).diagnostics, diagnostic);
if (found)
action.apply(view, found.from, found.to);
};
let { name } = action, keyIndex = keys[i] ? name.indexOf(keys[i]) : -1;
let nameElt = keyIndex < 0 ? name : [name.slice(0, keyIndex),
elt("u", name.slice(keyIndex, keyIndex + 1)),
name.slice(keyIndex + 1)];
let markClass = action.markClass ? " " + action.markClass : "";
return elt("button", {
type: "button",
class: "cm-diagnosticAction" + markClass,
onclick: click,
onmousedown: click,
"aria-label": ` Action: ${name}${keyIndex < 0 ? "" : ` (access key "${keys[i]})"`}.`
}, nameElt);
}), diagnostic.source && elt("div", { class: "cm-diagnosticSource" }, diagnostic.source));
}
class DiagnosticWidget extends WidgetType {
constructor(sev) {
super();
this.sev = sev;
}
eq(other) { return other.sev == this.sev; }
toDOM() {
return elt("span", { class: "cm-lintPoint cm-lintPoint-" + this.sev });
}
}
class PanelItem {
constructor(view, diagnostic) {
this.diagnostic = diagnostic;
this.id = "item_" + Math.floor(Math.random() * 0xffffffff).toString(16);
this.dom = renderDiagnostic(view, diagnostic, true);
this.dom.id = this.id;
this.dom.setAttribute("role", "option");
}
}
class LintPanel {
constructor(view) {
this.view = view;
this.items = [];
let onkeydown = (event) => {
if (event.keyCode == 27) { // Escape
closeLintPanel(this.view);
this.view.focus();
}
else if (event.keyCode == 38 || event.keyCode == 33) { // ArrowUp, PageUp
this.moveSelection((this.selectedIndex - 1 + this.items.length) % this.items.length);
}
else if (event.keyCode == 40 || event.keyCode == 34) { // ArrowDown, PageDown
this.moveSelection((this.selectedIndex + 1) % this.items.length);
}
else if (event.keyCode == 36) { // Home
this.moveSelection(0);
}
else if (event.keyCode == 35) { // End
this.moveSelection(this.items.length - 1);
}
else if (event.keyCode == 13) { // Enter
this.view.focus();
}
else if (event.keyCode >= 65 && event.keyCode <= 90 && this.selectedIndex >= 0) { // A-Z
let { diagnostic } = this.items[this.selectedIndex], keys = assignKeys(diagnostic.actions);
for (let i = 0; i < keys.length; i++)
if (keys[i].toUpperCase().charCodeAt(0) == event.keyCode) {
let found = findDiagnostic(this.view.state.field(lintState).diagnostics, diagnostic);
if (found)
diagnostic.actions[i].apply(view, found.from, found.to);
}
}
else {
return;
}
event.preventDefault();
};
let onclick = (event) => {
for (let i = 0; i < this.items.length; i++) {
if (this.items[i].dom.contains(event.target))
this.moveSelection(i);
}
};
this.list = elt("ul", {
tabIndex: 0,
role: "listbox",
"aria-label": this.view.state.phrase("Diagnostics"),
onkeydown,
onclick
});
this.dom = elt("div", { class: "cm-panel-lint" }, this.list, elt("button", {
type: "button",
name: "close",
"aria-label": this.view.state.phrase("close"),
onclick: () => closeLintPanel(this.view)
}, "×"));
this.update();
}
get selectedIndex() {
let selected = this.view.state.field(lintState).selected;
if (!selected)
return -1;
for (let i = 0; i < this.items.length; i++)
if (this.items[i].diagnostic == selected.diagnostic)
return i;
return -1;
}
update() {
let { diagnostics, selected } = this.view.state.field(lintState);
let i = 0, needsSync = false, newSelectedItem = null;
let seen = new Set();
diagnostics.between(0, this.view.state.doc.length, (_start, _end, { spec }) => {
for (let diagnostic of spec.diagnostics) {
if (seen.has(diagnostic))
continue;
seen.add(diagnostic);
let found = -1, item;
for (let j = i; j < this.items.length; j++)
if (this.items[j].diagnostic == diagnostic) {
found = j;
break;
}
if (found < 0) {
item = new PanelItem(this.view, diagnostic);
this.items.splice(i, 0, item);
needsSync = true;
}
else {
item = this.items[found];
if (found > i) {
this.items.splice(i, found - i);
needsSync = true;
}
}
if (selected && item.diagnostic == selected.diagnostic) {
if (!item.dom.hasAttribute("aria-selected")) {
item.dom.setAttribute("aria-selected", "true");
newSelectedItem = item;
}
}
else if (item.dom.hasAttribute("aria-selected")) {
item.dom.removeAttribute("aria-selected");
}
i++;
}
});
while (i < this.items.length && !(this.items.length == 1 && this.items[0].diagnostic.from < 0)) {
needsSync = true;
this.items.pop();
}
if (this.items.length == 0) {
this.items.push(new PanelItem(this.view, {
from: -1, to: -1,
severity: "info",
message: this.view.state.phrase("No diagnostics")
}));
needsSync = true;
}
if (newSelectedItem) {
this.list.setAttribute("aria-activedescendant", newSelectedItem.id);
this.view.requestMeasure({
key: this,
read: () => ({ sel: newSelectedItem.dom.getBoundingClientRect(), panel: this.list.getBoundingClientRect() }),
write: ({ sel, panel }) => {
let scaleY = panel.height / this.list.offsetHeight;
if (sel.top < panel.top)
this.list.scrollTop -= (panel.top - sel.top) / scaleY;
else if (sel.bottom > panel.bottom)
this.list.scrollTop += (sel.bottom - panel.bottom) / scaleY;
}
});
}
else if (this.selectedIndex < 0) {
this.list.removeAttribute("aria-activedescendant");
}
if (needsSync)
this.sync();
}
sync() {
let domPos = this.list.firstChild;
function rm() {
let prev = domPos;
domPos = prev.nextSibling;
prev.remove();
}
for (let item of this.items) {
if (item.dom.parentNode == this.list) {
while (domPos != item.dom)
rm();
domPos = item.dom.nextSibling;
}
else {
this.list.insertBefore(item.dom, domPos);
}
}
while (domPos)
rm();
}
moveSelection(selectedIndex) {
if (this.selectedIndex < 0)
return;
let field = this.view.state.field(lintState);
let selection = findDiagnostic(field.diagnostics, this.items[selectedIndex].diagnostic);
if (!selection)
return;
this.view.dispatch({
selection: { anchor: selection.from, head: selection.to },
scrollIntoView: true,
effects: movePanelSelection.of(selection)
});
}
static open(view) { return new LintPanel(view); }
}
function svg(content, attrs = `viewBox="0 0 40 40"`) {
return `url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" ${attrs}>${encodeURIComponent(content)}</svg>')`;
}
function underline(color) {
return svg(`<path d="m0 2.5 l2 -1.5 l1 0 l2 1.5 l1 0" stroke="${color}" fill="none" stroke-width=".7"/>`, `width="6" height="3"`);
}
const baseTheme = /*@__PURE__*/EditorView.baseTheme({
".cm-diagnostic": {
padding: "3px 6px 3px 8px",
marginLeft: "-1px",
display: "block",
whiteSpace: "pre-wrap"
},
".cm-diagnostic-error": { borderLeft: "5px solid #d11" },
".cm-diagnostic-warning": { borderLeft: "5px solid orange" },
".cm-diagnostic-info": { borderLeft: "5px solid #999" },
".cm-diagnostic-hint": { borderLeft: "5px solid #66d" },
".cm-diagnosticAction": {
font: "inherit",
border: "none",
padding: "2px 4px",
backgroundColor: "#444",
color: "white",
borderRadius: "3px",
marginLeft: "8px",
cursor: "pointer"
},
".cm-diagnosticSource": {
fontSize: "70%",
opacity: .7
},
".cm-lintRange": {
backgroundPosition: "left bottom",
backgroundRepeat: "repeat-x",
paddingBottom: "0.7px",
},
".cm-lintRange-error": { backgroundImage: /*@__PURE__*/underline("#d11") },
".cm-lintRange-warning": { backgroundImage: /*@__PURE__*/underline("orange") },
".cm-lintRange-info": { backgroundImage: /*@__PURE__*/underline("#999") },
".cm-lintRange-hint": { backgroundImage: /*@__PURE__*/underline("#66d") },
".cm-lintRange-active": { backgroundColor: "#ffdd9980" },
".cm-tooltip-lint": {
padding: 0,
margin: 0
},
".cm-lintPoint": {
position: "relative",
"&:after": {
content: '""',
position: "absolute",
bottom: 0,
left: "-2px",
borderLeft: "3px solid transparent",
borderRight: "3px solid transparent",
borderBottom: "4px solid #d11"
}
},
".cm-lintPoint-warning": {
"&:after": { borderBottomColor: "orange" }
},
".cm-lintPoint-info": {
"&:after": { borderBottomColor: "#999" }
},
".cm-lintPoint-hint": {
"&:after": { borderBottomColor: "#66d" }
},
".cm-panel.cm-panel-lint": {
position: "relative",
"& ul": {
maxHeight: "100px",
overflowY: "auto",
"& [aria-selected]": {
backgroundColor: "#ddd",
"& u": { textDecoration: "underline" }
},
"&:focus [aria-selected]": {
background_fallback: "#bdf",
backgroundColor: "Highlight",
color_fallback: "white",
color: "HighlightText"
},
"& u": { textDecoration: "none" },
padding: 0,
margin: 0
},
"& [name=close]": {
position: "absolute",
top: "0",
right: "2px",
background: "inherit",
border: "none",
font: "inherit",
padding: 0,
margin: 0
}
}
});
function severityWeight(sev) {
return sev == "error" ? 4 : sev == "warning" ? 3 : sev == "info" ? 2 : 1;
}
function maxSeverity(diagnostics) {
let sev = "hint", weight = 1;
for (let d of diagnostics) {
let w = severityWeight(d.severity);
if (w > weight) {
weight = w;
sev = d.severity;
}
}
return sev;
}
class LintGutterMarker extends GutterMarker {
constructor(diagnostics) {
super();
this.diagnostics = diagnostics;
this.severity = maxSeverity(diagnostics);
}
toDOM(view) {
let elt = document.createElement("div");
elt.className = "cm-lint-marker cm-lint-marker-" + this.severity;
let diagnostics = this.diagnostics;
let diagnosticsFilter = view.state.facet(lintGutterConfig).tooltipFilter;
if (diagnosticsFilter)
diagnostics = diagnosticsFilter(diagnostics, view.state);
if (diagnostics.length)
elt.onmouseover = () => gutterMarkerMouseOver(view, elt, diagnostics);
return elt;
}
}
function trackHoverOn(view, marker) {
let mousemove = (event) => {
let rect = marker.getBoundingClientRect();
if (event.clientX > rect.left - 10 /* Hover.Margin */ && event.clientX < rect.right + 10 /* Hover.Margin */ &&
event.clientY > rect.top - 10 /* Hover.Margin */ && event.clientY < rect.bottom + 10 /* Hover.Margin */)
return;
for (let target = event.target; target; target = target.parentNode) {
if (target.nodeType == 1 && target.classList.contains("cm-tooltip-lint"))
return;
}
window.removeEventListener("mousemove", mousemove);
if (view.state.field(lintGutterTooltip))
view.dispatch({ effects: setLintGutterTooltip.of(null) });
};
window.addEventListener("mousemove", mousemove);
}
function gutterMarkerMouseOver(view, marker, diagnostics) {
function hovered() {
let line = view.elementAtHeight(marker.getBoundingClientRect().top + 5 - view.documentTop);
const linePos = view.coordsAtPos(line.from);
if (linePos) {
view.dispatch({ effects: setLintGutterTooltip.of({
pos: line.from,
above: false,
clip: false,
create() {
return {
dom: diagnosticsTooltip(view, diagnostics),
getCoords: () => marker.getBoundingClientRect()
};
}
}) });
}
marker.onmouseout = marker.onmousemove = null;
trackHoverOn(view, marker);
}
let { hoverTime } = view.state.facet(lintGutterConfig);
let hoverTimeout = setTimeout(hovered, hoverTime);
marker.onmouseout = () => {
clearTimeout(hoverTimeout);
marker.onmouseout = marker.onmousemove = null;
};
marker.onmousemove = () => {
clearTimeout(hoverTimeout);
hoverTimeout = setTimeout(hovered, hoverTime);
};
}
function markersForDiagnostics(doc, diagnostics) {
let byLine = Object.create(null);
for (let diagnostic of diagnostics) {
let line = doc.lineAt(diagnostic.from);
(byLine[line.from] || (byLine[line.from] = [])).push(diagnostic);
}
let markers = [];
for (let line in byLine) {
markers.push(new LintGutterMarker(byLine[line]).range(+line));
}
return RangeSet.of(markers, true);
}
const lintGutterExtension = /*@__PURE__*/gutter({
class: "cm-gutter-lint",
markers: view => view.state.field(lintGutterMarkers),
widgetMarker: (view, widget, block) => {
let diagnostics = [];
view.state.field(lintGutterMarkers).between(block.from, block.to, (from, to, value) => {
if (from > block.from && from < block.to)
diagnostics.push(...value.diagnostics);
});
return diagnostics.length ? new LintGutterMarker(diagnostics) : null;
}
});
const lintGutterMarkers = /*@__PURE__*/StateField.define({
create() {
return RangeSet.empty;
},
update(markers, tr) {
markers = markers.map(tr.changes);
let diagnosticFilter = tr.state.facet(lintGutterConfig).markerFilter;
for (let effect of tr.effects) {
if (effect.is(setDiagnosticsEffect)) {
let diagnostics = effect.value;
if (diagnosticFilter)
diagnostics = diagnosticFilter(diagnostics || [], tr.state);
markers = markersForDiagnostics(tr.state.doc, diagnostics.slice(0));
}
}
return markers;
}
});
const setLintGutterTooltip = /*@__PURE__*/StateEffect.define();
const lintGutterTooltip = /*@__PURE__*/StateField.define({
create() { return null; },
update(tooltip, tr) {
if (tooltip && tr.docChanged)
tooltip = hideTooltip(tr, tooltip) ? null : { ...tooltip, pos: tr.changes.mapPos(tooltip.pos) };
return tr.effects.reduce((t, e) => e.is(setLintGutterTooltip) ? e.value : t, tooltip);
},
provide: field => showTooltip.from(field)
});
const lintGutterTheme = /*@__PURE__*/EditorView.baseTheme({
".cm-gutter-lint": {
width: "1.4em",
"& .cm-gutterElement": {
padding: ".2em"
}
},
".cm-lint-marker": {
width: "1em",
height: "1em"
},
".cm-lint-marker-info": {
content: /*@__PURE__*/svg(`<path fill="#aaf" stroke="#77e" stroke-width="6" stroke-linejoin="round" d="M5 5L35 5L35 35L5 35Z"/>`)
},
".cm-lint-marker-warning": {
content: /*@__PURE__*/svg(`<path fill="#fe8" stroke="#fd7" stroke-width="6" stroke-linejoin="round" d="M20 6L37 35L3 35Z"/>`),
},
".cm-lint-marker-error": {
content: /*@__PURE__*/svg(`<circle cx="20" cy="20" r="15" fill="#f87" stroke="#f43" stroke-width="6"/>`)
},
});
const lintExtensions = [
lintState,
/*@__PURE__*/EditorView.decorations.compute([lintState], state => {
let { selected, panel } = state.field(lintState);
return !selected || !panel || selected.from == selected.to ? Decoration.none : Decoration.set([
activeMark.range(selected.from, selected.to)
]);
}),
/*@__PURE__*/hoverTooltip(lintTooltip, { hideOn: hideTooltip }),
baseTheme
];
const lintGutterConfig = /*@__PURE__*/Facet.define({
combine(configs) {
return combineConfig(configs, {
hoverTime: 300 /* Hover.Time */,
markerFilter: null,
tooltipFilter: null
});
}
});
/**
Returns an extension that installs a gutter showing markers for
each line that has diagnostics, which can be hovered over to see
the diagnostics.
*/
function lintGutter(config = {}) {
return [lintGutterConfig.of(config), lintGutterMarkers, lintGutterExtension, lintGutterTheme, lintGutterTooltip];
}
/**
Iterate over the marked diagnostics for the given editor state,
calling `f` for each of them. Note that, if the document changed
since the diagnostics were created, the `Diagnostic` object will
hold the original outdated position, whereas the `to` and `from`
arguments hold the diagnostic's current position.
*/
function forEachDiagnostic(state, f) {
let lState = state.field(lintState, false);
if (lState && lState.diagnostics.size) {
let pending = [], pendingStart = [], lastEnd = -1;
for (let iter = RangeSet.iter([lState.diagnostics]);; iter.next()) {
for (let i = 0; i < pending.length; i++)
if (!iter.value || iter.value.spec.diagnostics.indexOf(pending[i]) < 0) {
f(pending[i], pendingStart[i], lastEnd);
pending.splice(i, 1);
pendingStart.splice(i--, 1);
}
if (!iter.value)
break;
for (let d of iter.value.spec.diagnostics)
if (pending.indexOf(d) < 0) {
pending.push(d);
pendingStart.push(iter.from);
}
lastEnd = iter.to;
}
}
}
export { closeLintPanel, diagnosticCount, forEachDiagnostic, forceLinting, lintGutter, lintKeymap, linter, nextDiagnostic, openLintPanel, previousDiagnostic, setDiagnostics, setDiagnosticsEffect };

40
frontend/node_modules/@codemirror/lint/package.json generated vendored Normal file
View File

@ -0,0 +1,40 @@
{
"name": "@codemirror/lint",
"version": "6.9.2",
"description": "Linting support for the CodeMirror code editor",
"scripts": {
"test": "cm-runtests",
"prepare": "cm-buildhelper src/lint.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/state": "^6.0.0",
"@codemirror/view": "^6.35.0",
"crelt": "^1.0.5"
},
"devDependencies": {
"@codemirror/buildhelper": "^1.0.0"
},
"repository": {
"type": "git",
"url": "https://github.com/codemirror/lint.git"
}
}