@xh/hoist 79.0.0-SNAPSHOT.1765576094437 → 79.0.0-SNAPSHOT.1765576473366
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/CHANGELOG.md +26 -0
- package/admin/tabs/cluster/instances/connpool/ConnPoolMonitorPanel.ts +1 -1
- package/admin/tabs/cluster/instances/services/DetailsPanel.ts +1 -1
- package/admin/tabs/cluster/objects/DetailPanel.ts +1 -1
- package/build/types/core/HoistBase.d.ts +1 -1
- package/build/types/desktop/cmp/input/CodeInput.d.ts +9 -21
- package/build/types/desktop/cmp/input/JsonInput.d.ts +15 -3
- package/core/HoistBase.ts +1 -7
- package/desktop/cmp/filechooser/FileChooserModel.ts +1 -2
- package/desktop/cmp/input/CodeInput.scss +21 -15
- package/desktop/cmp/input/CodeInput.ts +246 -193
- package/desktop/cmp/input/JsonInput.ts +126 -22
- package/package.json +10 -2
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -4,15 +4,27 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Copyright © 2025 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
|
-
import {hoistCmp} from '@xh/hoist/core';
|
|
7
|
+
import {hoistCmp, PlainObject} from '@xh/hoist/core';
|
|
8
8
|
import '@xh/hoist/desktop/register';
|
|
9
9
|
import {fmtJson} from '@xh/hoist/format';
|
|
10
|
-
import
|
|
11
|
-
import 'codemirror/mode/javascript/javascript';
|
|
10
|
+
import Ajv, {Options, SchemaObject, ValidateFunction} from 'ajv';
|
|
12
11
|
import {codeInput, CodeInputProps} from './CodeInput';
|
|
13
|
-
import {jsonlint} from './impl/jsonlint';
|
|
12
|
+
import {jsonlint} from './impl/jsonlint.js';
|
|
14
13
|
|
|
15
|
-
export
|
|
14
|
+
export interface JsonInputProps extends CodeInputProps {
|
|
15
|
+
/**
|
|
16
|
+
* JSON Schema object used to validate the input JSON. Accepts any valid JSON Schema keywords
|
|
17
|
+
* supported by AJV, such as `type`, `properties`, `required`, and `additionalProperties`.
|
|
18
|
+
* @see https://ajv.js.org/json-schema.html
|
|
19
|
+
*/
|
|
20
|
+
jsonSchema?: SchemaObject;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Configuration object with any properties supported by the AJV API.
|
|
24
|
+
* @see {@link https://ajv.js.org/options.html}
|
|
25
|
+
*/
|
|
26
|
+
ajvProps?: Options;
|
|
27
|
+
}
|
|
16
28
|
|
|
17
29
|
/**
|
|
18
30
|
* Code-editor style input for editing and validating JSON, powered by CodeMirror.
|
|
@@ -21,11 +33,13 @@ export const [JsonInput, jsonInput] = hoistCmp.withFactory<JsonInputProps>({
|
|
|
21
33
|
displayName: 'JsonInput',
|
|
22
34
|
className: 'xh-json-input',
|
|
23
35
|
render(props, ref) {
|
|
36
|
+
const {jsonSchema, ajvProps, ...rest} = props;
|
|
37
|
+
|
|
24
38
|
return codeInput({
|
|
25
|
-
linter:
|
|
39
|
+
linter: jsonLinterWrapper(jsonSchema, ajvProps),
|
|
26
40
|
formatter: fmtJson,
|
|
27
|
-
|
|
28
|
-
...
|
|
41
|
+
language: 'json',
|
|
42
|
+
...rest,
|
|
29
43
|
ref
|
|
30
44
|
});
|
|
31
45
|
}
|
|
@@ -33,24 +47,114 @@ export const [JsonInput, jsonInput] = hoistCmp.withFactory<JsonInputProps>({
|
|
|
33
47
|
(JsonInput as any).hasLayoutSupport = true;
|
|
34
48
|
|
|
35
49
|
//----------------------
|
|
36
|
-
//
|
|
37
|
-
|
|
38
|
-
function
|
|
39
|
-
|
|
40
|
-
if (!
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
// JSON Linter helper
|
|
51
|
+
//----------------------
|
|
52
|
+
function jsonLinterWrapper(jsonSchema?: PlainObject, ajvProps?: Options) {
|
|
53
|
+
// No schema → only use JSONLint
|
|
54
|
+
if (!jsonSchema) return jsonLintOnly;
|
|
55
|
+
|
|
56
|
+
const ajv = new Ajv({...ajvProps}),
|
|
57
|
+
validate = ajv.compile(jsonSchema);
|
|
58
|
+
|
|
59
|
+
return (text: string) => {
|
|
60
|
+
const annotations: any[] = [];
|
|
61
|
+
|
|
62
|
+
if (!text.trim()) return annotations;
|
|
63
|
+
|
|
64
|
+
runJsonLint(text, annotations);
|
|
65
|
+
if (annotations.length) return annotations;
|
|
66
|
+
|
|
67
|
+
runAjvValidation(text, validate, annotations);
|
|
68
|
+
|
|
69
|
+
return annotations;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Run JSONLint and append errors to annotations */
|
|
74
|
+
function runJsonLint(text: string, annotations: any[]) {
|
|
75
|
+
jsonlint.parseError = (message, hash) => {
|
|
76
|
+
const {first_line, first_column, last_line, last_column} = hash.loc;
|
|
77
|
+
annotations.push({
|
|
78
|
+
from: indexFromLineCol(text, first_line, first_column),
|
|
79
|
+
to: indexFromLineCol(text, last_line, last_column),
|
|
80
|
+
message,
|
|
81
|
+
severity: 'error'
|
|
48
82
|
});
|
|
49
83
|
};
|
|
50
84
|
|
|
51
85
|
try {
|
|
52
86
|
jsonlint.parse(text);
|
|
53
|
-
} catch
|
|
87
|
+
} catch {
|
|
88
|
+
// intentionally ignored: parseError handles reporting
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Run AJV schema validation and append errors to annotations */
|
|
93
|
+
function runAjvValidation(text: string, validate: ValidateFunction, annotations: any[]) {
|
|
94
|
+
let data: any;
|
|
95
|
+
try {
|
|
96
|
+
data = JSON.parse(text);
|
|
97
|
+
} catch {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const valid = validate(data);
|
|
102
|
+
if (valid || !validate.errors) return;
|
|
103
|
+
|
|
104
|
+
validate.errors.forEach(err => {
|
|
105
|
+
const {from, to} = getErrorPosition(err, text),
|
|
106
|
+
message = formatAjvMessage(err);
|
|
107
|
+
|
|
108
|
+
annotations.push({from, to, message, severity: 'error'});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Determine text positions for AJV error highlighting */
|
|
113
|
+
function getErrorPosition(err: any, text: string): {from: number; to: number} {
|
|
114
|
+
let from = 0,
|
|
115
|
+
to = 0,
|
|
116
|
+
key: string;
|
|
117
|
+
|
|
118
|
+
if (err.keyword === 'additionalProperties' && err.params?.additionalProperty) {
|
|
119
|
+
key = err.params.additionalProperty;
|
|
120
|
+
} else {
|
|
121
|
+
const parts = (err.instancePath || '').split('/').filter(Boolean);
|
|
122
|
+
key = parts[parts.length - 1];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (key) {
|
|
126
|
+
const idx = text.indexOf(`"${key}"`);
|
|
127
|
+
if (idx >= 0) {
|
|
128
|
+
from = idx;
|
|
129
|
+
to = idx + key.length + 2;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return {from, to};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Format AJV error messages nicely */
|
|
137
|
+
function formatAjvMessage(err: any): string {
|
|
138
|
+
const path = err.instancePath || '(root)';
|
|
139
|
+
if (err.keyword === 'additionalProperties' && err.params?.additionalProperty) {
|
|
140
|
+
return `Unexpected property "${err.params.additionalProperty}"`;
|
|
141
|
+
}
|
|
142
|
+
return `${path} ${err.message}`;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** JSONLint-only linter (used when no jsonSchema prop) */
|
|
146
|
+
function jsonLintOnly(text: string) {
|
|
147
|
+
const annotations: any[] = [];
|
|
148
|
+
if (!text) return annotations;
|
|
149
|
+
|
|
150
|
+
runJsonLint(text, annotations);
|
|
151
|
+
return annotations;
|
|
152
|
+
}
|
|
54
153
|
|
|
55
|
-
|
|
154
|
+
/** Convert line/col to string index */
|
|
155
|
+
function indexFromLineCol(text: string, line: number, col: number): number {
|
|
156
|
+
const lines = text.split('\n');
|
|
157
|
+
let idx = 0;
|
|
158
|
+
for (let i = 0; i < line - 1; i++) idx += lines[i].length + 1;
|
|
159
|
+
return idx + col;
|
|
56
160
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xh/hoist",
|
|
3
|
-
"version": "79.0.0-SNAPSHOT.
|
|
3
|
+
"version": "79.0.0-SNAPSHOT.1765576473366",
|
|
4
4
|
"description": "Hoist add-on for building and deploying React Applications.",
|
|
5
5
|
"repository": "github:xh/hoist-react",
|
|
6
6
|
"homepage": "https://xh.io",
|
|
@@ -33,6 +33,12 @@
|
|
|
33
33
|
"@blueprintjs/core": "^5.10.5",
|
|
34
34
|
"@blueprintjs/datetime": "^5.3.7",
|
|
35
35
|
"@blueprintjs/datetime2": "^2.3.7",
|
|
36
|
+
"@codemirror/commands": "6.9.0",
|
|
37
|
+
"@codemirror/language": "6.11.3",
|
|
38
|
+
"@codemirror/language-data": "6.5.2",
|
|
39
|
+
"@codemirror/lint": "6.9.0",
|
|
40
|
+
"@codemirror/search": "6.5.11",
|
|
41
|
+
"@codemirror/view": "6.38.6",
|
|
36
42
|
"@fortawesome/fontawesome-pro": "^6.6.0",
|
|
37
43
|
"@fortawesome/fontawesome-svg-core": "^6.6.0",
|
|
38
44
|
"@fortawesome/pro-light-svg-icons": "^6.6.0",
|
|
@@ -43,9 +49,11 @@
|
|
|
43
49
|
"@onsenui/fastclick": "~1.1.1",
|
|
44
50
|
"@popperjs/core": "~2.11.0",
|
|
45
51
|
"@seznam/compose-react-refs": "~1.0.5",
|
|
52
|
+
"@uiw/codemirror-themes-all": "~4.25.2",
|
|
53
|
+
"ajv": "~8.17.1",
|
|
46
54
|
"classnames": "~2.5.1",
|
|
47
55
|
"clipboard-copy": "~4.0.1",
|
|
48
|
-
"codemirror": "~
|
|
56
|
+
"codemirror": "~6.0.2",
|
|
49
57
|
"core-js": "3.x",
|
|
50
58
|
"debounce-promise": "~3.1.0",
|
|
51
59
|
"dompurify": "~3.3.0",
|