diff options
author | Kristóf Marussy <kristof@marussy.com> | 2022-11-25 15:28:56 +0100 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2022-12-09 00:07:38 +0100 |
commit | cc27b2fbea058022f2f3fc3b3f74d91355d7e237 (patch) | |
tree | 7b81505b181c821f66aa629f7702b975bd9eb2b3 /subprojects/frontend/src/editor/exposeDiagnostics.ts | |
parent | chore(web): fix lint error (diff) | |
download | refinery-cc27b2fbea058022f2f3fc3b3f74d91355d7e237.tar.gz refinery-cc27b2fbea058022f2f3fc3b3f74d91355d7e237.tar.zst refinery-cc27b2fbea058022f2f3fc3b3f74d91355d7e237.zip |
refactor(frontend): simplify diagnostic tracking
Diffstat (limited to 'subprojects/frontend/src/editor/exposeDiagnostics.ts')
-rw-r--r-- | subprojects/frontend/src/editor/exposeDiagnostics.ts | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/subprojects/frontend/src/editor/exposeDiagnostics.ts b/subprojects/frontend/src/editor/exposeDiagnostics.ts new file mode 100644 index 00000000..82f24c93 --- /dev/null +++ b/subprojects/frontend/src/editor/exposeDiagnostics.ts | |||
@@ -0,0 +1,80 @@ | |||
1 | import { setDiagnosticsEffect } from '@codemirror/lint'; | ||
2 | import { | ||
3 | StateField, | ||
4 | RangeSet, | ||
5 | type Extension, | ||
6 | type EditorState, | ||
7 | } from '@codemirror/state'; | ||
8 | |||
9 | import DiagnosticValue, { type Severity } from './DiagnosticValue'; | ||
10 | |||
11 | type SeverityCounts = Partial<Record<Severity, number>>; | ||
12 | |||
13 | interface ExposedDiagnostics { | ||
14 | readonly diagnostics: RangeSet<DiagnosticValue>; | ||
15 | |||
16 | readonly severityCounts: SeverityCounts; | ||
17 | } | ||
18 | |||
19 | function countSeverities( | ||
20 | diagnostics: RangeSet<DiagnosticValue>, | ||
21 | ): SeverityCounts { | ||
22 | const severityCounts: SeverityCounts = {}; | ||
23 | const iter = diagnostics.iter(); | ||
24 | while (iter.value !== null) { | ||
25 | const { | ||
26 | value: { severity }, | ||
27 | } = iter; | ||
28 | severityCounts[severity] = (severityCounts[severity] ?? 0) + 1; | ||
29 | iter.next(); | ||
30 | } | ||
31 | return severityCounts; | ||
32 | } | ||
33 | |||
34 | const exposedDiagnosticsState = StateField.define<ExposedDiagnostics>({ | ||
35 | create() { | ||
36 | return { | ||
37 | diagnostics: RangeSet.of([]), | ||
38 | severityCounts: {}, | ||
39 | }; | ||
40 | }, | ||
41 | |||
42 | update({ diagnostics: diagnosticsSet, severityCounts }, transaction) { | ||
43 | let newDiagnosticsSet = diagnosticsSet; | ||
44 | if (transaction.docChanged) { | ||
45 | newDiagnosticsSet = newDiagnosticsSet.map(transaction.changes); | ||
46 | } | ||
47 | transaction.effects.forEach((effect) => { | ||
48 | if (effect.is(setDiagnosticsEffect)) { | ||
49 | const diagnostics = effect.value.map(({ severity, from, to }) => | ||
50 | DiagnosticValue.VALUES[severity].range(from, to), | ||
51 | ); | ||
52 | diagnostics.sort(({ from: a }, { from: b }) => a - b); | ||
53 | newDiagnosticsSet = RangeSet.of(diagnostics); | ||
54 | } | ||
55 | }); | ||
56 | return { | ||
57 | diagnostics: newDiagnosticsSet, | ||
58 | severityCounts: | ||
59 | // Only recompute if the diagnostics were changed. | ||
60 | diagnosticsSet === newDiagnosticsSet | ||
61 | ? severityCounts | ||
62 | : countSeverities(newDiagnosticsSet), | ||
63 | }; | ||
64 | }, | ||
65 | }); | ||
66 | |||
67 | const exposeDiagnostics: Extension = [exposedDiagnosticsState]; | ||
68 | |||
69 | export default exposeDiagnostics; | ||
70 | |||
71 | export function getDiagnostics(state: EditorState): RangeSet<DiagnosticValue> { | ||
72 | return state.field(exposedDiagnosticsState).diagnostics; | ||
73 | } | ||
74 | |||
75 | export function countDiagnostics( | ||
76 | state: EditorState, | ||
77 | severity: Severity, | ||
78 | ): number { | ||
79 | return state.field(exposedDiagnosticsState).severityCounts[severity] ?? 0; | ||
80 | } | ||