|
| 1 | +import type * as MonacoTypes from 'monaco-editor' |
| 2 | +import { XMLValidator } from 'fast-xml-parser' |
| 3 | + |
| 4 | +export function setupXMLValidation(monaco: typeof MonacoTypes) { |
| 5 | + const markerId = 'xml-validation' |
| 6 | + |
| 7 | + function validate(model: MonacoTypes.editor.ITextModel) { |
| 8 | + const markers: MonacoTypes.editor.IMarkerData[] = [] |
| 9 | + const text = model.getValue() |
| 10 | + |
| 11 | + if (text.trim()) { |
| 12 | + const validationResult = XMLValidator.validate(text, { |
| 13 | + allowBooleanAttributes: true, |
| 14 | + }) |
| 15 | + |
| 16 | + if (validationResult !== true) { |
| 17 | + markers.push({ |
| 18 | + severity: monaco.MarkerSeverity.Error, |
| 19 | + startLineNumber: validationResult.err.line, |
| 20 | + startColumn: validationResult.err.col, |
| 21 | + endLineNumber: validationResult.err.line, |
| 22 | + endColumn: model.getLineContent(validationResult.err.line).length + 1, |
| 23 | + message: validationResult.err.msg, |
| 24 | + }) |
| 25 | + } |
| 26 | + } |
| 27 | + |
| 28 | + monaco.editor.setModelMarkers(model, markerId, markers) |
| 29 | + } |
| 30 | + |
| 31 | + const contentChangeListeners = new Map<MonacoTypes.editor.ITextModel, MonacoTypes.IDisposable>() |
| 32 | + function manageContentChangeListener(model: MonacoTypes.editor.ITextModel) { |
| 33 | + const isXml = model.getModeId() === 'xml' |
| 34 | + const listener = contentChangeListeners.get(model) |
| 35 | + |
| 36 | + if (isXml && !listener) { |
| 37 | + contentChangeListeners.set( |
| 38 | + model, |
| 39 | + model.onDidChangeContent(() => validate(model)) |
| 40 | + ) |
| 41 | + validate(model) |
| 42 | + } else if (!isXml && listener) { |
| 43 | + listener.dispose() |
| 44 | + contentChangeListeners.delete(model) |
| 45 | + monaco.editor.setModelMarkers(model, markerId, []) |
| 46 | + } |
| 47 | + } |
| 48 | + |
| 49 | + monaco.editor.onWillDisposeModel(model => { |
| 50 | + contentChangeListeners.delete(model) |
| 51 | + }) |
| 52 | + monaco.editor.onDidChangeModelLanguage(({ model }) => { |
| 53 | + manageContentChangeListener(model) |
| 54 | + }) |
| 55 | + monaco.editor.onDidCreateModel(model => { |
| 56 | + manageContentChangeListener(model) |
| 57 | + }) |
| 58 | +} |
0 commit comments