@wallarm-org/design-system 1.30.0 → 1.31.0
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/components/CodeEditor/CodeEditorContent.d.ts +17 -0
- package/dist/components/CodeEditor/CodeEditorContent.js +197 -0
- package/dist/components/CodeEditor/CodeEditorContext.d.ts +17 -0
- package/dist/components/CodeEditor/CodeEditorContext.js +8 -0
- package/dist/components/CodeEditor/CodeEditorRoot.d.ts +77 -0
- package/dist/components/CodeEditor/CodeEditorRoot.js +203 -0
- package/dist/components/CodeEditor/classes.d.ts +21 -0
- package/dist/components/CodeEditor/classes.js +41 -0
- package/dist/components/CodeEditor/engine/SearchPanel.d.ts +13 -0
- package/dist/components/CodeEditor/engine/SearchPanel.js +201 -0
- package/dist/components/CodeEditor/engine/adapterPainter.d.ts +23 -0
- package/dist/components/CodeEditor/engine/adapterPainter.js +110 -0
- package/dist/components/CodeEditor/engine/babelSyntax.d.ts +15 -0
- package/dist/components/CodeEditor/engine/babelSyntax.js +54 -0
- package/dist/components/CodeEditor/engine/completion.d.ts +17 -0
- package/dist/components/CodeEditor/engine/completion.js +129 -0
- package/dist/components/CodeEditor/engine/contentAttributes.d.ts +12 -0
- package/dist/components/CodeEditor/engine/contentAttributes.js +24 -0
- package/dist/components/CodeEditor/engine/diagnostics.d.ts +73 -0
- package/dist/components/CodeEditor/engine/diagnostics.js +327 -0
- package/dist/components/CodeEditor/engine/diff.d.ts +37 -0
- package/dist/components/CodeEditor/engine/diff.js +145 -0
- package/dist/components/CodeEditor/engine/folds.d.ts +25 -0
- package/dist/components/CodeEditor/engine/folds.js +458 -0
- package/dist/components/CodeEditor/engine/gutters.d.ts +22 -0
- package/dist/components/CodeEditor/engine/gutters.js +160 -0
- package/dist/components/CodeEditor/engine/index.d.ts +12 -0
- package/dist/components/CodeEditor/engine/index.js +387 -0
- package/dist/components/CodeEditor/engine/languages/http/index.d.ts +20 -0
- package/dist/components/CodeEditor/engine/languages/http/index.js +69 -0
- package/dist/components/CodeEditor/engine/languages/http/parser.d.ts +2 -0
- package/dist/components/CodeEditor/engine/languages/http/parser.js +31 -0
- package/dist/components/CodeEditor/engine/languages/http/parser.terms.d.ts +1 -0
- package/dist/components/CodeEditor/engine/languages/http/parser.terms.js +2 -0
- package/dist/components/CodeEditor/engine/languages/index.d.ts +8 -0
- package/dist/components/CodeEditor/engine/languages/index.js +41 -0
- package/dist/components/CodeEditor/engine/languages/json.d.ts +8 -0
- package/dist/components/CodeEditor/engine/languages/json.js +11 -0
- package/dist/components/CodeEditor/engine/languages/jsonPointers.d.ts +47 -0
- package/dist/components/CodeEditor/engine/languages/jsonPointers.js +125 -0
- package/dist/components/CodeEditor/engine/languages/yaml.d.ts +4 -0
- package/dist/components/CodeEditor/engine/languages/yaml.js +11 -0
- package/dist/components/CodeEditor/engine/lines.d.ts +22 -0
- package/dist/components/CodeEditor/engine/lines.js +131 -0
- package/dist/components/CodeEditor/engine/luaSyntax.d.ts +14 -0
- package/dist/components/CodeEditor/engine/luaSyntax.js +36 -0
- package/dist/components/CodeEditor/engine/positions.d.ts +19 -0
- package/dist/components/CodeEditor/engine/positions.js +22 -0
- package/dist/components/CodeEditor/engine/schema/complete.d.ts +12 -0
- package/dist/components/CodeEditor/engine/schema/complete.js +211 -0
- package/dist/components/CodeEditor/engine/schema/hover.d.ts +12 -0
- package/dist/components/CodeEditor/engine/schema/hover.js +73 -0
- package/dist/components/CodeEditor/engine/schema/loadSchema.d.ts +19 -0
- package/dist/components/CodeEditor/engine/schema/loadSchema.js +32 -0
- package/dist/components/CodeEditor/engine/schema/validate.d.ts +9 -0
- package/dist/components/CodeEditor/engine/schema/validate.js +67 -0
- package/dist/components/CodeEditor/engine/search.d.ts +13 -0
- package/dist/components/CodeEditor/engine/search.js +84 -0
- package/dist/components/CodeEditor/engine/searchMatches.d.ts +8 -0
- package/dist/components/CodeEditor/engine/searchMatches.js +15 -0
- package/dist/components/CodeEditor/engine/theme.d.ts +8 -0
- package/dist/components/CodeEditor/engine/theme.js +89 -0
- package/dist/components/CodeEditor/engine/types.d.ts +44 -0
- package/dist/components/CodeEditor/engine/types.js +0 -0
- package/dist/components/CodeEditor/hooks/useCodeEditor.d.ts +6 -0
- package/dist/components/CodeEditor/hooks/useCodeEditor.js +3 -0
- package/dist/components/CodeEditor/index.d.ts +6 -0
- package/dist/components/CodeEditor/index.js +5 -0
- package/dist/components/CodeEditor/lib/PortalOutlet.d.ts +11 -0
- package/dist/components/CodeEditor/lib/PortalOutlet.js +11 -0
- package/dist/components/CodeEditor/lib/httpCompletions.d.ts +7 -0
- package/dist/components/CodeEditor/lib/httpCompletions.js +102 -0
- package/dist/components/CodeEditor/lib/httpCompletionsData.d.ts +29 -0
- package/dist/components/CodeEditor/lib/httpCompletionsData.js +650 -0
- package/dist/components/CodeEditor/lib/keyboardHint.d.ts +5 -0
- package/dist/components/CodeEditor/lib/keyboardHint.js +2 -0
- package/dist/components/CodeEditor/lib/loadEngine.d.ts +7 -0
- package/dist/components/CodeEditor/lib/loadEngine.js +9 -0
- package/dist/components/CodeEditor/lib/portalRegistry.d.ts +20 -0
- package/dist/components/CodeEditor/lib/portalRegistry.js +47 -0
- package/dist/components/CodeEditor/lib/splitContentProps.d.ts +12 -0
- package/dist/components/CodeEditor/lib/splitContentProps.js +28 -0
- package/dist/components/CodeEditor/types.d.ts +72 -0
- package/dist/components/CodeEditor/types.js +0 -0
- package/dist/components/CodeSnippet/CodeSnippetCode.js +6 -23
- package/dist/components/CodeSnippet/CodeSnippetCopyButton.js +4 -3
- package/dist/components/CodeSnippet/CodeSnippetFrameContext.d.ts +25 -0
- package/dist/components/CodeSnippet/CodeSnippetFrameContext.js +3 -0
- package/dist/components/CodeSnippet/CodeSnippetFullscreenButton.js +2 -2
- package/dist/components/CodeSnippet/CodeSnippetRoot.d.ts +3 -5
- package/dist/components/CodeSnippet/CodeSnippetRoot.js +56 -50
- package/dist/components/CodeSnippet/CodeSnippetShowMoreButton.js +7 -5
- package/dist/components/CodeSnippet/CodeSnippetWrapButton.js +2 -2
- package/dist/components/CodeSnippet/adapters/highlightjs.js +1 -0
- package/dist/components/CodeSnippet/adapters/prism.js +3 -1
- package/dist/components/CodeSnippet/adapters/shiki.js +1 -0
- package/dist/components/CodeSnippet/adapters/types.d.ts +3 -3
- package/dist/components/CodeSnippet/classes.d.ts +3 -0
- package/dist/components/CodeSnippet/classes.js +14 -0
- package/dist/components/CodeSnippet/hooks/index.d.ts +1 -0
- package/dist/components/CodeSnippet/hooks/index.js +1 -0
- package/dist/components/CodeSnippet/hooks/useCodeSnippetFrame.d.ts +2 -0
- package/dist/components/CodeSnippet/hooks/useCodeSnippetFrame.js +8 -0
- package/dist/components/CodeSnippet/index.d.ts +2 -1
- package/dist/components/CodeSnippet/index.js +1 -1
- package/dist/components/CodeSnippet/internal/CodeSnippetFrame.d.ts +22 -0
- package/dist/components/CodeSnippet/internal/CodeSnippetFrame.js +81 -0
- package/dist/components/CodeSnippet/internal/CodeToken.d.ts +2 -1
- package/dist/components/CodeSnippet/internal/CodeToken.js +1 -1
- package/dist/components/CodeSnippet/internal/FoldSummary.d.ts +11 -0
- package/dist/components/CodeSnippet/internal/FoldSummary.js +27 -0
- package/dist/components/CodeSnippet/internal/FoldToggle.d.ts +2 -0
- package/dist/components/CodeSnippet/internal/FoldToggle.js +2 -1
- package/dist/components/CodeSnippet/internal/index.d.ts +1 -0
- package/dist/components/CodeSnippet/internal/index.js +1 -0
- package/dist/components/CodeSnippet/lib/foldUtils.d.ts +9 -2
- package/dist/components/CodeSnippet/lib/foldUtils.js +2 -2
- package/dist/components/CodeSnippet/lib/showMore.d.ts +7 -0
- package/dist/components/CodeSnippet/lib/showMore.js +7 -0
- package/dist/components/Copyable/Copyable.d.ts +5 -2
- package/dist/components/Copyable/Copyable.js +1 -1
- package/dist/metadata/components.json +1235 -5
- package/package.json +24 -1
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback } from "react";
|
|
3
|
+
import { SearchQuery, closeSearchPanel, findNext, findPrevious, replaceAll, replaceNext, setSearchQuery } from "@codemirror/search";
|
|
4
|
+
import { EditorView, runScopeHandlers } from "@codemirror/view";
|
|
5
|
+
import { ChevronDown } from "../../../icons/ChevronDown.js";
|
|
6
|
+
import { ChevronUp } from "../../../icons/ChevronUp.js";
|
|
7
|
+
import { X } from "../../../icons/X.js";
|
|
8
|
+
import { cn } from "../../../utils/cn.js";
|
|
9
|
+
import { Button } from "../../Button/index.js";
|
|
10
|
+
import { Input } from "../../Input/index.js";
|
|
11
|
+
import { ToggleButton } from "../../ToggleButton/index.js";
|
|
12
|
+
import { countMatches, matchCountMessage } from "./searchMatches.js";
|
|
13
|
+
const rowClassName = 'flex h-32 items-center gap-4 px-6';
|
|
14
|
+
const SearchPanel = ({ view, query, matchCount, readOnly, testId })=>{
|
|
15
|
+
const slot = (name)=>testId ? `${testId}--${name}` : void 0;
|
|
16
|
+
const focusOnMount = useCallback((input)=>{
|
|
17
|
+
input?.focus();
|
|
18
|
+
input?.select();
|
|
19
|
+
}, []);
|
|
20
|
+
const updateQuery = (patch)=>{
|
|
21
|
+
const next = new SearchQuery({
|
|
22
|
+
search: query.search,
|
|
23
|
+
replace: query.replace,
|
|
24
|
+
caseSensitive: query.caseSensitive,
|
|
25
|
+
regexp: query.regexp,
|
|
26
|
+
wholeWord: query.wholeWord,
|
|
27
|
+
literal: query.literal,
|
|
28
|
+
...patch
|
|
29
|
+
});
|
|
30
|
+
if (next.eq(query)) return;
|
|
31
|
+
const effects = [
|
|
32
|
+
setSearchQuery.of(next)
|
|
33
|
+
];
|
|
34
|
+
const announce = '' === next.search ? [] : [
|
|
35
|
+
EditorView.announce.of(next.valid ? matchCountMessage(countMatches(view.state, next)) : 'Invalid regular expression')
|
|
36
|
+
];
|
|
37
|
+
view.dispatch({
|
|
38
|
+
effects: [
|
|
39
|
+
...effects,
|
|
40
|
+
...announce
|
|
41
|
+
]
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
const handleKeyDown = (event, onEnter)=>{
|
|
45
|
+
if (event.nativeEvent.isComposing || 229 === event.keyCode) return;
|
|
46
|
+
if (runScopeHandlers(view, event.nativeEvent, 'search-panel')) return void event.preventDefault();
|
|
47
|
+
if ('Enter' === event.key) {
|
|
48
|
+
event.preventDefault();
|
|
49
|
+
onEnter(event.shiftKey);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const handleFindKeyDown = (event)=>handleKeyDown(event, (shift)=>(shift ? findPrevious : findNext)(view));
|
|
53
|
+
const handleReplaceKeyDown = (event)=>handleKeyDown(event, ()=>replaceNext(view));
|
|
54
|
+
const handlePanelKeyDown = (event)=>{
|
|
55
|
+
if (event.target instanceof HTMLInputElement) return;
|
|
56
|
+
if (runScopeHandlers(view, event.nativeEvent, 'search-panel')) event.preventDefault();
|
|
57
|
+
};
|
|
58
|
+
const canSearch = query.valid;
|
|
59
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
60
|
+
role: "search",
|
|
61
|
+
"aria-label": "Find and replace",
|
|
62
|
+
"data-slot": "code-editor-search",
|
|
63
|
+
"data-testid": slot('search'),
|
|
64
|
+
className: "flex flex-col border-b border-border-primary-light code-snippet-bg font-sans",
|
|
65
|
+
onKeyDown: handlePanelKeyDown,
|
|
66
|
+
children: [
|
|
67
|
+
/*#__PURE__*/ jsxs("div", {
|
|
68
|
+
className: rowClassName,
|
|
69
|
+
children: [
|
|
70
|
+
/*#__PURE__*/ jsx(Input, {
|
|
71
|
+
ref: focusOnMount,
|
|
72
|
+
size: "small",
|
|
73
|
+
className: "w-240",
|
|
74
|
+
placeholder: "Find",
|
|
75
|
+
"aria-label": "Find",
|
|
76
|
+
"main-field": "true",
|
|
77
|
+
value: query.search,
|
|
78
|
+
error: '' !== query.search && !canSearch,
|
|
79
|
+
"data-testid": slot('search-input'),
|
|
80
|
+
onChange: (event)=>updateQuery({
|
|
81
|
+
search: event.target.value
|
|
82
|
+
}),
|
|
83
|
+
onKeyDown: handleFindKeyDown
|
|
84
|
+
}),
|
|
85
|
+
/*#__PURE__*/ jsx("span", {
|
|
86
|
+
"aria-hidden": "true",
|
|
87
|
+
className: cn('min-w-72 text-xs text-text-secondary whitespace-nowrap', !canSearch && 'invisible'),
|
|
88
|
+
"data-testid": slot('search-count'),
|
|
89
|
+
children: null === matchCount ? '' : matchCountMessage(matchCount)
|
|
90
|
+
}),
|
|
91
|
+
/*#__PURE__*/ jsx(ToggleButton, {
|
|
92
|
+
variant: "ghost",
|
|
93
|
+
color: "neutral",
|
|
94
|
+
size: "small",
|
|
95
|
+
active: query.caseSensitive,
|
|
96
|
+
"aria-pressed": query.caseSensitive,
|
|
97
|
+
"aria-label": "Match case",
|
|
98
|
+
"data-testid": slot('search-case'),
|
|
99
|
+
onToggle: (active)=>updateQuery({
|
|
100
|
+
caseSensitive: active
|
|
101
|
+
}),
|
|
102
|
+
children: "Aa"
|
|
103
|
+
}),
|
|
104
|
+
/*#__PURE__*/ jsx(ToggleButton, {
|
|
105
|
+
variant: "ghost",
|
|
106
|
+
color: "neutral",
|
|
107
|
+
size: "small",
|
|
108
|
+
active: query.wholeWord,
|
|
109
|
+
"aria-pressed": query.wholeWord,
|
|
110
|
+
"aria-label": "Match whole word",
|
|
111
|
+
"data-testid": slot('search-whole-word'),
|
|
112
|
+
onToggle: (active)=>updateQuery({
|
|
113
|
+
wholeWord: active
|
|
114
|
+
}),
|
|
115
|
+
children: "W"
|
|
116
|
+
}),
|
|
117
|
+
/*#__PURE__*/ jsx(ToggleButton, {
|
|
118
|
+
variant: "ghost",
|
|
119
|
+
color: "neutral",
|
|
120
|
+
size: "small",
|
|
121
|
+
active: query.regexp,
|
|
122
|
+
"aria-pressed": query.regexp,
|
|
123
|
+
"aria-label": "Use regular expression",
|
|
124
|
+
"data-testid": slot('search-regexp'),
|
|
125
|
+
onToggle: (active)=>updateQuery({
|
|
126
|
+
regexp: active
|
|
127
|
+
}),
|
|
128
|
+
children: ".*"
|
|
129
|
+
}),
|
|
130
|
+
/*#__PURE__*/ jsx(Button, {
|
|
131
|
+
variant: "ghost",
|
|
132
|
+
color: "neutral",
|
|
133
|
+
size: "small",
|
|
134
|
+
"aria-label": "Previous match",
|
|
135
|
+
disabled: !canSearch,
|
|
136
|
+
"data-testid": slot('search-previous'),
|
|
137
|
+
onClick: ()=>findPrevious(view),
|
|
138
|
+
children: /*#__PURE__*/ jsx(ChevronUp, {})
|
|
139
|
+
}),
|
|
140
|
+
/*#__PURE__*/ jsx(Button, {
|
|
141
|
+
variant: "ghost",
|
|
142
|
+
color: "neutral",
|
|
143
|
+
size: "small",
|
|
144
|
+
"aria-label": "Next match",
|
|
145
|
+
disabled: !canSearch,
|
|
146
|
+
"data-testid": slot('search-next'),
|
|
147
|
+
onClick: ()=>findNext(view),
|
|
148
|
+
children: /*#__PURE__*/ jsx(ChevronDown, {})
|
|
149
|
+
}),
|
|
150
|
+
/*#__PURE__*/ jsx(Button, {
|
|
151
|
+
variant: "ghost",
|
|
152
|
+
color: "neutral",
|
|
153
|
+
size: "small",
|
|
154
|
+
className: "ml-auto",
|
|
155
|
+
"aria-label": "Close search",
|
|
156
|
+
"data-testid": slot('search-close'),
|
|
157
|
+
onClick: ()=>closeSearchPanel(view),
|
|
158
|
+
children: /*#__PURE__*/ jsx(X, {})
|
|
159
|
+
})
|
|
160
|
+
]
|
|
161
|
+
}),
|
|
162
|
+
!readOnly && /*#__PURE__*/ jsxs("div", {
|
|
163
|
+
className: rowClassName,
|
|
164
|
+
children: [
|
|
165
|
+
/*#__PURE__*/ jsx(Input, {
|
|
166
|
+
size: "small",
|
|
167
|
+
className: "w-240",
|
|
168
|
+
placeholder: "Replace",
|
|
169
|
+
"aria-label": "Replace",
|
|
170
|
+
value: query.replace,
|
|
171
|
+
"data-testid": slot('replace-input'),
|
|
172
|
+
onChange: (event)=>updateQuery({
|
|
173
|
+
replace: event.target.value
|
|
174
|
+
}),
|
|
175
|
+
onKeyDown: handleReplaceKeyDown
|
|
176
|
+
}),
|
|
177
|
+
/*#__PURE__*/ jsx(Button, {
|
|
178
|
+
variant: "ghost",
|
|
179
|
+
color: "neutral",
|
|
180
|
+
size: "small",
|
|
181
|
+
disabled: !canSearch,
|
|
182
|
+
"data-testid": slot('replace-next'),
|
|
183
|
+
onClick: ()=>replaceNext(view),
|
|
184
|
+
children: "Replace"
|
|
185
|
+
}),
|
|
186
|
+
/*#__PURE__*/ jsx(Button, {
|
|
187
|
+
variant: "ghost",
|
|
188
|
+
color: "neutral",
|
|
189
|
+
size: "small",
|
|
190
|
+
disabled: !canSearch,
|
|
191
|
+
"data-testid": slot('replace-all'),
|
|
192
|
+
onClick: ()=>replaceAll(view),
|
|
193
|
+
children: "Replace all"
|
|
194
|
+
})
|
|
195
|
+
]
|
|
196
|
+
})
|
|
197
|
+
]
|
|
198
|
+
});
|
|
199
|
+
};
|
|
200
|
+
SearchPanel.displayName = 'SearchPanel';
|
|
201
|
+
export { SearchPanel };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type Extension, type Text } from '@codemirror/state';
|
|
2
|
+
import { type DecorationSet, type EditorView } from '@codemirror/view';
|
|
3
|
+
import type { HighlightResult, SyntaxAdapter } from '../../CodeSnippet/adapters/types';
|
|
4
|
+
/** Delay between the last document change and the adapter re-highlight (spec §7.3). */
|
|
5
|
+
export declare const DEFAULT_PAINT_DEBOUNCE_MS = 100;
|
|
6
|
+
/**
|
|
7
|
+
* Converts an adapter result (tokens per line, offsets implied by `content.length`)
|
|
8
|
+
* into mark decorations over `doc`. Lines or token text beyond the document are clamped,
|
|
9
|
+
* so a result that does not exactly match the document never throws.
|
|
10
|
+
*/
|
|
11
|
+
export declare const buildTokenDecorations: (doc: Text, result: HighlightResult) => DecorationSet;
|
|
12
|
+
/**
|
|
13
|
+
* Paints `SyntaxAdapter` tokens as mark decorations (spec §7.3, D3).
|
|
14
|
+
* Every call returns a new plugin spec, so reconfiguring the painter compartment with a
|
|
15
|
+
* new adapter/language destroys the old instance and highlights again from scratch.
|
|
16
|
+
*/
|
|
17
|
+
export declare const adapterPainter: (config: {
|
|
18
|
+
adapter: SyntaxAdapter<string>;
|
|
19
|
+
language: string;
|
|
20
|
+
debounceMs?: number;
|
|
21
|
+
}) => Extension;
|
|
22
|
+
/** The painter's current token decorations (tests / diagnostics only). */
|
|
23
|
+
export declare const getPaintedDecorations: (view: EditorView) => DecorationSet;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { RangeSetBuilder, StateEffect } from "@codemirror/state";
|
|
2
|
+
import { Decoration, ViewPlugin } from "@codemirror/view";
|
|
3
|
+
import { TOKEN_CLASSES } from "../../CodeSnippet/internal/CodeToken.js";
|
|
4
|
+
const DEFAULT_PAINT_DEBOUNCE_MS = 100;
|
|
5
|
+
const paintEffect = StateEffect.define();
|
|
6
|
+
const markCache = new Map();
|
|
7
|
+
const markFor = (className)=>{
|
|
8
|
+
let mark = markCache.get(className);
|
|
9
|
+
if (!mark) {
|
|
10
|
+
mark = Decoration.mark({
|
|
11
|
+
class: className
|
|
12
|
+
});
|
|
13
|
+
markCache.set(className, mark);
|
|
14
|
+
}
|
|
15
|
+
return mark;
|
|
16
|
+
};
|
|
17
|
+
const tokenClass = (className, type)=>{
|
|
18
|
+
if (void 0 !== className) return '' === className ? null : className;
|
|
19
|
+
if ('plain' === type) return null;
|
|
20
|
+
return TOKEN_CLASSES[type];
|
|
21
|
+
};
|
|
22
|
+
const buildTokenDecorations = (doc, result)=>{
|
|
23
|
+
const builder = new RangeSetBuilder();
|
|
24
|
+
const lineCount = Math.min(result.tokens.length, doc.lines);
|
|
25
|
+
for(let index = 0; index < lineCount; index++){
|
|
26
|
+
const line = doc.line(index + 1);
|
|
27
|
+
const lineTokens = result.tokens[index] ?? [];
|
|
28
|
+
let offset = line.from;
|
|
29
|
+
for (const token of lineTokens){
|
|
30
|
+
const from = offset;
|
|
31
|
+
offset += token.content.length;
|
|
32
|
+
if (from >= line.to) break;
|
|
33
|
+
const to = Math.min(offset, line.to);
|
|
34
|
+
if (to <= from) continue;
|
|
35
|
+
const className = tokenClass(token.className, token.type);
|
|
36
|
+
if (className) builder.add(from, to, markFor(className));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return builder.finish();
|
|
40
|
+
};
|
|
41
|
+
class PainterPluginValue {
|
|
42
|
+
decorations = Decoration.none;
|
|
43
|
+
view;
|
|
44
|
+
config;
|
|
45
|
+
docVersion = 0;
|
|
46
|
+
timer = null;
|
|
47
|
+
destroyed = false;
|
|
48
|
+
errorReported = false;
|
|
49
|
+
constructor(view, config){
|
|
50
|
+
this.view = view;
|
|
51
|
+
this.config = config;
|
|
52
|
+
this.request();
|
|
53
|
+
}
|
|
54
|
+
update(update) {
|
|
55
|
+
if (update.docChanged) {
|
|
56
|
+
this.decorations = this.decorations.map(update.changes);
|
|
57
|
+
this.docVersion++;
|
|
58
|
+
this.schedule();
|
|
59
|
+
}
|
|
60
|
+
for (const transaction of update.transactions)for (const effect of transaction.effects)if (effect.is(paintEffect)) this.decorations = effect.value;
|
|
61
|
+
}
|
|
62
|
+
destroy() {
|
|
63
|
+
this.destroyed = true;
|
|
64
|
+
if (null !== this.timer) clearTimeout(this.timer);
|
|
65
|
+
this.timer = null;
|
|
66
|
+
}
|
|
67
|
+
schedule() {
|
|
68
|
+
if (null !== this.timer) clearTimeout(this.timer);
|
|
69
|
+
this.timer = setTimeout(()=>{
|
|
70
|
+
this.timer = null;
|
|
71
|
+
this.request();
|
|
72
|
+
}, this.config.debounceMs);
|
|
73
|
+
}
|
|
74
|
+
request() {
|
|
75
|
+
const version = this.docVersion;
|
|
76
|
+
const doc = this.view.state.doc;
|
|
77
|
+
const { adapter, language } = this.config;
|
|
78
|
+
let pending;
|
|
79
|
+
try {
|
|
80
|
+
pending = adapter.highlight(doc.toString(), language);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
this.reportError(error);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
pending.then((result)=>{
|
|
86
|
+
if (this.destroyed || version !== this.docVersion) return;
|
|
87
|
+
this.view.dispatch({
|
|
88
|
+
effects: paintEffect.of(buildTokenDecorations(doc, result))
|
|
89
|
+
});
|
|
90
|
+
}, (error)=>{
|
|
91
|
+
if (this.destroyed) return;
|
|
92
|
+
this.reportError(error);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
reportError(error) {
|
|
96
|
+
if (this.errorReported) return;
|
|
97
|
+
this.errorReported = true;
|
|
98
|
+
console.error(`[CodeEditor] Syntax adapter "${this.config.adapter.name}" failed to highlight "${this.config.language}"; keeping previous colours.`, error);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const painterPlugin = ViewPlugin.fromClass(PainterPluginValue, {
|
|
102
|
+
decorations: (plugin)=>plugin.decorations
|
|
103
|
+
});
|
|
104
|
+
const adapterPainter = (config)=>painterPlugin.of({
|
|
105
|
+
adapter: config.adapter,
|
|
106
|
+
language: config.language,
|
|
107
|
+
debounceMs: config.debounceMs ?? DEFAULT_PAINT_DEBOUNCE_MS
|
|
108
|
+
});
|
|
109
|
+
const getPaintedDecorations = (view)=>view.plugin(painterPlugin)?.decorations ?? Decoration.none;
|
|
110
|
+
export { DEFAULT_PAINT_DEBOUNCE_MS, adapterPainter, buildTokenDecorations, getPaintedDecorations };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Diagnostic } from '@codemirror/lint';
|
|
2
|
+
/** Languages whose syntax errors come from `@babel/parser` (spec §14 A5). */
|
|
3
|
+
export type BabelLanguage = 'javascript' | 'typescript';
|
|
4
|
+
type BabelParser = typeof import('@babel/parser');
|
|
5
|
+
/** Cached `import('@babel/parser')` — loaded only for javascript/typescript documents. A failed load is retried next time. */
|
|
6
|
+
export declare const loadBabelParser: () => Promise<BabelParser>;
|
|
7
|
+
/**
|
|
8
|
+
* Syntax diagnostics for `text` from an already loaded Babel parser: recovered `errors[]` plus
|
|
9
|
+
* a thrown fatal error, each at `error.pos` covering one character (clamped to the text end),
|
|
10
|
+
* sorted, one per position. `base` shifts offsets into the document.
|
|
11
|
+
*/
|
|
12
|
+
export declare const babelDiagnostics: (parser: BabelParser, text: string, language: BabelLanguage, base?: number) => Diagnostic[];
|
|
13
|
+
/** Loads Babel (cached) and returns the syntax diagnostics of `text`. */
|
|
14
|
+
export declare const babelSyntaxDiagnostics: (text: string, language: BabelLanguage) => Promise<Diagnostic[]>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
let pending = null;
|
|
2
|
+
const loadBabelParser = ()=>{
|
|
3
|
+
if (!pending) pending = import("@babel/parser").catch((error)=>{
|
|
4
|
+
pending = null;
|
|
5
|
+
throw error;
|
|
6
|
+
});
|
|
7
|
+
return pending;
|
|
8
|
+
};
|
|
9
|
+
const optionsFor = (language)=>({
|
|
10
|
+
sourceType: 'module',
|
|
11
|
+
errorRecovery: true,
|
|
12
|
+
allowReturnOutsideFunction: true,
|
|
13
|
+
plugins: "typescript" === language ? [
|
|
14
|
+
"typescript",
|
|
15
|
+
'explicitResourceManagement',
|
|
16
|
+
'decorators-legacy',
|
|
17
|
+
'decoratorAutoAccessors'
|
|
18
|
+
] : [
|
|
19
|
+
'jsx',
|
|
20
|
+
'explicitResourceManagement',
|
|
21
|
+
'decorators',
|
|
22
|
+
'decoratorAutoAccessors'
|
|
23
|
+
]
|
|
24
|
+
});
|
|
25
|
+
const isPositionedError = (value)=>'object' == typeof value && null !== value && 'number' == typeof value.pos && 'string' == typeof value.message;
|
|
26
|
+
const stripLocation = (message)=>message.replace(/ \(\d+:\d+\)$/, '');
|
|
27
|
+
const babelDiagnostics = (parser, text, language, base = 0)=>{
|
|
28
|
+
const errors = [];
|
|
29
|
+
try {
|
|
30
|
+
const result = parser.parse(text, optionsFor(language));
|
|
31
|
+
errors.push(...result.errors ?? []);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
errors.push(error);
|
|
34
|
+
}
|
|
35
|
+
const seen = new Set();
|
|
36
|
+
const out = [];
|
|
37
|
+
for (const error of errors){
|
|
38
|
+
if (!isPositionedError(error)) continue;
|
|
39
|
+
const from = Math.min(Math.max(error.pos, 0), text.length);
|
|
40
|
+
if (!seen.has(from)) {
|
|
41
|
+
seen.add(from);
|
|
42
|
+
out.push({
|
|
43
|
+
from: base + from,
|
|
44
|
+
to: base + Math.min(from + 1, text.length),
|
|
45
|
+
severity: 'error',
|
|
46
|
+
source: 'syntax',
|
|
47
|
+
message: stripLocation(error.message)
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return out.sort((a, b)=>a.from - b.from);
|
|
52
|
+
};
|
|
53
|
+
const babelSyntaxDiagnostics = async (text, language)=>babelDiagnostics(await loadBabelParser(), text, language);
|
|
54
|
+
export { babelDiagnostics, babelSyntaxDiagnostics, loadBabelParser };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type CompletionContext } from '@codemirror/autocomplete';
|
|
2
|
+
import type { Extension } from '@codemirror/state';
|
|
3
|
+
import type { CodeEditorCompletionContext, CodeEditorCompletionSource, CodeEditorLanguage, JsonSchema } from '../types';
|
|
4
|
+
/** Public, engine-free view of a CodeMirror completion request (spec §4). */
|
|
5
|
+
export declare const buildCompletionContext: (ctx: CompletionContext, language: CodeEditorLanguage, startingLineNumber: number) => CodeEditorCompletionContext;
|
|
6
|
+
/**
|
|
7
|
+
* Autocomplete (spec §7.14): built-in HTTP source for `http`, the JSON Schema source when
|
|
8
|
+
* `schema` is set, then consumer sources, all through `override` (language-data sources are
|
|
9
|
+
* off). `completionKeymap` comes with `defaultKeymap: true` at `Prec.highest`, so Enter,
|
|
10
|
+
* arrows and Escape reach the open list before `indentWithTab` / fullscreen Escape.
|
|
11
|
+
*/
|
|
12
|
+
export declare const completionExtension: (config: {
|
|
13
|
+
language: CodeEditorLanguage;
|
|
14
|
+
schema: JsonSchema | undefined;
|
|
15
|
+
sources: readonly CodeEditorCompletionSource[];
|
|
16
|
+
startingLineNumber: number;
|
|
17
|
+
}) => Extension;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { autocompletion } from "@codemirror/autocomplete";
|
|
2
|
+
import { EditorView } from "@codemirror/view";
|
|
3
|
+
import { cn } from "../../../utils/cn.js";
|
|
4
|
+
import { dropdownMenuItemVariants } from "../../DropdownMenu/classes.js";
|
|
5
|
+
import { httpCompletions } from "../lib/httpCompletions.js";
|
|
6
|
+
import { jsonRegion } from "./diagnostics.js";
|
|
7
|
+
import { httpContextAt } from "./languages/index.js";
|
|
8
|
+
import { pointerAt } from "./languages/jsonPointers.js";
|
|
9
|
+
import { offsetToPosition } from "./positions.js";
|
|
10
|
+
import { schemaCompletionSource } from "./schema/complete.js";
|
|
11
|
+
const COMPLETION_WORD = /[\w\-/.:]*/;
|
|
12
|
+
const KIND_TO_TYPE = {
|
|
13
|
+
keyword: 'keyword',
|
|
14
|
+
property: 'property',
|
|
15
|
+
value: 'constant',
|
|
16
|
+
method: 'method',
|
|
17
|
+
header: 'property',
|
|
18
|
+
snippet: 'text',
|
|
19
|
+
text: 'text'
|
|
20
|
+
};
|
|
21
|
+
const COMPLETION_TOOLTIP_CLASS = cn('overflow-hidden rounded-12 border border-border-primary-light! bg-bg-surface-2! p-4', 'font-sans text-text-primary shadow-md');
|
|
22
|
+
const COMPLETION_OPTION_CLASS = cn(dropdownMenuItemVariants({
|
|
23
|
+
variant: 'default'
|
|
24
|
+
}), 'px-8! py-6!', 'aria-selected:bg-states-primary-hover! aria-selected:text-text-primary!');
|
|
25
|
+
const completionTheme = EditorView.theme({
|
|
26
|
+
'.cm-tooltip.cm-tooltip-autocomplete > ul': {
|
|
27
|
+
fontFamily: 'inherit',
|
|
28
|
+
maxHeight: '240px',
|
|
29
|
+
minWidth: '200px'
|
|
30
|
+
},
|
|
31
|
+
'.cm-tooltip.cm-tooltip-autocomplete > ul > li': {
|
|
32
|
+
lineHeight: '20px'
|
|
33
|
+
},
|
|
34
|
+
'.cm-completionDetail': {
|
|
35
|
+
marginLeft: 'auto',
|
|
36
|
+
fontStyle: 'normal',
|
|
37
|
+
color: 'var(--color-text-secondary)'
|
|
38
|
+
},
|
|
39
|
+
'.cm-completionMatchedText': {
|
|
40
|
+
textDecoration: 'none',
|
|
41
|
+
fontWeight: '600'
|
|
42
|
+
},
|
|
43
|
+
'.cm-tooltip.cm-completionInfo': {
|
|
44
|
+
padding: '6px 8px'
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
const completionWord = (ctx)=>ctx.matchBefore(COMPLETION_WORD) ?? {
|
|
48
|
+
from: ctx.pos,
|
|
49
|
+
text: ''
|
|
50
|
+
};
|
|
51
|
+
const isJsonLike = (language)=>'json' === language || 'http' === language;
|
|
52
|
+
const jsonPointerAt = (ctx, language)=>{
|
|
53
|
+
if (!isJsonLike(language)) return;
|
|
54
|
+
const region = jsonRegion(ctx.state, language);
|
|
55
|
+
if (!region || ctx.pos < region.from || ctx.pos > region.to) return;
|
|
56
|
+
return pointerAt(ctx.state, ctx.pos, region);
|
|
57
|
+
};
|
|
58
|
+
const buildCompletionContext = (ctx, language, startingLineNumber)=>{
|
|
59
|
+
const { doc } = ctx.state;
|
|
60
|
+
const word = completionWord(ctx);
|
|
61
|
+
const http = 'http' === language ? httpContextAt(ctx.state, ctx.pos) : void 0;
|
|
62
|
+
const jsonPointer = jsonPointerAt(ctx, language);
|
|
63
|
+
return {
|
|
64
|
+
value: doc.toString(),
|
|
65
|
+
position: offsetToPosition(doc, ctx.pos, startingLineNumber),
|
|
66
|
+
lineText: doc.lineAt(ctx.pos).text,
|
|
67
|
+
word: {
|
|
68
|
+
text: word.text,
|
|
69
|
+
from: offsetToPosition(doc, word.from, startingLineNumber)
|
|
70
|
+
},
|
|
71
|
+
explicit: ctx.explicit,
|
|
72
|
+
...void 0 === http ? {} : {
|
|
73
|
+
http
|
|
74
|
+
},
|
|
75
|
+
...void 0 === jsonPointer ? {} : {
|
|
76
|
+
jsonPointer
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
const toCompletion = (item)=>({
|
|
81
|
+
label: item.label,
|
|
82
|
+
apply: item.apply,
|
|
83
|
+
detail: item.detail,
|
|
84
|
+
info: item.info,
|
|
85
|
+
type: void 0 === item.kind ? void 0 : KIND_TO_TYPE[item.kind]
|
|
86
|
+
});
|
|
87
|
+
let reported = false;
|
|
88
|
+
const reportSourceError = (error)=>{
|
|
89
|
+
if (!reported) {
|
|
90
|
+
reported = true;
|
|
91
|
+
console.error('[CodeEditor] a completion source failed', error);
|
|
92
|
+
}
|
|
93
|
+
return null;
|
|
94
|
+
};
|
|
95
|
+
const adaptSource = (source, language, startingLineNumber)=>(ctx)=>{
|
|
96
|
+
const from = completionWord(ctx).from;
|
|
97
|
+
const finish = (items)=>items && items.length > 0 ? {
|
|
98
|
+
from,
|
|
99
|
+
options: items.map(toCompletion)
|
|
100
|
+
} : null;
|
|
101
|
+
try {
|
|
102
|
+
const result = source(buildCompletionContext(ctx, language, startingLineNumber));
|
|
103
|
+
return Promise.resolve(result).then(finish, reportSourceError);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
return reportSourceError(error);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
const reopensAfter = (completion)=>'string' == typeof completion.apply && completion.apply.endsWith(': ');
|
|
109
|
+
const completionExtension = (config)=>{
|
|
110
|
+
const { language, schema, sources, startingLineNumber } = config;
|
|
111
|
+
const override = [];
|
|
112
|
+
if ('http' === language) override.push(adaptSource(httpCompletions, language, startingLineNumber));
|
|
113
|
+
if (void 0 !== schema && isJsonLike(language)) override.push(schemaCompletionSource(()=>schema, (state)=>jsonRegion(state, language)));
|
|
114
|
+
for (const source of sources)override.push(adaptSource(source, language, startingLineNumber));
|
|
115
|
+
if (0 === override.length) return [];
|
|
116
|
+
return [
|
|
117
|
+
autocompletion({
|
|
118
|
+
override,
|
|
119
|
+
activateOnTyping: true,
|
|
120
|
+
activateOnCompletion: reopensAfter,
|
|
121
|
+
defaultKeymap: true,
|
|
122
|
+
icons: false,
|
|
123
|
+
tooltipClass: ()=>COMPLETION_TOOLTIP_CLASS,
|
|
124
|
+
optionClass: ()=>COMPLETION_OPTION_CLASS
|
|
125
|
+
}),
|
|
126
|
+
completionTheme
|
|
127
|
+
];
|
|
128
|
+
};
|
|
129
|
+
export { buildCompletionContext, completionExtension };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attributes CodeMirror sets on `.cm-content` itself. A consumer value would
|
|
3
|
+
* overwrite them (CM merges only `class` and `style`), breaking the textbox
|
|
4
|
+
* semantics or the editing surface, so they are never forwarded (spec §9).
|
|
5
|
+
*/
|
|
6
|
+
export declare const RESERVED_CONTENT_ATTRIBUTES: readonly string[];
|
|
7
|
+
/**
|
|
8
|
+
* Drops reserved keys (with a development warning) and keeps everything else
|
|
9
|
+
* verbatim — `data-analytics-props` included. `class` is kept: CodeMirror
|
|
10
|
+
* concatenates it with its own classes instead of replacing them.
|
|
11
|
+
*/
|
|
12
|
+
export declare const sanitizeContentAttributes: (attrs: Record<string, string>) => Record<string, string>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const RESERVED_CONTENT_ATTRIBUTES = [
|
|
2
|
+
'role',
|
|
3
|
+
'contenteditable',
|
|
4
|
+
'aria-multiline',
|
|
5
|
+
'aria-readonly',
|
|
6
|
+
'spellcheck',
|
|
7
|
+
'autocorrect',
|
|
8
|
+
'autocapitalize',
|
|
9
|
+
'translate',
|
|
10
|
+
'writingsuggestions'
|
|
11
|
+
];
|
|
12
|
+
const RESERVED = new Set(RESERVED_CONTENT_ATTRIBUTES);
|
|
13
|
+
const sanitizeContentAttributes = (attrs)=>{
|
|
14
|
+
const result = {};
|
|
15
|
+
for (const [key, value] of Object.entries(attrs)){
|
|
16
|
+
if (RESERVED.has(key.toLowerCase())) {
|
|
17
|
+
if ('production' !== process.env.NODE_ENV) console.warn(`[CodeEditor] "${key}" is managed by the editor and cannot be set on CodeEditorContent; the value "${value}" was ignored.`);
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
result[key] = value;
|
|
21
|
+
}
|
|
22
|
+
return result;
|
|
23
|
+
};
|
|
24
|
+
export { RESERVED_CONTENT_ATTRIBUTES, sanitizeContentAttributes };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { type Diagnostic } from '@codemirror/lint';
|
|
2
|
+
import type { EditorState, Extension, Text } from '@codemirror/state';
|
|
3
|
+
import type { CodeEditorDiagnostic, CodeEditorLanguage, JsonSchema } from '../types';
|
|
4
|
+
/** Absolute document range holding JSON (whole doc for `json`, the JSON body for `http`). */
|
|
5
|
+
export interface JsonRegion {
|
|
6
|
+
from: number;
|
|
7
|
+
to: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Schema hook (spec §7.13). T13 passes a function that dynamically imports
|
|
11
|
+
* `./schema/validate` and returns CM diagnostics with absolute offsets.
|
|
12
|
+
* Called only when `schema` is set and the region is syntactically valid JSON.
|
|
13
|
+
*/
|
|
14
|
+
export type SchemaDiagnosticsSource = (state: EditorState, region: JsonRegion) => Promise<readonly Diagnostic[]>;
|
|
15
|
+
export interface DiagnosticsConfig {
|
|
16
|
+
language: CodeEditorLanguage;
|
|
17
|
+
schema: JsonSchema | undefined;
|
|
18
|
+
external: readonly CodeEditorDiagnostic[];
|
|
19
|
+
startingLineNumber: number;
|
|
20
|
+
onChange: (diagnostics: CodeEditorDiagnostic[]) => void;
|
|
21
|
+
schemaSource?: SchemaDiagnosticsSource;
|
|
22
|
+
}
|
|
23
|
+
/** Linter debounce after a change, in ms (spec §7.12). */
|
|
24
|
+
export declare const LINT_DELAY = 300;
|
|
25
|
+
export declare const SYNTAX_SOURCE = "syntax";
|
|
26
|
+
export declare const SCHEMA_SOURCE = "schema";
|
|
27
|
+
/**
|
|
28
|
+
* Where the JSON lives in the document: the whole document for `json`, the mounted
|
|
29
|
+
* `JsonText` body for `http` (null when the body is absent or not JSON), otherwise null.
|
|
30
|
+
*/
|
|
31
|
+
export declare const jsonRegion: (state: EditorState, language: CodeEditorLanguage) => JsonRegion | null;
|
|
32
|
+
export interface JsonSyntaxErrorLocation {
|
|
33
|
+
/** Offset relative to the parsed text, or null when the message carries no position. */
|
|
34
|
+
offset: number | null;
|
|
35
|
+
/** Human-readable message without engine-specific position suffixes. */
|
|
36
|
+
message: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Reads the error position out of a `JSON.parse` SyntaxError message.
|
|
40
|
+
* V8: `... in JSON at position N (line L column C)`; Firefox: `... at line L column C of the JSON data`;
|
|
41
|
+
* `Unexpected end of JSON input` / `unexpected end of data` → end of the content.
|
|
42
|
+
*/
|
|
43
|
+
export declare const locateJsonSyntaxError: (message: string, text: string) => JsonSyntaxErrorLocation;
|
|
44
|
+
/**
|
|
45
|
+
* Syntax errors from the Lezer tree (spec §14 A3): every error (⚠) node of the parsed tree — or
|
|
46
|
+
* only those inside `region` — becomes an `error` diagnostic; error nodes that touch are
|
|
47
|
+
* collapsed into one. If the parse times out, errors at or past the parsed extent (including
|
|
48
|
+
* "Unexpected end of input") are not reported. Empty for a state without a parser.
|
|
49
|
+
*/
|
|
50
|
+
export declare const syntaxErrorDiagnostics: (state: EditorState, region?: JsonRegion, timeout?: number) => Diagnostic[];
|
|
51
|
+
/** JSON syntax error of the region (at most one — `JSON.parse` stops at the first). */
|
|
52
|
+
export declare const jsonSyntaxDiagnostics: (state: EditorState, region: JsonRegion, timeout?: number) => Diagnostic[];
|
|
53
|
+
/**
|
|
54
|
+
* Consumer diagnostic → CM diagnostic. `null` when `from.line` is outside the document;
|
|
55
|
+
* a `to` line outside the document is clamped to the document end.
|
|
56
|
+
*/
|
|
57
|
+
export declare const toCmDiagnostic: (doc: Text, diagnostic: CodeEditorDiagnostic, startingLineNumber: number) => Diagnostic | null;
|
|
58
|
+
/** CM diagnostic → public form (absolute lines, 1-based columns). `hint` reads as `info`. */
|
|
59
|
+
export declare const toPublicDiagnostic: (doc: Text, diagnostic: Diagnostic, startingLineNumber: number) => CodeEditorDiagnostic;
|
|
60
|
+
/**
|
|
61
|
+
* Underlines per spec §7.10 (existing indicator tokens only) and the lint tooltip on the
|
|
62
|
+
* DS Tooltip surface (`TooltipContent`: `bg-component-tooltip-bg text-text-primary-alt
|
|
63
|
+
* text-xs font-medium rounded-8 py-4 px-8`, z-index `--tooltip-z-index`). The surface rule
|
|
64
|
+
* targets every hover tooltip so schema hover (T13) matches.
|
|
65
|
+
*/
|
|
66
|
+
export declare const diagnosticsTheme: Extension;
|
|
67
|
+
/**
|
|
68
|
+
* Diagnostics (spec §7.12, §14 A3 + A5): one debounced linter merging syntax errors (JSON.parse for
|
|
69
|
+
* json / the http JSON body, `@babel/parser` for javascript / typescript, `luaparse` for lua (A6), Lezer error nodes for
|
|
70
|
+
* yaml / python), schema errors (via `schemaSource`, T13) and the consumer `diagnostics` prop.
|
|
71
|
+
* Underlines + hover tooltip only — no lint gutter, panel or lint keymap.
|
|
72
|
+
*/
|
|
73
|
+
export declare const diagnosticsExtension: (config: DiagnosticsConfig) => Extension;
|