mrmd-js 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/README.md +842 -0
- package/dist/index.cjs +7613 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +7530 -0
- package/dist/index.js.map +1 -0
- package/dist/mrmd-js.iife.js +7618 -0
- package/dist/mrmd-js.iife.js.map +1 -0
- package/package.json +47 -0
- package/src/analysis/format.js +371 -0
- package/src/analysis/index.js +18 -0
- package/src/analysis/is-complete.js +394 -0
- package/src/constants.js +44 -0
- package/src/execute/css.js +205 -0
- package/src/execute/html.js +162 -0
- package/src/execute/index.js +41 -0
- package/src/execute/interface.js +144 -0
- package/src/execute/javascript.js +197 -0
- package/src/execute/registry.js +245 -0
- package/src/index.js +136 -0
- package/src/lsp/complete.js +353 -0
- package/src/lsp/format.js +310 -0
- package/src/lsp/hover.js +126 -0
- package/src/lsp/index.js +55 -0
- package/src/lsp/inspect.js +466 -0
- package/src/lsp/parse.js +455 -0
- package/src/lsp/variables.js +283 -0
- package/src/runtime.js +518 -0
- package/src/session/console-capture.js +181 -0
- package/src/session/context/iframe.js +407 -0
- package/src/session/context/index.js +12 -0
- package/src/session/context/interface.js +38 -0
- package/src/session/context/main.js +357 -0
- package/src/session/index.js +16 -0
- package/src/session/manager.js +327 -0
- package/src/session/session.js +678 -0
- package/src/transform/async.js +133 -0
- package/src/transform/extract.js +251 -0
- package/src/transform/index.js +10 -0
- package/src/transform/persistence.js +176 -0
- package/src/types/analysis.js +24 -0
- package/src/types/capabilities.js +44 -0
- package/src/types/completion.js +47 -0
- package/src/types/execution.js +62 -0
- package/src/types/index.js +16 -0
- package/src/types/inspection.js +39 -0
- package/src/types/session.js +32 -0
- package/src/types/streaming.js +74 -0
- package/src/types/variables.js +54 -0
- package/src/utils/ansi-renderer.js +301 -0
- package/src/utils/css-applicator.js +149 -0
- package/src/utils/html-renderer.js +355 -0
- package/src/utils/index.js +25 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Variable Inspection
|
|
3
|
+
*
|
|
4
|
+
* Provides variable listing and detailed inspection for the
|
|
5
|
+
* variables panel in notebook UIs.
|
|
6
|
+
*
|
|
7
|
+
* @module lsp/variables
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { splitObjectPath } from './parse.js';
|
|
11
|
+
import {
|
|
12
|
+
formatValue,
|
|
13
|
+
formatValueShort,
|
|
14
|
+
getTypeName,
|
|
15
|
+
isExpandable,
|
|
16
|
+
getSizeDescription,
|
|
17
|
+
} from './format.js';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @typedef {import('../session/context/interface.js').ExecutionContext} ExecutionContext
|
|
21
|
+
* @typedef {import('../types/variables.js').VariableFilter} VariableFilter
|
|
22
|
+
* @typedef {import('../types/variables.js').VariableInfo} VariableInfo
|
|
23
|
+
* @typedef {import('../types/variables.js').VariableDetailOptions} VariableDetailOptions
|
|
24
|
+
* @typedef {import('../types/variables.js').VariableDetail} VariableDetail
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* List all variables in the session namespace
|
|
29
|
+
*
|
|
30
|
+
* @param {ExecutionContext} context - Execution context
|
|
31
|
+
* @param {VariableFilter} [filter] - Optional filter
|
|
32
|
+
* @returns {VariableInfo[]}
|
|
33
|
+
*/
|
|
34
|
+
export function listVariables(context, filter = {}) {
|
|
35
|
+
const vars = context.getVariables();
|
|
36
|
+
const tracked = context.getTrackedVariables();
|
|
37
|
+
|
|
38
|
+
/** @type {VariableInfo[]} */
|
|
39
|
+
const result = [];
|
|
40
|
+
|
|
41
|
+
for (const name of tracked) {
|
|
42
|
+
if (!(name in vars)) continue;
|
|
43
|
+
|
|
44
|
+
const value = vars[name];
|
|
45
|
+
|
|
46
|
+
// Apply filters
|
|
47
|
+
if (filter.excludePrivate && name.startsWith('_')) continue;
|
|
48
|
+
if (filter.namePattern && !new RegExp(filter.namePattern).test(name)) continue;
|
|
49
|
+
if (filter.types && !filter.types.includes(getTypeName(value))) continue;
|
|
50
|
+
|
|
51
|
+
result.push(formatVariableInfo(name, value));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Sort by name
|
|
55
|
+
result.sort((a, b) => a.name.localeCompare(b.name));
|
|
56
|
+
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Get detailed information about a variable
|
|
62
|
+
*
|
|
63
|
+
* @param {string} name - Variable name
|
|
64
|
+
* @param {ExecutionContext} context - Execution context
|
|
65
|
+
* @param {VariableDetailOptions} [options]
|
|
66
|
+
* @returns {VariableDetail | null}
|
|
67
|
+
*/
|
|
68
|
+
export function getVariableDetail(name, context, options = {}) {
|
|
69
|
+
let value = context.getVariable(name);
|
|
70
|
+
|
|
71
|
+
// Navigate path
|
|
72
|
+
if (options.path && options.path.length > 0) {
|
|
73
|
+
for (const key of options.path) {
|
|
74
|
+
if (value == null) return null;
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
if (value instanceof Map) {
|
|
78
|
+
value = value.get(key);
|
|
79
|
+
} else {
|
|
80
|
+
value = /** @type {*} */ (value)[key];
|
|
81
|
+
}
|
|
82
|
+
} catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Check if exists
|
|
89
|
+
if (value === undefined && !context.hasVariable(name)) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const maxChildren = options.maxChildren ?? 100;
|
|
94
|
+
const maxValueLength = options.maxValueLength ?? 1000;
|
|
95
|
+
|
|
96
|
+
const info = formatVariableInfo(name, value);
|
|
97
|
+
|
|
98
|
+
/** @type {VariableDetail} */
|
|
99
|
+
const detail = {
|
|
100
|
+
...info,
|
|
101
|
+
fullValue: formatValue(value, maxValueLength),
|
|
102
|
+
truncated: false,
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// Add children for expandable values
|
|
106
|
+
if (isExpandable(value)) {
|
|
107
|
+
const children = getChildren(value);
|
|
108
|
+
detail.children = children.slice(0, maxChildren).map(
|
|
109
|
+
([k, v]) => formatVariableInfo(k, v)
|
|
110
|
+
);
|
|
111
|
+
detail.truncated = children.length > maxChildren;
|
|
112
|
+
|
|
113
|
+
// Get methods and attributes for objects
|
|
114
|
+
if (typeof value === 'object' && value !== null) {
|
|
115
|
+
detail.methods = getMethods(value);
|
|
116
|
+
detail.attributes = getAttributes(value);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return detail;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Expand a variable by path
|
|
125
|
+
*
|
|
126
|
+
* @param {string} baseName - Base variable name
|
|
127
|
+
* @param {string[]} path - Path to expand
|
|
128
|
+
* @param {ExecutionContext} context
|
|
129
|
+
* @param {number} [maxChildren=100]
|
|
130
|
+
* @returns {VariableInfo[] | null}
|
|
131
|
+
*/
|
|
132
|
+
export function expandVariable(baseName, path, context, maxChildren = 100) {
|
|
133
|
+
let value = context.getVariable(baseName);
|
|
134
|
+
|
|
135
|
+
if (value === undefined) return null;
|
|
136
|
+
|
|
137
|
+
// Navigate path
|
|
138
|
+
for (const key of path) {
|
|
139
|
+
if (value == null) return null;
|
|
140
|
+
|
|
141
|
+
try {
|
|
142
|
+
if (value instanceof Map) {
|
|
143
|
+
value = value.get(key);
|
|
144
|
+
} else {
|
|
145
|
+
value = /** @type {*} */ (value)[key];
|
|
146
|
+
}
|
|
147
|
+
} catch {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (!isExpandable(value)) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const children = getChildren(value);
|
|
157
|
+
return children.slice(0, maxChildren).map(([k, v]) => formatVariableInfo(k, v));
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Format a variable for display
|
|
162
|
+
* @param {string} name
|
|
163
|
+
* @param {*} value
|
|
164
|
+
* @returns {VariableInfo}
|
|
165
|
+
*/
|
|
166
|
+
export function formatVariableInfo(name, value) {
|
|
167
|
+
/** @type {VariableInfo} */
|
|
168
|
+
const info = {
|
|
169
|
+
name,
|
|
170
|
+
type: getTypeName(value),
|
|
171
|
+
value: formatValueShort(value, 100),
|
|
172
|
+
expandable: isExpandable(value),
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
// Add size info
|
|
176
|
+
const size = getSizeDescription(value);
|
|
177
|
+
if (size) {
|
|
178
|
+
info.size = size;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Add length for arrays/strings
|
|
182
|
+
if (Array.isArray(value)) {
|
|
183
|
+
info.length = value.length;
|
|
184
|
+
} else if (typeof value === 'string') {
|
|
185
|
+
info.length = value.length;
|
|
186
|
+
} else if (value instanceof Map || value instanceof Set) {
|
|
187
|
+
info.length = value.size;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Add shape for typed arrays
|
|
191
|
+
if (ArrayBuffer.isView(value) && 'length' in value) {
|
|
192
|
+
// @ts-ignore
|
|
193
|
+
info.length = value.length;
|
|
194
|
+
info.dtype = value.constructor.name.replace('Array', '').toLowerCase();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Add keys preview for objects
|
|
198
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
199
|
+
if (!(value instanceof Map) && !(value instanceof Set) && !ArrayBuffer.isView(value)) {
|
|
200
|
+
info.keys = Object.keys(value).slice(0, 10);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return info;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Get children of an expandable value
|
|
209
|
+
* @param {*} value
|
|
210
|
+
* @returns {Array<[string, *]>}
|
|
211
|
+
*/
|
|
212
|
+
export function getChildren(value) {
|
|
213
|
+
if (value === null || value === undefined) return [];
|
|
214
|
+
|
|
215
|
+
if (Array.isArray(value)) {
|
|
216
|
+
return value.map((v, i) => [String(i), v]);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (value instanceof Map) {
|
|
220
|
+
return Array.from(value.entries()).map(([k, v]) => [String(k), v]);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (value instanceof Set) {
|
|
224
|
+
return Array.from(value).map((v, i) => [String(i), v]);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (typeof value === 'object') {
|
|
228
|
+
return Object.entries(value);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return [];
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Get method names of an object
|
|
236
|
+
* @param {*} value
|
|
237
|
+
* @returns {string[]}
|
|
238
|
+
*/
|
|
239
|
+
export function getMethods(value) {
|
|
240
|
+
const methods = new Set();
|
|
241
|
+
let obj = value;
|
|
242
|
+
let depth = 0;
|
|
243
|
+
|
|
244
|
+
while (obj != null && obj !== Object.prototype && depth < 3) {
|
|
245
|
+
for (const name of Object.getOwnPropertyNames(obj)) {
|
|
246
|
+
if (name === 'constructor') continue;
|
|
247
|
+
|
|
248
|
+
try {
|
|
249
|
+
if (typeof obj[name] === 'function') {
|
|
250
|
+
methods.add(name);
|
|
251
|
+
}
|
|
252
|
+
} catch {
|
|
253
|
+
// Skip inaccessible
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
obj = Object.getPrototypeOf(obj);
|
|
258
|
+
depth++;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return Array.from(methods).sort();
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Get attribute (non-method) names of an object
|
|
266
|
+
* @param {*} value
|
|
267
|
+
* @returns {string[]}
|
|
268
|
+
*/
|
|
269
|
+
export function getAttributes(value) {
|
|
270
|
+
const attrs = [];
|
|
271
|
+
|
|
272
|
+
for (const name of Object.getOwnPropertyNames(value)) {
|
|
273
|
+
try {
|
|
274
|
+
if (typeof value[name] !== 'function') {
|
|
275
|
+
attrs.push(name);
|
|
276
|
+
}
|
|
277
|
+
} catch {
|
|
278
|
+
// Skip inaccessible
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return attrs.sort();
|
|
283
|
+
}
|