react-codemirror-editor 0.1.0 → 0.2.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.
Files changed (41) hide show
  1. package/README.md +229 -44
  2. package/dist/core/diagnostics/json/index.d.ts.map +1 -0
  3. package/dist/core/diagnostics/{jsonDiagnostics.d.ts → json/jsonDiagnostics.d.ts} +1 -1
  4. package/dist/core/diagnostics/json/jsonDiagnostics.d.ts.map +1 -0
  5. package/dist/core/diagnostics/json/jsonDiagnostics.js +32 -0
  6. package/dist/core/diagnostics/json/jsonLinter.d.ts +4 -0
  7. package/dist/core/diagnostics/json/jsonLinter.d.ts.map +1 -0
  8. package/dist/core/diagnostics/json/jsonLinter.js +42 -0
  9. package/dist/core/diagnostics/json/jsonValidation.d.ts +4 -0
  10. package/dist/core/diagnostics/json/jsonValidation.d.ts.map +1 -0
  11. package/dist/core/diagnostics/json/jsonValidation.js +8 -0
  12. package/dist/core/diagnostics/json/safeJsonCompletion.d.ts +3 -0
  13. package/dist/core/diagnostics/json/safeJsonCompletion.d.ts.map +1 -0
  14. package/dist/core/diagnostics/json/safeJsonCompletion.js +8 -0
  15. package/dist/core/editor/createEditor.d.ts +1 -1
  16. package/dist/core/editor/createEditor.d.ts.map +1 -1
  17. package/dist/core/editor/createEditor.js +3 -2
  18. package/dist/core/editor/editorController.d.ts.map +1 -1
  19. package/dist/core/editor/editorController.js +19 -1
  20. package/dist/core/extensions/fold.d.ts.map +1 -1
  21. package/dist/core/extensions/fold.js +14 -2
  22. package/dist/core/extensions/index.d.ts +1 -0
  23. package/dist/core/extensions/index.d.ts.map +1 -1
  24. package/dist/core/extensions/index.js +1 -0
  25. package/dist/core/extensions/search.d.ts +11 -0
  26. package/dist/core/extensions/search.d.ts.map +1 -0
  27. package/dist/core/extensions/search.js +54 -0
  28. package/dist/core/languages/buildExtensions.js +1 -1
  29. package/dist/types/editor.d.ts +17 -0
  30. package/dist/types/editor.d.ts.map +1 -1
  31. package/dist/ui/CodeEditor.d.ts.map +1 -1
  32. package/dist/ui/CodeEditor.js +2 -2
  33. package/dist/ui/EditorContainer.d.ts +1 -1
  34. package/dist/ui/EditorContainer.d.ts.map +1 -1
  35. package/dist/ui/EditorContainer.js +2 -1
  36. package/package.json +8 -6
  37. package/dist/core/diagnostics/index.d.ts.map +0 -1
  38. package/dist/core/diagnostics/jsonDiagnostics.d.ts.map +0 -1
  39. package/dist/core/diagnostics/jsonDiagnostics.js +0 -78
  40. /package/dist/core/diagnostics/{index.d.ts → json/index.d.ts} +0 -0
  41. /package/dist/core/diagnostics/{index.js → json/index.js} +0 -0
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # React Code Editor
2
2
 
3
- A modern, extensible **CodeMirror 6–based React code editor** with first-class TypeScript support, language-aware configuration, and optional diagnostics.
3
+ A modern, extensible **CodeMirror 6–based React code editor** featuring first-class TypeScript support, language-aware configuration, optional diagnostics, and search/validation support.
4
4
 
5
5
  This library is designed to scale from a simple embedded editor to a **multi-language, schema-aware editing platform**.
6
6
 
@@ -14,6 +14,8 @@ This library is designed to scale from a simple embedded editor to a **multi-lan
14
14
  - Optional diagnostics, completion, and hover
15
15
  - JSON Schema validation support
16
16
  - Light & dark themes
17
+ - Search & Replace support
18
+ - Validation state callback
17
19
  - Designed for future multi-language support
18
20
 
19
21
  ---
@@ -32,10 +34,10 @@ npm install react-code-editor
32
34
  npm install react react-dom
33
35
  ```
34
36
 
35
- ### JSON language support (optional but recommended)
37
+ ### JSON language support (optional, but recommended)
36
38
 
37
39
  ```bash
38
- npm install @codemirror/lang-json codemirrorirror-json-schema ajv
40
+ npm install @codemirror/lang-json codemirror-json-schema ajv
39
41
  ```
40
42
 
41
43
  > `ajv` is used internally by `codemirror-json-schema` for JSON Schema validation.
@@ -48,7 +50,7 @@ npm install @codemirror/lang-json codemirrorirror-json-schema ajv
48
50
  import { CodeEditor } from 'react-code-editor';
49
51
 
50
52
  export function Example() {
51
- return <CodeEditor language="json" defaultValue="{}" />;
53
+ return <CodeEditor language="json" defaultValue="{}" />;
52
54
  }
53
55
  ```
54
56
 
@@ -61,10 +63,7 @@ This creates an **uncontrolled JSON editor** with default configuration.
61
63
  ### Uncontrolled Editor
62
64
 
63
65
  ```tsx
64
- <CodeEditor
65
- language="json"
66
- defaultValue='{ "name": "John" }'
67
- />
66
+ <CodeEditor language="json" defaultValue='{ "name": "John" }' />
68
67
  ```
69
68
 
70
69
  ### Controlled Editor
