@seljs/editor 1.0.0 → 1.0.1-beta.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/completion/completion-items.cjs +36 -0
- package/dist/completion/completion-items.mjs +32 -0
- package/dist/completion/index.cjs +1 -0
- package/dist/completion/index.d.mts +1 -0
- package/dist/completion/index.mjs +2 -0
- package/dist/completion/schema-completion.cjs +182 -0
- package/dist/completion/schema-completion.d.cts +25 -0
- package/dist/completion/schema-completion.d.mts +25 -0
- package/dist/completion/schema-completion.mjs +181 -0
- package/dist/completion/tree-context.cjs +108 -0
- package/dist/completion/tree-context.mjs +108 -0
- package/dist/editor/create-editor.cjs +16 -0
- package/dist/editor/create-editor.d.cts +7 -0
- package/dist/editor/create-editor.d.mts +7 -0
- package/dist/editor/create-editor.mjs +16 -0
- package/dist/editor/editor-config.cjs +49 -0
- package/dist/editor/editor-config.d.cts +7 -0
- package/dist/editor/editor-config.d.mts +7 -0
- package/dist/editor/editor-config.mjs +49 -0
- package/dist/editor/index.cjs +3 -0
- package/dist/editor/index.d.cts +6 -0
- package/dist/editor/index.d.mts +6 -0
- package/dist/editor/index.mjs +4 -0
- package/dist/editor/theme.cjs +35 -0
- package/dist/editor/theme.d.cts +7 -0
- package/dist/editor/theme.d.mts +7 -0
- package/dist/editor/theme.mjs +34 -0
- package/dist/editor/type-display.cjs +71 -0
- package/dist/editor/type-display.mjs +71 -0
- package/dist/editor/types.d.cts +31 -0
- package/dist/editor/types.d.mts +31 -0
- package/dist/index.cjs +20 -0
- package/dist/index.d.cts +10 -0
- package/dist/index.d.mts +10 -0
- package/dist/index.mjs +11 -0
- package/dist/language/semantic-highlighter.cjs +55 -0
- package/dist/language/semantic-highlighter.mjs +55 -0
- package/dist/language/tokenizer-config.cjs +9 -0
- package/dist/language/tokenizer-config.d.cts +12 -0
- package/dist/language/tokenizer-config.d.mts +12 -0
- package/dist/language/tokenizer-config.mjs +9 -0
- package/dist/linting/diagnostic-mapper.cjs +37 -0
- package/dist/linting/{diagnostic-mapper.d.ts → diagnostic-mapper.d.cts} +7 -6
- package/dist/linting/diagnostic-mapper.d.mts +29 -0
- package/dist/linting/diagnostic-mapper.mjs +37 -0
- package/dist/linting/index.cjs +2 -0
- package/dist/linting/index.d.mts +2 -0
- package/dist/linting/index.mjs +3 -0
- package/dist/linting/sel-linter.cjs +28 -0
- package/dist/linting/sel-linter.d.cts +13 -0
- package/dist/linting/sel-linter.d.mts +13 -0
- package/dist/linting/sel-linter.mjs +28 -0
- package/package.json +29 -22
- package/dist/completion/completion-items.d.ts +0 -8
- package/dist/completion/completion-items.d.ts.map +0 -1
- package/dist/completion/completion-items.js +0 -29
- package/dist/completion/index.d.ts +0 -2
- package/dist/completion/index.d.ts.map +0 -1
- package/dist/completion/index.js +0 -1
- package/dist/completion/schema-completion.d.ts +0 -22
- package/dist/completion/schema-completion.d.ts.map +0 -1
- package/dist/completion/schema-completion.js +0 -220
- package/dist/completion/tree-context.d.ts +0 -23
- package/dist/completion/tree-context.d.ts.map +0 -1
- package/dist/completion/tree-context.js +0 -154
- package/dist/editor/create-editor.d.ts +0 -4
- package/dist/editor/create-editor.d.ts.map +0 -1
- package/dist/editor/create-editor.js +0 -14
- package/dist/editor/editor-config.d.ts +0 -4
- package/dist/editor/editor-config.d.ts.map +0 -1
- package/dist/editor/editor-config.js +0 -64
- package/dist/editor/index.d.ts +0 -6
- package/dist/editor/index.d.ts.map +0 -1
- package/dist/editor/index.js +0 -3
- package/dist/editor/theme.d.ts +0 -3
- package/dist/editor/theme.d.ts.map +0 -1
- package/dist/editor/theme.js +0 -43
- package/dist/editor/type-display.d.ts +0 -4
- package/dist/editor/type-display.d.ts.map +0 -1
- package/dist/editor/type-display.js +0 -75
- package/dist/editor/types.d.ts +0 -28
- package/dist/editor/types.d.ts.map +0 -1
- package/dist/editor/types.js +0 -1
- package/dist/index.d.ts +0 -5
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -4
- package/dist/language/index.d.ts +0 -2
- package/dist/language/index.d.ts.map +0 -1
- package/dist/language/index.js +0 -1
- package/dist/language/semantic-highlighter.d.ts +0 -4
- package/dist/language/semantic-highlighter.d.ts.map +0 -1
- package/dist/language/semantic-highlighter.js +0 -76
- package/dist/language/tokenizer-config.d.ts +0 -9
- package/dist/language/tokenizer-config.d.ts.map +0 -1
- package/dist/language/tokenizer-config.js +0 -6
- package/dist/linting/diagnostic-mapper.d.ts.map +0 -1
- package/dist/linting/diagnostic-mapper.js +0 -46
- package/dist/linting/index.d.ts +0 -3
- package/dist/linting/index.d.ts.map +0 -1
- package/dist/linting/index.js +0 -2
- package/dist/linting/sel-linter.d.ts +0 -12
- package/dist/linting/sel-linter.d.ts.map +0 -1
- package/dist/linting/sel-linter.js +0 -28
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { syntaxTree } from "@codemirror/language";
|
|
2
|
+
//#region src/completion/tree-context.ts
|
|
3
|
+
/**
|
|
4
|
+
* Walk up the tree looking for a MemberExpression ancestor.
|
|
5
|
+
* A MemberExpression has two Identifier children (or child nodes) separated by ".".
|
|
6
|
+
* The dot position is: firstChild.to + 1 (the "." character is between them).
|
|
7
|
+
* We are in dot-access context when pos >= dotPos.
|
|
8
|
+
*/
|
|
9
|
+
const findDotAccess = (state, node, pos) => {
|
|
10
|
+
let current = node;
|
|
11
|
+
while (current) {
|
|
12
|
+
if (current.name === "ArgList") break;
|
|
13
|
+
if (current.name === "MemberExpression" || current.name === "OptionalExpression") {
|
|
14
|
+
const firstChild = current.firstChild;
|
|
15
|
+
if (firstChild) {
|
|
16
|
+
const dotPos = firstChild.to + 1;
|
|
17
|
+
if (pos >= dotPos) return {
|
|
18
|
+
kind: "dot-access",
|
|
19
|
+
receiverText: state.doc.sliceString(current.from, firstChild.to),
|
|
20
|
+
from: dotPos
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
current = current.parent;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Count commas in ArgList text that appear before pos.
|
|
29
|
+
* Commas are anonymous tokens not exposed as named children,
|
|
30
|
+
* so we scan the raw source text.
|
|
31
|
+
*/
|
|
32
|
+
const countCommasBefore = (argList, state, pos) => {
|
|
33
|
+
const open = argList.from + 1;
|
|
34
|
+
const end = Math.min(pos, argList.to);
|
|
35
|
+
const text = state.doc.sliceString(open, end);
|
|
36
|
+
let count = 0;
|
|
37
|
+
for (const ch of text) if (ch === ",") count++;
|
|
38
|
+
return count;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Extract function name and optional receiver name from a CallExpression node.
|
|
42
|
+
*
|
|
43
|
+
* Tree shapes:
|
|
44
|
+
* foo(...) → CallExpression > Identifier, ArgList
|
|
45
|
+
* erc20.foo(...) → CallExpression > MemberExpression(Identifier "erc20", Identifier "foo"), ArgList
|
|
46
|
+
*/
|
|
47
|
+
const extractCallInfo = (state, callExpr) => {
|
|
48
|
+
const callee = callExpr.firstChild;
|
|
49
|
+
if (!callee) return;
|
|
50
|
+
if (callee.name === "Identifier") return { functionName: state.doc.sliceString(callee.from, callee.to) };
|
|
51
|
+
if (callee.name === "MemberExpression") {
|
|
52
|
+
const lastChild = callee.lastChild;
|
|
53
|
+
if (lastChild?.name === "Identifier") {
|
|
54
|
+
const functionName = state.doc.sliceString(lastChild.from, lastChild.to);
|
|
55
|
+
const receiverNode = callee.firstChild;
|
|
56
|
+
return {
|
|
57
|
+
functionName,
|
|
58
|
+
receiverName: receiverNode?.name === "Identifier" ? state.doc.sliceString(receiverNode.from, receiverNode.to) : void 0
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const findWordStart = (state, pos) => {
|
|
64
|
+
const text = state.doc.sliceString(0, pos);
|
|
65
|
+
const match = /\w+$/.exec(text);
|
|
66
|
+
return match ? pos - match[0].length : pos;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Walk up the tree looking for an ArgList ancestor.
|
|
70
|
+
* When found, count commas before pos to get paramIndex,
|
|
71
|
+
* then extract function name and optional receiver from the CallExpression.
|
|
72
|
+
*/
|
|
73
|
+
const findCallArg = (state, node, pos) => {
|
|
74
|
+
let current = node;
|
|
75
|
+
while (current) {
|
|
76
|
+
if (current.name === "ArgList") {
|
|
77
|
+
const paramIndex = countCommasBefore(current, state, pos);
|
|
78
|
+
const callExpr = current.parent;
|
|
79
|
+
if (callExpr?.name === "CallExpression") {
|
|
80
|
+
const info = extractCallInfo(state, callExpr);
|
|
81
|
+
if (info) return {
|
|
82
|
+
kind: "call-arg",
|
|
83
|
+
functionName: info.functionName,
|
|
84
|
+
receiverName: info.receiverName,
|
|
85
|
+
paramIndex,
|
|
86
|
+
from: pos
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
current = current.parent;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Extract completion context from the Lezer syntax tree at the given position.
|
|
95
|
+
*/
|
|
96
|
+
const getCompletionContext = (state, pos) => {
|
|
97
|
+
const node = syntaxTree(state).resolveInner(pos, -1);
|
|
98
|
+
const dotAccess = findDotAccess(state, node, pos);
|
|
99
|
+
if (dotAccess) return dotAccess;
|
|
100
|
+
const callArg = findCallArg(state, node, pos);
|
|
101
|
+
if (callArg) return callArg;
|
|
102
|
+
return {
|
|
103
|
+
kind: "top-level",
|
|
104
|
+
from: findWordStart(state, pos)
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
//#endregion
|
|
108
|
+
export { getCompletionContext };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const require_editor_config = require("./editor-config.cjs");
|
|
2
|
+
let _codemirror_state = require("@codemirror/state");
|
|
3
|
+
let _codemirror_view = require("@codemirror/view");
|
|
4
|
+
//#region src/editor/create-editor.ts
|
|
5
|
+
function createSELEditor(config) {
|
|
6
|
+
const extensions = require_editor_config.buildExtensions(config);
|
|
7
|
+
return new _codemirror_view.EditorView({
|
|
8
|
+
state: _codemirror_state.EditorState.create({
|
|
9
|
+
doc: config.value ?? "",
|
|
10
|
+
extensions
|
|
11
|
+
}),
|
|
12
|
+
parent: config.parent
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
exports.createSELEditor = createSELEditor;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { buildExtensions } from "./editor-config.mjs";
|
|
2
|
+
import { EditorState } from "@codemirror/state";
|
|
3
|
+
import { EditorView } from "@codemirror/view";
|
|
4
|
+
//#region src/editor/create-editor.ts
|
|
5
|
+
function createSELEditor(config) {
|
|
6
|
+
const extensions = buildExtensions(config);
|
|
7
|
+
return new EditorView({
|
|
8
|
+
state: EditorState.create({
|
|
9
|
+
doc: config.value ?? "",
|
|
10
|
+
extensions
|
|
11
|
+
}),
|
|
12
|
+
parent: config.parent
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { createSELEditor };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const require_tokenizer_config = require("../language/tokenizer-config.cjs");
|
|
2
|
+
const require_schema_completion = require("../completion/schema-completion.cjs");
|
|
3
|
+
const require_sel_linter = require("../linting/sel-linter.cjs");
|
|
4
|
+
const require_theme = require("./theme.cjs");
|
|
5
|
+
const require_type_display = require("./type-display.cjs");
|
|
6
|
+
const require_semantic_highlighter = require("../language/semantic-highlighter.cjs");
|
|
7
|
+
let _codemirror_autocomplete = require("@codemirror/autocomplete");
|
|
8
|
+
let _seljs_checker = require("@seljs/checker");
|
|
9
|
+
let _codemirror_language = require("@codemirror/language");
|
|
10
|
+
let _codemirror_state = require("@codemirror/state");
|
|
11
|
+
let _codemirror_view = require("@codemirror/view");
|
|
12
|
+
let _codemirror_commands = require("@codemirror/commands");
|
|
13
|
+
let _seljs_cel_lezer = require("@seljs/cel-lezer");
|
|
14
|
+
//#region src/editor/editor-config.ts
|
|
15
|
+
const buildExtensions = (config) => {
|
|
16
|
+
const checker = new _seljs_checker.SELChecker(config.schema, { rules: [..._seljs_checker.rules.builtIn] });
|
|
17
|
+
const extensions = [];
|
|
18
|
+
extensions.push((0, _seljs_cel_lezer.celLanguageSupport)(config.dark));
|
|
19
|
+
extensions.push((0, _codemirror_language.bracketMatching)());
|
|
20
|
+
const tokenizerConfig = require_tokenizer_config.createTokenizerConfig(config.schema);
|
|
21
|
+
extensions.push(require_semantic_highlighter.createSemanticHighlighter(tokenizerConfig, config.dark));
|
|
22
|
+
extensions.push(require_schema_completion.createSchemaCompletion(config.schema, checker));
|
|
23
|
+
extensions.push((0, _codemirror_autocomplete.closeBrackets)());
|
|
24
|
+
extensions.push(_codemirror_view.keymap.of([
|
|
25
|
+
..._codemirror_autocomplete.closeBracketsKeymap,
|
|
26
|
+
..._codemirror_commands.defaultKeymap,
|
|
27
|
+
..._codemirror_commands.historyKeymap
|
|
28
|
+
]));
|
|
29
|
+
extensions.push((0, _codemirror_commands.history)());
|
|
30
|
+
extensions.push(config.dark ? require_theme.selDarkTheme : require_theme.selLightTheme);
|
|
31
|
+
const validate = config.validate ?? ((expression) => checker.check(expression).diagnostics);
|
|
32
|
+
extensions.push(require_sel_linter.createSELLinter({
|
|
33
|
+
validate,
|
|
34
|
+
delay: config.validateDelay
|
|
35
|
+
}));
|
|
36
|
+
if (config.onChange) {
|
|
37
|
+
const onChange = config.onChange;
|
|
38
|
+
extensions.push(_codemirror_view.EditorView.updateListener.of((update) => {
|
|
39
|
+
if (update.docChanged) onChange(update.state.doc.toString());
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
if (config.readOnly) extensions.push(_codemirror_state.EditorState.readOnly.of(true));
|
|
43
|
+
if (config.placeholder) extensions.push((0, _codemirror_view.placeholder)(config.placeholder));
|
|
44
|
+
if (config.showType) extensions.push(require_type_display.createTypeDisplay(checker, config.dark ?? false));
|
|
45
|
+
if (config.extensions) extensions.push(...config.extensions);
|
|
46
|
+
return extensions;
|
|
47
|
+
};
|
|
48
|
+
//#endregion
|
|
49
|
+
exports.buildExtensions = buildExtensions;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { createTokenizerConfig } from "../language/tokenizer-config.mjs";
|
|
2
|
+
import { createSchemaCompletion } from "../completion/schema-completion.mjs";
|
|
3
|
+
import { createSELLinter } from "../linting/sel-linter.mjs";
|
|
4
|
+
import { selDarkTheme, selLightTheme } from "./theme.mjs";
|
|
5
|
+
import { createTypeDisplay } from "./type-display.mjs";
|
|
6
|
+
import { createSemanticHighlighter } from "../language/semantic-highlighter.mjs";
|
|
7
|
+
import { closeBrackets, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
8
|
+
import { SELChecker, rules } from "@seljs/checker";
|
|
9
|
+
import { bracketMatching } from "@codemirror/language";
|
|
10
|
+
import { EditorState } from "@codemirror/state";
|
|
11
|
+
import { EditorView, keymap, placeholder } from "@codemirror/view";
|
|
12
|
+
import { defaultKeymap, history, historyKeymap } from "@codemirror/commands";
|
|
13
|
+
import { celLanguageSupport } from "@seljs/cel-lezer";
|
|
14
|
+
//#region src/editor/editor-config.ts
|
|
15
|
+
const buildExtensions = (config) => {
|
|
16
|
+
const checker = new SELChecker(config.schema, { rules: [...rules.builtIn] });
|
|
17
|
+
const extensions = [];
|
|
18
|
+
extensions.push(celLanguageSupport(config.dark));
|
|
19
|
+
extensions.push(bracketMatching());
|
|
20
|
+
const tokenizerConfig = createTokenizerConfig(config.schema);
|
|
21
|
+
extensions.push(createSemanticHighlighter(tokenizerConfig, config.dark));
|
|
22
|
+
extensions.push(createSchemaCompletion(config.schema, checker));
|
|
23
|
+
extensions.push(closeBrackets());
|
|
24
|
+
extensions.push(keymap.of([
|
|
25
|
+
...closeBracketsKeymap,
|
|
26
|
+
...defaultKeymap,
|
|
27
|
+
...historyKeymap
|
|
28
|
+
]));
|
|
29
|
+
extensions.push(history());
|
|
30
|
+
extensions.push(config.dark ? selDarkTheme : selLightTheme);
|
|
31
|
+
const validate = config.validate ?? ((expression) => checker.check(expression).diagnostics);
|
|
32
|
+
extensions.push(createSELLinter({
|
|
33
|
+
validate,
|
|
34
|
+
delay: config.validateDelay
|
|
35
|
+
}));
|
|
36
|
+
if (config.onChange) {
|
|
37
|
+
const onChange = config.onChange;
|
|
38
|
+
extensions.push(EditorView.updateListener.of((update) => {
|
|
39
|
+
if (update.docChanged) onChange(update.state.doc.toString());
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
if (config.readOnly) extensions.push(EditorState.readOnly.of(true));
|
|
43
|
+
if (config.placeholder) extensions.push(placeholder(config.placeholder));
|
|
44
|
+
if (config.showType) extensions.push(createTypeDisplay(checker, config.dark ?? false));
|
|
45
|
+
if (config.extensions) extensions.push(...config.extensions);
|
|
46
|
+
return extensions;
|
|
47
|
+
};
|
|
48
|
+
//#endregion
|
|
49
|
+
export { buildExtensions };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { SELEditorConfig } from "./types.cjs";
|
|
2
|
+
import { createSELEditor } from "./create-editor.cjs";
|
|
3
|
+
import { buildExtensions } from "./editor-config.cjs";
|
|
4
|
+
import { selDarkTheme, selLightTheme } from "./theme.cjs";
|
|
5
|
+
import { EditorView as EditorView$1 } from "@codemirror/view";
|
|
6
|
+
export { type EditorView$1 as EditorView };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { SELEditorConfig } from "./types.mjs";
|
|
2
|
+
import { createSELEditor } from "./create-editor.mjs";
|
|
3
|
+
import { buildExtensions } from "./editor-config.mjs";
|
|
4
|
+
import { selDarkTheme, selLightTheme } from "./theme.mjs";
|
|
5
|
+
import { EditorView as EditorView$1 } from "@codemirror/view";
|
|
6
|
+
export { type EditorView$1 as EditorView };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
let _codemirror_view = require("@codemirror/view");
|
|
2
|
+
//#region src/editor/theme.ts
|
|
3
|
+
const selLightTheme = _codemirror_view.EditorView.theme({
|
|
4
|
+
"&": {
|
|
5
|
+
fontSize: "14px",
|
|
6
|
+
backgroundColor: "#ffffff",
|
|
7
|
+
color: "#1e1e1e"
|
|
8
|
+
},
|
|
9
|
+
".cm-content": {
|
|
10
|
+
caretColor: "#000000",
|
|
11
|
+
fontFamily: "'JetBrains Mono', 'Fira Code', 'Consolas', monospace",
|
|
12
|
+
padding: "4px 0"
|
|
13
|
+
},
|
|
14
|
+
"&.cm-focused .cm-cursor": { borderLeftColor: "#000000" },
|
|
15
|
+
"&.cm-focused .cm-selectionBackground, .cm-selectionBackground": { backgroundColor: "#d7d4f0" },
|
|
16
|
+
".cm-gutters": { display: "none" }
|
|
17
|
+
});
|
|
18
|
+
const selDarkTheme = _codemirror_view.EditorView.theme({
|
|
19
|
+
"&": {
|
|
20
|
+
fontSize: "14px",
|
|
21
|
+
backgroundColor: "#1e1e1e",
|
|
22
|
+
color: "#d4d4d4"
|
|
23
|
+
},
|
|
24
|
+
".cm-content": {
|
|
25
|
+
caretColor: "#ffffff",
|
|
26
|
+
fontFamily: "'JetBrains Mono', 'Fira Code', 'Consolas', monospace",
|
|
27
|
+
padding: "4px 0"
|
|
28
|
+
},
|
|
29
|
+
"&.cm-focused .cm-cursor": { borderLeftColor: "#ffffff" },
|
|
30
|
+
"&.cm-focused .cm-selectionBackground, .cm-selectionBackground": { backgroundColor: "#264f78" },
|
|
31
|
+
".cm-gutters": { display: "none" }
|
|
32
|
+
}, { dark: true });
|
|
33
|
+
//#endregion
|
|
34
|
+
exports.selDarkTheme = selDarkTheme;
|
|
35
|
+
exports.selLightTheme = selLightTheme;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as _codemirror_state0 from "@codemirror/state";
|
|
2
|
+
|
|
3
|
+
//#region src/editor/theme.d.ts
|
|
4
|
+
declare const selLightTheme: _codemirror_state0.Extension;
|
|
5
|
+
declare const selDarkTheme: _codemirror_state0.Extension;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { selDarkTheme, selLightTheme };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as _codemirror_state0 from "@codemirror/state";
|
|
2
|
+
|
|
3
|
+
//#region src/editor/theme.d.ts
|
|
4
|
+
declare const selLightTheme: _codemirror_state0.Extension;
|
|
5
|
+
declare const selDarkTheme: _codemirror_state0.Extension;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { selDarkTheme, selLightTheme };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { EditorView } from "@codemirror/view";
|
|
2
|
+
//#region src/editor/theme.ts
|
|
3
|
+
const selLightTheme = EditorView.theme({
|
|
4
|
+
"&": {
|
|
5
|
+
fontSize: "14px",
|
|
6
|
+
backgroundColor: "#ffffff",
|
|
7
|
+
color: "#1e1e1e"
|
|
8
|
+
},
|
|
9
|
+
".cm-content": {
|
|
10
|
+
caretColor: "#000000",
|
|
11
|
+
fontFamily: "'JetBrains Mono', 'Fira Code', 'Consolas', monospace",
|
|
12
|
+
padding: "4px 0"
|
|
13
|
+
},
|
|
14
|
+
"&.cm-focused .cm-cursor": { borderLeftColor: "#000000" },
|
|
15
|
+
"&.cm-focused .cm-selectionBackground, .cm-selectionBackground": { backgroundColor: "#d7d4f0" },
|
|
16
|
+
".cm-gutters": { display: "none" }
|
|
17
|
+
});
|
|
18
|
+
const selDarkTheme = EditorView.theme({
|
|
19
|
+
"&": {
|
|
20
|
+
fontSize: "14px",
|
|
21
|
+
backgroundColor: "#1e1e1e",
|
|
22
|
+
color: "#d4d4d4"
|
|
23
|
+
},
|
|
24
|
+
".cm-content": {
|
|
25
|
+
caretColor: "#ffffff",
|
|
26
|
+
fontFamily: "'JetBrains Mono', 'Fira Code', 'Consolas', monospace",
|
|
27
|
+
padding: "4px 0"
|
|
28
|
+
},
|
|
29
|
+
"&.cm-focused .cm-cursor": { borderLeftColor: "#ffffff" },
|
|
30
|
+
"&.cm-focused .cm-selectionBackground, .cm-selectionBackground": { backgroundColor: "#264f78" },
|
|
31
|
+
".cm-gutters": { display: "none" }
|
|
32
|
+
}, { dark: true });
|
|
33
|
+
//#endregion
|
|
34
|
+
export { selDarkTheme, selLightTheme };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
let _codemirror_state = require("@codemirror/state");
|
|
2
|
+
let _codemirror_view = require("@codemirror/view");
|
|
3
|
+
//#region src/editor/type-display.ts
|
|
4
|
+
const setType = _codemirror_state.StateEffect.define();
|
|
5
|
+
const typeField = _codemirror_state.StateField.define({
|
|
6
|
+
create: () => null,
|
|
7
|
+
update(value, tr) {
|
|
8
|
+
for (const e of tr.effects) if (e.is(setType)) return e.value;
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
function createTypePanel(dark) {
|
|
13
|
+
return (view) => {
|
|
14
|
+
const dom = document.createElement("div");
|
|
15
|
+
dom.className = "sel-type-display";
|
|
16
|
+
dom.style.cssText = [
|
|
17
|
+
"display: flex",
|
|
18
|
+
"align-items: center",
|
|
19
|
+
"gap: 6px",
|
|
20
|
+
`padding: 3px 8px`,
|
|
21
|
+
"font-size: 12px",
|
|
22
|
+
`font-family: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace`,
|
|
23
|
+
`color: ${dark ? "#9ca3af" : "#6b7280"}`,
|
|
24
|
+
`background: ${dark ? "#262626" : "#f9fafb"}`,
|
|
25
|
+
`border-top: 1px solid ${dark ? "#374151" : "#e5e7eb"}`
|
|
26
|
+
].join("; ");
|
|
27
|
+
const update = () => {
|
|
28
|
+
const type = view.state.field(typeField);
|
|
29
|
+
dom.textContent = "";
|
|
30
|
+
if (type) {
|
|
31
|
+
const label = document.createElement("span");
|
|
32
|
+
label.style.color = dark ? "#6b7280" : "#9ca3af";
|
|
33
|
+
label.textContent = "output";
|
|
34
|
+
const typeSpan = document.createElement("span");
|
|
35
|
+
typeSpan.style.color = dark ? "#93c5fd" : "#2563eb";
|
|
36
|
+
typeSpan.style.fontWeight = "500";
|
|
37
|
+
typeSpan.textContent = type;
|
|
38
|
+
dom.append(label, " ", typeSpan);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
update();
|
|
42
|
+
return {
|
|
43
|
+
dom,
|
|
44
|
+
update: () => {
|
|
45
|
+
update();
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function createTypeDisplay(checker, dark) {
|
|
51
|
+
let debounceTimer;
|
|
52
|
+
return [
|
|
53
|
+
typeField,
|
|
54
|
+
_codemirror_view.EditorView.updateListener.of((update) => {
|
|
55
|
+
if (!update.docChanged && !update.startState.field(typeField, false)) return;
|
|
56
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
57
|
+
debounceTimer = setTimeout(() => {
|
|
58
|
+
const doc = update.state.doc.toString().trim();
|
|
59
|
+
if (!doc) {
|
|
60
|
+
update.view.dispatch({ effects: setType.of(null) });
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const result = checker.check(doc);
|
|
64
|
+
update.view.dispatch({ effects: setType.of(result.valid ? result.type ?? null : null) });
|
|
65
|
+
}, 200);
|
|
66
|
+
}),
|
|
67
|
+
_codemirror_view.showPanel.of(createTypePanel(dark))
|
|
68
|
+
];
|
|
69
|
+
}
|
|
70
|
+
//#endregion
|
|
71
|
+
exports.createTypeDisplay = createTypeDisplay;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { StateEffect, StateField } from "@codemirror/state";
|
|
2
|
+
import { EditorView, showPanel } from "@codemirror/view";
|
|
3
|
+
//#region src/editor/type-display.ts
|
|
4
|
+
const setType = StateEffect.define();
|
|
5
|
+
const typeField = StateField.define({
|
|
6
|
+
create: () => null,
|
|
7
|
+
update(value, tr) {
|
|
8
|
+
for (const e of tr.effects) if (e.is(setType)) return e.value;
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
function createTypePanel(dark) {
|
|
13
|
+
return (view) => {
|
|
14
|
+
const dom = document.createElement("div");
|
|
15
|
+
dom.className = "sel-type-display";
|
|
16
|
+
dom.style.cssText = [
|
|
17
|
+
"display: flex",
|
|
18
|
+
"align-items: center",
|
|
19
|
+
"gap: 6px",
|
|
20
|
+
`padding: 3px 8px`,
|
|
21
|
+
"font-size: 12px",
|
|
22
|
+
`font-family: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace`,
|
|
23
|
+
`color: ${dark ? "#9ca3af" : "#6b7280"}`,
|
|
24
|
+
`background: ${dark ? "#262626" : "#f9fafb"}`,
|
|
25
|
+
`border-top: 1px solid ${dark ? "#374151" : "#e5e7eb"}`
|
|
26
|
+
].join("; ");
|
|
27
|
+
const update = () => {
|
|
28
|
+
const type = view.state.field(typeField);
|
|
29
|
+
dom.textContent = "";
|
|
30
|
+
if (type) {
|
|
31
|
+
const label = document.createElement("span");
|
|
32
|
+
label.style.color = dark ? "#6b7280" : "#9ca3af";
|
|
33
|
+
label.textContent = "output";
|
|
34
|
+
const typeSpan = document.createElement("span");
|
|
35
|
+
typeSpan.style.color = dark ? "#93c5fd" : "#2563eb";
|
|
36
|
+
typeSpan.style.fontWeight = "500";
|
|
37
|
+
typeSpan.textContent = type;
|
|
38
|
+
dom.append(label, " ", typeSpan);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
update();
|
|
42
|
+
return {
|
|
43
|
+
dom,
|
|
44
|
+
update: () => {
|
|
45
|
+
update();
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function createTypeDisplay(checker, dark) {
|
|
51
|
+
let debounceTimer;
|
|
52
|
+
return [
|
|
53
|
+
typeField,
|
|
54
|
+
EditorView.updateListener.of((update) => {
|
|
55
|
+
if (!update.docChanged && !update.startState.field(typeField, false)) return;
|
|
56
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
57
|
+
debounceTimer = setTimeout(() => {
|
|
58
|
+
const doc = update.state.doc.toString().trim();
|
|
59
|
+
if (!doc) {
|
|
60
|
+
update.view.dispatch({ effects: setType.of(null) });
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const result = checker.check(doc);
|
|
64
|
+
update.view.dispatch({ effects: setType.of(result.valid ? result.type ?? null : null) });
|
|
65
|
+
}, 200);
|
|
66
|
+
}),
|
|
67
|
+
showPanel.of(createTypePanel(dark))
|
|
68
|
+
];
|
|
69
|
+
}
|
|
70
|
+
//#endregion
|
|
71
|
+
export { createTypeDisplay };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { SELDiagnostic } from "../linting/diagnostic-mapper.cjs";
|
|
2
|
+
import { SELSchema } from "@seljs/schema";
|
|
3
|
+
import { Extension } from "@codemirror/state";
|
|
4
|
+
|
|
5
|
+
//#region src/editor/types.d.ts
|
|
6
|
+
interface SELEditorConfig {
|
|
7
|
+
/** Container element to mount into */
|
|
8
|
+
parent: HTMLElement;
|
|
9
|
+
/** Schema driving autocomplete and syntax highlighting */
|
|
10
|
+
schema: SELSchema;
|
|
11
|
+
/** Initial expression value */
|
|
12
|
+
value?: string;
|
|
13
|
+
/** Called on every expression change */
|
|
14
|
+
onChange?: (value: string) => void;
|
|
15
|
+
/** Validation function for error highlighting */
|
|
16
|
+
validate?: (expression: string) => SELDiagnostic[] | Promise<SELDiagnostic[]>;
|
|
17
|
+
/** Debounce delay for validation (default: 300ms) */
|
|
18
|
+
validateDelay?: number;
|
|
19
|
+
/** Dark mode */
|
|
20
|
+
dark?: boolean;
|
|
21
|
+
/** Whether the editor is read-only */
|
|
22
|
+
readOnly?: boolean;
|
|
23
|
+
/** Placeholder text */
|
|
24
|
+
placeholder?: string;
|
|
25
|
+
/** Show inferred output type below the editor */
|
|
26
|
+
showType?: boolean;
|
|
27
|
+
/** Additional CodeMirror extensions */
|
|
28
|
+
extensions?: Extension[];
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { SELEditorConfig };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { SELDiagnostic } from "../linting/diagnostic-mapper.mjs";
|
|
2
|
+
import { Extension } from "@codemirror/state";
|
|
3
|
+
import { SELSchema } from "@seljs/schema";
|
|
4
|
+
|
|
5
|
+
//#region src/editor/types.d.ts
|
|
6
|
+
interface SELEditorConfig {
|
|
7
|
+
/** Container element to mount into */
|
|
8
|
+
parent: HTMLElement;
|
|
9
|
+
/** Schema driving autocomplete and syntax highlighting */
|
|
10
|
+
schema: SELSchema;
|
|
11
|
+
/** Initial expression value */
|
|
12
|
+
value?: string;
|
|
13
|
+
/** Called on every expression change */
|
|
14
|
+
onChange?: (value: string) => void;
|
|
15
|
+
/** Validation function for error highlighting */
|
|
16
|
+
validate?: (expression: string) => SELDiagnostic[] | Promise<SELDiagnostic[]>;
|
|
17
|
+
/** Debounce delay for validation (default: 300ms) */
|
|
18
|
+
validateDelay?: number;
|
|
19
|
+
/** Dark mode */
|
|
20
|
+
dark?: boolean;
|
|
21
|
+
/** Whether the editor is read-only */
|
|
22
|
+
readOnly?: boolean;
|
|
23
|
+
/** Placeholder text */
|
|
24
|
+
placeholder?: string;
|
|
25
|
+
/** Show inferred output type below the editor */
|
|
26
|
+
showType?: boolean;
|
|
27
|
+
/** Additional CodeMirror extensions */
|
|
28
|
+
extensions?: Extension[];
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { SELEditorConfig };
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_tokenizer_config = require("./language/tokenizer-config.cjs");
|
|
3
|
+
const require_schema_completion = require("./completion/schema-completion.cjs");
|
|
4
|
+
require("./completion/index.cjs");
|
|
5
|
+
const require_sel_linter = require("./linting/sel-linter.cjs");
|
|
6
|
+
const require_diagnostic_mapper = require("./linting/diagnostic-mapper.cjs");
|
|
7
|
+
require("./linting/index.cjs");
|
|
8
|
+
const require_theme = require("./editor/theme.cjs");
|
|
9
|
+
const require_editor_config = require("./editor/editor-config.cjs");
|
|
10
|
+
const require_create_editor = require("./editor/create-editor.cjs");
|
|
11
|
+
require("./editor/index.cjs");
|
|
12
|
+
exports.SchemaCompletionProvider = require_schema_completion.SchemaCompletionProvider;
|
|
13
|
+
exports.buildExtensions = require_editor_config.buildExtensions;
|
|
14
|
+
exports.createSELEditor = require_create_editor.createSELEditor;
|
|
15
|
+
exports.createSELLinter = require_sel_linter.createSELLinter;
|
|
16
|
+
exports.createSchemaCompletion = require_schema_completion.createSchemaCompletion;
|
|
17
|
+
exports.createTokenizerConfig = require_tokenizer_config.createTokenizerConfig;
|
|
18
|
+
exports.mapCheckResult = require_diagnostic_mapper.mapCheckResult;
|
|
19
|
+
exports.selDarkTheme = require_theme.selDarkTheme;
|
|
20
|
+
exports.selLightTheme = require_theme.selLightTheme;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { TokenizerConfig, createTokenizerConfig } from "./language/tokenizer-config.cjs";
|
|
2
|
+
import { SchemaCompletionProvider, createSchemaCompletion } from "./completion/schema-completion.cjs";
|
|
3
|
+
import { SELDiagnostic, mapCheckResult } from "./linting/diagnostic-mapper.cjs";
|
|
4
|
+
import { SELLinterOptions, createSELLinter } from "./linting/sel-linter.cjs";
|
|
5
|
+
import { SELEditorConfig } from "./editor/types.cjs";
|
|
6
|
+
import { createSELEditor } from "./editor/create-editor.cjs";
|
|
7
|
+
import { buildExtensions } from "./editor/editor-config.cjs";
|
|
8
|
+
import { selDarkTheme, selLightTheme } from "./editor/theme.cjs";
|
|
9
|
+
import { EditorView } from "./editor/index.cjs";
|
|
10
|
+
export { EditorView, SELDiagnostic, SELEditorConfig, SELLinterOptions, SchemaCompletionProvider, TokenizerConfig, buildExtensions, createSELEditor, createSELLinter, createSchemaCompletion, createTokenizerConfig, mapCheckResult, selDarkTheme, selLightTheme };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { TokenizerConfig, createTokenizerConfig } from "./language/tokenizer-config.mjs";
|
|
2
|
+
import { SchemaCompletionProvider, createSchemaCompletion } from "./completion/schema-completion.mjs";
|
|
3
|
+
import { SELDiagnostic, mapCheckResult } from "./linting/diagnostic-mapper.mjs";
|
|
4
|
+
import { SELLinterOptions, createSELLinter } from "./linting/sel-linter.mjs";
|
|
5
|
+
import { SELEditorConfig } from "./editor/types.mjs";
|
|
6
|
+
import { createSELEditor } from "./editor/create-editor.mjs";
|
|
7
|
+
import { buildExtensions } from "./editor/editor-config.mjs";
|
|
8
|
+
import { selDarkTheme, selLightTheme } from "./editor/theme.mjs";
|
|
9
|
+
import { EditorView } from "./editor/index.mjs";
|
|
10
|
+
export { EditorView, SELDiagnostic, SELEditorConfig, SELLinterOptions, SchemaCompletionProvider, TokenizerConfig, buildExtensions, createSELEditor, createSELLinter, createSchemaCompletion, createTokenizerConfig, mapCheckResult, selDarkTheme, selLightTheme };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createTokenizerConfig } from "./language/tokenizer-config.mjs";
|
|
2
|
+
import { SchemaCompletionProvider, createSchemaCompletion } from "./completion/schema-completion.mjs";
|
|
3
|
+
import "./completion/index.mjs";
|
|
4
|
+
import { createSELLinter } from "./linting/sel-linter.mjs";
|
|
5
|
+
import { mapCheckResult } from "./linting/diagnostic-mapper.mjs";
|
|
6
|
+
import "./linting/index.mjs";
|
|
7
|
+
import { selDarkTheme, selLightTheme } from "./editor/theme.mjs";
|
|
8
|
+
import { buildExtensions } from "./editor/editor-config.mjs";
|
|
9
|
+
import { createSELEditor } from "./editor/create-editor.mjs";
|
|
10
|
+
import "./editor/index.mjs";
|
|
11
|
+
export { SchemaCompletionProvider, buildExtensions, createSELEditor, createSELLinter, createSchemaCompletion, createTokenizerConfig, mapCheckResult, selDarkTheme, selLightTheme };
|