Skip to content

Commit d22e5d4

Browse files
committed
Version 2.2.0.
* Adds support for custom injected scripts with automatic reload * Refactors extension
1 parent 6ce5d66 commit d22e5d4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1421
-716
lines changed

.vscode/settings.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@
77
"plantuml.exportOutDir": "docs/exported",
88
"typescript.updateImportsOnFileMove.enabled": "prompt",
99
"mochaExplorer.files": "./data-extraction/test/**/*.test.ts",
10-
"mochaExplorer.require": ["ts-node/register", "source-map-support/register"],
10+
"mochaExplorer.require": [
11+
"ts-node/register",
12+
"source-map-support/register"
13+
],
1114
"tasksStatusbar.taskLabelFilter": "dev",
12-
"editor.formatOnSave": true
15+
"editor.formatOnSave": true,
16+
"typescript.tsdk": "node_modules\\typescript\\lib"
1317
}

data-extraction/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@hediet/debug-visualizer-data-extraction",
33
"description": "A library that helps implementing data extractors for the Debug Visualizer VS Code extension.",
4-
"version": "0.13.1",
4+
"version": "0.14.0",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",
77
"author": {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { DataExtractor } from "./DataExtractorApi";
2+
import type * as helpersTypes from "../helpers"
3+
4+
export type LoadDataExtractorsFn = (
5+
register: (extractor: DataExtractor) => void,
6+
helpers: typeof helpersTypes
7+
) => void;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import {
2+
DataExtractor,
3+
ExtractionCollector,
4+
DataExtractorContext,
5+
LoadDataExtractorsFn,
6+
} from "..";
7+
import * as helpers from "../../helpers";
8+
9+
export class InjectedExtractor implements DataExtractor {
10+
readonly id = "injected-extractor";
11+
12+
getExtractions(
13+
data: unknown,
14+
extractionCollector: ExtractionCollector,
15+
context: DataExtractorContext
16+
): void {
17+
const key = "@hediet/debug-visualizer/injectedScripts";
18+
const injectedExtractorsFns = Object.values(
19+
(global as any)[key]
20+
) as LoadDataExtractorsFn[];
21+
22+
const extractors = new Array<DataExtractor>();
23+
24+
for (const fn of injectedExtractorsFns) {
25+
fn(extractor => {
26+
extractors.push(extractor);
27+
}, helpers);
28+
}
29+
30+
for (const extractor of extractors) {
31+
extractor.getExtractions(data, extractionCollector, context);
32+
}
33+
}
34+
}

data-extraction/src/js/api/default-extractors/registerDefaultDataExtractors.ts

Lines changed: 2 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { getDataExtractorApi } from "../injection";
99
import { GridExtractor } from "./GridExtractor";
1010
import { TableDataExtractor } from "./TableExtractor";
1111
import { StringDiffExtractor } from "./StringDiffExtractor";
12-
import { find } from "../../helpers";
12+
import { InjectedExtractor } from "./InjectedExtractor";
1313

1414
/**
1515
* The default data extractors should be registered by VS Code automatically.
@@ -28,101 +28,8 @@ export function registerDefaultExtractors(
2828
new GridExtractor(),
2929
new TableDataExtractor(),
3030
new StringDiffExtractor(),
31+
new InjectedExtractor(),
3132
]) {
3233
api.registerExtractor(item);
3334
}
34-
35-
function isRange(
36-
value: unknown
37-
): value is {
38-
startColumn: number;
39-
startLineNumber: number;
40-
endColumn: number;
41-
endLineNumber: number;
42-
} {
43-
return (
44-
typeof value === "object" &&
45-
!!value &&
46-
"startColumn" in value &&
47-
"startLineNumber" in value
48-
);
49-
}
50-
51-
function isPosition(
52-
value: unknown
53-
): value is { column: number; lineNumber: number } {
54-
return (
55-
typeof value === "object" &&
56-
!!value &&
57-
"column" in value &&
58-
"lineNumber" in value
59-
);
60-
}
61-
62-
// hedietDbgVis.find(x => x.constructor.name === 'TextModel').getValue()
63-
api.registerExtractor({
64-
id: "positionInTextModel",
65-
getExtractions(data, collector, context) {
66-
let range: {
67-
start: {
68-
line: number;
69-
column: number;
70-
};
71-
end: {
72-
line: number;
73-
column: number;
74-
};
75-
};
76-
if (isRange(data)) {
77-
range = {
78-
start: {
79-
line: data.startLineNumber - 1,
80-
column: data.startColumn - 1,
81-
},
82-
end: {
83-
line: data.endLineNumber - 1,
84-
column: data.endColumn - 1,
85-
},
86-
};
87-
} else if (isPosition(data)) {
88-
range = {
89-
start: {
90-
line: data.lineNumber - 1,
91-
column: data.column - 1,
92-
},
93-
end: {
94-
line: data.lineNumber - 1,
95-
column: data.column - 1,
96-
},
97-
};
98-
} else {
99-
return;
100-
}
101-
102-
if (!isRange(data) && !isPosition(data)) {
103-
return;
104-
}
105-
106-
const textModel: any = find(
107-
x =>
108-
typeof x === "object" &&
109-
!!x &&
110-
"constructor" in x &&
111-
(x as any).constructor.name === "TextModel"
112-
);
113-
114-
collector.addExtraction({
115-
id: "positionInTextModel",
116-
name: "Position In TextModel",
117-
extractData() {
118-
return {
119-
kind: { text: true },
120-
text: textModel.getValue(),
121-
decorations: [{ range }],
122-
};
123-
},
124-
priority: 1000,
125-
});
126-
},
127-
});
12835
}

data-extraction/src/js/api/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from "./DataExtractorApi";
22
export * from "./injection";
33
export { DataExtractorApiImpl } from "./DataExtractorApiImpl";
4+
export * from "./LoadDataExtractorsFn";

data-extraction/src/js/api/injection.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,18 @@ export function getExpressionToInitializeDataExtractorApi(): string {
2020
}
2121

2222
/**
23-
* Returns standalone JS code representing an expression returns the data extraction API.
23+
* Returns standalone JS code representing an expression that returns the data extraction API.
2424
* This expression returns an object of type `DataExtractorApi`.
25-
* If the API must be initialized with `getExpressionToInitializeDataExtractorApi()`,
26-
* it throws an exception containing the text of `ApiHasNotBeenInitializedCode`.
2725
* This function is called in the VS Code extension, the expression is evaluated in the debugee.
2826
*/
2927
export function getExpressionForDataExtractorApi(): string {
3028
return `((${selfContainedGetInitializedDataExtractorApi.toString()})())`;
3129
}
3230

31+
export function getExpressionToDetectDataExtractorApiPresence(): string {
32+
return `((${selfContainedIsDataExtractorApiInitialized.toString()})())`;
33+
}
34+
3335
const apiKey = "@hediet/data-extractor-api/v2";
3436

3537
export function getDataExtractorApi(): DataExtractorApi {
@@ -43,10 +45,15 @@ export function getDataExtractorApi(): DataExtractorApi {
4345
}
4446

4547
/**
46-
* This code is used to detect if the API has not been initialized yet.
4748
* @internal
4849
*/
49-
export const ApiHasNotBeenInitializedCode = "EgH0cybXij1jYUozyakO" as const;
50+
function selfContainedIsDataExtractorApiInitialized(): boolean {
51+
const globalObj =
52+
typeof window === "object" ? (window as any) : (global as any);
53+
const key: typeof apiKey = "@hediet/data-extractor-api/v2";
54+
let api: DataExtractorApi | undefined = globalObj[key];
55+
return api !== undefined;
56+
}
5057

5158
/**
5259
* @internal
@@ -57,11 +64,7 @@ function selfContainedGetInitializedDataExtractorApi(): DataExtractorApi {
5764
const key: typeof apiKey = "@hediet/data-extractor-api/v2";
5865
let api: DataExtractorApi | undefined = globalObj[key];
5966
if (!api) {
60-
const code: typeof ApiHasNotBeenInitializedCode =
61-
"EgH0cybXij1jYUozyakO";
62-
throw new Error(
63-
`Data Extractor API has not been initialized. Code: ${code}`
64-
);
67+
throw new Error(`Data Extractor API has not been initialized.`);
6568
}
6669
return api;
6770
}

demos/js/.vscode/settings.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
{
22
"editor.minimap.enabled": false,
3-
"git.enabled": false
3+
"git.enabled": false,
4+
"typescript.tsc.autoDetect": "off",
5+
"debugVisualizer.js.customScriptPaths": [
6+
"${workspaceFolder}/custom-visualizer.js",
7+
]
48
}

demos/js/custom-visualizer.js

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
// @ts-check
2+
/**
3+
* @type {import("@hediet/debug-visualizer-data-extraction").LoadDataExtractorsFn}
4+
*/
5+
module.exports = (register, helpers) => {
6+
register({
7+
id: "map",
8+
getExtractions(data, collector, context) {
9+
if (!(data instanceof Map)) {
10+
return;
11+
}
12+
13+
collector.addExtraction({
14+
priority: 1000,
15+
id: "map",
16+
name: "Map",
17+
extractData() {
18+
return helpers.asData({
19+
kind: { table: true },
20+
rows: [...data].map(([k, v]) => ({ key: k, value: v }))
21+
});
22+
},
23+
});
24+
},
25+
});
26+
};
27+
28+
29+
30+
31+
/*
32+
register({
33+
id: "binaryViewer",
34+
getExtractions(data, collector, context) {
35+
if (typeof data !== "number") {
36+
return;
37+
}
38+
39+
collector.addExtraction({
40+
priority: 100,
41+
id: "binary",
42+
name: "Bits of Integer",
43+
extractData() {
44+
return helpers.asData({
45+
kind: { text: true },
46+
text: data.toString(2),
47+
});
48+
},
49+
});
50+
},
51+
});
52+
53+
*/
54+
55+
(register, helpers) => {
56+
register({
57+
id: "positionOrRangeInTextModel",
58+
getExtractions(data, collector, context) {
59+
collector.addExtraction({
60+
priority: 100,
61+
id: "foo",
62+
name: "Foo",
63+
extractData() {
64+
return helpers.asData({
65+
kind: { text: true },
66+
text: Object.keys(context.variablesInScope).join(", "),
67+
});
68+
},
69+
});
70+
},
71+
});
72+
73+
register({
74+
id: "positionOrRangeInTextModel",
75+
getExtractions(data, collector, context) {
76+
/** @type {{ start: { line: number; column: number; }; end: { line: number; column: number; }; }} */
77+
let range;
78+
if (isRange(data)) {
79+
range = {
80+
start: {
81+
line: data.startLineNumber - 1,
82+
column: data.startColumn - 1,
83+
},
84+
end: {
85+
line: data.endLineNumber - 1,
86+
column: data.endColumn - 1,
87+
},
88+
};
89+
} else if (isPosition(data)) {
90+
range = {
91+
start: {
92+
line: data.lineNumber - 1,
93+
column: data.column - 1,
94+
},
95+
end: { line: data.lineNumber - 1, column: data.column - 1 },
96+
};
97+
} else {
98+
return;
99+
}
100+
101+
if (!isRange(data) && !isPosition(data)) {
102+
return;
103+
}
104+
105+
/** @type {any} */
106+
const textModel = helpers.find(
107+
x =>
108+
typeof x === "object" &&
109+
!!x &&
110+
"constructor" in x &&
111+
x.constructor.name === "TextModel"
112+
);
113+
114+
collector.addExtraction({
115+
id: "positionOrRangeInTextModel",
116+
name: "Position/Range In TextModel",
117+
extractData() {
118+
return helpers.asData({
119+
kind: { text: true },
120+
text: textModel.getValue(),
121+
decorations: [{ range }],
122+
});
123+
},
124+
priority: 1000,
125+
});
126+
},
127+
});
128+
};
129+
130+
/**
131+
* @return {value is { startColumn: number; startLineNumber: number; endColumn: number; endLineNumber: number; }}
132+
*/
133+
function isRange(value) {
134+
return (
135+
typeof value === "object" &&
136+
!!value &&
137+
"startColumn" in value &&
138+
"startLineNumber" in value
139+
);
140+
}
141+
142+
/**
143+
* @return {value is { column: number; lineNumber: number }}
144+
*/
145+
function isPosition(value) {
146+
return (
147+
typeof value === "object" &&
148+
!!value &&
149+
"column" in value &&
150+
"lineNumber" in value
151+
);
152+
}

0 commit comments

Comments
 (0)