@@ -72,14 +71,144 @@ This creates an **uncontrolled JSON editor** with default configuration.
72
71
  ```tsx
73
72
  const [value, setValue] = useState('{}');
74
73
 
74
+ <CodeEditor language="json" value={value} onChange={setValue} />;
75
+ ```
76
+
77
+ > ⚠️ Do not pass both `value` and `defaultValue`.
78
+
79
+ ---
80
+
81
+ ## 🎮 Editor Controller API
82
+
83
+ The editor exposes a controller API that allows you to trigger actions programmatically.
84
+
85
+ ### ⚠️ Important design choice
86
+
87
+ This library does **not** impose formatting logic.
88
+ Instead, you **pass a callback function** that receives the current editor value and returns the formatted result.
89
+
90
+ This keeps the editor **language-agnostic** and flexible.
91
+
92
+ ### Available Controller Actions
93
+
94
+ - `copy()`
95
+ - `format(formatter)`
96
+ - `foldAll()`
97
+ - `unfoldAll()`
98
+ - `openSearch()`
99
+ - `closeSearch()`
100
+ - `findNext()`
101
+ - `findPrev()`
102
+ - `replace(replacement: string)`
103
+ - `replaceAll(replacement: string)`
104
+
105
+ ### 🧠 Format API (Callback-Based)
106
+
107
+ ```tsx
108
+ format(formatter: (value: string) => string): void
109
+ ```
110
+
111
+ - The editor passes the **current content**
112
+ - Your formatter returns the **new formatted content**
113
+ - The editor updates itself with the returned value
114
+
115
+ ### Example
116
+
117
+ ```tsx
118
+ import { useRef } from 'react';
119
+ import type { EditorController } from 'react-codemirror-editor';
120
+
121
+ const controllerRef = useRef<EditorController | null>(null);
122
+
75
123
  <CodeEditor
76
124
  language="json"
77
- value={value}
78
- onChange={setValue}
125
+ controllerRef={controllerRef}
79
126
  />;
127
+
128
+ function formatJson(value: string) {
129
+ try {
130
+ return JSON.stringify(JSON.parse(value), null, 2);
131
+ } catch {
132
+ return value;
133
+ }
134
+ }
135
+
136
+ <button onClick={() => controllerRef.current?.format(formatJson)}>Format</button>
137
+ <button onClick={() => controllerRef.current?.copy()}>Copy</button>
138
+ <button onClick={() => controllerRef.current?.foldAll()}>Fold All</button>
139
+ <button onClick={() => controllerRef.current?.unfoldAll()}>Unfold All</button>
140
+ <button onClick={() => controllerRef.current?.openSearch()}>Search</button>
141
+ <button onClick={() => controllerRef.current?.closeSearch()}>Close Search</button>
80
142
  ```
81
143
 
82
- > ⚠️ Do not pass both `value` and `defaultValue`.
144
+ - Works for **any language**
145
+ - Supports **custom formatter functions**
146
+ - Search UI is **optional** and can be enabled via props
147
+
148
+ ### Example: Prettier Integration (Concept)
149
+
150
+ ```tsx
151
+ controllerRef.current?.format((code) =>
152
+ prettier.format(code, { parser: 'json' }),
153
+ );
154
+ ```
155
+
156
+ ---
157
+
158
+ ## 📋 Why Callback-Based Formatting?
159
+
160
+ - Keeps core editor **small**
161
+ - Avoids hard dependency on Prettier
162
+ - Supports **any language**
163
+ - Lets consumers decide formatting rules
164
+
165
+ This is a library-level design decision, not a limitation.
166
+
167
+ ---
168
+
169
+ ## 🔍 Search & Replace
170
+
171
+ The editor includes **search & replace functionality** via a controller API:
172
+
173
+ - `openSearch()` – Opens the search panel
174
+ - `closeSearch()` – Closes the search panel
175
+ - `findNext()` – Finds the next match
176
+ - `findPrev()` – Finds the previous match
177
+ - `replace(replacement: string)` – Replaces the current match
178
+ - `replaceAll(replacement: string)` – Replaces all matches
179
+
180
+ You can pass **search configuration**:
181
+
182
+ ```tsx
183
+ <CodeEditor
184
+ language="json"
185
+ searchOptions={{
186
+ top: true,
187
+ caseSensitive: false,
188
+ }}
189
+ />
190
+ ```
191
+
192
+ ---
193
+
194
+ ## ✅ JSON Validation State
195
+
196
+ You can track JSON validity and react to changes in real-time via `onValidationChange`:
197
+
198
+ ```tsx
199
+ <CodeEditor
200
+ language="json"
201
+ languageOptions={{
202
+ json: {
203
+ schema: myJsonSchema,
204
+ onValidationChange: (isValid) => console.log('Valid:', isValid),
205
+ },
206
+ }}
207
+ />
208
+ ```
209
+
210
+ - `isValid` is `true` if there are no syntax or schema errors
211
+ - Useful for enabling/disabling Save buttons or warnings in your UI
83
212
 
84
213
  ---
85
214
 
@@ -88,9 +217,11 @@ const [value, setValue] = useState('{}');
88
217
  Languages are enabled explicitly using the `language` prop.
89
218
 
90
219
  ### Currently supported
220
+
91
221
  - **JSON**
92
222
 
93
- The architecture is designed to support additional languages such as:
223
+ Future support for:
224
+
94
225
  - JavaScript
95
226
  - TypeScript
96
227
  - Python
@@ -102,32 +233,31 @@ The architecture is designed to support additional languages such as:
102
233
 
103
234
  Language-specific behavior is configured via `languageOptions`.
104
235
 
