22
33import { EditorView , basicSetup } from 'codemirror' ;
44import { createApp } from "petite-vue" ;
5- import { Compartment , EditorState } from '@codemirror/state'
5+ import { Compartment , EditorState , RangeSetBuilder } from '@codemirror/state'
66import { indentWithTab } from '@codemirror/commands' ;
77import { json , jsonLanguage , jsonParseLinter } from "@codemirror/lang-json" ;
88import { syntaxTree , StreamLanguage } from '@codemirror/language' ;
99import { ntriples } from '@codemirror/legacy-modes/mode/ntriples' ;
10- import { keymap } from '@codemirror/view' ;
10+ import { Decoration , keymap , ViewPlugin } from '@codemirror/view' ;
1111import { linter } from '@codemirror/lint' ;
1212import YAML from 'yaml' ;
1313import { yaml } from '@codemirror/lang-yaml' ;
@@ -190,6 +190,64 @@ const jsonLdCompletions = jsonLanguage.data.of({
190190 autocomplete : completeJSONLDTerms
191191} ) ;
192192
193+ // Create a decoration that applies a CSS class for JSON‑LD property names
194+ const jsonLdPropertyDecoration = Decoration . mark ( { class : 'cm-jsonld-property' } ) ;
195+
196+ const jsonLdKeywords = new Set (
197+ [ ] . concat ( ...Object . values ( jsonLdAtTerms ) ) . map ( ( term ) => term . label ) ) ;
198+
199+ /**
200+ * A view plugin that scans the document for PropertyName nodes and, if their
201+ * content (without quotes) is a JSON‑LD keyword, adds a decoration to style it.
202+ */
203+ const jsonLdKeywordHighlighter = ViewPlugin . fromClass ( class {
204+ constructor ( view ) {
205+ this . decorations = this . buildDecorations ( view ) ;
206+ }
207+
208+ update ( update ) {
209+ if ( update . docChanged || update . viewportChanged ) {
210+ this . decorations = this . buildDecorations ( update . view ) ;
211+ }
212+ }
213+
214+ buildDecorations ( view ) {
215+ let builder = new RangeSetBuilder ( ) ;
216+ let tree = syntaxTree ( view . state ) ;
217+ // Only inspect nodes in the current viewport
218+ tree . iterate ( {
219+ from : view . viewport . from ,
220+ to : view . viewport . to ,
221+ enter : ( node ) => {
222+ // Look for property names (as defined by lang-json)
223+ if ( node . name === "PropertyName" || node . name === "String" ) {
224+ let token = view . state . doc . sliceString ( node . from , node . to ) ;
225+ // Remove the surrounding quotes, if any
226+ if ( token . startsWith ( '"' ) && token . endsWith ( '"' ) ) {
227+ token = token . slice ( 1 , - 1 ) ;
228+ }
229+ if ( jsonLdKeywords . has ( token ) ) {
230+ builder . add ( node . from , node . to , jsonLdPropertyDecoration ) ;
231+ }
232+ }
233+ }
234+ } ) ;
235+ return builder . finish ( ) ;
236+ }
237+
238+ destroy ( ) { }
239+ } , {
240+ decorations : v => v . decorations
241+ } ) ;
242+
243+ // A base theme for our decoration
244+ const jsonLdHighlightTheme = EditorView . baseTheme ( {
245+ '.cm-jsonld-property' : {
246+ color : '#333' ,
247+ fontWeight : 'bold'
248+ }
249+ } ) ;
250+
193251function initEditor ( id , content , varName ) {
194252 return new EditorView ( {
195253 parent : document . getElementById ( id ) ,
@@ -198,6 +256,8 @@ function initEditor(id, content, varName) {
198256 basicSetup ,
199257 keymap . of ( [ indentWithTab ] ) ,
200258 jsonLanguage ,
259+ jsonLdKeywordHighlighter ,
260+ jsonLdHighlightTheme ,
201261 linter ( jsonParseLinter ( ) ) ,
202262 jsonLdCompletions ,
203263 editorListener . call ( this , varName )
0 commit comments