dustyui 1.0.2 → 2.0.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.
- package/LICENSE +21 -0
- package/README.md +56 -1
- package/dist/Avatar/Avatar.d.ts +9 -0
- package/dist/Avatar/Avatar.js +17 -0
- package/dist/Avatar/Avatar.module.css +33 -0
- package/dist/Avatar/getInitials.d.ts +1 -0
- package/dist/Avatar/getInitials.js +13 -0
- package/dist/Badge/Badge.d.ts +3 -13
- package/dist/Badge/Badge.js +5 -31
- package/dist/Badge/Badge.module.css +12 -11
- package/dist/Button/Button.d.ts +6 -11
- package/dist/Button/Button.js +21 -40
- package/dist/Button/Button.module.css +93 -22
- package/dist/IconButton/IconButton.d.ts +7 -0
- package/dist/IconButton/IconButton.js +8 -0
- package/dist/IconButton/IconButton.module.css +17 -0
- package/dist/ObjectInspector/InspectorDetails.d.ts +6 -0
- package/dist/ObjectInspector/InspectorDetails.js +32 -0
- package/dist/ObjectInspector/InspectorDetails.module.css +47 -0
- package/dist/ObjectInspector/InspectorSearch.d.ts +9 -0
- package/dist/ObjectInspector/InspectorSearch.js +12 -0
- package/dist/ObjectInspector/InspectorSearch.module.css +39 -0
- package/dist/ObjectInspector/ObjectInspector.d.ts +8 -0
- package/dist/ObjectInspector/ObjectInspector.js +83 -0
- package/dist/ObjectInspector/ObjectInspector.module.css +46 -0
- package/dist/ObjectInspector/describe/describe.d.ts +31 -0
- package/dist/ObjectInspector/describe/describe.js +123 -0
- package/dist/ObjectInspector/describe/getChildren.d.ts +21 -0
- package/dist/ObjectInspector/describe/getChildren.js +77 -0
- package/dist/ObjectInspector/describe/getNode.d.ts +2 -0
- package/dist/ObjectInspector/describe/getNode.js +9 -0
- package/dist/ObjectInspector/describe/getPath.d.ts +26 -0
- package/dist/ObjectInspector/describe/getPath.js +58 -0
- package/dist/ObjectInspector/describe/getPreview.d.ts +10 -0
- package/dist/ObjectInspector/describe/getPreview.js +189 -0
- package/dist/ObjectInspector/describe/getValueKind.d.ts +2 -0
- package/dist/ObjectInspector/describe/getValueKind.js +64 -0
- package/dist/ObjectInspector/describe/safeRead.d.ts +12 -0
- package/dist/ObjectInspector/describe/safeRead.js +88 -0
- package/dist/ObjectInspector/getCopyText.d.ts +2 -0
- package/dist/ObjectInspector/getCopyText.js +103 -0
- package/dist/ObjectInspector/getLabelText.d.ts +2 -0
- package/dist/ObjectInspector/getLabelText.js +15 -0
- package/dist/ObjectInspector/getValueText.d.ts +2 -0
- package/dist/ObjectInspector/getValueText.js +5 -0
- package/dist/ObjectInspector/search/getHighlightParts.d.ts +5 -0
- package/dist/ObjectInspector/search/getHighlightParts.js +20 -0
- package/dist/ObjectInspector/search/getMatches.d.ts +6 -0
- package/dist/ObjectInspector/search/getMatches.js +46 -0
- package/dist/ObjectInspector/search/getSearchStatus.d.ts +2 -0
- package/dist/ObjectInspector/search/getSearchStatus.js +14 -0
- package/dist/Tree/Tree.d.ts +14 -0
- package/dist/Tree/Tree.js +166 -0
- package/dist/Tree/Tree.module.css +65 -0
- package/dist/Tree/getWindow.d.ts +22 -0
- package/dist/Tree/getWindow.js +43 -0
- package/dist/Tree/treeModel.d.ts +55 -0
- package/dist/Tree/treeModel.js +203 -0
- package/dist/Tree/useRowWindow.d.ts +3 -0
- package/dist/Tree/useRowWindow.js +78 -0
- package/dist/Tree/useTypeahead.d.ts +2 -0
- package/dist/Tree/useTypeahead.js +15 -0
- package/dist/announcer/announcer.d.ts +2 -0
- package/dist/announcer/announcer.js +41 -0
- package/dist/index.d.ts +10 -2
- package/dist/index.js +9 -6
- package/dist/styles/themes/dusty.css +22 -0
- package/dist/styles/themes/mono.css +21 -0
- package/dist/styles/tokens.css +19 -13
- package/dist/styles/visuallyHidden.module.css +8 -0
- package/package.json +54 -38
- package/dist/Badge/Badge.cjs +0 -67
- package/dist/Button/Button.cjs +0 -74
- package/dist/index.cjs +0 -32
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { getValueKind } from "./getValueKind.js";
|
|
2
|
+
import { getConstructorName, getDataProperty, getDateTime, getFailureReason, getMapSize, getRegExpText, getSetSize, getSymbolText, getTypedArrayLength, isClass, } from "./safeRead.js";
|
|
3
|
+
const MAX_TEXT_LENGTH = 80;
|
|
4
|
+
const MAX_NESTED_TEXT_LENGTH = 20;
|
|
5
|
+
const MAX_MEMBERS = 5;
|
|
6
|
+
const ELLIPSIS = "…";
|
|
7
|
+
const GETTER = "(...)";
|
|
8
|
+
const IDENTIFIER = /^[A-Za-z_$][\w$]*$/u;
|
|
9
|
+
const LINE_BREAKING = /[\p{Cc}\u2028\u2029]/gu;
|
|
10
|
+
function toSingleLine(text) {
|
|
11
|
+
return text.replace(LINE_BREAKING, (character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, "0")}`);
|
|
12
|
+
}
|
|
13
|
+
function truncate(text, limit) {
|
|
14
|
+
const characters = Array.from(text);
|
|
15
|
+
return characters.length > limit
|
|
16
|
+
? `${characters.slice(0, limit).join("")}${ELLIPSIS}`
|
|
17
|
+
: text;
|
|
18
|
+
}
|
|
19
|
+
function quote(text, limit) {
|
|
20
|
+
return JSON.stringify(truncate(text, limit));
|
|
21
|
+
}
|
|
22
|
+
function withSize(name, size) {
|
|
23
|
+
return `${name}(${size})`;
|
|
24
|
+
}
|
|
25
|
+
function getArrayLength(value) {
|
|
26
|
+
try {
|
|
27
|
+
return getTypedArrayLength(value);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
const length = getDataProperty(value, "length");
|
|
31
|
+
return typeof length === "number" ? length : 0;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function getUninspectablePreview(reason) {
|
|
35
|
+
return `Uninspectable: ${truncate(reason, MAX_TEXT_LENGTH)}`;
|
|
36
|
+
}
|
|
37
|
+
function getFunctionPreview(value) {
|
|
38
|
+
const name = getDataProperty(value, "name");
|
|
39
|
+
const label = typeof name === "string" ? truncate(name, MAX_NESTED_TEXT_LENGTH) : "";
|
|
40
|
+
return isClass(value) ? `class ${label}`.trimEnd() : `ƒ ${label}()`;
|
|
41
|
+
}
|
|
42
|
+
function getDatePreview(value) {
|
|
43
|
+
const time = getDateTime(value);
|
|
44
|
+
return Number.isNaN(time) ? "Invalid Date" : new Date(time).toISOString();
|
|
45
|
+
}
|
|
46
|
+
function getErrorPreview(value) {
|
|
47
|
+
const name = getConstructorName(value) ?? "Error";
|
|
48
|
+
const message = getDataProperty(value, "message");
|
|
49
|
+
return typeof message === "string" && message !== ""
|
|
50
|
+
? `${name}: ${truncate(message, MAX_TEXT_LENGTH)}`
|
|
51
|
+
: name;
|
|
52
|
+
}
|
|
53
|
+
function getPrimitivePreview(value, kind, textLimit) {
|
|
54
|
+
switch (kind) {
|
|
55
|
+
case "string":
|
|
56
|
+
return quote(value, textLimit);
|
|
57
|
+
case "number":
|
|
58
|
+
return Object.is(value, -0) ? "-0" : String(value);
|
|
59
|
+
case "bigint":
|
|
60
|
+
return `${String(value)}n`;
|
|
61
|
+
case "boolean":
|
|
62
|
+
case "null":
|
|
63
|
+
case "undefined":
|
|
64
|
+
return String(value);
|
|
65
|
+
case "symbol":
|
|
66
|
+
return truncate(getSymbolText(value), textLimit);
|
|
67
|
+
default:
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function getNestedObjectPreview(value, kind) {
|
|
72
|
+
switch (kind) {
|
|
73
|
+
case "function":
|
|
74
|
+
return getFunctionPreview(value);
|
|
75
|
+
case "array":
|
|
76
|
+
return withSize(getConstructorName(value) ?? "Array", getArrayLength(value));
|
|
77
|
+
case "map":
|
|
78
|
+
return withSize("Map", getMapSize(value));
|
|
79
|
+
case "set":
|
|
80
|
+
return withSize("Set", getSetSize(value));
|
|
81
|
+
case "date":
|
|
82
|
+
return getDatePreview(value);
|
|
83
|
+
case "regexp":
|
|
84
|
+
return truncate(getRegExpText(value), MAX_NESTED_TEXT_LENGTH);
|
|
85
|
+
case "error":
|
|
86
|
+
return getConstructorName(value) ?? "Error";
|
|
87
|
+
default: {
|
|
88
|
+
const name = getConstructorName(value);
|
|
89
|
+
return name && name !== "Object" ? name : `{${ELLIPSIS}}`;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function getNestedPreview(value) {
|
|
94
|
+
try {
|
|
95
|
+
const kind = getValueKind(value);
|
|
96
|
+
return (getPrimitivePreview(value, kind, MAX_NESTED_TEXT_LENGTH) ??
|
|
97
|
+
getNestedObjectPreview(value, kind));
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
return getUninspectablePreview(getFailureReason(error));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function getSourcePreview(source) {
|
|
104
|
+
switch (source.type) {
|
|
105
|
+
case "value":
|
|
106
|
+
return getNestedPreview(source.value);
|
|
107
|
+
case "getter":
|
|
108
|
+
return GETTER;
|
|
109
|
+
case "failure":
|
|
110
|
+
return getUninspectablePreview(source.reason);
|
|
111
|
+
case "entry":
|
|
112
|
+
return `${getNestedPreview(source.key)} => ${getNestedPreview(source.value)}`;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function getMemberName(child) {
|
|
116
|
+
switch (child.step.type) {
|
|
117
|
+
case "property":
|
|
118
|
+
return IDENTIFIER.test(child.step.key)
|
|
119
|
+
? truncate(child.step.key, MAX_NESTED_TEXT_LENGTH)
|
|
120
|
+
: quote(child.step.key, MAX_NESTED_TEXT_LENGTH);
|
|
121
|
+
case "symbol":
|
|
122
|
+
return truncate(getSymbolText(child.step.key), MAX_NESTED_TEXT_LENGTH);
|
|
123
|
+
default:
|
|
124
|
+
return "";
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function getMembersPreview(children, open, close) {
|
|
128
|
+
const members = children.slice(0, MAX_MEMBERS).map((child) => {
|
|
129
|
+
const name = getMemberName(child);
|
|
130
|
+
const value = getSourcePreview(child.source);
|
|
131
|
+
return name === "" ? value : `${name}: ${value}`;
|
|
132
|
+
});
|
|
133
|
+
if (children.length > members.length) {
|
|
134
|
+
members.push(ELLIPSIS);
|
|
135
|
+
}
|
|
136
|
+
return `${open}${members.join(", ")}${close}`;
|
|
137
|
+
}
|
|
138
|
+
function getContainerPreview(input, value) {
|
|
139
|
+
const { kind, typeName, children } = input;
|
|
140
|
+
switch (kind) {
|
|
141
|
+
case "function":
|
|
142
|
+
return getFunctionPreview(value);
|
|
143
|
+
case "date":
|
|
144
|
+
return getDatePreview(value);
|
|
145
|
+
case "regexp":
|
|
146
|
+
return truncate(getRegExpText(value), MAX_TEXT_LENGTH);
|
|
147
|
+
case "error":
|
|
148
|
+
return getErrorPreview(value);
|
|
149
|
+
case "array":
|
|
150
|
+
return `${withSize(typeName ?? "Array", getArrayLength(value))} ${getMembersPreview(children, "[", "]")}`;
|
|
151
|
+
case "map":
|
|
152
|
+
return `${withSize("Map", getMapSize(value))} ${getMembersPreview(children, "{", "}")}`;
|
|
153
|
+
case "set":
|
|
154
|
+
return `${withSize("Set", getSetSize(value))} ${getMembersPreview(children, "{", "}")}`;
|
|
155
|
+
default: {
|
|
156
|
+
const name = typeName && typeName !== "Object"
|
|
157
|
+
? `${truncate(typeName, MAX_NESTED_TEXT_LENGTH)} `
|
|
158
|
+
: "";
|
|
159
|
+
return `${name}${getMembersPreview(children, "{", "}")}`;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
function getValuePreview(input) {
|
|
164
|
+
const value = input.source.type === "value" ? input.source.value : undefined;
|
|
165
|
+
try {
|
|
166
|
+
return (getPrimitivePreview(value, input.kind, MAX_TEXT_LENGTH) ??
|
|
167
|
+
getContainerPreview(input, value));
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
return getUninspectablePreview(getFailureReason(error));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function getRawPreview(input) {
|
|
174
|
+
switch (input.kind) {
|
|
175
|
+
case "getter":
|
|
176
|
+
return GETTER;
|
|
177
|
+
case "uninspectable":
|
|
178
|
+
return getUninspectablePreview(input.detail);
|
|
179
|
+
case "circular":
|
|
180
|
+
return `[Circular ${truncate(input.detail, MAX_TEXT_LENGTH)}]`;
|
|
181
|
+
case "entry":
|
|
182
|
+
return getSourcePreview(input.source);
|
|
183
|
+
default:
|
|
184
|
+
return getValuePreview(input);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
export function getPreview(input) {
|
|
188
|
+
return toSingleLine(getRawPreview(input));
|
|
189
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export type ValueKind = "string" | "number" | "bigint" | "boolean" | "null" | "undefined" | "symbol" | "function" | "array" | "object" | "map" | "set" | "date" | "regexp" | "error" | "entry" | "getter" | "circular" | "uninspectable";
|
|
2
|
+
export declare function getValueKind(value: unknown): ValueKind;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { getDateTime, getMapSize, getRegExpSource, getSetSize, getTypedArrayLength, } from "./safeRead.js";
|
|
2
|
+
function succeeds(read) {
|
|
3
|
+
try {
|
|
4
|
+
read();
|
|
5
|
+
return true;
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function isRegExp(value) {
|
|
12
|
+
return value !== RegExp.prototype && succeeds(() => getRegExpSource(value));
|
|
13
|
+
}
|
|
14
|
+
function isError(value) {
|
|
15
|
+
const { isError: nativeIsError } = Error;
|
|
16
|
+
return nativeIsError ? nativeIsError(value) : value instanceof Error;
|
|
17
|
+
}
|
|
18
|
+
function isTypedArray(value) {
|
|
19
|
+
return (ArrayBuffer.isView(value) && succeeds(() => getTypedArrayLength(value)));
|
|
20
|
+
}
|
|
21
|
+
function hasPlainPrototype(value) {
|
|
22
|
+
try {
|
|
23
|
+
const prototype = Reflect.getPrototypeOf(value);
|
|
24
|
+
return prototype === Object.prototype || prototype === null;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function getObjectKind(value) {
|
|
31
|
+
if (Array.isArray(value) || isTypedArray(value)) {
|
|
32
|
+
return "array";
|
|
33
|
+
}
|
|
34
|
+
if (hasPlainPrototype(value)) {
|
|
35
|
+
return "object";
|
|
36
|
+
}
|
|
37
|
+
if (succeeds(() => getMapSize(value))) {
|
|
38
|
+
return "map";
|
|
39
|
+
}
|
|
40
|
+
if (succeeds(() => getSetSize(value))) {
|
|
41
|
+
return "set";
|
|
42
|
+
}
|
|
43
|
+
if (succeeds(() => getDateTime(value))) {
|
|
44
|
+
return "date";
|
|
45
|
+
}
|
|
46
|
+
if (isRegExp(value)) {
|
|
47
|
+
return "regexp";
|
|
48
|
+
}
|
|
49
|
+
if (isError(value)) {
|
|
50
|
+
return "error";
|
|
51
|
+
}
|
|
52
|
+
return "object";
|
|
53
|
+
}
|
|
54
|
+
export function getValueKind(value) {
|
|
55
|
+
if (value === null) {
|
|
56
|
+
return "null";
|
|
57
|
+
}
|
|
58
|
+
switch (typeof value) {
|
|
59
|
+
case "object":
|
|
60
|
+
return getObjectKind(value);
|
|
61
|
+
default:
|
|
62
|
+
return typeof value;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const getMapSize: (target: unknown) => number;
|
|
2
|
+
export declare const getSetSize: (target: unknown) => number;
|
|
3
|
+
export declare const getTypedArrayLength: (target: unknown) => number;
|
|
4
|
+
export declare const getRegExpSource: (target: unknown) => string;
|
|
5
|
+
export declare function getDateTime(value: object): number;
|
|
6
|
+
export declare function getRegExpText(value: object): string;
|
|
7
|
+
export declare function getSymbolText(value: symbol): string;
|
|
8
|
+
export declare function isClass(value: object): boolean;
|
|
9
|
+
export declare function getDataProperty(target: object, key: PropertyKey): unknown;
|
|
10
|
+
export declare function getArrayLength(value: unknown): number | undefined;
|
|
11
|
+
export declare function getConstructorName(value: object): string | undefined;
|
|
12
|
+
export declare function getFailureReason(error: unknown): string;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
function nativeGetter(prototype, name) {
|
|
2
|
+
const get = Object.getOwnPropertyDescriptor(prototype, name)?.get;
|
|
3
|
+
if (!get) {
|
|
4
|
+
throw new TypeError(`Missing native getter: ${name}`);
|
|
5
|
+
}
|
|
6
|
+
return (target) => get.call(target);
|
|
7
|
+
}
|
|
8
|
+
const typedArrayPrototype = Object.getPrototypeOf(Uint8Array.prototype);
|
|
9
|
+
const getTime = Date.prototype.getTime;
|
|
10
|
+
const functionToString = Function.prototype.toString;
|
|
11
|
+
const symbolToString = Symbol.prototype.toString;
|
|
12
|
+
export const getMapSize = nativeGetter(Map.prototype, "size");
|
|
13
|
+
export const getSetSize = nativeGetter(Set.prototype, "size");
|
|
14
|
+
export const getTypedArrayLength = nativeGetter(typedArrayPrototype, "length");
|
|
15
|
+
export const getRegExpSource = nativeGetter(RegExp.prototype, "source");
|
|
16
|
+
const regExpFlags = [
|
|
17
|
+
["d", "hasIndices"],
|
|
18
|
+
["g", "global"],
|
|
19
|
+
["i", "ignoreCase"],
|
|
20
|
+
["m", "multiline"],
|
|
21
|
+
["s", "dotAll"],
|
|
22
|
+
["u", "unicode"],
|
|
23
|
+
["v", "unicodeSets"],
|
|
24
|
+
["y", "sticky"],
|
|
25
|
+
].flatMap(([flag, name]) => Object.getOwnPropertyDescriptor(RegExp.prototype, name)?.get
|
|
26
|
+
? [[flag, nativeGetter(RegExp.prototype, name)]]
|
|
27
|
+
: []);
|
|
28
|
+
export function getDateTime(value) {
|
|
29
|
+
return getTime.call(value);
|
|
30
|
+
}
|
|
31
|
+
export function getRegExpText(value) {
|
|
32
|
+
const flags = regExpFlags
|
|
33
|
+
.filter(([, isSet]) => isSet(value))
|
|
34
|
+
.map(([flag]) => flag)
|
|
35
|
+
.join("");
|
|
36
|
+
return `/${getRegExpSource(value)}/${flags}`;
|
|
37
|
+
}
|
|
38
|
+
export function getSymbolText(value) {
|
|
39
|
+
return symbolToString.call(value);
|
|
40
|
+
}
|
|
41
|
+
export function isClass(value) {
|
|
42
|
+
return functionToString.call(value).startsWith("class");
|
|
43
|
+
}
|
|
44
|
+
export function getDataProperty(target, key) {
|
|
45
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(target, key);
|
|
46
|
+
return descriptor && "value" in descriptor ? descriptor.value : undefined;
|
|
47
|
+
}
|
|
48
|
+
export function getArrayLength(value) {
|
|
49
|
+
try {
|
|
50
|
+
if (!Array.isArray(value)) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
const length = getDataProperty(value, "length");
|
|
54
|
+
return typeof length === "number" ? length : undefined;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export function getConstructorName(value) {
|
|
61
|
+
const prototype = Reflect.getPrototypeOf(value);
|
|
62
|
+
if (prototype === null) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
const constructor = getDataProperty(prototype, "constructor");
|
|
66
|
+
if (typeof constructor !== "function") {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
const name = getDataProperty(constructor, "name");
|
|
70
|
+
return typeof name === "string" && name !== "" ? name : undefined;
|
|
71
|
+
}
|
|
72
|
+
export function getFailureReason(error) {
|
|
73
|
+
try {
|
|
74
|
+
if (typeof error === "string") {
|
|
75
|
+
return error;
|
|
76
|
+
}
|
|
77
|
+
if (typeof error === "object" && error !== null) {
|
|
78
|
+
const message = getDataProperty(error, "message");
|
|
79
|
+
if (typeof message === "string" && message !== "") {
|
|
80
|
+
return message;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return "unknown error";
|
|
86
|
+
}
|
|
87
|
+
return "unknown error";
|
|
88
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { getArrayLength } from "./describe/safeRead.js";
|
|
2
|
+
import { getLabelText } from "./getLabelText.js";
|
|
3
|
+
import { getValueText } from "./getValueText.js";
|
|
4
|
+
const IDENTIFIER = /^[A-Za-z_$][\w$]*$/u;
|
|
5
|
+
const INDENT = " ";
|
|
6
|
+
const PLAIN_TYPES = new Set(["Object", "Array"]);
|
|
7
|
+
function getPrefix(node, isRoot) {
|
|
8
|
+
if (isRoot || !node.label || node.label.type === "index") {
|
|
9
|
+
return "";
|
|
10
|
+
}
|
|
11
|
+
const text = getLabelText(node.label);
|
|
12
|
+
const isPlain = node.label.type !== "property" || IDENTIFIER.test(text);
|
|
13
|
+
return `${isPlain ? text : JSON.stringify(text)}: `;
|
|
14
|
+
}
|
|
15
|
+
function getLeafText(node) {
|
|
16
|
+
if (node.kind === "string" && typeof node.value === "string") {
|
|
17
|
+
return JSON.stringify(node.value);
|
|
18
|
+
}
|
|
19
|
+
const length = getListLength(node);
|
|
20
|
+
if (length !== undefined && length > 0) {
|
|
21
|
+
return `[${getHoleText(length).slice(0, -1)}]`;
|
|
22
|
+
}
|
|
23
|
+
return node.typeName && PLAIN_TYPES.has(node.typeName)
|
|
24
|
+
? getOpening(node) + getClosing(node)
|
|
25
|
+
: node.preview;
|
|
26
|
+
}
|
|
27
|
+
function getOpening(node) {
|
|
28
|
+
const bracket = node.kind === "array" ? "[" : "{";
|
|
29
|
+
return node.typeName && !PLAIN_TYPES.has(node.typeName)
|
|
30
|
+
? `${node.typeName} ${bracket}`
|
|
31
|
+
: bracket;
|
|
32
|
+
}
|
|
33
|
+
function getListLength(node) {
|
|
34
|
+
return node.kind === "array" ? getArrayLength(node.value) : undefined;
|
|
35
|
+
}
|
|
36
|
+
function getHoleText(count) {
|
|
37
|
+
return `<${count} empty ${count === 1 ? "item" : "items"}>,`;
|
|
38
|
+
}
|
|
39
|
+
function getClosing(node) {
|
|
40
|
+
return node.kind === "array" ? "]" : "}";
|
|
41
|
+
}
|
|
42
|
+
export function getCopyText(root, limit = 5000) {
|
|
43
|
+
if (root.childCount === 0) {
|
|
44
|
+
return root.kind === "string" ? getValueText(root) : getLeafText(root);
|
|
45
|
+
}
|
|
46
|
+
const lines = [];
|
|
47
|
+
const pending = [root];
|
|
48
|
+
const depths = new Map([[root, 0]]);
|
|
49
|
+
let remaining = limit;
|
|
50
|
+
let isCut = false;
|
|
51
|
+
for (let item = pending.pop(); item !== undefined; item = pending.pop()) {
|
|
52
|
+
if (typeof item === "string") {
|
|
53
|
+
lines.push(item);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const depth = depths.get(item) ?? 0;
|
|
57
|
+
depths.delete(item);
|
|
58
|
+
const indent = INDENT.repeat(depth);
|
|
59
|
+
const end = item === root ? "" : ",";
|
|
60
|
+
if (remaining <= 0) {
|
|
61
|
+
if (!isCut) {
|
|
62
|
+
isCut = true;
|
|
63
|
+
lines.push(`${indent}…`);
|
|
64
|
+
}
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
remaining -= 1;
|
|
68
|
+
const prefix = indent + getPrefix(item, item === root);
|
|
69
|
+
if (item.childCount === 0) {
|
|
70
|
+
lines.push(prefix + getLeafText(item) + end);
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (item.childCount > limit) {
|
|
74
|
+
lines.push(prefix + item.preview + end);
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
lines.push(prefix + getOpening(item));
|
|
78
|
+
pending.push(indent + getClosing(item) + end);
|
|
79
|
+
const children = item.children();
|
|
80
|
+
const childIndent = INDENT.repeat(depth + 1);
|
|
81
|
+
const length = getListLength(item);
|
|
82
|
+
const isList = length !== undefined;
|
|
83
|
+
let next = length ?? 0;
|
|
84
|
+
for (let index = children.length - 1; index >= 0; index--) {
|
|
85
|
+
const child = children[index];
|
|
86
|
+
if (!child) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (isList && child.label?.type === "index") {
|
|
90
|
+
if (child.label.index + 1 < next) {
|
|
91
|
+
pending.push(childIndent + getHoleText(next - child.label.index - 1));
|
|
92
|
+
}
|
|
93
|
+
next = child.label.index;
|
|
94
|
+
}
|
|
95
|
+
depths.set(child, depth + 1);
|
|
96
|
+
pending.push(child);
|
|
97
|
+
}
|
|
98
|
+
if (isList && next > 0) {
|
|
99
|
+
pending.push(childIndent + getHoleText(next));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return lines.join("\n");
|
|
103
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function getLabelText(label) {
|
|
2
|
+
switch (label.type) {
|
|
3
|
+
case "property":
|
|
4
|
+
return label.key === "" ? '""' : label.key;
|
|
5
|
+
case "symbol":
|
|
6
|
+
return Symbol.prototype.toString.call(label.key);
|
|
7
|
+
case "index":
|
|
8
|
+
case "entry":
|
|
9
|
+
return String(label.index);
|
|
10
|
+
case "entryKey":
|
|
11
|
+
return "key";
|
|
12
|
+
case "entryValue":
|
|
13
|
+
return "value";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function getHighlightParts(text, search) {
|
|
2
|
+
const query = search.trim().toLocaleLowerCase();
|
|
3
|
+
const lowered = text.toLocaleLowerCase();
|
|
4
|
+
if (query === "" || lowered.length !== text.length) {
|
|
5
|
+
return [{ text, isMatch: false }];
|
|
6
|
+
}
|
|
7
|
+
const parts = [];
|
|
8
|
+
let position = 0;
|
|
9
|
+
for (let found = lowered.indexOf(query); found >= 0; found = lowered.indexOf(query, position)) {
|
|
10
|
+
if (found > position) {
|
|
11
|
+
parts.push({ text: text.slice(position, found), isMatch: false });
|
|
12
|
+
}
|
|
13
|
+
position = found + query.length;
|
|
14
|
+
parts.push({ text: text.slice(found, position), isMatch: true });
|
|
15
|
+
}
|
|
16
|
+
if (position < text.length || parts.length === 0) {
|
|
17
|
+
parts.push({ text: text.slice(position), isMatch: false });
|
|
18
|
+
}
|
|
19
|
+
return parts;
|
|
20
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { getLabelText } from "../getLabelText.js";
|
|
2
|
+
import { getValueText } from "../getValueText.js";
|
|
3
|
+
const NO_MATCHES = { ids: [], isComplete: true };
|
|
4
|
+
function isMatch(node, query) {
|
|
5
|
+
if (node.label &&
|
|
6
|
+
getLabelText(node.label).toLocaleLowerCase().includes(query)) {
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
return (node.childCount === 0 &&
|
|
10
|
+
getValueText(node).toLocaleLowerCase().includes(query));
|
|
11
|
+
}
|
|
12
|
+
export function getMatches(root, text, limit) {
|
|
13
|
+
const query = text.trim().toLocaleLowerCase();
|
|
14
|
+
if (query === "") {
|
|
15
|
+
return NO_MATCHES;
|
|
16
|
+
}
|
|
17
|
+
const ids = [];
|
|
18
|
+
const pending = [root];
|
|
19
|
+
let remaining = limit;
|
|
20
|
+
let isComplete = true;
|
|
21
|
+
for (let node = pending.pop(); node; node = pending.pop()) {
|
|
22
|
+
if (remaining <= 0) {
|
|
23
|
+
isComplete = false;
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
remaining -= 1;
|
|
27
|
+
if (isMatch(node, query)) {
|
|
28
|
+
ids.push(node.id);
|
|
29
|
+
}
|
|
30
|
+
if (node.childCount === 0) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (node.childCount > limit) {
|
|
34
|
+
isComplete = false;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
const children = node.children();
|
|
38
|
+
for (let index = children.length - 1; index >= 0; index--) {
|
|
39
|
+
const child = children[index];
|
|
40
|
+
if (child) {
|
|
41
|
+
pending.push(child);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return { ids, isComplete };
|
|
46
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function getSearchStatus(query, matches, current) {
|
|
2
|
+
if (query.trim() === "") {
|
|
3
|
+
return "";
|
|
4
|
+
}
|
|
5
|
+
const count = matches.ids.length;
|
|
6
|
+
const scope = matches.isComplete ? "" : " in the part that was searched";
|
|
7
|
+
if (count === 0) {
|
|
8
|
+
return `No matches${scope}`;
|
|
9
|
+
}
|
|
10
|
+
if (current >= 0) {
|
|
11
|
+
return `${current + 1} of ${count}${scope}`;
|
|
12
|
+
}
|
|
13
|
+
return `${count} ${count === 1 ? "match" : "matches"}${scope}`;
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ComponentProps, type ReactNode } from "react";
|
|
2
|
+
import { type TreeNode, type TreeRow } from "./treeModel.js";
|
|
3
|
+
export interface TreeProps<Node extends TreeNode> extends Omit<ComponentProps<"div">, "children" | "dangerouslySetInnerHTML" | "role" | "aria-label" | "aria-labelledby"> {
|
|
4
|
+
root: Node;
|
|
5
|
+
label: string;
|
|
6
|
+
renderRow: (row: TreeRow<Node>) => ReactNode;
|
|
7
|
+
getRowText?: (row: TreeRow<Node>) => string;
|
|
8
|
+
expanded?: ReadonlySet<string>;
|
|
9
|
+
defaultExpanded?: Iterable<string>;
|
|
10
|
+
onExpandedChange?: (expanded: ReadonlySet<string>) => void;
|
|
11
|
+
selected?: string;
|
|
12
|
+
onSelectedChange?: (selected: string) => void;
|
|
13
|
+
}
|
|
14
|
+
export declare function Tree<Node extends TreeNode>({ root, label, renderRow, getRowText, expanded: controlledExpanded, defaultExpanded, onExpandedChange, selected: controlledSelected, onSelectedChange, className, onKeyDown, onFocus, onBlur, ref, ...props }: TreeProps<Node>): import("react").JSX.Element;
|