105
- ### JSON Configuration Example
106
-
107
236
  ```tsx
108
237
  <CodeEditor
109
- language="json"
110
- languageOptions={{
111
- json: {
112
- schema: myJsonSchema,
113
- diagnostics: true,
114
- completion: true,
115
- hover: true
116
- }
117
- }}
238
+ language="json"
239
+ languageOptions={{
240
+ json: {
241
+ schema: myJsonSchema,
242
+ diagnostics: true,
243
+ completion: true,
244
+ hover: true,
245
+ },
246
+ }}
118
247
  />
119
248
  ```
120
249
 
121
- ---
122
-
123
250
  ### JSON Options
124
251
 
125
- | Option | Description | Default |
126
- |------|------------|---------|
127
- | `schema` | JSON Schema object for validation | `undefined` |
128
- | `diagnostics` | Enable JSON linting | `true` |
129
- | `completion` | Enable schema-based autocompletion | `true` |
130
- | `hover` | Enable schema hover tooltips | `true` |
252
+ | Option | Type | Default | Description |
253
+ | -------------------- | ---------------------------- | ------------------------- | ------------------------------------------------------ |
254
+ | `schema` | `object` | `undefined` | JSON Schema used for validation, completion, and hover |
255
+ | `diagnostics` | `boolean` | `true` | Enables JSON syntax diagnostics |
256
+ | `gutter` | `boolean` | `true` | Shows the diagnostics gutter (error markers) |
257
+ | `schemaLint` | `boolean` | `true if schema provided` | Enables schema-based validation |
258
+ | `hover` | `boolean` | `true if schema provided` | Enables hover tooltips from schema |
259
+ | `autocomplete` | `boolean` | `true if schema provided` | Enables schema-based autocompletion |
260
+ | `onValidationChange` | `(isValid: boolean) => void` | `undefined` | Callback called whenever JSON validity changes |
131
261
 
132
262
  > If no schema is provided, the editor still works normally with **syntax diagnostics only**.
133
263
 
@@ -137,11 +267,12 @@ Language-specific behavior is configured via `languageOptions`.
137
267
 
138
268
  Diagnostics are **configurable per language**.
139
269
 
140
- ### JSON diagnostics include:
270
+ ### JSON diagnostics include
271
+
141
272
  - Syntax errors
142
273
  - Schema validation errors (when schema is provided)
143
274
 
144
- You may disable diagnostics entirely:
275
+ Disable diagnostics:
145
276
 
146
277
  ```tsx
147
278
  languageOptions={{
@@ -156,25 +287,79 @@ languageOptions={{
156
287
  ## 🔒 Read-Only Mode
157
288
 
158
289
  ```tsx
159
- <CodeEditor
160
- language="json"
161
- value={json}
162
- readOnly
163
- />
290
+ <CodeEditor language="json" value={json} readOnly={true} />
291
+ ```
292
+
293
+ **Notes:**
294
+
295
+ - `readOnly` must be a boolean
296
+ - Default is `false`
297
+ - When enabled, the editor is non-editable but remains selectable and scrollable
298
+
299
+ ---
300
+
301
+ ## 📐 Layout & Sizing
302
+
303
+ By default, CodeMirror sizes itself based on content height.
304
+ This can result in a single-line editor when the value contains only one line.
305
+
306
+ The editor is designed to expand and fill its container.
307
+ To ensure a consistent height, define a height or `min-height` via CSS.
308
+
309
+ ```css
310
+ .cm-editor-container {
311
+ min-height: 200px;
312
+ }
313
+
314
+ .cm-editor-container,
315
+ .cm-editor-container .cm-editor {
316
+ width: 100%;
317
+ height: 100%;
318
+ }
164
319
  ```
165
320
 
321
+ **Notes:**
322
+
323
+ - The editor always fills the container height
324
+ - Padding, borders, and background should be applied to the container
325
+ - Provides full control over responsive layouts
326
+
166
327
  ---
167
328
 
168
329
  ## 🎨 Theming
169
330
 
170
331
  ```tsx
