Skip to content

Commit a7c478a

Browse files
committed
Improve variable handling
1 parent 437ef0f commit a7c478a

File tree

8 files changed

+141
-72
lines changed

8 files changed

+141
-72
lines changed

e2e/E2ETest.js

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
const SourcePlusPlus = require("sourceplusplus");
2-
SourcePlusPlus.start().then(() => {
3-
// Run tests
4-
console.log("Running tests...");
5-
// Keep running this method, so we can test breakpoints, logs, etc.
6-
(function test() {
7-
let i = 0;
82

9-
for (let j = 0; j < 10; j++) {
10-
if (j % 2 === 0) {
11-
i++;
3+
setTimeout(() => {
4+
SourcePlusPlus.start().then(() => {
5+
// Run tests
6+
console.log("Running tests...");
7+
// Keep running this method, so we can test breakpoints, logs, etc.
8+
(function test() {
9+
let i = 0;
10+
11+
for (let j = 0; j < 10; j++) {
12+
if (j % 2 === 0) {
13+
i++;
14+
}
1215
}
13-
}
1416

15-
setTimeout(test, 1000);
16-
})();
17-
});
17+
setTimeout(test, 1000);
18+
})();
19+
20+
setTimeout(() => console.log("Source mappings: ", Object.fromEntries(SourcePlusPlus.liveInstrumentRemote.sourceMapper.mapped)), 1000);
21+
});
22+
}, 15000); // Wait for Source++ Platform to fully start

src/SourcePlusPlus.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ namespace SourcePlusPlus {
2727
let getConfigValueNumber = (env, def, trueDef) =>
2828
getConfigValue<number>(env, def, trueDef, (str) => Number(str));
2929

30-
let probeConfig: SourcePlusPlusConfig;
31-
let liveInstrumentRemote: LiveInstrumentRemote;
30+
export let probeConfig: SourcePlusPlusConfig;
31+
export let liveInstrumentRemote: LiveInstrumentRemote;
3232

3333
let debug = false;
3434

src/control/ContextReceiver.ts

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -28,42 +28,6 @@ namespace ContextReceiver {
2828
return `${frame.url} - ${frame.functionName}(${frame.location.lineNumber})`;
2929
}
3030

31-
function encodeVariable(variable: Runtime.PropertyDescriptor) {
32-
if (!variable.value) {
33-
return JSON.stringify({
34-
'@class': "null",
35-
'@id': 'null',
36-
'@skip': 'Error: No variable value'
37-
});
38-
}
39-
let clazz, id, value;
40-
if (variable.value.type === 'object') {
41-
clazz = variable.value.className;
42-
id = variable.value.objectId;
43-
value = ""; // TODO: Include variable value
44-
} else if (variable.value.type === 'function') {
45-
// TODO: Correctly handle these, variable.value.description contains the entire class/function definition
46-
clazz = 'function';
47-
id = variable.value.objectId;
48-
} else {
49-
clazz = variable.value.type;
50-
id = ""; // Primitive types don't have an object id
51-
value = variable.value.value;
52-
}
53-
54-
let obj = {
55-
'@class': clazz,
56-
'@id': id
57-
};
58-
obj[variable.name] = "";
59-
60-
return JSON.stringify(obj);
61-
}
62-
63-
export function test(variables) {
64-
console.log(tryFindVariable('i', variables));
65-
}
66-
6731
export function applyMeter(liveMeterId: string, variables) {
6832
// TODO: implement
6933
}
@@ -120,8 +84,6 @@ namespace ContextReceiver {
12084
stream.write(logData);
12185

12286
stream.end();
123-
124-
12587
}
12688
}
12789

src/control/LiveInstrumentRemote.ts

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import LiveMeter from "../model/instruments/LiveMeter";
88
import EventBus from "@vertx/eventbus-bridge-client.js";
99
import LiveInstrumentCommand from "../model/command/LiveInstrumentCommand";
1010
import CommandType from "../model/command/CommandType";
11+
import LiveBreakpoint from "../model/instruments/LiveBreakpoint";
12+
import {randomUUID} from "crypto";
13+
import VariableUtil from "../util/VariableUtil";
1114

1215
export interface VariableInfo {
1316
block: Runtime.PropertyDescriptor[]
@@ -72,23 +75,24 @@ export default class LiveInstrumentRemote {
7275
let variables = {}
7376
let promises = [];
7477

75-
// Attempt to get variables from the
78+
// Attempt to get variables from the top call frame
7679
for (let scope of frame.scopeChain) {
80+
if (scope.type === 'global') {
81+
continue; // TODO: Ignore this until we have a better way of filtering out the hundreds of js properties
82+
}
83+
7784
promises.push(this.getVariable(scope.object.objectId, 2)
78-
.then(res => variables[scope.type] = res.result));
85+
.then(res => {
86+
if (scope.type === 'local' || scope.type === 'block') {
87+
variables['local'] = res
88+
} else if (scope.type === 'closure') {
89+
variables['field'] = res[0].value.value; // TODO: Ensure result[0] is always the class instance
90+
} else if (scope.type === 'global') {
91+
// Handle this once we have a better way of filtering out the hundreds of js properties
92+
}
93+
}));
7994
}
8095

81-
this.session.post('Debugger.evaluateOnCallFrame', {
82-
callFrameId: frame.callFrameId,
83-
expression: "Object.keys(this).reduce((acc, current, _) => {acc[current] = this[current]; return acc}, {})",
84-
}, (err, res) => {
85-
if (err) {
86-
console.log(err);
87-
} else {
88-
console.log(res.result);
89-
}
90-
})
91-
9296
Promise.all(promises).then(() => {
9397
// Do stuff
9498
let instrumentIds = this.breakpointIdToInstrumentIds.get(message.params.hitBreakpoints[0]); // TODO: Handle multiple hit breakpoints
@@ -126,6 +130,9 @@ export default class LiveInstrumentRemote {
126130
variables
127131
);
128132
}
133+
if (instrument.isFinished()) {
134+
this.removeBreakpoint(instrumentId);
135+
}
129136
}
130137
});
131138

