@tsplc/debug 0.2.16 → 0.2.18
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/dist/format.js +36 -18
- package/dist/format.js.map +4 -4
- package/dist/index.js +768 -516
- package/dist/index.js.map +20 -17
- package/dist/manifest.js +6 -2
- package/dist/manifest.js.map +3 -3
- package/dist/paths.js +60 -28
- package/dist/paths.js.map +3 -3
- package/package.json +47 -46
- package/src/adapter.ts +43 -36
- package/src/api.ts +128 -126
- package/src/debugger.ts +584 -467
- package/src/errors.ts +3 -0
- package/src/hardware.ts +127 -96
- package/src/http.ts +147 -116
- package/src/index.ts +34 -4
- package/src/jobs.ts +102 -77
- package/src/login-value.ts +165 -0
- package/src/login.ts +233 -253
- package/src/manifest.ts +200 -194
- package/src/opcua.ts +55 -55
- package/src/paths.ts +230 -157
- package/src/requests.ts +86 -0
- package/src/telemetry.ts +104 -90
- package/src/timeline.ts +96 -61
- package/src/trace.ts +41 -31
- package/src/ui/bits.ts +45 -29
- package/src/ui/client.ts +33 -26
- package/src/ui/dom.ts +189 -108
- package/src/ui/format.ts +127 -72
- package/src/ui/hardware.ts +416 -343
- package/src/ui/header.ts +186 -164
- package/src/ui/index.ts +16 -9
- package/src/ui/jobs.ts +263 -214
- package/src/ui/main.ts +52 -48
- package/src/ui/overview.ts +152 -108
- package/src/ui/recent.ts +329 -276
- package/src/ui/requests.ts +69 -73
- package/src/ui/store.ts +236 -198
- package/src/ui/tree.ts +162 -130
- package/src/ui/variables.ts +557 -431
- package/src/watch.ts +22 -17
- package/src/ui/dev.ts +0 -579
- package/src/ui/fixture.ts +0 -548
package/src/ui/tree.ts
CHANGED
|
@@ -3,154 +3,186 @@ import { joinPath, pathSegments, typeOf } from "../paths.ts";
|
|
|
3
3
|
|
|
4
4
|
/** One row of the instance tree: a root, a record field, an array element or a folded constant. */
|
|
5
5
|
export interface TreeNode {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
6
|
+
path: string;
|
|
7
|
+
/** The last segment: a field name, `[3]`, or the whole path for a top-level node. */
|
|
8
|
+
name: string;
|
|
9
|
+
type: string;
|
|
10
|
+
declaration?: SourceRange;
|
|
11
|
+
/** Whether the target adapter can read it at runtime. */
|
|
12
|
+
readable: boolean;
|
|
13
|
+
generated: boolean;
|
|
14
|
+
constant?: DebugConstant;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export interface TreeRow {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
node: TreeNode;
|
|
19
|
+
depth: number;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export const parentPath = (path: string) =>
|
|
23
|
-
|
|
23
|
+
path.slice(0, Math.max(path.lastIndexOf("."), path.lastIndexOf("[")));
|
|
24
24
|
|
|
25
25
|
/** Every proper prefix of `path` at a `.` or `[` boundary, shortest first. */
|
|
26
26
|
export const ancestorPaths = (path: string) =>
|
|
27
|
-
|
|
27
|
+
[...path.matchAll(/[.[]/g)].map((match) => path.slice(0, match.index));
|
|
28
28
|
|
|
29
29
|
/** The manifest's instances as a lazily expanded tree, addressed by TypeScript path. */
|
|
30
30
|
export class ManifestTree {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
readonly top: TreeNode[];
|
|
32
|
+
private readonly constantsByParent = new Map<string, DebugConstant[]>();
|
|
33
|
+
private readonly children = new Map<string, TreeNode[]>();
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
35
|
+
constructor(readonly manifest: DebugManifest) {
|
|
36
|
+
const roots = manifest.roots.map((root) => ({
|
|
37
|
+
path: root.path,
|
|
38
|
+
name: root.path,
|
|
39
|
+
type: root.type,
|
|
40
|
+
declaration: root.declaration,
|
|
41
|
+
readable: root.readable,
|
|
42
|
+
generated: root.generated === true,
|
|
43
|
+
}));
|
|
44
|
+
for (const constant of manifest.constants) {
|
|
45
|
+
const parent = parentPath(constant.path);
|
|
46
|
+
this.constantsByParent.set(parent, [
|
|
47
|
+
...(this.constantsByParent.get(parent) ?? []),
|
|
48
|
+
constant,
|
|
49
|
+
]);
|
|
50
|
+
}
|
|
51
|
+
const orphans = manifest.constants.filter(
|
|
52
|
+
(constant) => !this.resolveVariable(roots, parentPath(constant.path)),
|
|
53
|
+
);
|
|
54
|
+
this.top = [
|
|
55
|
+
...roots,
|
|
56
|
+
...orphans.map((constant) => this.constantNode(constant, constant.path)),
|
|
57
|
+
];
|
|
58
|
+
}
|
|
53
59
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
60
|
+
expandable(node: TreeNode) {
|
|
61
|
+
if (node.constant) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
const kind = typeOf(this.manifest, node.type).kind;
|
|
65
|
+
return kind === "record" || kind === "array";
|
|
66
|
+
}
|
|
59
67
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}))
|
|
74
|
-
: type.kind === "array"
|
|
75
|
-
? Array.from({ length: type.length }, (_, offset) => ({
|
|
76
|
-
path: `${node.path}[${type.lower + offset}]`,
|
|
77
|
-
name: `[${type.lower + offset}]`,
|
|
78
|
-
type: type.element,
|
|
79
|
-
declaration: node.declaration,
|
|
80
|
-
readable: node.readable,
|
|
81
|
-
generated: node.generated,
|
|
82
|
-
}))
|
|
83
|
-
: [];
|
|
84
|
-
const constants = (this.constantsByParent.get(node.path) ?? []).map((constant) =>
|
|
85
|
-
this.constantNode(constant, constant.path.slice(node.path.length + 1)),
|
|
86
|
-
);
|
|
87
|
-
const children = [...variables, ...constants];
|
|
88
|
-
this.children.set(node.path, children);
|
|
89
|
-
return children;
|
|
90
|
-
}
|
|
68
|
+
childrenOf(node: TreeNode): TreeNode[] {
|
|
69
|
+
const cached = this.children.get(node.path);
|
|
70
|
+
if (cached) {
|
|
71
|
+
return cached;
|
|
72
|
+
}
|
|
73
|
+
const constants = (this.constantsByParent.get(node.path) ?? []).map(
|
|
74
|
+
(constant) =>
|
|
75
|
+
this.constantNode(constant, constant.path.slice(node.path.length + 1)),
|
|
76
|
+
);
|
|
77
|
+
const children = [...this.variablesOf(node), ...constants];
|
|
78
|
+
this.children.set(node.path, children);
|
|
79
|
+
return children;
|
|
80
|
+
}
|
|
91
81
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
82
|
+
/** The rows shown for an expansion state, depth first. */
|
|
83
|
+
rows(expanded: ReadonlySet<string>, showGenerated: boolean): TreeRow[] {
|
|
84
|
+
const rows: TreeRow[] = [];
|
|
85
|
+
const visit = (nodes: TreeNode[], depth: number) => {
|
|
86
|
+
for (const node of nodes) {
|
|
87
|
+
if (node.generated && !showGenerated) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
rows.push({ node, depth });
|
|
91
|
+
if (expanded.has(node.path) && this.expandable(node)) {
|
|
92
|
+
visit(this.childrenOf(node), depth + 1);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
visit(this.top, 0);
|
|
97
|
+
return rows;
|
|
98
|
+
}
|
|
106
99
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
100
|
+
/** Nodes whose path contains `query` (case-insensitive), in tree order, at most `limit`. */
|
|
101
|
+
search(query: string, showGenerated: boolean, limit: number) {
|
|
102
|
+
const needle = query.toLowerCase();
|
|
103
|
+
const found: TreeNode[] = [];
|
|
104
|
+
let total = 0;
|
|
105
|
+
const visit = (nodes: TreeNode[]) => {
|
|
106
|
+
for (const node of nodes) {
|
|
107
|
+
if (node.generated && !showGenerated) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (node.path.toLowerCase().includes(needle) && total++ < limit) {
|
|
111
|
+
found.push(node);
|
|
112
|
+
}
|
|
113
|
+
if (this.expandable(node)) {
|
|
114
|
+
visit(this.childrenOf(node));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
visit(this.top);
|
|
119
|
+
return { nodes: found, total };
|
|
120
|
+
}
|
|
122
121
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
122
|
+
resolve(path: string): TreeNode | undefined {
|
|
123
|
+
const constant = this.manifest.constants.find(
|
|
124
|
+
(entry) => entry.path === path,
|
|
125
|
+
);
|
|
126
|
+
if (constant) {
|
|
127
|
+
return this.constantNode(constant, path);
|
|
128
|
+
}
|
|
129
|
+
return this.resolveVariable(this.top, path);
|
|
130
|
+
}
|
|
128
131
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
132
|
+
private resolveVariable(top: TreeNode[], path: string): TreeNode | undefined {
|
|
133
|
+
let node = top.find(
|
|
134
|
+
(root) =>
|
|
135
|
+
path === root.path ||
|
|
136
|
+
(path.startsWith(root.path) &&
|
|
137
|
+
/^[.[]/.test(path.slice(root.path.length))),
|
|
138
|
+
);
|
|
139
|
+
while (node && node.path !== path) {
|
|
140
|
+
const rest = path.slice(node.path.length);
|
|
141
|
+
const [segment] = pathSegments(rest);
|
|
142
|
+
if (!segment) {
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|
|
145
|
+
const childPath = joinPath(node.path, segment);
|
|
146
|
+
node = this.childrenOf(node).find((child) => child.path === childPath);
|
|
147
|
+
}
|
|
148
|
+
return node;
|
|
149
|
+
}
|
|
144
150
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
151
|
+
/** A record's fields or an array's elements, which share its readability and generated mark. */
|
|
152
|
+
private variablesOf(node: TreeNode): TreeNode[] {
|
|
153
|
+
const type = typeOf(this.manifest, node.type);
|
|
154
|
+
if (type.kind === "record") {
|
|
155
|
+
return type.fields.map((field) => ({
|
|
156
|
+
path: `${node.path}.${field.name}`,
|
|
157
|
+
name: field.name,
|
|
158
|
+
type: field.type,
|
|
159
|
+
declaration: field.declaration,
|
|
160
|
+
readable: node.readable,
|
|
161
|
+
generated: node.generated || field.generated === true,
|
|
162
|
+
}));
|
|
163
|
+
}
|
|
164
|
+
if (type.kind === "array") {
|
|
165
|
+
return Array.from({ length: type.length }, (_, offset) => ({
|
|
166
|
+
path: `${node.path}[${type.lower + offset}]`,
|
|
167
|
+
name: `[${type.lower + offset}]`,
|
|
168
|
+
type: type.element,
|
|
169
|
+
declaration: node.declaration,
|
|
170
|
+
readable: node.readable,
|
|
171
|
+
generated: node.generated,
|
|
172
|
+
}));
|
|
173
|
+
}
|
|
174
|
+
return [];
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
private constantNode(constant: DebugConstant, name: string): TreeNode {
|
|
178
|
+
return {
|
|
179
|
+
path: constant.path,
|
|
180
|
+
name,
|
|
181
|
+
type: constant.type,
|
|
182
|
+
declaration: constant.declaration,
|
|
183
|
+
readable: false,
|
|
184
|
+
generated: false,
|
|
185
|
+
constant,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
156
188
|
}
|