171
- <CodeEditor
172
- language="json"
173
- theme="dark"
174
- />
332
+ <CodeEditor language="json" theme="dark" />
175
333
  ```
176
334
 
177
- Both **light and dark themes** are supported, with multiple variants included.
335
+ Both **light and dark themes** are supported, each with multiple variants.
336
+
337
+ Available themes:
338
+
339
+ Light themes:
340
+
341
+ - light
342
+ - ayu_light
343
+ - clouds_light
344
+ - espresso_light
345
+ - noctis_lilac_light
346
+ - rose_pine_dawn_light
347
+ - smoothy_light
348
+ - tomorrow_light
349
+
350
+ Dark themes:
351
+
352
+ - dark
353
+ - barf_dark
354
+ - cobalt_dark
355
+ - cool_glow_dark
356
+ - dracula_dark
357
+
358
+ Theme names are type-safe via the exported ThemeName union.
359
+
360
+ ```tsx
361
+ import type { ThemeName } from 'react-codemirror-editor';
362
+ ```
178
363
 
179
364
  ---
180
365
 
@@ -182,7 +367,7 @@ Both **light and dark themes** are supported, with multiple variants included.
182
367
 
183
368
  - Built on **CodeMirror 6**
184
369
  - Language features are isolated and composable
185
- - Diagnostics, completion, and hover are opt-in
370
+ - Diagnostics, completion, hover, and search are opt-in
186
371
  - Clean separation between core editor, languages, and UI
187
372
  - Designed for long-term multi-language expansion
188
373
 
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/diagnostics/json/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -1,4 +1,4 @@
1
1
  import { Extension } from '@codemirror/state';
2
- import { JsonEditorConfig } from '../../types';
2
+ import { JsonEditorConfig } from '../../../types';
3
3
  export declare const jsonDiagnosticsExtension: (options?: JsonEditorConfig) => Extension;
4
4
  //# sourceMappingURL=jsonDiagnostics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonDiagnostics.d.ts","sourceRoot":"","sources":["../../../../src/core/diagnostics/json/jsonDiagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAa9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,eAAO,MAAM,wBAAwB,aACxB,gBAAgB,KAC1B,SA4CF,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { hoverTooltip } from '@codemirror/view';
2
+ import { linter, lintGutter } from '@codemirror/lint';
3
+ import { autocompletion } from '@codemirror/autocomplete';
4
+ import { jsonSchemaLinter, jsonSchemaHover, stateExtensions, } from 'codemirror-json-schema';
5
+ import { validation } from './jsonValidation';
6
+ import { jsonLinter } from './jsonLinter';
7
+ import { safeJsonCompletion } from './safeJsonCompletion';
8
+ export const jsonDiagnosticsExtension = (options = {}) => {
9
+ const { diagnostics = true, gutter = true, schema, schemaLint = !!schema, hover = !!schema, autocomplete = !!schema, onValidationChange, } = options;
10
+ const extensions = [];
11
+ if (diagnostics) {
12
+ extensions.push(linter(validation(jsonLinter, onValidationChange)));
13
+ if (gutter) {
14
+ extensions.push(lintGutter());
15
+ }
16
+ }
17
+ if (schema) {
18
+ extensions.push(stateExtensions(schema));
19
+ if (schemaLint) {
20
+ extensions.push(linter(validation(jsonSchemaLinter(schema), onValidationChange)));
21
+ }
22
+ if (hover) {
23
+ extensions.push(hoverTooltip(jsonSchemaHover(schema)));
24
+ }
25
+ if (autocomplete) {
26
+ extensions.push(autocompletion({
27
+ override: [safeJsonCompletion(schema)],
28
+ }));
29
+ }
30
+ }
31
+ return extensions;
32
+ };
@@ -0,0 +1,4 @@
1
+ import { EditorView } from '@codemirror/view';
2
+ import { Diagnostic } from '@codemirror/lint';
3
+ export declare const jsonLinter: (view: EditorView) => Diagnostic[];
4
+ //# sourceMappingURL=jsonLinter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonLinter.d.ts","sourceRoot":"","sources":["../../../../src/core/diagnostics/json/jsonLinter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AA+B9C,eAAO,MAAM,UAAU,SAAU,UAAU,KAAG,UAAU,EAsBvD,CAAC"}
@@ -0,0 +1,42 @@
1
+ import { syntaxTree } from '@codemirror/language';
2
+ const getErrorMessage = (view, from) => {
3
+ const doc = view.state.doc;
4
+ const charBefore = from > 0 ? doc.sliceString(from - 1, from) : '';
5
+ const charAfter = doc.sliceString(from, from + 1);
6
+ if (charBefore === ',') {
7
+ return 'Trailing comma is not allowed in JSON';
8
+ }
9
+ if (charAfter === '}' || charAfter === ']') {
10
+ return 'Missing value before closing bracket';
11
+ }
12
+ if (charAfter === ':') {
13
+ return 'Missing value after ":"';
14
+ }
15
+ if (charBefore === ':') {
16
+ return 'Missing value after ":"';
17
+ }
18
+ if (!charAfter) {
19
+ return 'Unexpected end of JSON input';
20
+ }
21
+ return 'Invalid JSON syntax';
22
+ };
23
+ export const jsonLinter = (view) => {
24
+ const diagnostics = [];
25
+ const tree = syntaxTree(view.state);
26
+ const docLength = view.state.doc.length;
27
+ tree.iterate({
28
+ enter(node) {
29
+ if (!node.type.isError)
30
+ return;
31
+ const from = node.from;
32
+ const to = Math.min(node.to, docLength);
33
+ diagnostics.push({
34
+ from,
35
+ to: from === to ? from + 1 : to,
36
+ severity: 'error',
37
+ message: getErrorMessage(view, from),
38
+ });
39
+ },
40
+ });
41
+ return diagnostics;
42
+ };
@@ -0,0 +1,4 @@
1
+ import { EditorView } from '@codemirror/view';
2
+ import { Diagnostic } from '@codemirror/lint';
3
+ export declare const validation: (linterFn: (view: EditorView) => Diagnostic[], onValidationChange?: (isValid: boolean) => void) => (view: EditorView) => Diagnostic[];
4
+ //# sourceMappingURL=jsonValidation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonValidation.d.ts","sourceRoot":"","sources":["../../../../src/core/diagnostics/json/jsonValidation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,eAAO,MAAM,UAAU,aAEL,CAAC,IAAI,EAAE,UAAU,KAAK,UAAU,EAAE,uBACvB,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,YAE5C,UAAU,KAAG,UAAU,EAS7B,CAAC"}
@@ -0,0 +1,8 @@
1
+ export const validation = (linterFn, onValidationChange) => (view) => {
2
+ const diagnostics = linterFn(view);
3
+ if (onValidationChange) {
4
+ const isValid = diagnostics.every((d) => d.severity !== 'error');
5
+ onValidationChange(isValid);
6
+ }
7
+ return diagnostics;
8
+ };
@@ -0,0 +1,3 @@
1
+ import { CompletionContext, CompletionResult } from '@codemirror/autocomplete';
2
+ export declare const safeJsonCompletion: (schema: Record<string, any>) => (ctx: CompletionContext) => CompletionResult | null;
3
+ //# sourceMappingURL=safeJsonCompletion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safeJsonCompletion.d.ts","sourceRoot":"","sources":["../../../../src/core/diagnostics/json/safeJsonCompletion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAG/E,eAAO,MAAM,kBAAkB,WAAY,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,WAG7C,iBAAiB,KAAG,gBAAgB,GAAG,IAIvD,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { jsonCompletion } from 'codemirror-json-schema';
2
+ export const safeJsonCompletion = (schema) => {
3
+ const source = jsonCompletion(schema);
4
+ return (ctx) => {
5
+ const result = source(ctx);
6
+ return Array.isArray(result) ? null : result;
7
+ };
8
+ };
@@ -1,4 +1,4 @@
1
1
  import { EditorView } from '@codemirror/view';
2
2
  import { CreateEditorOptions } from '../../types';
3
- export declare const createEditor: ({ value, parent, theme, readOnly, language, languageOptions, onChange, }: CreateEditorOptions) => EditorView;
3
+ export declare const createEditor: ({ value, parent, theme, readOnly, language, languageOptions, search, onChange, }: CreateEditorOptions) => EditorView;
4
4
  //# sourceMappingURL=createEditor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createEditor.d.ts","sourceRoot":"","sources":["../../../src/core/editor/createEditor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAM9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGlD,eAAO,MAAM,YAAY,6EAQtB,mBAAmB,eAoBrB,CAAC"}
1
+ {"version":3,"file":"createEditor.d.ts","sourceRoot":"","sources":["../../../src/core/editor/createEditor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAM9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGlD,eAAO,MAAM,YAAY,qFAStB,mBAAmB,eAqBrB,CAAC"}
@@ -1,10 +1,10 @@
1
1
  import { EditorState } from '@codemirror/state';
2
2
  import { EditorView } from '@codemirror/view';
3
3
  import { basicSetup } from 'codemirror';
4
- import { readOnlyExtension } from '../extensions';
4
+ import { readOnlyExtension, searchExtensions } from '../extensions';
5
5
  import { buildLanguageExtensions } from '../languages';
6
6
  import { getThemeExtension } from '../themes';
7
- export const createEditor = ({ value, parent, theme, readOnly = false, language, languageOptions, onChange, }) => {
7
+ export const createEditor = ({ value, parent, theme, readOnly = false, language, languageOptions, search, onChange, }) => {
8
8
  const state = EditorState.create({
9
9
  doc: value,
10
10
  extensions: [
@@ -12,6 +12,7 @@ export const createEditor = ({ value, parent, theme, readOnly = false, language,
12
12
  ...buildLanguageExtensions(language, languageOptions),
13
13
  getThemeExtension(theme),
14
14
  readOnlyExtension(readOnly),
15
+ searchExtensions(search),
15
16
  EditorView.updateListener.of((update) => {
16
17
  if (update.docChanged) {
17
18
  onChange?.(update.state.doc.toString());
@@ -1 +1 @@
1
- {"version":3,"file":"editorController.d.ts","sourceRoot":"","sources":["../../../src/core/editor/editorController.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,wBAAgB,sBAAsB,IAAI,gBAAgB,CAuBzD"}
1
+ {"version":3,"file":"editorController.d.ts","sourceRoot":"","sources":["../../../src/core/editor/editorController.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,wBAAgB,sBAAsB,IAAI,gBAAgB,CAyCzD"}
@@ -1,4 +1,4 @@
1
- import { copyToClipboard, foldAllCode, unfoldAllCode, formatCode, } from '../extensions';
1
+ import { copyToClipboard, foldAllCode, unfoldAllCode, formatCode, openSearch, closeSearch, replace, replaceAllOccurrences, searchNext, searchPrevious, } from '../extensions';
2
2
  export function createEditorController() {
3
3
  let view = null;
4
4
  return {
@@ -20,5 +20,23 @@ export function createEditorController() {
20
20
  format(formatter) {
21
21
  return formatCode(view, formatter);
22
22
  },
23
+ openSearch() {
24
+ openSearch(view);
25
+ },
26
+ closeSearch() {
27
+ closeSearch(view);
28
+ },
29
+ searchNext() {
30
+ searchNext(view);
31
+ },
32
+ searchPrevious() {
33
+ searchPrevious(view);
34
+ },
35
+ replace() {
36
+ replace(view);
37
+ },
38
+ replaceAll() {
39
+ replaceAllOccurrences(view);
40
+ },
23
41
  };
24
42
  }
@@ -1 +1 @@
1
- {"version":3,"file":"fold.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/fold.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnD,eAAO,MAAM,WAAW,SAAU,UAAU,GAAG,IAAI,GAAG,SAAS,YAI9D,CAAC;AAEF,eAAO,MAAM,aAAa,SAAU,UAAU,GAAG,IAAI,GAAG,SAAS,YAIhE,CAAC"}
1
+ {"version":3,"file":"fold.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/fold.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AASnD,eAAO,MAAM,WAAW,SAAU,UAAU,GAAG,IAAI,GAAG,SAAS,YAmB9D,CAAC;AAEF,eAAO,MAAM,aAAa,SAAU,UAAU,GAAG,IAAI,GAAG,SAAS,YAIhE,CAAC"}
@@ -1,8 +1,20 @@
1
- import { foldAll, unfoldAll } from '@codemirror/language';
1
+ import { syntaxTree, foldable, foldEffect, unfoldAll, } from '@codemirror/language';
2
2
  export const foldAllCode = (view) => {
3
3
  if (!view)
4
4
  return false;
5
- return foldAll(view);
5
+ const effects = [];
6
+ syntaxTree(view.state).iterate({
7
+ enter(node) {
8
+ const range = foldable(view.state, node.from, node.to);
9
+ if (range) {
10
+ effects.push(foldEffect.of(range));
11
+ }
12
+ },
13
+ });
14
+ if (!effects.length)
15
+ return false;
16
+ view.dispatch({ effects });
17
+ return true;
6
18
  };
7
19
  export const unfoldAllCode = (view) => {
8
20
  if (!view)
@@ -2,4 +2,5 @@ export { copyToClipboard } from './copy';
2
2
  export { foldAllCode, unfoldAllCode } from './fold';
3
3
  export { formatCode } from './format';
4
4
  export { readOnlyExtension } from './readOnly';
5
+ export { openSearch, closeSearch, searchExtensions, searchNext, searchPrevious, replace, replaceAllOccurrences, } from './search';
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EACH,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,UAAU,EACV,cAAc,EACd,OAAO,EACP,qBAAqB,GACxB,MAAM,UAAU,CAAC"}
@@ -2,3 +2,4 @@ export { copyToClipboard } from './copy';
2
2
  export { foldAllCode, unfoldAllCode } from './fold';
3
3
  export { formatCode } from './format';
4
4
  export { readOnlyExtension } from './readOnly';
5
+ export { openSearch, closeSearch, searchExtensions, searchNext, searchPrevious, replace, replaceAllOccurrences, } from './search';
@@ -0,0 +1,11 @@
1
+ import type { EditorView } from '@codemirror/view';
2
+ import { Extension } from '@codemirror/state';
3
+ import { SearchOptions } from '../../types';
4
+ export declare const openSearch: (view: EditorView | null | undefined) => void;
5
+ export declare const closeSearch: (view: EditorView | null | undefined) => void;
6
+ export declare const searchNext: (view: EditorView | null | undefined) => void;
7
+ export declare const searchPrevious: (view: EditorView | null | undefined) => void;
8
+ export declare const replace: (view: EditorView | null | undefined) => void;
9
+ export declare const replaceAllOccurrences: (view: EditorView | null | undefined) => void;
10
+ export declare const searchExtensions: (searchConfig?: boolean | SearchOptions) => Extension;
11
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAUnD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,eAAO,MAAM,UAAU,SAAU,UAAU,GAAG,IAAI,GAAG,SAAS,SAI7D,CAAC;AAEF,eAAO,MAAM,WAAW,SAAU,UAAU,GAAG,IAAI,GAAG,SAAS,SAI9D,CAAC;AAEF,eAAO,MAAM,UAAU,SAAU,UAAU,GAAG,IAAI,GAAG,SAAS,SAI7D,CAAC;AAEF,eAAO,MAAM,cAAc,SAAU,UAAU,GAAG,IAAI,GAAG,SAAS,SAIjE,CAAC;AAEF,eAAO,MAAM,OAAO,SAAU,UAAU,GAAG,IAAI,GAAG,SAAS,SAI1D,CAAC;AAEF,eAAO,MAAM,qBAAqB,SAAU,UAAU,GAAG,IAAI,GAAG,SAAS,SAIxE,CAAC;AAeF,eAAO,MAAM,gBAAgB,kBACX,OAAO,GAAG,aAAa,KACtC,SAkBF,CAAC"}
@@ -0,0 +1,54 @@
1
+ import { openSearchPanel, closeSearchPanel, search, findPrevious, findNext, replaceNext, replaceAll, } from '@codemirror/search';
2
+ export const openSearch = (view) => {
3
+ if (!view)
4
+ return;
5
+ openSearchPanel(view);
6
+ };
7
+ export const closeSearch = (view) => {
8
+ if (!view)
9
+ return;
10
+ closeSearchPanel(view);
11
+ };
12
+ export const searchNext = (view) => {
13
+ if (!view)
14
+ return;
15
+ findNext(view);
16
+ };
17
+ export const searchPrevious = (view) => {
18
+ if (!view)
19
+ return;
20
+ findPrevious(view);
21
+ };
22
+ export const replace = (view) => {
23
+ if (!view)
24
+ return;
25
+ replaceNext(view);
26
+ };
27
+ export const replaceAllOccurrences = (view) => {
28
+ if (!view)
29
+ return;
30
+ replaceAll(view);
31
+ };
32
+ const resolveSearch = (search) => {
33
+ if (!search)
34
+ return { enabled: false };
35
+ if (search === true) {
36
+ return { enabled: true };
37
+ }
38
+ return {
39
+ enabled: search.enabled ?? true,
40
+ ...search,
41
+ };
42
+ };
43
+ export const searchExtensions = (searchConfig = {}) => {
44
+ const options = resolveSearch(searchConfig);
45
+ if (!options.enabled)
46
+ return [];
47
+ const { top = true, caseSensitive = false, regexp = false, wholeWord = false, } = options ?? {};
48
+ return search({
49
+ top,
50
+ caseSensitive,
51
+ regexp,
52
+ wholeWord,
53
+ });
54
+ };
@@ -1,5 +1,5 @@
1
1
  import { jsonLanguage } from '.';
2
- import { jsonDiagnosticsExtension } from '../diagnostics';
2
+ import { jsonDiagnosticsExtension } from '../diagnostics/json';
3
3
  export const buildLanguageExtensions = (language, options) => {
4
4
  switch (language) {
5
5
  case 'json':
@@ -11,6 +11,12 @@ export interface EditorController {
11
11
  foldAll(): boolean;
12
12
  unfoldAll(): boolean;
13
13
  format(formatter: (code: string) => string): boolean;
14
+ openSearch(): void;
15
+ closeSearch(): void;
16
+ searchNext(): void;
17
+ searchPrevious(): void;
18
+ replace(): void;
19
+ replaceAll(): void;
14
20
  }
15
21
  export interface CreateEditorOptions {
16
22
  parent: HTMLElement;
@@ -19,6 +25,7 @@ export interface CreateEditorOptions {
19
25
  readOnly?: boolean;
20
26
  language: EditorLanguage;
21
27
  languageOptions?: LanguageOptions;
28
+ search?: boolean | SearchOptions;
22
29
  onChange?: (value: string) => void;
23
30
  }
24
31
  export interface EditorContainerProps {
@@ -28,6 +35,7 @@ export interface EditorContainerProps {
28
35
  readOnly?: boolean;
29
36
  language: EditorLanguage;
30
37
  languageOptions?: LanguageOptions;
38
+ search?: boolean | SearchOptions;
31
39
  onChange?: (value: string) => void;
32
40
  }
33
41
  interface BaseCodeEditorProps {
@@ -35,6 +43,7 @@ interface BaseCodeEditorProps {
35
43
  readOnly?: boolean;
36
44
  language: EditorLanguage;
37
45
  languageOptions?: LanguageOptions;
46
+ search?: boolean | SearchOptions;
38
47
  onReady?: (controller: EditorController) => void;
39
48
  }
40
49
  interface ControlledCodeEditorProps {
@@ -59,6 +68,14 @@ export interface JsonEditorConfig {
59
68
  schemaLint?: boolean;
60
69
  hover?: boolean;
61
70
  autocomplete?: boolean;
71
+ onValidationChange?: (isValid: boolean) => void;
72
+ }
73
+ export interface SearchOptions {
74
+ enabled?: boolean;
75
+ top?: boolean;
76
+ caseSensitive?: boolean;
77
+ regexp?: boolean;
78
+ wholeWord?: boolean;
62
79
  }
63
80
  export {};
64
81
  //# sourceMappingURL=editor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../src/types/editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,MAAM,SAAS,GACf,OAAO,GACP,MAAM,GACN,WAAW,GACX,cAAc,GACd,gBAAgB,GAChB,oBAAoB,GACpB,sBAAsB,GACtB,eAAe,GACf,gBAAgB,GAChB,WAAW,GACX,aAAa,GACb,gBAAgB,GAChB,cAAc,CAAC;AAErB,MAAM,MAAM,cAAc,GAAG,MAAM,eAAe,CAAC;AAEnD,MAAM,WAAW,eAAe;IAC5B,IAAI,CAAC,EAAE,gBAAgB,CAAC;CAQ3B;AAED,MAAM,WAAW,gBAAgB;IAC7B,OAAO,IAAI,UAAU,GAAG,IAAI,CAAC;IAC7B,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI,CAAC;IACvC,IAAI,IAAI,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IACrC,OAAO,IAAI,OAAO,CAAC;IACnB,SAAS,IAAI,OAAO,CAAC;IACrB,MAAM,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,OAAO,CAAC;CACxD;AAED,MAAM,WAAW,mBAAmB;IAChC,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,cAAc,CAAC;IACzB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED,MAAM,WAAW,oBAAoB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,gBAAgB,CAAC;IAC7B,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,cAAc,CAAC;IACzB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED,UAAU,mBAAmB;IACzB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,cAAc,CAAC;IACzB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,gBAAgB,KAAK,IAAI,CAAC;CACpD;AAED,UAAU,yBAAyB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,YAAY,CAAC,EAAE,KAAK,CAAC;CACxB;AAED,UAAU,2BAA2B;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,QAAQ,CAAC,EAAE,KAAK,CAAC;CACpB;AAED,MAAM,MAAM,eAAe,GACrB,CAAC,mBAAmB,GAAG,yBAAyB,CAAC,GACjD,CAAC,mBAAmB,GAAG,2BAA2B,CAAC,CAAC;AAE1D,MAAM,WAAW,2BAA2B;IACxC,IAAI,EAAE,YAAY,GAAG,cAAc,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,YAAY,CAAC,EAAE,OAAO,CAAC;CAC1B"}
1
+ {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../src/types/editor.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"CodeEditor.d.ts","sourceRoot":"","sources":["../../src/ui/CodeEditor.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3C,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAkChD,CAAC"}
1
+ {"version":3,"file":"CodeEditor.d.ts","sourceRoot":"","sources":["../../src/ui/CodeEditor.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3C,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CA0ChD,CAAC"}
@@ -4,7 +4,7 @@ import { createEditorController } from '../core/editor';
4
4
  import { resolveControlledInvariant } from '../core/invariants';
5
5
  import { EditorContainer } from './';
6
6
  export const CodeEditor = (props) => {
7
- const { theme, readOnly, language, languageOptions, onChange, onReady } = props;
7
+ const { theme, readOnly, language, languageOptions, search, onChange, onReady, } = props;
8
8
  const { mode, value: resolvedContent } = resolveControlledInvariant(props);
9
9
  const [internalContent, setInternalContent] = useState(resolvedContent);
10
10
  const controller = useMemo(() => createEditorController(), []);
@@ -17,5 +17,5 @@ export const CodeEditor = (props) => {
17
17
  useEffect(() => {
18
18
  onReady?.(controller);
19
19
  }, [controller, onReady]);
20
- return (_jsx(EditorContainer, { value: mode === 'controlled' ? resolvedContent : internalContent, theme: theme, readOnly: readOnly, language: language, languageOptions: languageOptions, onChange: handleEditorChange, controller: controller }));
20
+ return (_jsx(EditorContainer, { value: mode === 'controlled' ? resolvedContent : internalContent, theme: theme, readOnly: readOnly, language: language, languageOptions: languageOptions, search: search, onChange: handleEditorChange, controller: controller }));
21
21
  };
@@ -1,3 +1,3 @@
1
1
  import { EditorContainerProps } from '../types';
2
- export declare const EditorContainer: ({ value, theme, readOnly, language, languageOptions, controller, onChange, }: EditorContainerProps) => import("react/jsx-runtime").JSX.Element;
2
+ export declare const EditorContainer: ({ value, theme, readOnly, language, languageOptions, search, controller, onChange, }: EditorContainerProps) => import("react/jsx-runtime").JSX.Element;
3
3
  //# sourceMappingURL=EditorContainer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"EditorContainer.d.ts","sourceRoot":"","sources":["../../src/ui/EditorContainer.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAEhD,eAAO,MAAM,eAAe,iFAQzB,oBAAoB,4CA0CtB,CAAC"}
1
+ {"version":3,"file":"EditorContainer.d.ts","sourceRoot":"","sources":["../../src/ui/EditorContainer.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAEhD,eAAO,MAAM,eAAe,yFASzB,oBAAoB,4CA2CtB,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useEffect, useRef } from 'react';
3
3
  import { createEditor } from '../core/editor';
4
- export const EditorContainer = ({ value, theme, readOnly, language, languageOptions, controller, onChange, }) => {
4
+ export const EditorContainer = ({ value, theme, readOnly, language, languageOptions, search, controller, onChange, }) => {
5
5
  const editorRef = useRef(null);
6
6
  useEffect(() => {
7
7
  const editor = editorRef.current;
@@ -14,6 +14,7 @@ export const EditorContainer = ({ value, theme, readOnly, language, languageOpti
14
14
  readOnly,
15
15
  language,
16
16
  languageOptions,
17
+ search,
17
18
  onChange,
18
19
  });
19
20
  controller.setView(view);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-codemirror-editor",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "private": false,
5
5
  "description": "A modular, extensible React code editor built on CodeMirror 6 with first-class JSON support.",
6
6
  "type": "module",
@@ -43,11 +43,13 @@
43
43
  },
44
44
  "keywords": [
45
45
  "react",
46
- "code-editor",
47
46
  "codemirror",
48
- "json-editor",
49
- "schema-validation",
50
- "react-library"
47
+ "codemirror6",
48
+ "editor",
49
+ "code-editor",
50
+ "react-editor",
51
+ "react-codemirror",
52
+ "ide"
51
53
  ],
52
54
  "license": "MIT"
53
- }
55
+ }
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/diagnostics/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"jsonDiagnostics.d.ts","sourceRoot":"","sources":["../../../src/core/diagnostics/jsonDiagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAS9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAsE/C,eAAO,MAAM,wBAAwB,aACxB,gBAAgB,KAC1B,SAuCF,CAAC"}
@@ -1,78 +0,0 @@
1
- import { hoverTooltip } from '@codemirror/view';
2
- import { linter, lintGutter } from '@codemirror/lint';
3
- import { autocompletion, } from '@codemirror/autocomplete';
4
- import { syntaxTree } from '@codemirror/language';
5
- import { jsonSchemaLinter, jsonSchemaHover, jsonCompletion, stateExtensions, } from 'codemirror-json-schema';
6
- const getErrorMessage = (view, from) => {
7
- const doc = view.state.doc;
8
- const charBefore = from > 0 ? doc.sliceString(from - 1, from) : '';
9
- const charAfter = doc.sliceString(from, from + 1);
10
- if (charBefore === ',') {
11
- return 'Trailing comma is not allowed in JSON';
12
- }
13
- if (charAfter === '}' || charAfter === ']') {
14
- return 'Missing value before closing bracket';
15
- }
16
- if (charAfter === ':') {
17
- return 'Missing value after ":"';
18
- }
19
- if (charBefore === ':') {
20
- return 'Missing value after ":"';
21
- }
22
- if (!charAfter) {
23
- return 'Unexpected end of JSON input';
24
- }
25
- return 'Invalid JSON syntax';
26
- };
27
- const jsonLinter = (view) => {
28
- const diagnostics = [];
29
- const tree = syntaxTree(view.state);
30
- const docLength = view.state.doc.length;
31
- tree.iterate({
32
- enter(node) {
33
- if (!node.type.isError)
34
- return;
35
- const from = node.from;
36
- const to = Math.min(node.to, docLength);
37
- diagnostics.push({
38
- from,
39
- to: from === to ? from + 1 : to,
40
- severity: 'error',
41
- message: getErrorMessage(view, from),
42
- });
43
- },
44
- });
45
- return diagnostics;
46
- };
47
- const safeJsonCompletion = (schema) => {
48
- const source = jsonCompletion(schema);
49
- return (ctx) => {
50
- const result = source(ctx);
51
- return Array.isArray(result) ? null : result;
52
- };
53
- };
54
- export const jsonDiagnosticsExtension = (options = {}) => {
55
- const { diagnostics = true, gutter = true, schema, schemaLint = !!schema, hover = !!schema, autocomplete = !!schema, } = options;
56
- const extensions = [];
57
- if (diagnostics) {
58
- extensions.push(linter(jsonLinter));
59
- if (gutter) {
60
- extensions.push(lintGutter());
61
- }
62
- }
63
- if (schema) {
64
- extensions.push(stateExtensions(schema));
65
- if (schemaLint) {
66
- extensions.push(linter(jsonSchemaLinter(schema)));
67
- }
68
- if (hover) {
69
- extensions.push(hoverTooltip(jsonSchemaHover(schema)));
70
- }
71
- if (autocomplete) {
72
- extensions.push(autocompletion({
73
- override: [safeJsonCompletion(schema)],
74
- }));
75
- }
76
- }
77
- return extensions;
78
- };