@@ -152,7 +159,7 @@ export default class LiveInstrumentRemote {
152159
});
153160
}
154161

155-
private getVariable(objectId: string, remainingDepth: number): Promise<any> {
162+
private getVariable(objectId: string, remainingDepth: number): Promise<Runtime.PropertyDescriptor[]> {
156163
return new Promise<any>((resolve, reject) => {
157164
this.session.post("Runtime.getProperties", {
158165
objectId: objectId,
@@ -161,8 +168,23 @@ export default class LiveInstrumentRemote {
161168
if (err) {
162169
reject(err);
163170
} else {
164-
console.log(res.result);
165-
resolve(res.result);
171+
let result: Runtime.PropertyDescriptor[] = res.result;
172+
173+
VariableUtil.processVariables(result)
174+
175+
if (remainingDepth <= 0)
176+
return resolve(result);
177+
178+
let newRemainingDepth = remainingDepth - 1;
179+
180+
let promises = [];
181+
for (let variable of result) {
182+
promises.push(this.getVariable(variable.value.objectId, newRemainingDepth)
183+
.then(res => variable.value.value = res));
184+
}
185+
Promise.all(promises).then(() => {
186+
resolve(result)
187+
});
166188
}
167189
});
168190
});
@@ -287,4 +309,16 @@ export default class LiveInstrumentRemote {
287309
}
288310
});
289311
}
312+
313+
test() {
314+
let instrument = new LiveBreakpoint();
315+
instrument.id = randomUUID();
316+
instrument.location = {source: "test/javascript/test.js", line: 5};
317+
instrument.hitLimit = 1;
318+
instrument.applyImmediately = true;
319+
instrument.applied = false;
320+
instrument.pending = false;
321+
instrument.meta = {};
322+
this.addInstrument(instrument);
323+
}
290324
}

src/model/LiveInstrument.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export default class LiveInstrument {
1919
if (this.expiresAt && this.expiresAt < Date.now()) {
2020
return true;
2121
}
22-
if (this.hitLimit > 0 && this.hitLimit <= this.throttle.totalHitCount) {
22+
if (this.throttle && this.hitLimit > 0 && this.hitLimit <= this.throttle.totalHitCount) {
2323
return true;
2424
}
2525
return false;

src/util/SourceMapper.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ export default class SourceMapper {
5050
mapLocation(location: LiveSourceLocation): MappedLocation {
5151
let mappedFile: MappedFile = this.mapped.get(location.source);
5252

53-
console.log(mappedFile);
54-
5553
if (!mappedFile) return undefined;
5654

5755
return {

src/util/VariableUtil.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import {Runtime} from "inspector";
2+
3+
namespace VariableUtil {
4+
export function processVariable(variable) {
5+
if (variable.value) {
6+
if (variable.value.description) {
7+
// Only consider the first line of description, since we do not want the entire class/function definition
8+
variable.value.description = variable.value.description.split('\n')[0];
9+
}
10+
}
11+
delete variable.writable;
12+
delete variable.configurable;
13+
delete variable.enumerable;
14+
delete variable.isOwn;
15+
return variable;
16+
}
17+
18+
export function processVariables(variables) {
19+
for (let variable of variables) {
20+
processVariable(variable);
21+
}
22+
return variables;
23+
}
24+
25+
export function encodeVariable(variable: Runtime.PropertyDescriptor) {
26+
if (!variable.value) {
27+
return JSON.stringify({
28+
'@class': "null",
29+
'@id': 'null',
30+
'@skip': 'Error: No variable value'
31+
});
32+
}
33+
let clazz, id, value;
34+
if (variable.value.type === 'object') {
35+
clazz = variable.value.className;
36+
id = variable.value.objectId;
37+
value = ""; // TODO: Include variable value
38+
} else if (variable.value.type === 'function') {
39+
// TODO: Correctly handle these, variable.value.description contains the entire class/function definition
40+
clazz = 'function';
41+
id = variable.value.objectId;
42+
} else {
43+
clazz = variable.value.type;
44+
id = ""; // Primitive types don't have an object id
45+
value = variable.value.value;
46+
}
47+
48+
let obj = {
49+
'@class': clazz,
50+
'@id': id
51+
};
52+
obj[variable.name] = "";
53+
if (variable.value.value) {
54+
if (variable.value.type !== 'object') { // TODO: Handle arrays
55+
obj[variable.name] = value;
56+
} else {
57+
obj[variable.name] = variable.value.value.reduce((acc, v) => {
58+
acc[v.name] = encodeVariable(v);
59+
return acc;
60+
}, {});
61+
}
62+
}
63+
64+
return JSON.stringify(obj);
65+
}
66+
}
67+
68+
export default VariableUtil;

test/javascript/test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
const SourcePlusPlus = require("../../dist/SourcePlusPlus.js");
22
SourcePlusPlus.start({}, true).then(() => {
33
console.log("test");
4+
5+
SourcePlusPlus.liveInstrumentRemote.test();
46
});

0 commit comments

Comments
 (0)