Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f2b4f620fe | ||
|
|
d22e5d4111 | ||
|
|
6ce5d666a3 | ||
|
|
6da44bd722 | ||
|
|
db1e5a8086 | ||
|
|
28d02ca4ab | ||
|
|
1e65dd1990 | ||
|
|
76fa30f71a | ||
|
|
3c8ccd9a53 | ||
|
|
9c70e06ee7 | ||
|
|
8f83a1d96e | ||
|
|
9cd290ab57 | ||
|
|
061ccdca33 | ||
|
|
12099d6152 | ||
|
|
b47efb7176 | ||
|
|
ee9f405033 | ||
|
|
cc272acb06 | ||
|
|
4a81e9910b | ||
|
|
d8840bf33b | ||
|
|
e882593cea | ||
|
|
7ab4e0c4b5 | ||
|
|
4aca50f67a | ||
|
|
6ef0ecb60f | ||
|
|
0ce1b02b2c | ||
|
|
abfa44b4f9 | ||
|
|
fa1432ffc8 | ||
|
|
fc142926b8 | ||
|
|
d68d3b4076 | ||
|
|
f8c3b73d4f | ||
|
|
a8e1a5a36c | ||
|
|
d421fa1497 | ||
|
|
118d02e797 | ||
|
|
c420ff7f6f | ||
|
|
7aaebf0332 | ||
|
|
2f44c2d6f8 | ||
|
|
f5f6f5d56d | ||
|
|
3e64d3b05c | ||
|
|
0429eac23e | ||
|
|
dc9b07a4b6 | ||
|
|
2b6dbf52e9 | ||
|
|
e4606a4ae3 | ||
|
|
508062768c | ||
|
|
d7dc1f27e0 | ||
|
|
4525c226c8 | ||
|
|
c09dadb199 | ||
|
|
c88e98cc24 | ||
|
|
17be602906 |
10
.vscode/launch.json
vendored
@@ -47,7 +47,7 @@
|
|||||||
"runtimeExecutable": "${execPath}",
|
"runtimeExecutable": "${execPath}",
|
||||||
"args": [
|
"args": [
|
||||||
"--extensionDevelopmentPath=${workspaceFolder}/extension",
|
"--extensionDevelopmentPath=${workspaceFolder}/extension",
|
||||||
"${workspaceFolder}/demos/python"
|
"${workspaceFolder}/demos/js"
|
||||||
],
|
],
|
||||||
"env": {
|
"env": {
|
||||||
"HOT_RELOAD": "",
|
"HOT_RELOAD": "",
|
||||||
@@ -70,6 +70,12 @@
|
|||||||
},
|
},
|
||||||
"outFiles": ["${workspaceFolder}/extension/dist/**/*.js"],
|
"outFiles": ["${workspaceFolder}/extension/dist/**/*.js"],
|
||||||
"preLaunchTask": "npm: dev - extension"
|
"preLaunchTask": "npm: dev - extension"
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
"type": "dart",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Run Dart samples",
|
||||||
|
"program": "demos/dart/demo.dart"
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
9
.vscode/settings.json
vendored
@@ -7,6 +7,11 @@
|
|||||||
"plantuml.exportOutDir": "docs/exported",
|
"plantuml.exportOutDir": "docs/exported",
|
||||||
"typescript.updateImportsOnFileMove.enabled": "prompt",
|
"typescript.updateImportsOnFileMove.enabled": "prompt",
|
||||||
"mochaExplorer.files": "./data-extraction/test/**/*.test.ts",
|
"mochaExplorer.files": "./data-extraction/test/**/*.test.ts",
|
||||||
"mochaExplorer.require": ["ts-node/register", "source-map-support/register"],
|
"mochaExplorer.require": [
|
||||||
"tasksStatusbar.taskLabelFilter": "dev"
|
"ts-node/register",
|
||||||
|
"source-map-support/register"
|
||||||
|
],
|
||||||
|
"tasksStatusbar.taskLabelFilter": "dev",
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"typescript.tsdk": "node_modules\\typescript\\lib"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,16 +42,10 @@ Implements the UI and is hosted inside a webview in VS Code.
|
|||||||
Can be opened in a browser window.
|
Can be opened in a browser window.
|
||||||
Uses websockets and JSON RPC to communicate with the extension.
|
Uses websockets and JSON RPC to communicate with the extension.
|
||||||
|
|
||||||
### visualization
|
### hediet/visualization
|
||||||
|
|
||||||
Contains React components that visualize various JSON documents.
|
Contains all the visualizers and visualization infrastructure.
|
||||||
Also provides infrastructure for selecting the best visualization for a given JSON document.
|
This external project can be found [here](https://github.com/hediet/visualization).
|
||||||
|
|
||||||
### visualization-playground
|
|
||||||
|
|
||||||
A playground to test and play with the visualizations for the web.
|
|
||||||
Is hosted at [https://hediet.github.io/vscode-debug-visualizer/](https://hediet.github.io/vscode-debug-visualizer/).
|
|
||||||
Aims to have fast build times.
|
|
||||||
|
|
||||||
### extension
|
### extension
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@hediet/debug-visualizer-data-extraction",
|
"name": "@hediet/debug-visualizer-data-extraction",
|
||||||
"description": "A library that helps implementing data extractors for the Debug Visualizer VS Code extension.",
|
"description": "A library that helps implementing data extractors for the Debug Visualizer VS Code extension.",
|
||||||
"version": "0.13.0",
|
"version": "0.14.0",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
"author": {
|
"author": {
|
||||||
@@ -29,17 +29,17 @@
|
|||||||
"dependencies": {},
|
"dependencies": {},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/mocha": "^7.0.2",
|
"@types/mocha": "^7.0.2",
|
||||||
|
"@types/node": "^13.7.4",
|
||||||
|
"@types/plotly.js": "1.44.28",
|
||||||
"coveralls": "^3.0.11",
|
"coveralls": "^3.0.11",
|
||||||
"mocha": "^7.1.1",
|
"mocha": "^7.1.1",
|
||||||
"mocha-lcov-reporter": "^1.3.0",
|
"mocha-lcov-reporter": "^1.3.0",
|
||||||
"nyc": "^15.0.0",
|
"nyc": "^15.0.0",
|
||||||
"source-map-support": "^0.5.16",
|
"source-map-support": "^0.5.16",
|
||||||
"typescript": "^3.8.2",
|
"ts-loader": "^6.2.1",
|
||||||
"@types/plotly.js": "1.44.28",
|
|
||||||
"@types/node": "^13.7.4",
|
|
||||||
"tslint": "^6.0.0",
|
"tslint": "^6.0.0",
|
||||||
|
"typescript": "^3.8.2",
|
||||||
"webpack": "^4.41.6",
|
"webpack": "^4.41.6",
|
||||||
"webpack-cli": "^3.3.11",
|
"webpack-cli": "^3.3.11"
|
||||||
"ts-loader": "^6.2.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export type KnownVisualizationData =
|
|||||||
| GridVisualizationData
|
| GridVisualizationData
|
||||||
| ImageVisualizationData
|
| ImageVisualizationData
|
||||||
| MonacoTextVisualizationData
|
| MonacoTextVisualizationData
|
||||||
|
| MonacoTextDiffVisualizationData
|
||||||
| TableVisualizationData
|
| TableVisualizationData
|
||||||
| PlotlyVisualizationData
|
| PlotlyVisualizationData
|
||||||
| SimpleTextVisualizationData
|
| SimpleTextVisualizationData
|
||||||
@@ -106,7 +107,7 @@ export type GraphEdge = {
|
|||||||
label?: string;
|
label?: string;
|
||||||
id?: string;
|
id?: string;
|
||||||
color?: string;
|
color?: string;
|
||||||
dashes?: boolean;
|
style?: "solid" | "dashed" | "dotted";
|
||||||
};
|
};
|
||||||
|
|
||||||
export type GridVisualizationData = {
|
export type GridVisualizationData = {
|
||||||
@@ -156,6 +157,50 @@ export type MonacoTextVisualizationData = {
|
|||||||
* The text to show
|
* The text to show
|
||||||
*/
|
*/
|
||||||
text: string;
|
text: string;
|
||||||
|
decorations?: {
|
||||||
|
range: LineColumnRange;
|
||||||
|
label?: string;
|
||||||
|
}[];
|
||||||
|
/**
|
||||||
|
* An optional filename that might be used for chosing a syntax highlighter
|
||||||
|
*/
|
||||||
|
fileName?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LineColumnRange = {
|
||||||
|
/**
|
||||||
|
* The start position
|
||||||
|
*/
|
||||||
|
start: LineColumnPosition;
|
||||||
|
/**
|
||||||
|
* The end position
|
||||||
|
*/
|
||||||
|
end: LineColumnPosition;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LineColumnPosition = {
|
||||||
|
/**
|
||||||
|
* The 0-based line number
|
||||||
|
*/
|
||||||
|
line: number;
|
||||||
|
/**
|
||||||
|
* The 0-based column number
|
||||||
|
*/
|
||||||
|
column: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MonacoTextDiffVisualizationData = {
|
||||||
|
kind: {
|
||||||
|
text: true;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* The text to show
|
||||||
|
*/
|
||||||
|
text: string;
|
||||||
|
/**
|
||||||
|
* The text to compare against
|
||||||
|
*/
|
||||||
|
otherText: string;
|
||||||
/**
|
/**
|
||||||
* An optional filename that might be used for chosing a syntax highlighter
|
* An optional filename that might be used for chosing a syntax highlighter
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ export interface DataExtractorApi {
|
|||||||
getData(
|
getData(
|
||||||
valueFn: () => unknown,
|
valueFn: () => unknown,
|
||||||
evalFn: <T>(expression: string) => T,
|
evalFn: <T>(expression: string) => T,
|
||||||
preferredDataExtractorId: string | undefined
|
preferredDataExtractorId: string | undefined,
|
||||||
|
variablesInScope: Record<string, unknown>
|
||||||
): JSONString<DataResult>;
|
): JSONString<DataResult>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -68,6 +69,8 @@ export interface DataExtractorContext {
|
|||||||
* Evaluates an expression in the context of the active stack frame.
|
* Evaluates an expression in the context of the active stack frame.
|
||||||
*/
|
*/
|
||||||
evalFn: <TEval>(expression: string) => TEval;
|
evalFn: <TEval>(expression: string) => TEval;
|
||||||
|
|
||||||
|
variablesInScope: Record<string, unknown>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DataExtraction {
|
export interface DataExtraction {
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ import { registerDefaultExtractors } from "./default-extractors";
|
|||||||
*/
|
*/
|
||||||
export class DataExtractorApiImpl implements DataExtractorApi {
|
export class DataExtractorApiImpl implements DataExtractorApi {
|
||||||
public static lastEvalFn: (<T>(expression: string) => T) | undefined;
|
public static lastEvalFn: (<T>(expression: string) => T) | undefined;
|
||||||
|
public static lastVariablesInScope:
|
||||||
|
| Record<string, unknown>
|
||||||
|
| undefined = undefined;
|
||||||
|
|
||||||
private readonly extractors = new Map<string, DataExtractor>();
|
private readonly extractors = new Map<string, DataExtractor>();
|
||||||
|
|
||||||
@@ -34,7 +37,8 @@ export class DataExtractorApiImpl implements DataExtractorApi {
|
|||||||
public getData(
|
public getData(
|
||||||
valueFn: () => unknown,
|
valueFn: () => unknown,
|
||||||
evalFn: <T>(expression: string) => T,
|
evalFn: <T>(expression: string) => T,
|
||||||
preferredDataExtractorId: string | undefined
|
preferredDataExtractorId: string | undefined,
|
||||||
|
variablesInScope: Record<string, unknown>
|
||||||
): JSONString<DataResult> {
|
): JSONString<DataResult> {
|
||||||
const extractions = new Array<DataExtraction>();
|
const extractions = new Array<DataExtraction>();
|
||||||
const extractionCollector: ExtractionCollector = {
|
const extractionCollector: ExtractionCollector = {
|
||||||
@@ -43,13 +47,20 @@ export class DataExtractorApiImpl implements DataExtractorApi {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DataExtractorApiImpl.lastVariablesInScope = variablesInScope;
|
||||||
DataExtractorApiImpl.lastEvalFn = evalFn;
|
DataExtractorApiImpl.lastEvalFn = evalFn;
|
||||||
const value = valueFn();
|
const value = valueFn();
|
||||||
DataExtractorApiImpl.lastEvalFn = undefined;
|
|
||||||
|
|
||||||
for (const e of this.extractors.values()) {
|
for (const e of this.extractors.values()) {
|
||||||
e.getExtractions(value, extractionCollector, { evalFn });
|
e.getExtractions(value, extractionCollector, {
|
||||||
|
evalFn,
|
||||||
|
variablesInScope,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DataExtractorApiImpl.lastVariablesInScope = undefined;
|
||||||
|
DataExtractorApiImpl.lastEvalFn = undefined;
|
||||||
|
|
||||||
extractions.sort((a, b) => b.priority - a.priority);
|
extractions.sort((a, b) => b.priority - a.priority);
|
||||||
let usedExtraction = extractions[0];
|
let usedExtraction = extractions[0];
|
||||||
if (!usedExtraction) {
|
if (!usedExtraction) {
|
||||||
|
|||||||
7
data-extraction/src/js/api/LoadDataExtractorsFn.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { DataExtractor } from "./DataExtractorApi";
|
||||||
|
import type * as helpersTypes from "../helpers"
|
||||||
|
|
||||||
|
export type LoadDataExtractorsFn = (
|
||||||
|
register: (extractor: DataExtractor) => void,
|
||||||
|
helpers: typeof helpersTypes
|
||||||
|
) => void;
|
||||||
@@ -24,7 +24,7 @@ export class GridExtractor implements DataExtractor {
|
|||||||
extractData: () =>
|
extractData: () =>
|
||||||
expect<GridVisualizationData>({
|
expect<GridVisualizationData>({
|
||||||
kind: { grid: true },
|
kind: { grid: true },
|
||||||
rows: [{ columns: data.map(d => ({ tag: d })) }],
|
rows: [{ columns: data.map(d => ({ tag: "" + d })) }],
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import {
|
||||||
|
DataExtractor,
|
||||||
|
ExtractionCollector,
|
||||||
|
DataExtractorContext,
|
||||||
|
LoadDataExtractorsFn,
|
||||||
|
} from "..";
|
||||||
|
import * as helpers from "../../helpers";
|
||||||
|
|
||||||
|
export class InjectedExtractor implements DataExtractor {
|
||||||
|
readonly id = "injected-extractor";
|
||||||
|
|
||||||
|
getExtractions(
|
||||||
|
data: unknown,
|
||||||
|
extractionCollector: ExtractionCollector,
|
||||||
|
context: DataExtractorContext
|
||||||
|
): void {
|
||||||
|
const key = "@hediet/debug-visualizer/injectedScripts";
|
||||||
|
const injectedExtractorsFns = Object.values(
|
||||||
|
(global as any)[key]
|
||||||
|
) as LoadDataExtractorsFn[];
|
||||||
|
|
||||||
|
const extractors = new Array<DataExtractor>();
|
||||||
|
|
||||||
|
for (const fn of injectedExtractorsFns) {
|
||||||
|
fn(extractor => {
|
||||||
|
extractors.push(extractor);
|
||||||
|
}, helpers);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const extractor of extractors) {
|
||||||
|
extractor.getExtractions(data, extractionCollector, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { DataExtractor, DataExtractorContext, ExtractionCollector } from "../..";
|
||||||
|
|
||||||
|
export class StringDiffExtractor implements DataExtractor {
|
||||||
|
public readonly id = "string-diff";
|
||||||
|
|
||||||
|
public getExtractions(data: unknown,
|
||||||
|
collector: ExtractionCollector,
|
||||||
|
context: DataExtractorContext) {
|
||||||
|
if (Array.isArray(data) && data.length === 2 && typeof data[0] === "string" && typeof data[1] === "string") {
|
||||||
|
collector.addExtraction({
|
||||||
|
id: "string-diff",
|
||||||
|
name: "String Diff",
|
||||||
|
priority: 1000,
|
||||||
|
extractData: () => ({
|
||||||
|
kind: { text: true },
|
||||||
|
text: data[0],
|
||||||
|
otherText: data[1]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { isAssertionExpression } from "typescript";
|
||||||
|
import { DataExtractor, ExtractionCollector, DataExtractorContext } from "..";
|
||||||
|
import { TableVisualizationData } from "../../../CommonDataTypes";
|
||||||
|
import { expect } from "../../../util";
|
||||||
|
|
||||||
|
function assert<T>(value: unknown): asserts value {}
|
||||||
|
|
||||||
|
export class TableDataExtractor implements DataExtractor {
|
||||||
|
readonly id = "table";
|
||||||
|
|
||||||
|
getExtractions(
|
||||||
|
data: unknown,
|
||||||
|
collector: ExtractionCollector,
|
||||||
|
context: DataExtractorContext
|
||||||
|
): void {
|
||||||
|
if (!Array.isArray(data)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!data.every(d => typeof d === "object" && d)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert<object[]>(data);
|
||||||
|
|
||||||
|
collector.addExtraction({
|
||||||
|
id: "table",
|
||||||
|
name: "Table",
|
||||||
|
priority: 1000,
|
||||||
|
extractData() {
|
||||||
|
return expect<TableVisualizationData>({
|
||||||
|
kind: {
|
||||||
|
table: true,
|
||||||
|
},
|
||||||
|
rows: data,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.addExtraction({
|
||||||
|
id: "table-with-type-name",
|
||||||
|
name: "Table (With Type Name)",
|
||||||
|
priority: 950,
|
||||||
|
extractData() {
|
||||||
|
return expect<TableVisualizationData>({
|
||||||
|
kind: {
|
||||||
|
table: true,
|
||||||
|
},
|
||||||
|
rows: data.map(d => ({ type: d.constructor.name, ...d })),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -107,6 +107,7 @@ export class TypeScriptAstDataExtractor implements DataExtractor {
|
|||||||
root: helper.toTreeNode(
|
root: helper.toTreeNode(
|
||||||
rootNode || finalRootSourceFile,
|
rootNode || finalRootSourceFile,
|
||||||
"root",
|
"root",
|
||||||
|
"",
|
||||||
marked,
|
marked,
|
||||||
fn
|
fn
|
||||||
),
|
),
|
||||||
@@ -121,19 +122,24 @@ export class TypeScriptAstDataExtractor implements DataExtractor {
|
|||||||
class Helper {
|
class Helper {
|
||||||
constructor(private readonly tsApi: typeof ts) {}
|
constructor(private readonly tsApi: typeof ts) {}
|
||||||
|
|
||||||
findKey(value: any, object: any): string | null {
|
getPropertyNameInParent(value: any, parent: any): string | undefined {
|
||||||
for (var key in object) {
|
for (const propertyName in parent) {
|
||||||
if (key.startsWith("_")) continue;
|
if (propertyName.startsWith("_")) continue;
|
||||||
|
|
||||||
var member = object[key];
|
const member = parent[propertyName];
|
||||||
if (member === value) return key;
|
if (member === value) {
|
||||||
|
return propertyName;
|
||||||
|
}
|
||||||
|
|
||||||
if (Array.isArray(member) && member.indexOf(value) !== -1) {
|
if (Array.isArray(member)) {
|
||||||
return key;
|
const index = member.indexOf(value);
|
||||||
|
if (index !== -1) {
|
||||||
|
return `${propertyName}[${index}]`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
getChildren(node: ts.Node): ts.Node[] {
|
getChildren(node: ts.Node): ts.Node[] {
|
||||||
@@ -147,30 +153,38 @@ class Helper {
|
|||||||
toTreeNode(
|
toTreeNode(
|
||||||
node: ts.Node,
|
node: ts.Node,
|
||||||
memberName: string,
|
memberName: string,
|
||||||
|
segmentName: string,
|
||||||
marked: Set<ts.Node>,
|
marked: Set<ts.Node>,
|
||||||
emphasizedValueFn: (node: ts.Node) => string | undefined
|
emphasizedValueFn: (node: ts.Node) => string | undefined
|
||||||
): AstTreeNode {
|
): AstTreeNode {
|
||||||
const name = this.tsApi.SyntaxKind[node.kind];
|
const name = this.tsApi.SyntaxKind[node.kind];
|
||||||
const children = this.getChildren(node)
|
const children = this.getChildren(node)
|
||||||
.map((childNode, idx) => {
|
.map((childNode, idx) => {
|
||||||
let parentPropertyName = this.findKey(childNode, node) || "";
|
let parentPropertyName =
|
||||||
|
this.getPropertyNameInParent(childNode, node) || "";
|
||||||
|
|
||||||
if (childNode.kind == this.tsApi.SyntaxKind.SyntaxList) {
|
if (childNode.kind == this.tsApi.SyntaxKind.SyntaxList) {
|
||||||
const children = this.getChildren(childNode);
|
const children = this.getChildren(childNode);
|
||||||
children.some(c => {
|
for (const c of children) {
|
||||||
parentPropertyName = this.findKey(c, node) || "";
|
const name =
|
||||||
return !!parentPropertyName;
|
this.getPropertyNameInParent(c, node) || "";
|
||||||
});
|
if (name) {
|
||||||
|
parentPropertyName = name;
|
||||||
if (children.length === 0) return null!;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let segmentName = "." + parentPropertyName;
|
||||||
if (node.kind == this.tsApi.SyntaxKind.SyntaxList) {
|
if (node.kind == this.tsApi.SyntaxKind.SyntaxList) {
|
||||||
parentPropertyName = "" + idx;
|
parentPropertyName = "" + idx;
|
||||||
|
segmentName = `[${idx}]`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.toTreeNode(
|
return this.toTreeNode(
|
||||||
childNode,
|
childNode,
|
||||||
parentPropertyName,
|
parentPropertyName,
|
||||||
|
segmentName,
|
||||||
marked,
|
marked,
|
||||||
emphasizedValueFn
|
emphasizedValueFn
|
||||||
);
|
);
|
||||||
@@ -201,6 +215,7 @@ class Helper {
|
|||||||
return {
|
return {
|
||||||
items,
|
items,
|
||||||
children: children,
|
children: children,
|
||||||
|
segment: segmentName,
|
||||||
span: {
|
span: {
|
||||||
length: node.end - node.pos,
|
length: node.end - node.pos,
|
||||||
start: node.pos,
|
start: node.pos,
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ import { PlotlyDataExtractor } from "./PlotlyDataExtractor";
|
|||||||
import { ObjectGraphExtractor } from "./ObjectGraphExtractor";
|
import { ObjectGraphExtractor } from "./ObjectGraphExtractor";
|
||||||
import { getDataExtractorApi } from "../injection";
|
import { getDataExtractorApi } from "../injection";
|
||||||
import { GridExtractor } from "./GridExtractor";
|
import { GridExtractor } from "./GridExtractor";
|
||||||
|
import { TableDataExtractor } from "./TableExtractor";
|
||||||
|
import { StringDiffExtractor } from "./StringDiffExtractor";
|
||||||
|
import { InjectedExtractor } from "./InjectedExtractor";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default data extractors should be registered by VS Code automatically.
|
* The default data extractors should be registered by VS Code automatically.
|
||||||
@@ -23,6 +26,9 @@ export function registerDefaultExtractors(
|
|||||||
new PlotlyDataExtractor(),
|
new PlotlyDataExtractor(),
|
||||||
new ObjectGraphExtractor(),
|
new ObjectGraphExtractor(),
|
||||||
new GridExtractor(),
|
new GridExtractor(),
|
||||||
|
new TableDataExtractor(),
|
||||||
|
new StringDiffExtractor(),
|
||||||
|
new InjectedExtractor(),
|
||||||
]) {
|
]) {
|
||||||
api.registerExtractor(item);
|
api.registerExtractor(item);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
export * from "./DataExtractorApi";
|
export * from "./DataExtractorApi";
|
||||||
export * from "./injection";
|
export * from "./injection";
|
||||||
export { DataExtractorApiImpl } from "./DataExtractorApiImpl";
|
export { DataExtractorApiImpl } from "./DataExtractorApiImpl";
|
||||||
|
export * from "./LoadDataExtractorsFn";
|
||||||
|
|||||||
@@ -20,16 +20,18 @@ export function getExpressionToInitializeDataExtractorApi(): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns standalone JS code representing an expression returns the data extraction API.
|
* Returns standalone JS code representing an expression that returns the data extraction API.
|
||||||
* This expression returns an object of type `DataExtractorApi`.
|
* This expression returns an object of type `DataExtractorApi`.
|
||||||
* If the API must be initialized with `getExpressionToInitializeDataExtractorApi()`,
|
|
||||||
* it throws an exception containing the text of `ApiHasNotBeenInitializedCode`.
|
|
||||||
* This function is called in the VS Code extension, the expression is evaluated in the debugee.
|
* This function is called in the VS Code extension, the expression is evaluated in the debugee.
|
||||||
*/
|
*/
|
||||||
export function getExpressionForDataExtractorApi(): string {
|
export function getExpressionForDataExtractorApi(): string {
|
||||||
return `((${selfContainedGetInitializedDataExtractorApi.toString()})())`;
|
return `((${selfContainedGetInitializedDataExtractorApi.toString()})())`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getExpressionToDetectDataExtractorApiPresence(): string {
|
||||||
|
return `((${selfContainedIsDataExtractorApiInitialized.toString()})())`;
|
||||||
|
}
|
||||||
|
|
||||||
const apiKey = "@hediet/data-extractor-api/v2";
|
const apiKey = "@hediet/data-extractor-api/v2";
|
||||||
|
|
||||||
export function getDataExtractorApi(): DataExtractorApi {
|
export function getDataExtractorApi(): DataExtractorApi {
|
||||||
@@ -43,10 +45,15 @@ export function getDataExtractorApi(): DataExtractorApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This code is used to detect if the API has not been initialized yet.
|
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
export const ApiHasNotBeenInitializedCode = "EgH0cybXij1jYUozyakO" as const;
|
function selfContainedIsDataExtractorApiInitialized(): boolean {
|
||||||
|
const globalObj =
|
||||||
|
typeof window === "object" ? (window as any) : (global as any);
|
||||||
|
const key: typeof apiKey = "@hediet/data-extractor-api/v2";
|
||||||
|
let api: DataExtractorApi | undefined = globalObj[key];
|
||||||
|
return api !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
@@ -57,11 +64,7 @@ function selfContainedGetInitializedDataExtractorApi(): DataExtractorApi {
|
|||||||
const key: typeof apiKey = "@hediet/data-extractor-api/v2";
|
const key: typeof apiKey = "@hediet/data-extractor-api/v2";
|
||||||
let api: DataExtractorApi | undefined = globalObj[key];
|
let api: DataExtractorApi | undefined = globalObj[key];
|
||||||
if (!api) {
|
if (!api) {
|
||||||
const code: typeof ApiHasNotBeenInitializedCode =
|
throw new Error(`Data Extractor API has not been initialized.`);
|
||||||
"EgH0cybXij1jYUozyakO";
|
|
||||||
throw new Error(
|
|
||||||
`Data Extractor API has not been initialized. Code: ${code}`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return api;
|
return api;
|
||||||
}
|
}
|
||||||
|
|||||||
6
data-extraction/src/js/helpers/asData.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { KnownVisualizationData } from "../../CommonDataTypes";
|
||||||
|
import { VisualizationData } from "../../DataExtractionResult";
|
||||||
|
|
||||||
|
export function asData(data: KnownVisualizationData): VisualizationData {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
@@ -4,7 +4,8 @@ import {
|
|||||||
GraphVisualizationData,
|
GraphVisualizationData,
|
||||||
} from "../../CommonDataTypes";
|
} from "../../CommonDataTypes";
|
||||||
|
|
||||||
export type CreateGraphEdge<T> = { to: T } & Omit<GraphEdge, "from" | "to">;
|
export type CreateGraphEdge<T> = ({ to: T } | { from: T } | { include: T }) &
|
||||||
|
Omit<GraphEdge, "from" | "to">;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a list of roots, it creates a graph by following their edges recursively.
|
* Given a list of roots, it creates a graph by following their edges recursively.
|
||||||
@@ -58,13 +59,31 @@ export function createGraph<T>(
|
|||||||
const fromId = getId(item);
|
const fromId = getId(item);
|
||||||
r.nodes.push({ ...nodeInfo, id: fromId, ["edges" as any]: undefined });
|
r.nodes.push({ ...nodeInfo, id: fromId, ["edges" as any]: undefined });
|
||||||
for (const e of nodeInfo.edges) {
|
for (const e of nodeInfo.edges) {
|
||||||
const toId = getId(e.to);
|
let other: T;
|
||||||
r.edges.push({
|
let toId: string | undefined;
|
||||||
...e,
|
let fromId_: string | undefined;
|
||||||
from: fromId,
|
if ("to" in e) {
|
||||||
to: toId,
|
other = e.to;
|
||||||
});
|
toId = getId(e.to);
|
||||||
let shouldPush = !processed.has(e.to);
|
fromId_ = fromId;
|
||||||
|
} else if ("from" in e) {
|
||||||
|
other = e.from;
|
||||||
|
toId = getId(e.from);
|
||||||
|
fromId_ = fromId;
|
||||||
|
} else if ("include" in e) {
|
||||||
|
other = e.include;
|
||||||
|
} else {
|
||||||
|
throw new Error("Every edge must either have 'to' or 'from'");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fromId_ !== undefined && toId !== undefined) {
|
||||||
|
r.edges.push({
|
||||||
|
...e,
|
||||||
|
from: fromId_,
|
||||||
|
to: toId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let shouldPush = !processed.has(other);
|
||||||
if (
|
if (
|
||||||
options.maxSize &&
|
options.maxSize &&
|
||||||
processed.size + queue.length > options.maxSize
|
processed.size + queue.length > options.maxSize
|
||||||
@@ -72,7 +91,7 @@ export function createGraph<T>(
|
|||||||
shouldPush = false;
|
shouldPush = false;
|
||||||
}
|
}
|
||||||
if (shouldPush) {
|
if (shouldPush) {
|
||||||
queue.push({ item: e.to, dist: dist + 1 });
|
queue.push({ item: other, dist: dist + 1 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
34
data-extraction/src/js/helpers/find.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { DataExtractorApiImpl } from "../api";
|
||||||
|
|
||||||
|
export function find(predicate: (obj: unknown) => boolean): unknown {
|
||||||
|
const processed = new Set();
|
||||||
|
if (!DataExtractorApiImpl.lastVariablesInScope) {
|
||||||
|
throw new Error("No variables in scope!");
|
||||||
|
}
|
||||||
|
|
||||||
|
const values = Object.values(DataExtractorApiImpl.lastVariablesInScope);
|
||||||
|
const queue = [...values];
|
||||||
|
|
||||||
|
let i = 10000;
|
||||||
|
while (i > 0) {
|
||||||
|
i--;
|
||||||
|
|
||||||
|
const top = queue.shift();
|
||||||
|
processed.add(top);
|
||||||
|
|
||||||
|
if (predicate(top)) {
|
||||||
|
return top;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof top === "object" && top) {
|
||||||
|
for (const val of Object.values(top)) {
|
||||||
|
if (!processed.has(val)) {
|
||||||
|
processed.add(val);
|
||||||
|
queue.push(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
@@ -3,3 +3,5 @@ export * from "./createGraphFromPointers";
|
|||||||
export * from "./tryEval";
|
export * from "./tryEval";
|
||||||
export * from "./markedGrid";
|
export * from "./markedGrid";
|
||||||
export * from "./cache";
|
export * from "./cache";
|
||||||
|
export * from "./asData";
|
||||||
|
export * from "./find";
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
import { GridVisualizationData } from "../../CommonDataTypes";
|
import { GridVisualizationData } from "../../CommonDataTypes";
|
||||||
|
|
||||||
export function markedGrid(
|
export function markedGrid(
|
||||||
arr: any[],
|
arr: unknown[],
|
||||||
marked: Record<string, number>
|
marked: Record<string, number | undefined>
|
||||||
): GridVisualizationData {
|
): GridVisualizationData {
|
||||||
return {
|
return {
|
||||||
kind: { grid: true },
|
kind: { grid: true },
|
||||||
rows: [{ columns: arr.map(d => ({ tag: d })) }],
|
rows: [{ columns: arr.map(d => ({ content: "" + d, tag: "" + d })) }],
|
||||||
markers: Object.entries(marked).map(([key, val]) => ({
|
markers: Object.entries(marked)
|
||||||
id: key,
|
.map(([key, val]) => ({
|
||||||
row: 0,
|
id: "" + key,
|
||||||
column: val,
|
row: 0,
|
||||||
})),
|
column: val!,
|
||||||
|
}))
|
||||||
|
.filter(c => c.column !== undefined),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
85
demos/dart/debug_visualizers.dart
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
String graph(List<GraphNode> nodes, List<GraphEdge> edges) {
|
||||||
|
return jsonEncode({
|
||||||
|
'kind': {'graph': true},
|
||||||
|
'nodes': nodes,
|
||||||
|
'edges': edges,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
String plotly(List<num> values) {
|
||||||
|
return jsonEncode({
|
||||||
|
'kind': {'plotly': true},
|
||||||
|
'data': [
|
||||||
|
{'y': values}
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
String tree(TreeNode root) {
|
||||||
|
return jsonEncode({
|
||||||
|
'kind': {'tree': true},
|
||||||
|
'root': root,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class Graph {
|
||||||
|
List<GraphNode> nodes;
|
||||||
|
List<GraphEdge> edges;
|
||||||
|
}
|
||||||
|
|
||||||
|
class GraphEdge {
|
||||||
|
final String from;
|
||||||
|
final String to;
|
||||||
|
final String label;
|
||||||
|
|
||||||
|
GraphEdge(this.from, this.to, this.label);
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'from': from,
|
||||||
|
'to': to,
|
||||||
|
'label': label,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class GraphNode {
|
||||||
|
final String id;
|
||||||
|
final String label;
|
||||||
|
|
||||||
|
GraphNode(
|
||||||
|
this.id,
|
||||||
|
this.label,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'id': id,
|
||||||
|
'label': label,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class TreeNode {
|
||||||
|
final List<TreeNode> children;
|
||||||
|
final List<TreeNodeItem> items;
|
||||||
|
final String segment;
|
||||||
|
final bool isMarked;
|
||||||
|
|
||||||
|
TreeNode(this.children, this.items, this.segment, [this.isMarked = false]);
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'children': children ?? [],
|
||||||
|
'items': items,
|
||||||
|
'segment': segment,
|
||||||
|
'isMarked': isMarked,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class TreeNodeItem {
|
||||||
|
final String text;
|
||||||
|
|
||||||
|
TreeNodeItem(this.text);
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'text': text,
|
||||||
|
};
|
||||||
|
}
|
||||||
83
demos/dart/demo.dart
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import 'dart:collection';
|
||||||
|
import 'dart:developer';
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
// ignore: unused_import
|
||||||
|
import 'debug_visualizers.dart';
|
||||||
|
|
||||||
|
final _rnd = Random();
|
||||||
|
|
||||||
|
String Function() visualize;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
debugger();
|
||||||
|
// Open a Debug Visualizer window and evalute the expression "visualize()"
|
||||||
|
// and then press Continue to step through the samples.
|
||||||
|
plotly_demo();
|
||||||
|
graph_demo();
|
||||||
|
tree_demo();
|
||||||
|
}
|
||||||
|
|
||||||
|
void plotly_demo() {
|
||||||
|
final values = <int>[];
|
||||||
|
visualize = () => plotly(values);
|
||||||
|
for (var i = 0; i < 20; i++) {
|
||||||
|
debugger();
|
||||||
|
values.add(i + _rnd.nextInt(5) - 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void graph_demo() {
|
||||||
|
graphFromDoubleLinked<T>(
|
||||||
|
DoubleLinkedQueue<T> values, String Function(T) toString) {
|
||||||
|
node(T s) => GraphNode(toString(s), toString(s));
|
||||||
|
edge(DoubleLinkedQueueEntry<T> e) => [
|
||||||
|
if (e.nextEntry() != null)
|
||||||
|
GraphEdge(
|
||||||
|
toString(e.element),
|
||||||
|
toString(e.nextEntry().element),
|
||||||
|
"next",
|
||||||
|
),
|
||||||
|
if (e.previousEntry() != null)
|
||||||
|
GraphEdge(
|
||||||
|
toString(e.element),
|
||||||
|
toString(e.previousEntry().element),
|
||||||
|
"prev",
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
final nodes = values.map(node).toList();
|
||||||
|
final edges = <GraphEdge>[];
|
||||||
|
values.forEachEntry((e) => edges.addAll(edge(e)));
|
||||||
|
return graph(nodes, edges);
|
||||||
|
}
|
||||||
|
|
||||||
|
final values = DoubleLinkedQueue<String>();
|
||||||
|
visualize = () => graphFromDoubleLinked(values, (s) => s);
|
||||||
|
|
||||||
|
for (var i = 0; i < 10; i++) {
|
||||||
|
debugger();
|
||||||
|
values.addLast('Node $i');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tree_demo() {
|
||||||
|
var nodeNum = 1;
|
||||||
|
TreeNode createNode(int levels) {
|
||||||
|
final name = 'Node ${nodeNum++}';
|
||||||
|
final children =
|
||||||
|
levels > 0 ? List.generate(2, (_) => createNode(levels - 1)) : null;
|
||||||
|
return TreeNode(children, [TreeNodeItem(name)], name);
|
||||||
|
}
|
||||||
|
|
||||||
|
var levels = 0;
|
||||||
|
visualize = () {
|
||||||
|
nodeNum = 1;
|
||||||
|
return tree(createNode(levels));
|
||||||
|
};
|
||||||
|
|
||||||
|
for (var i = 1; i < 5; i++) {
|
||||||
|
debugger();
|
||||||
|
levels = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,17 +1,28 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<projectDescription>
|
<projectDescription>
|
||||||
<name>java</name>
|
<name>java</name>
|
||||||
<comment/>
|
<comment></comment>
|
||||||
<projects>
|
<projects>
|
||||||
</projects>
|
</projects>
|
||||||
<buildSpec>
|
<buildSpec>
|
||||||
<buildCommand>
|
<buildCommand>
|
||||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
<arguments>
|
<arguments>
|
||||||
</arguments>
|
</arguments>
|
||||||
</buildCommand>
|
</buildCommand>
|
||||||
</buildSpec>
|
</buildSpec>
|
||||||
<natures>
|
<natures>
|
||||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
</natures>
|
</natures>
|
||||||
</projectDescription>
|
<filteredResources>
|
||||||
|
<filter>
|
||||||
|
<id>1599063072264</id>
|
||||||
|
<name></name>
|
||||||
|
<type>30</type>
|
||||||
|
<matcher>
|
||||||
|
<id>org.eclipse.core.resources.regexFilterMatcher</id>
|
||||||
|
<arguments>node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
|
||||||
|
</matcher>
|
||||||
|
</filter>
|
||||||
|
</filteredResources>
|
||||||
|
</projectDescription>
|
||||||
|
|||||||
8
demos/js/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"editor.minimap.enabled": false,
|
||||||
|
"git.enabled": false,
|
||||||
|
"typescript.tsc.autoDetect": "off",
|
||||||
|
"debugVisualizer.js.customScriptPaths": [
|
||||||
|
"${workspaceFolder}/custom-visualizer.js",
|
||||||
|
]
|
||||||
|
}
|
||||||
152
demos/js/custom-visualizer.js
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
// @ts-check
|
||||||
|
/**
|
||||||
|
* @type {import("@hediet/debug-visualizer-data-extraction").LoadDataExtractorsFn}
|
||||||
|
*/
|
||||||
|
module.exports = (register, helpers) => {
|
||||||
|
register({
|
||||||
|
id: "map",
|
||||||
|
getExtractions(data, collector, context) {
|
||||||
|
if (!(data instanceof Map)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
collector.addExtraction({
|
||||||
|
priority: 1000,
|
||||||
|
id: "map",
|
||||||
|
name: "Map",
|
||||||
|
extractData() {
|
||||||
|
return helpers.asData({
|
||||||
|
kind: { table: true },
|
||||||
|
rows: [...data].map(([k, v]) => ({ key: k, value: v }))
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
register({
|
||||||
|
id: "binaryViewer",
|
||||||
|
getExtractions(data, collector, context) {
|
||||||
|
if (typeof data !== "number") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
collector.addExtraction({
|
||||||
|
priority: 100,
|
||||||
|
id: "binary",
|
||||||
|
name: "Bits of Integer",
|
||||||
|
extractData() {
|
||||||
|
return helpers.asData({
|
||||||
|
kind: { text: true },
|
||||||
|
text: data.toString(2),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
(register, helpers) => {
|
||||||
|
register({
|
||||||
|
id: "positionOrRangeInTextModel",
|
||||||
|
getExtractions(data, collector, context) {
|
||||||
|
collector.addExtraction({
|
||||||
|
priority: 100,
|
||||||
|
id: "foo",
|
||||||
|
name: "Foo",
|
||||||
|
extractData() {
|
||||||
|
return helpers.asData({
|
||||||
|
kind: { text: true },
|
||||||
|
text: Object.keys(context.variablesInScope).join(", "),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
register({
|
||||||
|
id: "positionOrRangeInTextModel",
|
||||||
|
getExtractions(data, collector, context) {
|
||||||
|
/** @type {{ start: { line: number; column: number; }; end: { line: number; column: number; }; }} */
|
||||||
|
let range;
|
||||||
|
if (isRange(data)) {
|
||||||
|
range = {
|
||||||
|
start: {
|
||||||
|
line: data.startLineNumber - 1,
|
||||||
|
column: data.startColumn - 1,
|
||||||
|
},
|
||||||
|
end: {
|
||||||
|
line: data.endLineNumber - 1,
|
||||||
|
column: data.endColumn - 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
} else if (isPosition(data)) {
|
||||||
|
range = {
|
||||||
|
start: {
|
||||||
|
line: data.lineNumber - 1,
|
||||||
|
column: data.column - 1,
|
||||||
|
},
|
||||||
|
end: { line: data.lineNumber - 1, column: data.column - 1 },
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isRange(data) && !isPosition(data)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {any} */
|
||||||
|
const textModel = helpers.find(
|
||||||
|
x =>
|
||||||
|
typeof x === "object" &&
|
||||||
|
!!x &&
|
||||||
|
"constructor" in x &&
|
||||||
|
x.constructor.name === "TextModel"
|
||||||
|
);
|
||||||
|
|
||||||
|
collector.addExtraction({
|
||||||
|
id: "positionOrRangeInTextModel",
|
||||||
|
name: "Position/Range In TextModel",
|
||||||
|
extractData() {
|
||||||
|
return helpers.asData({
|
||||||
|
kind: { text: true },
|
||||||
|
text: textModel.getValue(),
|
||||||
|
decorations: [{ range }],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
priority: 1000,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {value is { startColumn: number; startLineNumber: number; endColumn: number; endLineNumber: number; }}
|
||||||
|
*/
|
||||||
|
function isRange(value) {
|
||||||
|
return (
|
||||||
|
typeof value === "object" &&
|
||||||
|
!!value &&
|
||||||
|
"startColumn" in value &&
|
||||||
|
"startLineNumber" in value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {value is { column: number; lineNumber: number }}
|
||||||
|
*/
|
||||||
|
function isPosition(value) {
|
||||||
|
return (
|
||||||
|
typeof value === "object" &&
|
||||||
|
!!value &&
|
||||||
|
"column" in value &&
|
||||||
|
"lineNumber" in value
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hediet/node-reload": "0.7.3",
|
"@hediet/node-reload": "0.7.3",
|
||||||
"@types/node": "^13.7.4",
|
"@types/node": "^13.7.4",
|
||||||
|
"node-fetch": "^2.6.1",
|
||||||
"typescript": "^3.8.2"
|
"typescript": "^3.8.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
807
demos/js/src/demo_address_book.ts
Normal file
@@ -0,0 +1,807 @@
|
|||||||
|
|
||||||
|
class Person {
|
||||||
|
constructor(public id: number, public firstName: string, public lastName: string, public email: string, public gender: string, public company: string) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Company {
|
||||||
|
constructor(public id: number, public name: string, public street: string, public email: string) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
class AddressBook {
|
||||||
|
public static loadPersons(): Person[] {
|
||||||
|
const contactsData = [{
|
||||||
|
"id": 1,
|
||||||
|
"first_name": "Burg",
|
||||||
|
"last_name": "Legg",
|
||||||
|
"email": "blegg0@elpais.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Zoozzy"
|
||||||
|
}, {
|
||||||
|
"id": 2,
|
||||||
|
"first_name": "Erminia",
|
||||||
|
"last_name": "Heersema",
|
||||||
|
"email": "eheersema1@jugem.jp",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Skipfire"
|
||||||
|
}, {
|
||||||
|
"id": 3,
|
||||||
|
"first_name": "Penrod",
|
||||||
|
"last_name": "Claxton",
|
||||||
|
"email": "pclaxton2@furl.net",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Dabvine"
|
||||||
|
}, {
|
||||||
|
"id": 4,
|
||||||
|
"first_name": "Peterus",
|
||||||
|
"last_name": "Alabone",
|
||||||
|
"email": "palabone3@icio.us",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Gabtune"
|
||||||
|
}, {
|
||||||
|
"id": 5,
|
||||||
|
"first_name": "Rickie",
|
||||||
|
"last_name": "Belsher",
|
||||||
|
"email": "rbelsher4@marketwatch.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Digitube"
|
||||||
|
}, {
|
||||||
|
"id": 6,
|
||||||
|
"first_name": "Griffie",
|
||||||
|
"last_name": "Poulsum",
|
||||||
|
"email": "gpoulsum5@printfriendly.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Mymm"
|
||||||
|
}, {
|
||||||
|
"id": 7,
|
||||||
|
"first_name": "Fidelio",
|
||||||
|
"last_name": "Gateland",
|
||||||
|
"email": "fgateland6@intel.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Meeveo"
|
||||||
|
}, {
|
||||||
|
"id": 8,
|
||||||
|
"first_name": "Fayth",
|
||||||
|
"last_name": "D'Oyly",
|
||||||
|
"email": "fdoyly7@twitter.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Podcat"
|
||||||
|
}, {
|
||||||
|
"id": 9,
|
||||||
|
"first_name": "Janela",
|
||||||
|
"last_name": "Shelton",
|
||||||
|
"email": "jshelton8@dion.ne.jp",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Kayveo"
|
||||||
|
}, {
|
||||||
|
"id": 10,
|
||||||
|
"first_name": "Yance",
|
||||||
|
"last_name": "Vatcher",
|
||||||
|
"email": "yvatcher9@ask.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Photobug"
|
||||||
|
}, {
|
||||||
|
"id": 11,
|
||||||
|
"first_name": "Filippo",
|
||||||
|
"last_name": "Timoney",
|
||||||
|
"email": "ftimoneya@spotify.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Rhyzio"
|
||||||
|
}, {
|
||||||
|
"id": 12,
|
||||||
|
"first_name": "Helli",
|
||||||
|
"last_name": "Friskey",
|
||||||
|
"email": "hfriskeyb@usa.gov",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Eare"
|
||||||
|
}, {
|
||||||
|
"id": 13,
|
||||||
|
"first_name": "Enos",
|
||||||
|
"last_name": "Connick",
|
||||||
|
"email": "econnickc@sitemeter.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Meetz"
|
||||||
|
}, {
|
||||||
|
"id": 14,
|
||||||
|
"first_name": "Lorri",
|
||||||
|
"last_name": "Chessun",
|
||||||
|
"email": "lchessund@wp.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Jaxworks"
|
||||||
|
}, {
|
||||||
|
"id": 15,
|
||||||
|
"first_name": "Justina",
|
||||||
|
"last_name": "Spedroni",
|
||||||
|
"email": "jspedronie@abc.net.au",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Rhyzio"
|
||||||
|
}, {
|
||||||
|
"id": 16,
|
||||||
|
"first_name": "Odilia",
|
||||||
|
"last_name": "Ealden",
|
||||||
|
"email": "oealdenf@fastcompany.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Blognation"
|
||||||
|
}, {
|
||||||
|
"id": 17,
|
||||||
|
"first_name": "Dale",
|
||||||
|
"last_name": "Bretherick",
|
||||||
|
"email": "dbretherickg@dmoz.org",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Skipfire"
|
||||||
|
}, {
|
||||||
|
"id": 18,
|
||||||
|
"first_name": "Syman",
|
||||||
|
"last_name": "Lawdham",
|
||||||
|
"email": "slawdhamh@so-net.ne.jp",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Wordify"
|
||||||
|
}, {
|
||||||
|
"id": 19,
|
||||||
|
"first_name": "Catarina",
|
||||||
|
"last_name": "Stoile",
|
||||||
|
"email": "cstoilei@hud.gov",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Avaveo"
|
||||||
|
}, {
|
||||||
|
"id": 20,
|
||||||
|
"first_name": "Simonette",
|
||||||
|
"last_name": "Danett",
|
||||||
|
"email": "sdanettj@eepurl.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Realblab"
|
||||||
|
}, {
|
||||||
|
"id": 21,
|
||||||
|
"first_name": "Fielding",
|
||||||
|
"last_name": "MacHarg",
|
||||||
|
"email": "fmachargk@blogtalkradio.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Photolist"
|
||||||
|
}, {
|
||||||
|
"id": 22,
|
||||||
|
"first_name": "Anni",
|
||||||
|
"last_name": "Hounsom",
|
||||||
|
"email": "ahounsoml@wikia.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Devify"
|
||||||
|
}, {
|
||||||
|
"id": 23,
|
||||||
|
"first_name": "Evelin",
|
||||||
|
"last_name": "Gaytor",
|
||||||
|
"email": "egaytorm@myspace.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Aivee"
|
||||||
|
}, {
|
||||||
|
"id": 24,
|
||||||
|
"first_name": "Lynde",
|
||||||
|
"last_name": "Itscowicz",
|
||||||
|
"email": "litscowiczn@fc2.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Skipfire"
|
||||||
|
}, {
|
||||||
|
"id": 25,
|
||||||
|
"first_name": "Reta",
|
||||||
|
"last_name": "Felipe",
|
||||||
|
"email": "rfelipeo@free.fr",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Ainyx"
|
||||||
|
}, {
|
||||||
|
"id": 26,
|
||||||
|
"first_name": "Bar",
|
||||||
|
"last_name": "Shillingford",
|
||||||
|
"email": "bshillingfordp@sun.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Skilith"
|
||||||
|
}, {
|
||||||
|
"id": 27,
|
||||||
|
"first_name": "Mel",
|
||||||
|
"last_name": "Cooch",
|
||||||
|
"email": "mcoochq@icq.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Meevee"
|
||||||
|
}, {
|
||||||
|
"id": 28,
|
||||||
|
"first_name": "Wheeler",
|
||||||
|
"last_name": "Kettlesting",
|
||||||
|
"email": "wkettlestingr@miitbeian.gov.cn",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Mybuzz"
|
||||||
|
}, {
|
||||||
|
"id": 29,
|
||||||
|
"first_name": "Corabel",
|
||||||
|
"last_name": "Pordall",
|
||||||
|
"email": "cpordalls@sourceforge.net",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Blogtag"
|
||||||
|
}, {
|
||||||
|
"id": 30,
|
||||||
|
"first_name": "Merrily",
|
||||||
|
"last_name": "Weatherhill",
|
||||||
|
"email": "mweatherhillt@printfriendly.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Divape"
|
||||||
|
}, {
|
||||||
|
"id": 31,
|
||||||
|
"first_name": "Reynard",
|
||||||
|
"last_name": "Osgodby",
|
||||||
|
"email": "rosgodbyu@eepurl.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Yakijo"
|
||||||
|
}, {
|
||||||
|
"id": 32,
|
||||||
|
"first_name": "Guilbert",
|
||||||
|
"last_name": "Bilston",
|
||||||
|
"email": "gbilstonv@devhub.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Vinder"
|
||||||
|
}, {
|
||||||
|
"id": 33,
|
||||||
|
"first_name": "Farr",
|
||||||
|
"last_name": "Skehan",
|
||||||
|
"email": "fskehanw@t-online.de",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Linkbuzz"
|
||||||
|
}, {
|
||||||
|
"id": 34,
|
||||||
|
"first_name": "Roger",
|
||||||
|
"last_name": "Langelay",
|
||||||
|
"email": "rlangelayx@pcworld.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Tekfly"
|
||||||
|
}, {
|
||||||
|
"id": 35,
|
||||||
|
"first_name": "Jemmy",
|
||||||
|
"last_name": "Yggo",
|
||||||
|
"email": "jyggoy@ifeng.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Jabberstorm"
|
||||||
|
}, {
|
||||||
|
"id": 36,
|
||||||
|
"first_name": "Cybill",
|
||||||
|
"last_name": "Chastaing",
|
||||||
|
"email": "cchastaingz@mayoclinic.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Riffpedia"
|
||||||
|
}, {
|
||||||
|
"id": 37,
|
||||||
|
"first_name": "Samuele",
|
||||||
|
"last_name": "Zorzoni",
|
||||||
|
"email": "szorzoni10@opensource.org",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Devcast"
|
||||||
|
}, {
|
||||||
|
"id": 38,
|
||||||
|
"first_name": "Svend",
|
||||||
|
"last_name": "Hamill",
|
||||||
|
"email": "shamill11@google.co.jp",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Kwilith"
|
||||||
|
}, {
|
||||||
|
"id": 39,
|
||||||
|
"first_name": "Carlin",
|
||||||
|
"last_name": "Roote",
|
||||||
|
"email": "croote12@gov.uk",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Twitterlist"
|
||||||
|
}, {
|
||||||
|
"id": 40,
|
||||||
|
"first_name": "Dawna",
|
||||||
|
"last_name": "Lanfer",
|
||||||
|
"email": "dlanfer13@mlb.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Jayo"
|
||||||
|
}, {
|
||||||
|
"id": 41,
|
||||||
|
"first_name": "Melissa",
|
||||||
|
"last_name": "Chappelow",
|
||||||
|
"email": "mchappelow14@usa.gov",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Skibox"
|
||||||
|
}, {
|
||||||
|
"id": 42,
|
||||||
|
"first_name": "George",
|
||||||
|
"last_name": "Hargreaves",
|
||||||
|
"email": "ghargreaves15@pagesperso-orange.fr",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Zazio"
|
||||||
|
}, {
|
||||||
|
"id": 43,
|
||||||
|
"first_name": "Sampson",
|
||||||
|
"last_name": "Steaning",
|
||||||
|
"email": "ssteaning16@state.gov",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Jaxworks"
|
||||||
|
}, {
|
||||||
|
"id": 44,
|
||||||
|
"first_name": "Brana",
|
||||||
|
"last_name": "Wims",
|
||||||
|
"email": "bwims17@icio.us",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Flashset"
|
||||||
|
}, {
|
||||||
|
"id": 45,
|
||||||
|
"first_name": "Shawn",
|
||||||
|
"last_name": "Saffen",
|
||||||
|
"email": "ssaffen18@shutterfly.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Twitterwire"
|
||||||
|
}, {
|
||||||
|
"id": 46,
|
||||||
|
"first_name": "Alessandro",
|
||||||
|
"last_name": "Gasker",
|
||||||
|
"email": "agasker19@slashdot.org",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Dabtype"
|
||||||
|
}, {
|
||||||
|
"id": 47,
|
||||||
|
"first_name": "Bobby",
|
||||||
|
"last_name": "Mulcock",
|
||||||
|
"email": "bmulcock1a@time.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Quamba"
|
||||||
|
}, {
|
||||||
|
"id": 48,
|
||||||
|
"first_name": "Ashlen",
|
||||||
|
"last_name": "Midner",
|
||||||
|
"email": "amidner1b@devhub.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Thoughtstorm"
|
||||||
|
}, {
|
||||||
|
"id": 49,
|
||||||
|
"first_name": "Mallory",
|
||||||
|
"last_name": "Joel",
|
||||||
|
"email": "mjoel1c@upenn.edu",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Twitterbeat"
|
||||||
|
}, {
|
||||||
|
"id": 50,
|
||||||
|
"first_name": "Maximilian",
|
||||||
|
"last_name": "Scraggs",
|
||||||
|
"email": "mscraggs1d@ucla.edu",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Twiyo"
|
||||||
|
}, {
|
||||||
|
"id": 51,
|
||||||
|
"first_name": "Beverlie",
|
||||||
|
"last_name": "Pittet",
|
||||||
|
"email": "bpittet1e@github.io",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Riffpath"
|
||||||
|
}, {
|
||||||
|
"id": 52,
|
||||||
|
"first_name": "Enrique",
|
||||||
|
"last_name": "Rentilll",
|
||||||
|
"email": "erentilll1f@smugmug.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Blognation"
|
||||||
|
}, {
|
||||||
|
"id": 53,
|
||||||
|
"first_name": "Cathrin",
|
||||||
|
"last_name": "McKendry",
|
||||||
|
"email": "cmckendry1g@hc360.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Shuffledrive"
|
||||||
|
}, {
|
||||||
|
"id": 54,
|
||||||
|
"first_name": "Isabeau",
|
||||||
|
"last_name": "Quincey",
|
||||||
|
"email": "iquincey1h@msn.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Tagcat"
|
||||||
|
}, {
|
||||||
|
"id": 55,
|
||||||
|
"first_name": "Geoffrey",
|
||||||
|
"last_name": "Grzegorczyk",
|
||||||
|
"email": "ggrzegorczyk1i@loc.gov",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Youfeed"
|
||||||
|
}, {
|
||||||
|
"id": 56,
|
||||||
|
"first_name": "Ruggiero",
|
||||||
|
"last_name": "Vaar",
|
||||||
|
"email": "rvaar1j@unesco.org",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Babbleset"
|
||||||
|
}, {
|
||||||
|
"id": 57,
|
||||||
|
"first_name": "Alfonso",
|
||||||
|
"last_name": "Tarzey",
|
||||||
|
"email": "atarzey1k@weebly.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Pixonyx"
|
||||||
|
}, {
|
||||||
|
"id": 58,
|
||||||
|
"first_name": "Marylin",
|
||||||
|
"last_name": "Bissex",
|
||||||
|
"email": "mbissex1l@microsoft.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Tagfeed"
|
||||||
|
}, {
|
||||||
|
"id": 59,
|
||||||
|
"first_name": "Cathryn",
|
||||||
|
"last_name": "Morhall",
|
||||||
|
"email": "cmorhall1m@irs.gov",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Tagopia"
|
||||||
|
}, {
|
||||||
|
"id": 60,
|
||||||
|
"first_name": "Terza",
|
||||||
|
"last_name": "Easey",
|
||||||
|
"email": "teasey1n@thetimes.co.uk",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Devcast"
|
||||||
|
}, {
|
||||||
|
"id": 61,
|
||||||
|
"first_name": "Hale",
|
||||||
|
"last_name": "Gaudon",
|
||||||
|
"email": "hgaudon1o@webnode.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Quinu"
|
||||||
|
}, {
|
||||||
|
"id": 62,
|
||||||
|
"first_name": "Hadley",
|
||||||
|
"last_name": "Elwood",
|
||||||
|
"email": "helwood1p@japanpost.jp",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Plajo"
|
||||||
|
}, {
|
||||||
|
"id": 63,
|
||||||
|
"first_name": "Seamus",
|
||||||
|
"last_name": "Straker",
|
||||||
|
"email": "sstraker1q@live.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Yoveo"
|
||||||
|
}, {
|
||||||
|
"id": 64,
|
||||||
|
"first_name": "Urbano",
|
||||||
|
"last_name": "Gisbey",
|
||||||
|
"email": "ugisbey1r@sitemeter.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Quinu"
|
||||||
|
}, {
|
||||||
|
"id": 65,
|
||||||
|
"first_name": "Gerri",
|
||||||
|
"last_name": "McInulty",
|
||||||
|
"email": "gmcinulty1s@businessinsider.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Agimba"
|
||||||
|
}, {
|
||||||
|
"id": 66,
|
||||||
|
"first_name": "Lena",
|
||||||
|
"last_name": "Gonthier",
|
||||||
|
"email": "lgonthier1t@newsvine.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Geba"
|
||||||
|
}, {
|
||||||
|
"id": 67,
|
||||||
|
"first_name": "Ameline",
|
||||||
|
"last_name": "Wheatcroft",
|
||||||
|
"email": "awheatcroft1u@163.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Twitternation"
|
||||||
|
}, {
|
||||||
|
"id": 68,
|
||||||
|
"first_name": "Kathryn",
|
||||||
|
"last_name": "Castelli",
|
||||||
|
"email": "kcastelli1v@about.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Photospace"
|
||||||
|
}, {
|
||||||
|
"id": 69,
|
||||||
|
"first_name": "Terrell",
|
||||||
|
"last_name": "Walicki",
|
||||||
|
"email": "twalicki1w@amazon.co.jp",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Babblestorm"
|
||||||
|
}, {
|
||||||
|
"id": 70,
|
||||||
|
"first_name": "Claudianus",
|
||||||
|
"last_name": "Tremathack",
|
||||||
|
"email": "ctremathack1x@walmart.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Skyndu"
|
||||||
|
}, {
|
||||||
|
"id": 71,
|
||||||
|
"first_name": "Sanford",
|
||||||
|
"last_name": "Devinn",
|
||||||
|
"email": "sdevinn1y@ehow.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Dynazzy"
|
||||||
|
}, {
|
||||||
|
"id": 72,
|
||||||
|
"first_name": "Gwendolen",
|
||||||
|
"last_name": "Turfrey",
|
||||||
|
"email": "gturfrey1z@va.gov",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Yacero"
|
||||||
|
}, {
|
||||||
|
"id": 73,
|
||||||
|
"first_name": "Alta",
|
||||||
|
"last_name": "Leap",
|
||||||
|
"email": "aleap20@ezinearticles.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Twitterlist"
|
||||||
|
}, {
|
||||||
|
"id": 74,
|
||||||
|
"first_name": "Johnath",
|
||||||
|
"last_name": "Andrzejowski",
|
||||||
|
"email": "jandrzejowski21@google.com.hk",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Lazzy"
|
||||||
|
}, {
|
||||||
|
"id": 75,
|
||||||
|
"first_name": "Yancy",
|
||||||
|
"last_name": "Askham",
|
||||||
|
"email": "yaskham22@sciencedaily.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Yabox"
|
||||||
|
}, {
|
||||||
|
"id": 76,
|
||||||
|
"first_name": "Paula",
|
||||||
|
"last_name": "Warder",
|
||||||
|
"email": "pwarder23@harvard.edu",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Zooxo"
|
||||||
|
}, {
|
||||||
|
"id": 77,
|
||||||
|
"first_name": "Grannie",
|
||||||
|
"last_name": "Hauxley",
|
||||||
|
"email": "ghauxley24@symantec.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Yakidoo"
|
||||||
|
}, {
|
||||||
|
"id": 78,
|
||||||
|
"first_name": "Enid",
|
||||||
|
"last_name": "Grealy",
|
||||||
|
"email": "egrealy25@homestead.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Gabcube"
|
||||||
|
}, {
|
||||||
|
"id": 79,
|
||||||
|
"first_name": "Lazarus",
|
||||||
|
"last_name": "Itscowicz",
|
||||||
|
"email": "litscowicz26@epa.gov",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Demizz"
|
||||||
|
}, {
|
||||||
|
"id": 80,
|
||||||
|
"first_name": "Marmaduke",
|
||||||
|
"last_name": "Gilligan",
|
||||||
|
"email": "mgilligan27@tiny.cc",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Yombu"
|
||||||
|
}, {
|
||||||
|
"id": 81,
|
||||||
|
"first_name": "Linnell",
|
||||||
|
"last_name": "Chree",
|
||||||
|
"email": "lchree28@ocn.ne.jp",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Buzzshare"
|
||||||
|
}, {
|
||||||
|
"id": 82,
|
||||||
|
"first_name": "Pavia",
|
||||||
|
"last_name": "Pocke",
|
||||||
|
"email": "ppocke29@newsvine.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Eidel"
|
||||||
|
}, {
|
||||||
|
"id": 83,
|
||||||
|
"first_name": "Golda",
|
||||||
|
"last_name": "Stuchburie",
|
||||||
|
"email": "gstuchburie2a@oaic.gov.au",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Flipstorm"
|
||||||
|
}, {
|
||||||
|
"id": 84,
|
||||||
|
"first_name": "Trace",
|
||||||
|
"last_name": "Lodge",
|
||||||
|
"email": "tlodge2b@whitehouse.gov",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Zazio"
|
||||||
|
}, {
|
||||||
|
"id": 85,
|
||||||
|
"first_name": "Nikolia",
|
||||||
|
"last_name": "Bartolomivis",
|
||||||
|
"email": "nbartolomivis2c@opensource.org",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Devshare"
|
||||||
|
}, {
|
||||||
|
"id": 86,
|
||||||
|
"first_name": "Dela",
|
||||||
|
"last_name": "Wimp",
|
||||||
|
"email": "dwimp2d@miitbeian.gov.cn",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Wordware"
|
||||||
|
}, {
|
||||||
|
"id": 87,
|
||||||
|
"first_name": "Rustie",
|
||||||
|
"last_name": "Drury",
|
||||||
|
"email": "rdrury2e@sun.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Youbridge"
|
||||||
|
}, {
|
||||||
|
"id": 88,
|
||||||
|
"first_name": "Phedra",
|
||||||
|
"last_name": "Shrimptone",
|
||||||
|
"email": "pshrimptone2f@unicef.org",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Realcube"
|
||||||
|
}, {
|
||||||
|
"id": 89,
|
||||||
|
"first_name": "Alaster",
|
||||||
|
"last_name": "Vittori",
|
||||||
|
"email": "avittori2g@senate.gov",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Livepath"
|
||||||
|
}, {
|
||||||
|
"id": 90,
|
||||||
|
"first_name": "Pascal",
|
||||||
|
"last_name": "Neissen",
|
||||||
|
"email": "pneissen2h@mediafire.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Mydo"
|
||||||
|
}, {
|
||||||
|
"id": 91,
|
||||||
|
"first_name": "Brian",
|
||||||
|
"last_name": "Manuel",
|
||||||
|
"email": "bmanuel2i@blog.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Roomm"
|
||||||
|
}, {
|
||||||
|
"id": 92,
|
||||||
|
"first_name": "Jen",
|
||||||
|
"last_name": "Laydon",
|
||||||
|
"email": "jlaydon2j@hubpages.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Plambee"
|
||||||
|
}, {
|
||||||
|
"id": 93,
|
||||||
|
"first_name": "Beltran",
|
||||||
|
"last_name": "Brandoni",
|
||||||
|
"email": "bbrandoni2k@digg.com",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Yacero"
|
||||||
|
}, {
|
||||||
|
"id": 94,
|
||||||
|
"first_name": "Sarene",
|
||||||
|
"last_name": "Gaymar",
|
||||||
|
"email": "sgaymar2l@surveymonkey.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Katz"
|
||||||
|
}, {
|
||||||
|
"id": 95,
|
||||||
|
"first_name": "Iormina",
|
||||||
|
"last_name": "Peedell",
|
||||||
|
"email": "ipeedell2m@seattletimes.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Youfeed"
|
||||||
|
}, {
|
||||||
|
"id": 96,
|
||||||
|
"first_name": "Abigail",
|
||||||
|
"last_name": "Kielty",
|
||||||
|
"email": "akielty2n@npr.org",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Reallinks"
|
||||||
|
}, {
|
||||||
|
"id": 97,
|
||||||
|
"first_name": "Hallie",
|
||||||
|
"last_name": "Toomey",
|
||||||
|
"email": "htoomey2o@google.com.au",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Flipbug"
|
||||||
|
}, {
|
||||||
|
"id": 98,
|
||||||
|
"first_name": "Sergeant",
|
||||||
|
"last_name": "Pourveer",
|
||||||
|
"email": "spourveer2p@amazon.co.uk",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Skinix"
|
||||||
|
}, {
|
||||||
|
"id": 99,
|
||||||
|
"first_name": "Elfie",
|
||||||
|
"last_name": "McKinlay",
|
||||||
|
"email": "emckinlay2q@xrea.com",
|
||||||
|
"gender": "Female",
|
||||||
|
"company": "Devcast"
|
||||||
|
}, {
|
||||||
|
"id": 100,
|
||||||
|
"first_name": "Wainwright",
|
||||||
|
"last_name": "Juggins",
|
||||||
|
"email": "wjuggins2r@tamu.edu",
|
||||||
|
"gender": "Male",
|
||||||
|
"company": "Topiclounge"
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const contacts = contactsData.map(d => new Person(d.id, d.first_name, d.last_name, d.email, d.gender, d.company));
|
||||||
|
return contacts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static loadCompanies() {
|
||||||
|
const companies = [{
|
||||||
|
"id": 101,
|
||||||
|
"city": "Lakshmīpur",
|
||||||
|
"street": "36300 Lake View Center",
|
||||||
|
"email": "ogovier0@gmpg.org",
|
||||||
|
"company": "Fiveclub"
|
||||||
|
}, {
|
||||||
|
"id": 102,
|
||||||
|
"city": "El Quetzal",
|
||||||
|
"street": "551 New Castle Parkway",
|
||||||
|
"email": "elander1@g.co",
|
||||||
|
"company": "Twitterwire"
|
||||||
|
}, {
|
||||||
|
"id": 103,
|
||||||
|
"city": "Mayakovski",
|
||||||
|
"street": "1 Norway Maple Center",
|
||||||
|
"email": "dcustance2@hostgator.com",
|
||||||
|
"company": "Jabbersphere"
|
||||||
|
}, {
|
||||||
|
"id": 104,
|
||||||
|
"city": "Al Jawādīyah",
|
||||||
|
"street": "02 Carey Hill",
|
||||||
|
"email": "evanoort3@sciencedaily.com",
|
||||||
|
"company": "Zoovu"
|
||||||
|
}, {
|
||||||
|
"id": 105,
|
||||||
|
"city": "Girona",
|
||||||
|
"street": "3 Lillian Center",
|
||||||
|
"email": "dducker4@cbsnews.com",
|
||||||
|
"company": "Innojam"
|
||||||
|
}, {
|
||||||
|
"id": 106,
|
||||||
|
"city": "Vouani",
|
||||||
|
"street": "5165 Vera Avenue",
|
||||||
|
"email": "orzehorz5@arizona.edu",
|
||||||
|
"company": "Zoovu"
|
||||||
|
}, {
|
||||||
|
"id": 107,
|
||||||
|
"city": "Caibarién",
|
||||||
|
"street": "3739 Burrows Drive",
|
||||||
|
"email": "ltrahair6@pinterest.com",
|
||||||
|
"company": "Quamba"
|
||||||
|
}, {
|
||||||
|
"id": 108,
|
||||||
|
"city": "Wushi",
|
||||||
|
"street": "88 Bay Hill",
|
||||||
|
"email": "plebourn7@springer.com",
|
||||||
|
"company": "Feednation"
|
||||||
|
}, {
|
||||||
|
"id": 109,
|
||||||
|
"city": "Zbýšov",
|
||||||
|
"street": "38 Dovetail Place",
|
||||||
|
"email": "slace8@netscape.com",
|
||||||
|
"company": "Zoomzone"
|
||||||
|
}, {
|
||||||
|
"id": 110,
|
||||||
|
"city": "Nová Cerekev",
|
||||||
|
"street": "90194 Dixon Avenue",
|
||||||
|
"email": "mdoxey9@goo.gl",
|
||||||
|
"company": "Devpoint"
|
||||||
|
}];
|
||||||
|
|
||||||
|
return companies.map(c => new Company(c.id, c.company, c.street, c.email));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static loadContacts() {
|
||||||
|
const result = new Array<Person | Company>();
|
||||||
|
result.push(...this.loadPersons());
|
||||||
|
result.push(...this.loadCompanies());
|
||||||
|
let idx = 0;
|
||||||
|
while (idx++ < 1000) {
|
||||||
|
const i = Math.round(Math.random() * (result.length - 1));
|
||||||
|
const j = Math.round(Math.random() * (result.length - 1));
|
||||||
|
const temp = result[i];
|
||||||
|
result[i] = result[j];
|
||||||
|
result[j] = temp;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const contacts = AddressBook.loadContacts();
|
||||||
|
|
||||||
|
debugger;
|
||||||
@@ -10,49 +10,70 @@ setTimeout(() => {
|
|||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
class Main {
|
class Main {
|
||||||
|
/** @pure */
|
||||||
run() {
|
run() {
|
||||||
const list = new DoublyLinkedList("1");
|
id = 0;
|
||||||
list.setNext(new DoublyLinkedList("2"));
|
const head = new DoublyLinkedListNode("1");
|
||||||
list.next!.setNext(new DoublyLinkedList("3"));
|
head.setNext(new DoublyLinkedListNode("2"));
|
||||||
list.next!.next!.setNext(new DoublyLinkedList("4"));
|
head.next!.setNext(new DoublyLinkedListNode("3"));
|
||||||
|
const tail = new DoublyLinkedListNode("4");
|
||||||
// Use `visualize()` as expression to visualize in the Debug Visualizer!
|
head.next!.next!.setNext(tail);
|
||||||
const visualize = () =>
|
reverse(new DoublyLinkedList(head, tail));
|
||||||
createGraphFromPointers({ list, last, cur }, i => ({
|
|
||||||
id: i.id,
|
|
||||||
label: i.name,
|
|
||||||
color: finished.has(i) ? "lime" : undefined,
|
|
||||||
edges: [
|
|
||||||
{ to: i.next!, label: "next" },
|
|
||||||
{ to: i.prev!, label: "prev", color: "lightgray" },
|
|
||||||
].filter(r => !!r.to),
|
|
||||||
}));
|
|
||||||
|
|
||||||
const finished = new Set();
|
|
||||||
var cur: DoublyLinkedList | undefined = list;
|
|
||||||
// Reverses `list`. Finished nodes have correct pointers,
|
|
||||||
// their next node is also finished.
|
|
||||||
var last: DoublyLinkedList | undefined = undefined;
|
|
||||||
while (cur) {
|
|
||||||
cur.prev = cur.next;
|
|
||||||
cur.next = last;
|
|
||||||
finished.add(cur);
|
|
||||||
last = cur;
|
|
||||||
cur = cur.prev;
|
|
||||||
}
|
|
||||||
console.log("finished");
|
console.log("finished");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let id = 0;
|
function reverse(list: DoublyLinkedList) {
|
||||||
|
// Open a new Debug Visualizer
|
||||||
|
// and enter `visualize()`!
|
||||||
|
const visualize = () =>
|
||||||
|
createGraphFromPointers(
|
||||||
|
{
|
||||||
|
last,
|
||||||
|
"list.head": list.head,
|
||||||
|
"list.tail": list.tail
|
||||||
|
},
|
||||||
|
i => ({
|
||||||
|
id: i.id,
|
||||||
|
label: i.name,
|
||||||
|
color: finished.has(i) ? "lime" : "lightblue",
|
||||||
|
edges: [
|
||||||
|
{ to: i.next!, label: "next", color: "lightblue", },
|
||||||
|
{ to: i.prev!, label: "prev", color: "lightgray" },
|
||||||
|
].filter(r => !!r.to),
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Finished nodes have correct pointers,
|
||||||
|
// their next node is also finished.
|
||||||
|
const finished = new Set();
|
||||||
|
var last: DoublyLinkedListNode | null = null;
|
||||||
|
list.tail = list.head;
|
||||||
|
while (list.head) {
|
||||||
|
list.head.prev = list.head.next;
|
||||||
|
list.head.next = last;
|
||||||
|
finished.add(list.head);
|
||||||
|
last = list.head;
|
||||||
|
list.head = list.head.prev;
|
||||||
|
}
|
||||||
|
list.head = last;
|
||||||
|
}
|
||||||
|
|
||||||
class DoublyLinkedList {
|
class DoublyLinkedList {
|
||||||
|
constructor(
|
||||||
|
public head: DoublyLinkedListNode | null,
|
||||||
|
public tail: DoublyLinkedListNode | null
|
||||||
|
) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = 0;
|
||||||
|
class DoublyLinkedListNode {
|
||||||
public readonly id = (id++).toString();
|
public readonly id = (id++).toString();
|
||||||
constructor(public name: string) {}
|
constructor(public name: string) { }
|
||||||
|
|
||||||
next: DoublyLinkedList | undefined;
|
next: DoublyLinkedListNode | null = null;
|
||||||
prev: DoublyLinkedList | undefined;
|
prev: DoublyLinkedListNode | null = null;
|
||||||
|
|
||||||
public setNext(val: DoublyLinkedList): void {
|
public setNext(val: DoublyLinkedListNode): void {
|
||||||
val.prev = this;
|
val.prev = this;
|
||||||
this.next = val;
|
this.next = val;
|
||||||
}
|
}
|
||||||
|
|||||||
7
demos/js/src/demo_fetch.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
const fetch = require("node-fetch");
|
||||||
|
|
||||||
|
fetch("https://jsonplaceholder.typicode.com/users")
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((json) => {
|
||||||
|
debugger;
|
||||||
|
});
|
||||||
@@ -1,12 +1,20 @@
|
|||||||
// visualize `data`
|
// visualize `data`
|
||||||
const data = new Array<number>();
|
const data = new Array<number>();
|
||||||
let value = 0;
|
let curValue = 0;
|
||||||
for (let i = 0; i < 100000; i++) {
|
|
||||||
const delta = Math.random() > 0.5 ? 1 : -1;
|
|
||||||
data.push(value);
|
|
||||||
value += delta;
|
|
||||||
|
|
||||||
if (i % 1000 === 0) {
|
for (let j = 0; j < 100; j++) {
|
||||||
debugger;
|
addManyRandomValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
function addManyRandomValues() {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
addRandomValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addRandomValue() {
|
||||||
|
const delta = Math.random()
|
||||||
|
> 0.5 ? 1 : -1;
|
||||||
|
data.push(curValue);
|
||||||
|
curValue += delta;
|
||||||
|
}
|
||||||
@@ -13,9 +13,13 @@ hedietDbgVis.markedGrid(
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// From https://github.com/AvraamMavridis/Algorithms-Data-Structures-in-Typescript/blob/master/algorithms/quickSort.md
|
// From https://github.com/AvraamMavridis/Algorithms-Data-Structures-in-Typescript/blob/master/algorithms/quickSort.md
|
||||||
const array = [1, 2, 33, 31, 1, 2, 63, 123, 6, 32, 943, 346, 24];
|
/** @pure */
|
||||||
const sorted = quickSort(array, 0, array.length - 1);
|
function main() {
|
||||||
console.log(sorted);
|
const array = [1, 2, 33, 31, 1, 2, 63, 123, 6, 32, 943, 346, 24];
|
||||||
|
const sorted = quickSort(array, 0, array.length - 1);
|
||||||
|
console.log(sorted);
|
||||||
|
}
|
||||||
|
main();
|
||||||
|
|
||||||
function swap(array: Array<number>, i: number, j: number) {
|
function swap(array: Array<number>, i: number, j: number) {
|
||||||
[array[i], array[j]] = [array[j], array[i]];
|
[array[i], array[j]] = [array[j], array[i]];
|
||||||
|
|||||||
@@ -11,13 +11,14 @@ setTimeout(() => {
|
|||||||
|
|
||||||
class Main {
|
class Main {
|
||||||
run() {
|
run() {
|
||||||
const files = new Map<string, string>([
|
/*const files = new Map<string, string>([
|
||||||
[
|
[
|
||||||
"main.ts",
|
"main.ts",
|
||||||
`
|
`
|
||||||
class Test1 {
|
class Test1 {
|
||||||
public foo(a: number) {
|
public foo(a: number) {
|
||||||
const x = { a: 5 };
|
const x = { a: 5 };
|
||||||
|
const y = { a: 5 };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
@@ -34,7 +35,7 @@ class Test1 {
|
|||||||
const c = prog.getTypeChecker();
|
const c = prog.getTypeChecker();
|
||||||
let myValue = undefined; // Visualize `myValue` here!
|
let myValue = undefined; // Visualize `myValue` here!
|
||||||
const sourceFileAst = prog.getSourceFiles()[0];
|
const sourceFileAst = prog.getSourceFiles()[0];
|
||||||
myValue = sourceFileAst.getText();
|
myValue = sourceFileAst;
|
||||||
console.log("myValue is the source code of the AST");
|
console.log("myValue is the source code of the AST");
|
||||||
debugger;
|
debugger;
|
||||||
|
|
||||||
@@ -64,7 +65,24 @@ class Test1 {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
console.log("myValue is AST, annotated with symbol information");
|
console.log("myValue is AST, annotated with symbol information");
|
||||||
debugger;
|
debugger;*/
|
||||||
|
require;
|
||||||
|
|
||||||
|
const sf = ts.createSourceFile("main.ts",
|
||||||
|
`
|
||||||
|
class Test1 {
|
||||||
|
public foo(a: number) {
|
||||||
|
const x = { a: 5 };
|
||||||
|
const y = { a: 24 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`, ts.ScriptTarget.ESNext, true);
|
||||||
|
const traverse = (node: ts.Node) => {
|
||||||
|
ts.forEachChild(node, child => {
|
||||||
|
traverse(child);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
traverse(sf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -271,6 +271,11 @@ fsevents@^2.0.6:
|
|||||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.0.7.tgz#382c9b443c6cbac4c57187cdda23aa3bf1ccfc2a"
|
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.0.7.tgz#382c9b443c6cbac4c57187cdda23aa3bf1ccfc2a"
|
||||||
integrity sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ==
|
integrity sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ==
|
||||||
|
|
||||||
|
function-bind@^1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
|
||||||
|
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
|
||||||
|
|
||||||
get-func-name@^2.0.0:
|
get-func-name@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
|
resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
|
||||||
@@ -296,6 +301,13 @@ has-flag@^3.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
|
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
|
||||||
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
|
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
|
||||||
|
|
||||||
|
has@^1.0.3:
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
|
||||||
|
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
|
||||||
|
dependencies:
|
||||||
|
function-bind "^1.1.1"
|
||||||
|
|
||||||
io-ts@^1.8.6:
|
io-ts@^1.8.6:
|
||||||
version "1.10.4"
|
version "1.10.4"
|
||||||
resolved "https://registry.yarnpkg.com/io-ts/-/io-ts-1.10.4.tgz#cd5401b138de88e4f920adbcb7026e2d1967e6e2"
|
resolved "https://registry.yarnpkg.com/io-ts/-/io-ts-1.10.4.tgz#cd5401b138de88e4f920adbcb7026e2d1967e6e2"
|
||||||
@@ -310,6 +322,13 @@ is-binary-path@^2.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
binary-extensions "^2.0.0"
|
binary-extensions "^2.0.0"
|
||||||
|
|
||||||
|
is-core-module@^2.2.0:
|
||||||
|
version "2.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.4.0.tgz#8e9fc8e15027b011418026e98f0e6f4d86305cc1"
|
||||||
|
integrity sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==
|
||||||
|
dependencies:
|
||||||
|
has "^1.0.3"
|
||||||
|
|
||||||
is-extglob@^2.1.1:
|
is-extglob@^2.1.1:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
|
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
|
||||||
@@ -368,11 +387,21 @@ nise@^1.4.10:
|
|||||||
lolex "^4.1.0"
|
lolex "^4.1.0"
|
||||||
path-to-regexp "^1.7.0"
|
path-to-regexp "^1.7.0"
|
||||||
|
|
||||||
|
node-fetch@^2.6.1:
|
||||||
|
version "2.6.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
||||||
|
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||||
|
|
||||||
normalize-path@^3.0.0:
|
normalize-path@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
|
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
|
||||||
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
|
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
|
||||||
|
|
||||||
|
path-parse@^1.0.6:
|
||||||
|
version "1.0.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
|
||||||
|
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
|
||||||
|
|
||||||
path-to-regexp@^1.7.0:
|
path-to-regexp@^1.7.0:
|
||||||
version "1.7.0"
|
version "1.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d"
|
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d"
|
||||||
@@ -402,6 +431,14 @@ readdirp@^3.1.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
picomatch "^2.0.4"
|
picomatch "^2.0.4"
|
||||||
|
|
||||||
|
resolve@>=1.9.0:
|
||||||
|
version "1.20.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
|
||||||
|
integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
|
||||||
|
dependencies:
|
||||||
|
is-core-module "^2.2.0"
|
||||||
|
path-parse "^1.0.6"
|
||||||
|
|
||||||
sinon@^7.2.7:
|
sinon@^7.2.7:
|
||||||
version "7.3.2"
|
version "7.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/sinon/-/sinon-7.3.2.tgz#82dba3a6d85f6d2181e1eca2c10d8657c2161f28"
|
resolved "https://registry.yarnpkg.com/sinon/-/sinon-7.3.2.tgz#82dba3a6d85f6d2181e1eca2c10d8657c2161f28"
|
||||||
@@ -447,15 +484,22 @@ to-regex-range@^5.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
is-number "^7.0.0"
|
is-number "^7.0.0"
|
||||||
|
|
||||||
|
ttypescript@^1.5.12:
|
||||||
|
version "1.5.12"
|
||||||
|
resolved "https://registry.yarnpkg.com/ttypescript/-/ttypescript-1.5.12.tgz#27a8356d7d4e719d0075a8feb4df14b52384f044"
|
||||||
|
integrity sha512-1ojRyJvpnmgN9kIHmUnQPlEV1gq+VVsxVYjk/NfvMlHSmYxjK5hEvOOU2MQASrbekTUiUM7pR/nXeCc8bzvMOQ==
|
||||||
|
dependencies:
|
||||||
|
resolve ">=1.9.0"
|
||||||
|
|
||||||
type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.5:
|
type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.5:
|
||||||
version "4.0.8"
|
version "4.0.8"
|
||||||
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
|
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
|
||||||
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
|
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
|
||||||
|
|
||||||
typescript@^3.8.2:
|
typescript@^3.9.0:
|
||||||
version "3.9.7"
|
version "3.9.9"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.9.tgz#e69905c54bc0681d0518bd4d587cc6f2d0b1a674"
|
||||||
integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
|
integrity sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==
|
||||||
|
|
||||||
ws@^7.0.0:
|
ws@^7.0.0:
|
||||||
version "7.1.1"
|
version "7.1.1"
|
||||||
|
|||||||
39
demos/python/insertion_sort.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
"""Python demo for sorting using VS Code Debug Visualizer."""
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
def serialize(arr):
|
||||||
|
"""Serialize an array into a format the visualizer can understand."""
|
||||||
|
formatted = {
|
||||||
|
"kind": {"grid": True},
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"columns": [
|
||||||
|
{"content": str(value), "tag": str(value)} for value in arr
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
return json.dumps(formatted)
|
||||||
|
|
||||||
|
|
||||||
|
arr = [6, 9, 3, 12, 1, 11, 5, 13, 8, 14, 2, 4, 10, 0, 7]
|
||||||
|
|
||||||
|
# Put serialized into the Debug Visualizer console
|
||||||
|
serialized = serialize(arr)
|
||||||
|
|
||||||
|
# Set a breakpoint on the line below and go through the code in debug mode to
|
||||||
|
# watch it update
|
||||||
|
for target_idx in range(1, len(arr)):
|
||||||
|
target_value = arr[target_idx]
|
||||||
|
compare_idx = target_idx - 1
|
||||||
|
|
||||||
|
while compare_idx >= 0 and arr[compare_idx] > target_value:
|
||||||
|
arr[compare_idx + 1] = arr[compare_idx]
|
||||||
|
serialized = serialize(arr)
|
||||||
|
compare_idx -= 1
|
||||||
|
|
||||||
|
arr[compare_idx + 1] = target_value
|
||||||
|
serialized = serialize(arr)
|
||||||
|
|
||||||
|
assert arr == sorted(arr)
|
||||||
14
demos/rust/.vscode/launch.json
vendored
@@ -7,8 +7,18 @@
|
|||||||
{
|
{
|
||||||
"type": "lldb",
|
"type": "lldb",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "Debug",
|
"name": "run rust demo",
|
||||||
"program": "${workspaceFolder}/target/debug/rust_demo",
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"--bin=rust_demo",
|
||||||
|
"--package=rust_demo",
|
||||||
|
],
|
||||||
|
"filter": {
|
||||||
|
"name": "rust_demo",
|
||||||
|
"kind": "bin",
|
||||||
|
},
|
||||||
|
},
|
||||||
"args": [],
|
"args": [],
|
||||||
"cwd": "${workspaceFolder}"
|
"cwd": "${workspaceFolder}"
|
||||||
}
|
}
|
||||||
|
|||||||
8
demos/rust/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"debugVisualizer.debugAdapterConfigurations": {
|
||||||
|
"lldb": {
|
||||||
|
"expressionTemplate": "${expr}",
|
||||||
|
"context": "watch"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,77 +1,77 @@
|
|||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
// expected to mirror
|
||||||
struct Label {
|
// https://hediet.github.io/visualization/docs/visualization-data-schema.json
|
||||||
label: Option<String>,
|
//
|
||||||
}
|
// implements the grid visualizer as an example
|
||||||
#[derive(Debug, Serialize)]
|
|
||||||
struct Row {
|
|
||||||
label: Option<String>,
|
|
||||||
columns: Vec<Column>,
|
|
||||||
}
|
|
||||||
#[derive(Debug, Serialize)]
|
|
||||||
struct Column {
|
|
||||||
content: Option<String>,
|
|
||||||
tag: Option<String>,
|
|
||||||
color: Option<String>,
|
|
||||||
}
|
|
||||||
#[derive(Debug, Serialize)]
|
|
||||||
struct Marker {
|
|
||||||
id: String,
|
|
||||||
row: u64,
|
|
||||||
column: u64,
|
|
||||||
rows: Option<u64>,
|
|
||||||
columns: Option<u64>,
|
|
||||||
label: Option<String>,
|
|
||||||
color: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
pub type Label = String;
|
||||||
fn is_false(b: &bool) -> bool {
|
|
||||||
!*b
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
|
||||||
struct Kind {
|
|
||||||
#[serde(skip_serializing_if = "is_false")]
|
|
||||||
array: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// `GridVisualizationData` in schema
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub struct Grid {
|
pub struct Grid {
|
||||||
kind: Kind,
|
kind: Kind,
|
||||||
#[serde(rename = "columnLabels")]
|
|
||||||
column_labels: Option<Vec<Label>>,
|
|
||||||
rows: Vec<Row>,
|
rows: Vec<Row>,
|
||||||
markers: Option<Vec<Marker>>,
|
|
||||||
|
#[serde(rename = "columnLabels")]
|
||||||
|
#[serde(skip_serializing_if="Option::is_none")]
|
||||||
|
column_labels: Option<Vec<Label>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
pub struct Kind {
|
||||||
|
grid: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
pub struct Row {
|
||||||
|
columns: Vec<Column>,
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if="Option::is_none")]
|
||||||
|
label: Option<Label>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
pub struct Column {
|
||||||
|
/// value to display to the user
|
||||||
|
#[serde(skip_serializing_if="Option::is_none")]
|
||||||
|
content: Option<String>,
|
||||||
|
|
||||||
|
/// unique value to identify this cell, if desired
|
||||||
|
#[serde(skip_serializing_if="Option::is_none")]
|
||||||
|
tag: Option<String>,
|
||||||
|
|
||||||
|
// TODO: valid values / syntax?
|
||||||
|
#[serde(skip_serializing_if="Option::is_none")]
|
||||||
|
color: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_arr(a: &[i32]) -> String {
|
fn show_arr(a: &[i32]) -> String {
|
||||||
let n = a.len();
|
|
||||||
let labels: Vec<Label> = (0..n)
|
|
||||||
.map(|i| Label {
|
|
||||||
label: Some(i.to_string()),
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let columns: Vec<Column> = a
|
let columns: Vec<Column> = a
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| Column {
|
.map(|x| Column {
|
||||||
content: Some(format!("{:?}", x)),
|
content: Some(format!("{:?}", x)),
|
||||||
tag: Some(x.to_string()),
|
tag: None,
|
||||||
color: None,
|
|
||||||
|
// TODO: `color` value doesn't seem to change visualizer's output at all
|
||||||
|
color: "who-knows".to_owned().into(),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let row = Row {
|
let row = Row {
|
||||||
label: None,
|
|
||||||
columns,
|
columns,
|
||||||
|
// TODO: visualizer doesn't seem to render this
|
||||||
|
label: "my row".to_owned().into(),
|
||||||
};
|
};
|
||||||
let kind = Kind { array: true };
|
|
||||||
|
let kind = Kind { grid: true };
|
||||||
|
|
||||||
let grid = Grid {
|
let grid = Grid {
|
||||||
kind,
|
kind,
|
||||||
column_labels: Some(labels),
|
|
||||||
rows: vec![row],
|
rows: vec![row],
|
||||||
markers: None,
|
|
||||||
|
// TODO: visualizer doesn't seem to work if this is non-`None`
|
||||||
|
column_labels: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
serde_json::to_string(&grid).unwrap()
|
serde_json::to_string(&grid).unwrap()
|
||||||
@@ -81,9 +81,9 @@ fn main() {
|
|||||||
let mut arr = vec![1, 2, 3];
|
let mut arr = vec![1, 2, 3];
|
||||||
let mut _s = show_arr(&arr);
|
let mut _s = show_arr(&arr);
|
||||||
for _ in 0..5 {
|
for _ in 0..5 {
|
||||||
arr.swap(0, 2); // break point
|
arr.swap(0, 2); // set a break-point here, to easily observe the change
|
||||||
_s = show_arr(&arr);
|
_s = show_arr(&arr);
|
||||||
}
|
}
|
||||||
dbg!(arr); // break point
|
dbg!(arr);
|
||||||
println!("Hello, world!");
|
println!("break-point here, too");
|
||||||
}
|
}
|
||||||
295
docs/architecture.drawio.svg
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="241px" height="971px" viewBox="-0.5 -0.5 241 971" content="<mxfile host="localhost" modified="2020-05-18T21:20:25.100Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Code/1.45.1 Chrome/78.0.3904.130 Electron/7.2.4 Safari/537.36" etag="wIym9edGWidWU1rSQKSs" version="13.0.9"><diagram id="6hGFLwfOUW9BJ-s0fimq" name="Page-1">7Vpbd6I6FP41Pp4uCKDlcWq9HqVntBXlDUgqseGyIAr660+QoCB06prRdpw1L0o2ySbZ++PbF21IbTfphWbgjH2ISAMIMGlIjw0AZKXFPlPBNhMogpwJliGGmUg8CqZ4h7hQ4NI1higqTaS+TygOykLb9zxk05LMDEM/Lk979Un5qYG5RBXB1DZJVapjSJ1Meg9aR3kf4aWTP1lsqtkd18wn85NEjgn9uCCSOg2pHfo+za7cpI1IarvcLtm67jt3DxsLkUfPWtDMVmxMsuaH4xuj2/y0ob/2IEoXCA3pIXYwRdPAtNO7MXMvkznUJWwksstXTEjbJ37Ixp7vsUkP1T3xbW5QSFFSEPE99pDvIhpu2RR+V+Lm4nhpNvk4PlofyFzmFCwvtbjQ5B5fHlQfjcIuuF3esRG4RRsp4EwbieASNhJu0UbnwkiWL2CiKoo6CUVehH3v10yVjhDEiI6w94bgo0lNdgdth6LtvuEnPHRNPSFP+H4zAmMyFjqb2VwjtjfeTHuzteWStbFVO8ZcC2FPjUfAIUaPENhWgQ20jdF7oUZvhqFuU+iSHdS7kTkPiI1VgvoTYnlaYAF5Y0vD1QjMZMh02oBsLKwI9nYQDTxNWMyHwmAVtAautrHag+a4HWOrx547ZdcrQx21h8Ryv+MnZo0FUKPByk+YLDJ1hbBrZSyJ6gW8r5a9L4pV9x9ehqL7mxfwvlTx/jDqpCOTMgB0vCVmGP9TYCDMwEJPxMV8wmTKnH2vzG76LCNYgJfNZG44Vn/mwB6DydtsbYAUCuq/dnld13JhYLkva9gfYwaHHex1t5DBh51pZYEYP62+RQM3Seew6478Oo2xoStvJahNC1Dbaerr99S0nKAuCqcDuXwGnOT34cQo8y+OfgFHY/FDHD0PpNe5cBUUSconokipoCj1NgtLoWmntDRB0ZrQG4XTG3O/M9JZROoPnYU0KcBqwiDT7TK4bRe6Jpi6un5xZ2xtIoy8yW6AY2xLE8f2ShEpLkSkuBYi+AgRrX+NiKV8JjiqlYFYQQLy4Le0nmIjP0Be2fPsJi/dWAYtPUTUDGk+G2LT9T347GAvv5XPlXNBF5ODKsjqL/5YP6SOv/Q9k3SO0geT4CVT9UjQK7PBQ2pizAq2b1xs+ZT6bqopwXSeIvdO4aNF/gx2/ZhwUO8HWz5415GRvw5tVErv2MaXKK8+MlG6+XOc/Y9YZoJsFCLCUoRN2QV1fuV6//Mx2+VBKWiVISSfQiM7A19VrBRPFInKO+EuV5SdvKJoD7PDYc9CXquCvHaITMoq/o/xdwI6aEbOnqnEE2xeCwZSFQbymTAovtS5l34X78vSB4ou53214n2e2KT+FzpJEKIoK5qEZ/8GECFXEaF8HSIOenKWEX6WD04VXQ8RoliBBHq3dGaRlZY9m4cGm3kJhTXBwcUQ7oMIQxbemdZeVerfIN38/jjKQ0N5THWtqR9xNH1WS6JVE+Av0rOp1qSRw44C/zSb1rXClGsZtVqZ7dvfdyylobda4UuGPgSmPpNGkrZdbFVqAVaptVUt+/5Bo6dQNWmPk7pGz66QVgtP82ukzU31E9NmsZq9xMjaYBT/aa9VXRe+eaXXClRDwBTtw9GX5wA391JquNh97dTWsk+lDm3no3ZHMd9RqvmO+IUp8GmeIp/C8WcTHuV6CU9eTBbQPsPRmrHDDoV3zPoQhW2fUYR3q82ZU/CuLCDGFlCI5U12I9EIbGnmMAA2jflgDfuafEZTJnmaC9HAna2NUm+vU+jtvSjX6tvd1+QYYl2ScYkYU9P+nexBkeZuwqCaFP9lxK9kRLGmBMxf8d+BEpuXosTWaTF5QUqs9qpzStz/gsZZ8UbpEJhzTVzoSYDc7r4fzRGsH+Wz7Q9608VfSxOtX0eD47g85xqJtirXkKB0LRKsJtpXIsG/hHZCaDl5lQjtK5tainrXUsrx+P5nOa0l3IGyLlW5FK2x4fG/Xdn04x/kpM7/</diagram></mxfile>">
|
||||||
|
<defs/>
|
||||||
|
<g>
|
||||||
|
<rect x="0" y="600" width="240" height="370" fill="none" stroke="#000000" pointer-events="all"/>
|
||||||
|
<rect x="0" y="460" width="240" height="120" fill="none" stroke="#000000" pointer-events="all"/>
|
||||||
|
<rect x="0" y="0" width="240" height="440" fill="none" stroke="#000000" pointer-events="all"/>
|
||||||
|
<rect x="60" y="50" width="120" height="60" fill="#ffffff" stroke="#000000" pointer-events="all"/>
|
||||||
|
<g transform="translate(-0.5 -0.5)">
|
||||||
|
<switch>
|
||||||
|
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||||
|
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 80px; margin-left: 61px;">
|
||||||
|
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||||
|
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||||
|
Extension
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</foreignObject>
|
||||||
|
<text x="120" y="84" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||||
|
Extension
|
||||||
|
</text>
|
||||||
|
</switch>
|
||||||
|
</g>
|
||||||
|
<rect x="60" y="170" width="120" height="60" fill="#ffffff" stroke="#000000" pointer-events="all"/>
|
||||||
|
<g transform="translate(-0.5 -0.5)">
|
||||||
|
<switch>
|
||||||
|
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||||
|
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 200px; margin-left: 61px;">
|
||||||
|
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||||
|
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||||
|
JsEvaluationEngine
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</foreignObject>
|
||||||
|
<text x="120" y="204" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||||
|
JsEvaluationEngine
|
||||||
|
</text>
|
||||||
|
</switch>
|
||||||
|
</g>
|
||||||
|
<rect x="60" y="290" width="120" height="60" fill="#ffffff" stroke="#000000" pointer-events="all"/>
|
||||||
|
<g transform="translate(-0.5 -0.5)">
|
||||||
|
<switch>
|
||||||
|
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||||
|
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 320px; margin-left: 61px;">
|
||||||
|
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||||
|
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||||
|
JsEvaluator
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</foreignObject>
|
||||||
|
<text x="120" y="324" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||||
|
JsEvaluator
|
||||||
|
</text>
|
||||||
|
</switch>
|
||||||
|
</g>
|
||||||
|
<rect x="60" y="490" width="120" height="60" fill="#ffffff" stroke="#000000" pointer-events="all"/>
|
||||||
|
<g transform="translate(-0.5 -0.5)">
|
||||||
|
<switch>
|
||||||
|
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||||
|
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 520px; margin-left: 61px;">
|
||||||
|
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||||
|
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||||
|
DataExtractionResult
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</foreignObject>
|
||||||
|
<text x="120" y="524" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||||
|
DataExtractionResult
|
||||||
|
</text>
|
||||||
|
</switch>
|
||||||
|
</g>
|
||||||
|
<path d="M 120 125.99 L 120 167.76" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"/>
|
||||||
|
<path d="M 120 110.99 L 124.41 118.49 L 120 125.99 L 115.59 118.49 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||||
|
<path d="M 113.5 155.88 L 120 168.88 L 126.5 155.88" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||||
|
<g transform="translate(-0.5 -0.5)">
|
||||||
|
<switch>
|
||||||
|
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||||
|
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 107px; margin-left: 125px;">
|
||||||
|
<div style="box-sizing: border-box; font-size: 0; text-align: left; ">
|
||||||
|
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">
|
||||||
|
1
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</foreignObject>
|
||||||
|
<text x="125" y="107" fill="#000000" font-family="Helvetica" font-size="11px">
|
||||||
|
1
|
||||||
|
</text>
|
||||||
|
</switch>
|
||||||
|
</g>
|
||||||
|
<path d="M 120 230 L 120 287.76" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/>
|
||||||
|
<path d="M 113.5 275.88 L 120 288.88 L 126.5 275.88" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||||
|
<g transform="translate(-0.5 -0.5)">
|
||||||
|
<switch>
|
||||||
|
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||||
|
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 260px; margin-left: 120px;">
|
||||||
|
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||||
|
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">
|
||||||
|
Creates
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</foreignObject>
|
||||||
|
<text x="120" y="263" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">
|
||||||
|
Creates
|
||||||
|
</text>
|
||||||
|
</switch>
|
||||||
|
</g>
|
||||||
|
<path d="M 120 350 L 120 487.76" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/>
|
||||||
|
<path d="M 113.5 475.88 L 120 488.88 L 126.5 475.88" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||||
|
<g transform="translate(-0.5 -0.5)">
|
||||||
|
<switch>
|
||||||
|
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||||
|
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 420px; margin-left: 120px;">
|
||||||
|
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||||
|
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">
|
||||||
|
Evaluates Expression To
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</foreignObject>
|
||||||
|
<text x="120" y="423" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">
|
||||||
|
Evaluates Expression To
|
||||||
|
</text>
|
||||||
|
</switch>
|
||||||
|
</g>
|
||||||
|
<rect x="0" y="0" width="70" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||||
|
<g transform="translate(-0.5 -0.5)">
|
||||||
|
<switch>
|
||||||
|
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||||
|
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 10px; margin-left: 35px;">
|
||||||
|
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||||
|
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; ">
|
||||||
|
extension
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</foreignObject>
|
||||||
|
<text x="35" y="14" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||||
|
extension
|
||||||
|
</text>
|
||||||
|
</switch>
|
||||||
|
</g>
|
||||||
|
<rect x="0" y="460" width="50" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||||
|
<g transform="translate(-0.5 -0.5)">
|
||||||
|
<switch>
|
||||||
|
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||||
|
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 470px; margin-left: 25px;">
|
||||||
|
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||||
|
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; ">
|
||||||
|
shared
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</foreignObject>
|
||||||
|
<text x="25" y="474" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||||
|
shared
|
||||||
|
</text>
|
||||||
|
</switch>
|
||||||
|
</g>
|
||||||
|
<rect x="60" y="630" width="120" height="60" fill="#ffffff" stroke="#000000" pointer-events="all"/>
|
||||||
|
<g transform="translate(-0.5 -0.5)">
|
||||||
|
<switch>
|
||||||
|
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||||
|
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 660px; margin-left: 61px;">
|
||||||
|
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||||
|
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||||
|
Model.state
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</foreignObject>
|
||||||
|
<text x="120" y="664" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||||
|
Model.state
|
||||||
|
</text>
|
||||||
|
</switch>
|
||||||
|
</g>
|
||||||
|
<rect x="0" y="600" width="60" height="20" fill="none" stroke="none" pointer-events="all"/>
|
||||||
|
<g transform="translate(-0.5 -0.5)">
|
||||||
|
<switch>
|
||||||
|
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||||
|
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 610px; margin-left: 30px;">
|
||||||
|
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||||
|
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: nowrap; ">
|
||||||
|
webview
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</foreignObject>
|
||||||
|
<text x="30" y="614" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||||
|
webview
|
||||||
|
</text>
|
||||||
|
</switch>
|
||||||
|
</g>
|
||||||
|
<path d="M 120 550 L 120 627.76" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/>
|
||||||
|
<path d="M 113.5 615.88 L 120 628.88 L 126.5 615.88" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||||
|
<g transform="translate(-0.5 -0.5)">
|
||||||
|
<switch>
|
||||||
|
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||||
|
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 590px; margin-left: 120px;">
|
||||||
|
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||||
|
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">
|
||||||
|
Sent To
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</foreignObject>
|
||||||
|
<text x="120" y="593" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">
|
||||||
|
Sent To
|
||||||
|
</text>
|
||||||
|
</switch>
|
||||||
|
</g>
|
||||||
|
<rect x="60" y="760" width="150" height="60" fill="#ffffff" stroke="#000000" pointer-events="all"/>
|
||||||
|
<g transform="translate(-0.5 -0.5)">
|
||||||
|
<switch>
|
||||||
|
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||||
|
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 148px; height: 1px; padding-top: 790px; margin-left: 61px;">
|
||||||
|
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||||
|
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||||
|
Visualizer.renderContent
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</foreignObject>
|
||||||
|
<text x="135" y="794" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||||
|
Visualizer.renderContent
|
||||||
|
</text>
|
||||||
|
</switch>
|
||||||
|
</g>
|
||||||
|
<path d="M 120 690 L 130.17 757.79" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/>
|
||||||
|
<path d="M 121.98 747 L 130.33 758.89 L 134.83 745.07" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||||
|
<g transform="translate(-0.5 -0.5)">
|
||||||
|
<switch>
|
||||||
|
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||||
|
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 725px; margin-left: 125px;">
|
||||||
|
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||||
|
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">
|
||||||
|
Rendered In
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</foreignObject>
|
||||||
|
<text x="125" y="728" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">
|
||||||
|
Rendered In
|
||||||
|
</text>
|
||||||
|
</switch>
|
||||||
|
</g>
|
||||||
|
<rect x="60" y="880" width="130" height="60" fill="#ffffff" stroke="#000000" pointer-events="all"/>
|
||||||
|
<g transform="translate(-0.5 -0.5)">
|
||||||
|
<switch>
|
||||||
|
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||||
|
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 910px; margin-left: 61px;">
|
||||||
|
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||||
|
<div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; ">
|
||||||
|
Visualization.render
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</foreignObject>
|
||||||
|
<text x="125" y="914" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle">
|
||||||
|
Visualization.render
|
||||||
|
</text>
|
||||||
|
</switch>
|
||||||
|
</g>
|
||||||
|
<path d="M 132.5 820 L 127.69 877.77" fill="none" stroke="#000000" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/>
|
||||||
|
<path d="M 122.19 865.39 L 127.59 878.89 L 135.15 866.47" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="all"/>
|
||||||
|
<g transform="translate(-0.5 -0.5)">
|
||||||
|
<switch>
|
||||||
|
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
|
||||||
|
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 850px; margin-left: 130px;">
|
||||||
|
<div style="box-sizing: border-box; font-size: 0; text-align: center; ">
|
||||||
|
<div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; ">
|
||||||
|
Rendered In
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</foreignObject>
|
||||||
|
<text x="130" y="853" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle">
|
||||||
|
Rendered In
|
||||||
|
</text>
|
||||||
|
</switch>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<switch>
|
||||||
|
<g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/>
|
||||||
|
<a transform="translate(0,-5)" xlink:href="https://desk.draw.io/support/solutions/articles/16000042487" target="_blank">
|
||||||
|
<text text-anchor="middle" font-size="10px" x="50%" y="100%">
|
||||||
|
Viewer does not support full SVG 1.1
|
||||||
|
</text>
|
||||||
|
</a>
|
||||||
|
</switch>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 24 KiB |
BIN
docs/ast-demo.gif
Normal file
|
After Width: | Height: | Size: 2.2 MiB |
BIN
docs/custom-script-map.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 3.5 MiB After Width: | Height: | Size: 4.2 MiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 17 KiB |
@@ -3,15 +3,13 @@
|
|||||||
[data-extraction]
|
[data-extraction]
|
||||||
[webview]
|
[webview]
|
||||||
[extension]
|
[extension]
|
||||||
[visualization]
|
[hediet/visualization]
|
||||||
[visualization-playground]
|
|
||||||
|
|
||||||
[webview] ..> [extension]: "Uses RPC contracts, connects using websockets"
|
[webview] ..> [extension]: "Uses RPC contracts, connects using websockets"
|
||||||
[extension] ..> [webview]: "Loads into a Webview in VS Code"
|
[extension] ..> [webview]: "Loads into a Webview in VS Code"
|
||||||
|
|
||||||
[webview] ..> [visualization]: "Uses React Components"
|
[webview] ..> [hediet/visualization]: "Uses React Components"
|
||||||
|
|
||||||
[visualization-playground] ..> [visualization]: "Uses React Components"
|
|
||||||
|
|
||||||
[extension] ..> [data-extraction]: "Injects Runtime into JavaScript applications"
|
[extension] ..> [data-extraction]: "Injects Runtime into JavaScript applications"
|
||||||
|
|
||||||
|
|||||||
BIN
docs/table-demo.gif
Normal file
|
After Width: | Height: | Size: 2.6 MiB |
BIN
docs/visualization-plotly-random-walk.gif
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
@@ -1,2 +1 @@
|
|||||||
node_modules
|
./node_modules
|
||||||
ui/node_modules
|
|
||||||
@@ -1,5 +1,22 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## 2.2.0
|
||||||
|
|
||||||
|
- Adds setting `debugVisualizer.js.customScriptPaths` to inject custom scripts when debugging JavaScript. Such scripts are reloaded automatically when changed.
|
||||||
|
|
||||||
|
## 2.1.0
|
||||||
|
|
||||||
|
- Adds text diff and text decoration viewer.
|
||||||
|
- Supports more js debug adapters
|
||||||
|
|
||||||
|
## 2.0.6
|
||||||
|
|
||||||
|
- Fixes grid extractor bug
|
||||||
|
- Fixes Perspective.js bug
|
||||||
|
- Fixes AST visualizer bug
|
||||||
|
- Adds table data extractor
|
||||||
|
- Improves typescript data extractor
|
||||||
|
|
||||||
## 2.0.0
|
## 2.0.0
|
||||||
|
|
||||||
- Support for the new JS debug adapters
|
- Support for the new JS debug adapters
|
||||||
|
|||||||
@@ -3,218 +3,77 @@
|
|||||||
[](https://twitter.com/intent/follow?screen_name=hediet_dev)
|
[](https://twitter.com/intent/follow?screen_name=hediet_dev)
|
||||||
|
|
||||||
A VS Code extension for visualizing data structures while debugging.
|
A VS Code extension for visualizing data structures while debugging.
|
||||||
Like the VS Code's watch view, but with custom visualizations.
|
Like the VS Code's watch view, but with rich visualizations of the watched value.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
## [Visualization Playground](https://hediet.github.io/visualization/)
|
||||||
|
|
||||||
|
Click [here](https://hediet.github.io/visualization/) to explore all available visualizations.
|
||||||
|
|
||||||
## Supported Languages
|
## Supported Languages
|
||||||
|
|
||||||
See [demos](../demos/) for demos. These languages and debuggers are verified to work with this extension:
|
See [demos](../demos/) for demos. These languages and debuggers are verified to work with this extension:
|
||||||
|
|
||||||
- JavaScript/TypeScript/... using `node`/`node2`/`extensionHost` or `chrome` debug adapter: [⭐ Full Support](../demos/js)
|
- JavaScript/TypeScript/... using `node`/`node2`/`extensionHost`/`chrome`/`pwa-chrome`/`pwa-node` debug adapter: [⭐ Full Support](../demos/js)
|
||||||
- Go using `go` (Delve) debug adapter: [✅ Rudimentary Support](../demos/golang)
|
- Dart/Flutter using `dart` debug adapter: [✅ Basic Support](../demos/dart)
|
||||||
- Python using `python` debug adapter: [✅ Rudimentary Support](../demos/python)
|
- Go using `go` (Delve) debug adapter: [✅ Basic Support](../demos/golang)
|
||||||
- C# using `coreclr` debug adapter: [✅ Rudimentary Support](../demos/csharp)
|
- Python using `python` debug adapter: [✅ Basic Support](../demos/python)
|
||||||
- PHP using `php` debug adapter: [✅ Rudimentary Support](../demos/php)
|
- C# using `coreclr` debug adapter: [✅ Basic Support](../demos/csharp) (work in progress for Full Support)
|
||||||
- Java using `java` debug adapter: [✅ Rudimentary Support](../demos/java)
|
- PHP using `php` debug adapter: [✅ Basic Support](../demos/php)
|
||||||
- C++ using `cppdbg` debug adapter: [✅ Rudimentary Support](../demos/cpp)
|
- Java using `java` debug adapter: [✅ Basic Support](../demos/java)
|
||||||
- Swift using `lldb` debug adapter: [✅ Rudimentary Support](../demos/swift)
|
- C++ using `cppdbg` debug adapter: [✅ Basic Support](../demos/cpp)
|
||||||
- Rust using `lldb` debug adapter: [✅ Rudimentary Support](../demos/rust)
|
- Swift using `lldb` debug adapter: [✅ Basic Support](../demos/swift)
|
||||||
|
- Rust using `lldb` debug adapter: [✅ Basic Support](../demos/rust)
|
||||||
|
|
||||||
All other languages and debuggers might work too.
|
All other languages and debuggers might work too.
|
||||||
For languages with _Rudimentary Support_, only JSON strings can be visualized - you must implement some logic that builds this JSON for your data structure!
|
For languages with _Basic Support_, only JSON strings can be visualized - you must implement some logic that builds this JSON for your data structure!
|
||||||
Fully supported languages offer _Data Extractors_ which convert some well known data structures to json.
|
Fully supported languages offer _Data Extractors_ which convert some well known data structures to json.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
After installing this extension, use the command `Debug Visualizer: New View` to open a new visualizer view.
|
After installing this extension, use the command `Debug Visualizer: New View` to open a new visualizer view.
|
||||||
In this view you can enter an expression that is evaluated and visualized while stepping through your application.
|
In this view you can enter an expression that is evaluated and visualized while stepping through your application.
|
||||||
This view works the same as the watch view of VS Code, except that the resulting value is presented visually rather than textually.
|
This view works the same as the watch view of VS Code, except that the resulting value is presented visually rather than textually and you can only watch one expression (but you can still open multiple windows).
|
||||||
|
|
||||||
You can refresh the evaluation and open the current visualizer view into a new browser window by using the top right buttons.
|
Use the command `Debug Visualizer: Use Selection as Expression` _(Shift + F1)_ to use the currently selected text as expression
|
||||||
You can also unfold the details pane to select a _Data Extractor_ and a _Visualizer_.
|
|
||||||
|
|
||||||
Use the command `Debug Visualizer: Use Selection as Expression` (Shift + F1) to use the currently selected text as expression
|
|
||||||
in the most recently opened debug visualizer.
|
in the most recently opened debug visualizer.
|
||||||
|
|
||||||
## Supported Values
|
## Supported Values
|
||||||
|
|
||||||
Visualizers consume specific JSON data. See [Integrated Visualizers](#Integrated%20Visualizers) for the schema of supported JSON data.
|
Not all values can be processed.
|
||||||
|
Visualizers consume specific JSON data. This extension uses [hediet/visualization](https://github.com/hediet/visualization), a generic visualization framework.
|
||||||
|
You can see in its [playground](https://hediet.github.io/visualization/) which data can be visualized and how the visualization looks like.
|
||||||
|
|
||||||
The currently watched expression should evaluate to a JSON Object string,
|
The currently watched expression should evaluate to a JSON Object string,
|
||||||
matching the schema of one of the supported visualizers. This JSON string may be surrounded by single or double quotation marks (or none at all) and must not be escaped.
|
matching the [schema](https://hediet.github.io/visualization/docs/visualization-data-schema.json) of one of the supported visualizers. This JSON string may be surrounded by single or double quotation marks (or none at all) and must not be escaped.
|
||||||
A valid example is `"{ "kind": { "text": true }, "text": "some text\nmore text" }"`.
|
A valid example is `"{ "kind": { "text": true }, "text": "some text\nmore text" }"`.
|
||||||
|
Use the watch window to see what an expression evaluates to. This extension simply interprets that result.
|
||||||
|
|
||||||
For some languages (TypeScript/JavaScript), runtime code is injected to support _Data Extractors_.
|
For some languages (TypeScript/JavaScript), runtime code is injected to support _Data Extractors_.
|
||||||
A Data Extractor lifts the requirement for the visualized value to be a JSON string
|
A Data Extractor lifts the requirement for the visualized value to be a JSON string
|
||||||
and acts as a bridge between custom data structures and the JSON data processed by the visualizers.
|
and acts as a bridge between custom data structures and the JSON data processed by the visualizers.
|
||||||
When multiple Data Extractors are applicable, a preferred one can be selected in the visualization view.
|
When multiple Data Extractors are applicable, a preferred one can be selected in the visualization view.
|
||||||
|
|
||||||
## Integrated Visualizers
|
There is a [JSON Schema for all supported visualizations](https://hediet.github.io/visualization/docs/visualization-data-schema.json) and a [typescript declaration file](https://hediet.github.io/visualization/docs/visualization-data.ts).
|
||||||
|
|
||||||
The following visualizers are built into this extension.
|
## Selected Demos
|
||||||
|
|
||||||
### Graph Visualization
|
### Reversing a Doubly Linked List
|
||||||
|
|
||||||
[Demo](https://hediet.github.io/vscode-debug-visualizer/?value=%7B%0A++++%22kind%22%3A+%7B+%22graph%22%3A+true+%7D%2C%0A++++%22nodes%22%3A+%5B%0A++++++++%7B+%22id%22%3A+%221%22%2C+%22label%22%3A+%221%22+%7D%2C%0A++++++++%7B+%22id%22%3A+%222%22%2C+%22label%22%3A+%222%22%2C+%22color%22%3A+%22orange%22+%7D%2C%0A++++++++%7B+%22id%22%3A+%223%22%2C+%22label%22%3A+%223%22+%7D%0A++++%5D%2C%0A++++%22edges%22%3A+%5B%0A++++++++%7B+%22from%22%3A+%221%22%2C+%22to%22%3A+%222%22%2C+%22color%22%3A+%22red%22+%7D%2C%0A++++++++%7B+%22from%22%3A+%221%22%2C+%22to%22%3A+%223%22+%7D%0A++++%5D%0A%7D).
|

|
||||||
The Graphviz and vis.js visualizers render data that matches the `Graph` interface.
|
|
||||||
|
|
||||||
```ts
|
### Random Walk
|
||||||
interface Graph {
|
|
||||||
kind: { graph: true };
|
|
||||||
nodes: NodeGraphData[];
|
|
||||||
edges: EdgeGraphData[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface NodeGraphData {
|

|
||||||
id: string;
|
|
||||||
label?: string;
|
|
||||||
color?: string;
|
|
||||||
shape?: "ellipse" | "box";
|
|
||||||
}
|
|
||||||
|
|
||||||
interface EdgeGraphData {
|
### Ast Visualizer
|
||||||
from: string;
|
|
||||||
to: string;
|
|
||||||
label?: string;
|
|
||||||
id?: string;
|
|
||||||
color?: string;
|
|
||||||
dashes?: boolean;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The graphviz visualizer uses the SVG viewer to render the SVG created by `viz.js`.
|

|
||||||
|
|
||||||

|
### Table Visualizer
|
||||||

|
|
||||||
|
|
||||||
### Plotly Visualization
|

|
||||||
|
|
||||||
[Demo](https://hediet.github.io/vscode-debug-visualizer/?value=%7B%22kind%22%3A%7B%22plotly%22%3Atrue%7D%2C%22data%22%3A%5B%7B%22y%22%3A%5B0%2C1%2C2%2C3%2C4%2C3%2C4%2C3%2C2%2C1%2C2%5D%7D%5D%7D).
|
|
||||||
The plotly visualizer uses plotly and can visualize JSON data matching the following interface:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
export interface Plotly {
|
|
||||||
kind: { plotly: true };
|
|
||||||
data: Partial<Plotly.Data>[];
|
|
||||||
}
|
|
||||||
// See plotly docs for Plotly.Data.
|
|
||||||
```
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Tree Visualization
|
|
||||||
|
|
||||||
The tree visualizer renders data that matches the `Tree` interface.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
interface Tree<TData = unknown> {
|
|
||||||
kind: { tree: true };
|
|
||||||
root: TreeNode<TData>;
|
|
||||||
}
|
|
||||||
interface TreeNode<TExtraData> {
|
|
||||||
id: string | undefined;
|
|
||||||
name: string;
|
|
||||||
value: string | undefined;
|
|
||||||
emphasizedValue: string | undefined;
|
|
||||||
children: TreeNode<TExtraData>[];
|
|
||||||
data: TExtraData;
|
|
||||||
isMarked: boolean;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### AST Visualization
|
|
||||||
|
|
||||||
[Demo](https://hediet.github.io/vscode-debug-visualizer/?value=%7B%22kind%22%3A%7B%22text%22%3Atrue%2C%22tree%22%3Atrue%2C%22ast%22%3Atrue%7D%2C%22root%22%3A%7B%22name%22%3A%22SourceFile%22%2C%22id%22%3A%22root%22%2C%22children%22%3A%5B%7B%22name%22%3A%22ClassDeclaration%22%2C%22id%22%3A%22statements%22%2C%22children%22%3A%5B%7B%22name%22%3A%22Identifier%22%2C%22id%22%3A%22name%22%2C%22children%22%3A%5B%5D%2C%22data%22%3A%7B%22length%22%3A6%2C%22position%22%3A6%7D%2C%22isMarked%22%3Afalse%2C%22value%22%3A%22Test1%22%7D%2C%7B%22name%22%3A%22MethodDeclaration%22%2C%22id%22%3A%22members%22%2C%22children%22%3A%5B%7B%22name%22%3A%22PublicKeyword%22%2C%22id%22%3A%22modifiers%22%2C%22children%22%3A%5B%5D%2C%22data%22%3A%7B%22length%22%3A8%2C%22position%22%3A14%7D%2C%22isMarked%22%3Afalse%7D%2C%7B%22name%22%3A%22Identifier%22%2C%22id%22%3A%22name%22%2C%22children%22%3A%5B%5D%2C%22data%22%3A%7B%22length%22%3A4%2C%22position%22%3A22%7D%2C%22isMarked%22%3Afalse%2C%22value%22%3A%22foo%22%7D%2C%7B%22name%22%3A%22Parameter%22%2C%22id%22%3A%22parameters%22%2C%22children%22%3A%5B%7B%22name%22%3A%22Identifier%22%2C%22id%22%3A%22name%22%2C%22children%22%3A%5B%5D%2C%22data%22%3A%7B%22length%22%3A1%2C%22position%22%3A27%7D%2C%22isMarked%22%3Afalse%2C%22value%22%3A%22a%22%7D%2C%7B%22name%22%3A%22NumberKeyword%22%2C%22id%22%3A%22type%22%2C%22children%22%3A%5B%5D%2C%22data%22%3A%7B%22length%22%3A7%2C%22position%22%3A29%7D%2C%22isMarked%22%3Afalse%7D%5D%2C%22data%22%3A%7B%22length%22%3A9%2C%22position%22%3A27%7D%2C%22isMarked%22%3Afalse%7D%2C%7B%22name%22%3A%22Block%22%2C%22id%22%3A%22body%22%2C%22children%22%3A%5B%7B%22name%22%3A%22VariableStatement%22%2C%22id%22%3A%22statements%22%2C%22children%22%3A%5B%7B%22name%22%3A%22VariableDeclarationList%22%2C%22id%22%3A%22declarationList%22%2C%22children%22%3A%5B%7B%22name%22%3A%22VariableDeclaration%22%2C%22id%22%3A%22declarations%22%2C%22children%22%3A%5B%7B%22name%22%3A%22Identifier%22%2C%22id%22%3A%22name%22%2C%22children%22%3A%5B%5D%2C%22data%22%3A%7B%22length%22%3A2%2C%22position%22%3A47%7D%2C%22isMarked%22%3Afalse%2C%22value%22%3A%22x%22%7D%2C%7B%22name%22%3A%22ObjectLiteralExpression%22%2C%22id%22%3A%22initializer%22%2C%22children%22%3A%5B%7B%22name%22%3A%22PropertyAssignment%22%2C%22id%22%3A%22properties%22%2C%22children%22%3A%5B%7B%22name%22%3A%22Identifier%22%2C%22id%22%3A%22name%22%2C%22children%22%3A%5B%5D%2C%22data%22%3A%7B%22length%22%3A2%2C%22position%22%3A53%7D%2C%22isMarked%22%3Afalse%2C%22value%22%3A%22a%22%7D%2C%7B%22name%22%3A%22FirstLiteralToken%22%2C%22id%22%3A%22initializer%22%2C%22children%22%3A%5B%5D%2C%22data%22%3A%7B%22length%22%3A2%2C%22position%22%3A56%7D%2C%22isMarked%22%3Afalse%2C%22value%22%3A%225%22%7D%5D%2C%22data%22%3A%7B%22length%22%3A5%2C%22position%22%3A53%7D%2C%22isMarked%22%3Afalse%7D%5D%2C%22data%22%3A%7B%22length%22%3A9%2C%22position%22%3A51%7D%2C%22isMarked%22%3Afalse%7D%5D%2C%22data%22%3A%7B%22length%22%3A13%2C%22position%22%3A47%7D%2C%22isMarked%22%3Afalse%7D%5D%2C%22data%22%3A%7B%22length%22%3A21%2C%22position%22%3A39%7D%2C%22isMarked%22%3Afalse%7D%5D%2C%22data%22%3A%7B%22length%22%3A22%2C%22position%22%3A39%7D%2C%22isMarked%22%3Afalse%7D%5D%2C%22data%22%3A%7B%22length%22%3A27%2C%22position%22%3A37%7D%2C%22isMarked%22%3Afalse%7D%5D%2C%22data%22%3A%7B%22length%22%3A50%2C%22position%22%3A14%7D%2C%22isMarked%22%3Afalse%7D%5D%2C%22data%22%3A%7B%22length%22%3A66%2C%22position%22%3A0%7D%2C%22isMarked%22%3Afalse%7D%2C%7B%22name%22%3A%22EndOfFileToken%22%2C%22id%22%3A%22endOfFileToken%22%2C%22children%22%3A%5B%5D%2C%22data%22%3A%7B%22length%22%3A1%2C%22position%22%3A66%7D%2C%22isMarked%22%3Afalse%7D%5D%2C%22data%22%3A%7B%22length%22%3A67%2C%22position%22%3A0%7D%2C%22isMarked%22%3Atrue%7D%2C%22text%22%3A%22%5Cnclass+Test1+%7B%5Cn%5Ctpublic+foo%28a%3A+number%29+%7B%5Cn%5Ct%5Ctconst+x+%3D+%7B+a%3A+5+%7D%3B%5Cn%5Ct%7D%5Cn%7D%5Cn%22%2C%22fileName%22%3A%22index.ts%22%7D).
|
|
||||||
The AST (Abstract Syntax Tree) visualizer renders data that matches the `Ast` interface.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
interface Ast
|
|
||||||
extends Tree<{
|
|
||||||
position: number;
|
|
||||||
length: number;
|
|
||||||
}>,
|
|
||||||
Text {
|
|
||||||
kind: { text: true; tree: true; ast: true };
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Additionally to the tree view, the source code is rendered and when selecting an AST node,
|
|
||||||
its span in the source code is highlighted.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Grid Visualization
|
|
||||||
|
|
||||||
Visualizes data matching the following interface:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
export interface Grid {
|
|
||||||
kind: { array: true };
|
|
||||||
columnLabels?: { label?: string }[];
|
|
||||||
rows: {
|
|
||||||
label?: string;
|
|
||||||
columns: {
|
|
||||||
content?: string;
|
|
||||||
tag?: string;
|
|
||||||
color?: string;
|
|
||||||
}[];
|
|
||||||
}[];
|
|
||||||
markers?: {
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
row: number;
|
|
||||||
column: number;
|
|
||||||
rows?: number;
|
|
||||||
columns?: number;
|
|
||||||
|
|
||||||
label?: string;
|
|
||||||
color?: string;
|
|
||||||
}[];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Text Visualization
|
|
||||||
|
|
||||||
The text visualizer renders data that matches the `Text` interface.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
interface Text {
|
|
||||||
kind: { text: true };
|
|
||||||
text: string;
|
|
||||||
mimeType?: string;
|
|
||||||
fileName?: string;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The `mimeType` and the file extension of `fileName` are used for syntax highlighting.
|
|
||||||
|
|
||||||
### SVG Visualization
|
|
||||||
|
|
||||||
The SVG visualizer renders data that matches the `Svg` interface.
|
|
||||||
The actual SVG data must be stored in `text`.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
interface Svg extends Text {
|
|
||||||
kind: { text: true; svg: true };
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Dot Graph Visualization
|
|
||||||
|
|
||||||
The Graphviz Dot visualizer renders data that matches the `DotGraph` interface.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
interface DotGraph extends Text {
|
|
||||||
kind: { text: true; dotGraph: true };
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
`Viz.js` (Graphviz) is used for rendering.
|
|
||||||
|
|
||||||
## JavaScript/TypeScript Integrated Data Extractors
|
## JavaScript/TypeScript Integrated Data Extractors
|
||||||
|
|
||||||
@@ -224,35 +83,22 @@ Custom data extractors can be registered too.
|
|||||||
See the package `@hediet/debug-visualizer-data-extraction` and its [README](../data-extraction/README.md) for the implementation and its API.
|
See the package `@hediet/debug-visualizer-data-extraction` and its [README](../data-extraction/README.md) for the implementation and its API.
|
||||||
Also, a global object of name `hedietDbgVis` with helper functions is injected.
|
Also, a global object of name `hedietDbgVis` with helper functions is injected.
|
||||||
|
|
||||||
### ToString
|
- **ToString**
|
||||||
|
- Just calls `.toString()` on values and treats the result as text.
|
||||||
Just calls `.toString()` on values and treats the result as text.
|
- **TypeScript AST**
|
||||||
|
- Direct Visualization of `ts.Node`s
|
||||||
### TypeScript AST
|
- Visualization of `Record<string, ts.Node>` and `ts.Node[]`. If the record contains a key `fn`, its value is displayed for each node.
|
||||||
|
- **As Is Data Extractor**
|
||||||
- Direct Visualization of `ts.Node`s
|
- Treats the data as direct input to the visualizer.
|
||||||
- Visualization of `Record<string, ts.Node>` and `[ts.Node]`. If the record contains a key `fn`, its value is displayed for each node.
|
- **Use Method 'getVisualizationData'**
|
||||||
|
- Calls `.getVisualizationData()` on values and treats the result as direct input to the visualizer.
|
||||||
### As Is Data Extractor
|
- **Plotly y-Values**
|
||||||
|
- Uses plotly to plot an array of numbers.
|
||||||
Treats the data as direct input to the visualizer.
|
- **Object Graph**
|
||||||
|
- Constructs a graph containing all objects reachable from object the expression evaluates to.
|
||||||
### Use Method 'getDebugVisualization'
|
Graph is constructed using a breadth search. Stops after 50 nodes.
|
||||||
|
- **Array Grid**
|
||||||
Calls `.getDebugVisualization()` on values and treats the result as direct input to the visualizer.
|
- Creates Grid visualization data for an array.
|
||||||
|
|
||||||
### Plotly y-Values
|
|
||||||
|
|
||||||
Uses plotly to plot an array of numbers.
|
|
||||||
|
|
||||||
### Object Graph
|
|
||||||
|
|
||||||
Constructs a graph containing all objects reachable from object the expression evaluates to.
|
|
||||||
Graph is constructed using a breadth search. Stops after 50 nodes.
|
|
||||||
|
|
||||||
### Array Grid
|
|
||||||
|
|
||||||
Creates Grid visualization data for an array.
|
|
||||||
|
|
||||||
## UI Features
|
## UI Features
|
||||||
|
|
||||||
@@ -282,10 +128,53 @@ This extension provides these configuration options:
|
|||||||
|
|
||||||
Configurations here overwrite the built-in support for the corresponding debug adapter type.
|
Configurations here overwrite the built-in support for the corresponding debug adapter type.
|
||||||
|
|
||||||
* `debugVisualizer.useChromeKioskMode`
|
- `debugVisualizer.useChromeKioskMode`
|
||||||
|
|
||||||
Specifies whether to pop out Debug Visualization Views with Chrome in Kiosk Mode. Uses the default browser otherwise or if Chrome is not found. Defaults to `true`.
|
Specifies whether to pop out Debug Visualization Views with Chrome in Kiosk Mode. Uses the default browser otherwise or if Chrome is not found. Defaults to `true`.
|
||||||
|
|
||||||
|
- `debugVisualizer.js.customScriptPaths`
|
||||||
|
|
||||||
|
Specifies a list of JavaScript files that are injected into the debugee when debugging JavaScript.
|
||||||
|
Each script must assign `module.exports` with a function of type `import("@hediet/debug-visualizer-data-extraction").LoadDataExtractorsFn`.
|
||||||
|
Paths must be absolute and can use the variable `${workspaceFolder}`.
|
||||||
|
Scripts are automatically reloaded when they are changed.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// @ts-check
|
||||||
|
/**
|
||||||
|
* @type {import("@hediet/debug-visualizer-data-extraction").LoadDataExtractorsFn}
|
||||||
|
*/
|
||||||
|
module.exports = (register, helpers) => {
|
||||||
|
register({
|
||||||
|
id: "map",
|
||||||
|
getExtractions(data, collector, context) {
|
||||||
|
if (!(data instanceof Map)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
collector.addExtraction({
|
||||||
|
priority: 1000,
|
||||||
|
id: "map",
|
||||||
|
name: "Map",
|
||||||
|
extractData() {
|
||||||
|
return helpers.asData({
|
||||||
|
kind: { table: true },
|
||||||
|
rows: [...data].map(([k, v]) => ({
|
||||||
|
key: k,
|
||||||
|
value: v,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
# See Also
|
# See Also
|
||||||
|
|
||||||
This extension works very well together with my library [`@hediet/node-reload`](https://github.com/hediet/node-reload) for TypeScript/JavaScript.
|
This extension works very well together with my library [`@hediet/node-reload`](https://github.com/hediet/node-reload) for TypeScript/JavaScript.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"displayName": "Debug Visualizer",
|
"displayName": "Debug Visualizer",
|
||||||
"description": "A visual watch window that lets you visualize your data structures while debugging.",
|
"description": "A visual watch window that lets you visualize your data structures while debugging.",
|
||||||
"icon": "docs/logo.drawio.png",
|
"icon": "docs/logo.drawio.png",
|
||||||
"version": "2.0.0",
|
"version": "2.2.1",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"vscode": "^1.46.0"
|
"vscode": "^1.46.0"
|
||||||
@@ -41,6 +41,11 @@
|
|||||||
"onDebug",
|
"onDebug",
|
||||||
"onWebviewPanel:debugVisualizer"
|
"onWebviewPanel:debugVisualizer"
|
||||||
],
|
],
|
||||||
|
"capabilities": {
|
||||||
|
"untrustedWorkspaces": {
|
||||||
|
"supported": false
|
||||||
|
}
|
||||||
|
},
|
||||||
"main": "./dist/extension.js",
|
"main": "./dist/extension.js",
|
||||||
"contributes": {
|
"contributes": {
|
||||||
"commands": [
|
"commands": [
|
||||||
@@ -63,6 +68,14 @@
|
|||||||
"configuration": {
|
"configuration": {
|
||||||
"title": "Debug Visualizer",
|
"title": "Debug Visualizer",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"debugVisualizer.js.customScriptPaths": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "Defines JavaScript sources that are injected into the debuggee.",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The file path to a custom js script. Must be absolute. You can use ${workspaceFolder}."
|
||||||
|
}
|
||||||
|
},
|
||||||
"debugVisualizer.useChromeKioskMode": {
|
"debugVisualizer.useChromeKioskMode": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": true,
|
"default": true,
|
||||||
@@ -123,6 +136,7 @@
|
|||||||
"webpack": "^4.41.6",
|
"webpack": "^4.41.6",
|
||||||
"webpack-cli": "^3.3.11",
|
"webpack-cli": "^3.3.11",
|
||||||
"ts-loader": "^6.2.1",
|
"ts-loader": "^6.2.1",
|
||||||
"shx": "^0.3.2"
|
"shx": "^0.3.2",
|
||||||
|
"vsce": "^1.93.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,29 @@ export class Config {
|
|||||||
{ serializer: serializerWithDefault<DebugAdapterConfigs>({}) }
|
{ serializer: serializerWithDefault<DebugAdapterConfigs>({}) }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
private readonly _customScriptPaths = new VsCodeSetting(
|
||||||
|
"debugVisualizer.js.customScriptPaths",
|
||||||
|
{ serializer: serializerWithDefault<string[]>([]) }
|
||||||
|
);
|
||||||
|
|
||||||
|
public get customScriptPaths(): string[] {
|
||||||
|
return this._customScriptPaths.get().map(p => {
|
||||||
|
const tpl = new SimpleTemplate(p);
|
||||||
|
return tpl.render({
|
||||||
|
workspaceFolder: () => {
|
||||||
|
const workspaceFolder = (workspace.workspaceFolders ||
|
||||||
|
[])[0];
|
||||||
|
if (!workspaceFolder) {
|
||||||
|
throw new Error(
|
||||||
|
`Cannot get workspace folder - '${p}' cannot be evaluated!`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return workspaceFolder.uri.fsPath;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
private _vsCodeTheme = window.activeColorTheme;
|
private _vsCodeTheme = window.activeColorTheme;
|
||||||
|
|
||||||
@@ -85,3 +108,13 @@ function evaluateTemplate(
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class SimpleTemplate {
|
||||||
|
constructor(private readonly str: string) {}
|
||||||
|
|
||||||
|
render(data: Record<string, () => string>): string {
|
||||||
|
return this.str.replace(/\$\{([a-zA-Z0-9]+)\}/g, (substr, grp1) => {
|
||||||
|
return data[grp1]();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
import { EvaluationEngine, Evaluator } from "./EvaluationEngine";
|
|
||||||
import { EnhancedDebugSession } from "../../debugger/EnhancedDebugSession";
|
|
||||||
|
|
||||||
export class ComposedEvaluationEngine implements EvaluationEngine {
|
|
||||||
constructor(public readonly engines: EvaluationEngine[]) {}
|
|
||||||
|
|
||||||
createEvaluator(session: EnhancedDebugSession): Evaluator | undefined {
|
|
||||||
for (const f of this.engines) {
|
|
||||||
const evaluator = f.createEvaluator(session);
|
|
||||||
if (evaluator) {
|
|
||||||
return evaluator;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
import { DataExtractorId } from "@hediet/debug-visualizer-data-extraction";
|
|
||||||
import { EnhancedDebugSession } from "../../debugger/EnhancedDebugSession";
|
|
||||||
import { EvaluationEngine, Evaluator } from "./EvaluationEngine";
|
|
||||||
import { Config, DebugAdapterConfig } from "../../Config";
|
|
||||||
import { GenericEvaluator } from "./GenericEvaluationEngine";
|
|
||||||
import { registerUpdateReconciler, hotClass } from "@hediet/node-reload";
|
|
||||||
|
|
||||||
registerUpdateReconciler(module);
|
|
||||||
|
|
||||||
@hotClass(module)
|
|
||||||
export class ConfiguredEvaluationEngine implements EvaluationEngine {
|
|
||||||
constructor(private readonly config: Config) {}
|
|
||||||
|
|
||||||
createEvaluator(session: EnhancedDebugSession): Evaluator | undefined {
|
|
||||||
const config = this.config.getDebugAdapterConfig(session.session.type);
|
|
||||||
if (!config) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return new ConfiguredEvaluator(session, config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ConfiguredEvaluator extends GenericEvaluator {
|
|
||||||
constructor(
|
|
||||||
session: EnhancedDebugSession,
|
|
||||||
private readonly config: DebugAdapterConfig
|
|
||||||
) {
|
|
||||||
super(session);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected getContext() {
|
|
||||||
return this.config.context;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected getFinalExpression({
|
|
||||||
expression,
|
|
||||||
preferredExtractorId,
|
|
||||||
}: {
|
|
||||||
expression: string;
|
|
||||||
preferredExtractorId: DataExtractorId | undefined;
|
|
||||||
}) {
|
|
||||||
return this.config.getFinalExpression({
|
|
||||||
expression,
|
|
||||||
preferredExtractorId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
import {
|
|
||||||
DataExtractionResult,
|
|
||||||
DataExtractorId,
|
|
||||||
} from "@hediet/debug-visualizer-data-extraction";
|
|
||||||
import { EnhancedDebugSession } from "../../debugger/EnhancedDebugSession";
|
|
||||||
import { FormattedMessage } from "../../webviewContract";
|
|
||||||
|
|
||||||
export interface EvaluationEngine {
|
|
||||||
createEvaluator(session: EnhancedDebugSession): Evaluator | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Evaluator {
|
|
||||||
evaluate(
|
|
||||||
args: EvaluationArgs
|
|
||||||
): Promise<
|
|
||||||
| { kind: "data"; result: DataExtractionResult }
|
|
||||||
| { kind: "error"; message: FormattedMessage }
|
|
||||||
>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The language that expressions must be written in.
|
|
||||||
*/
|
|
||||||
readonly languageId: string | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EvaluationArgs {
|
|
||||||
expression: string;
|
|
||||||
preferredExtractorId: DataExtractorId | undefined;
|
|
||||||
frameId: number | undefined;
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
import {
|
|
||||||
DataExtractionResult,
|
|
||||||
DataExtractorId,
|
|
||||||
} from "@hediet/debug-visualizer-data-extraction";
|
|
||||||
import { EnhancedDebugSession } from "../../debugger/EnhancedDebugSession";
|
|
||||||
import {
|
|
||||||
EvaluationEngine,
|
|
||||||
Evaluator,
|
|
||||||
EvaluationArgs,
|
|
||||||
} from "./EvaluationEngine";
|
|
||||||
import { parseEvaluationResultFromGenericDebugAdapter } from "./parseEvaluationResultFromGenericDebugAdapter";
|
|
||||||
import { FormattedMessage } from "../../webviewContract";
|
|
||||||
import { hotClass, registerUpdateReconciler } from "@hediet/node-reload";
|
|
||||||
|
|
||||||
registerUpdateReconciler(module);
|
|
||||||
|
|
||||||
@hotClass(module)
|
|
||||||
export class GenericEvaluationEngine implements EvaluationEngine {
|
|
||||||
createEvaluator(session: EnhancedDebugSession): Evaluator | undefined {
|
|
||||||
return new GenericEvaluator(session);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class GenericEvaluator implements Evaluator {
|
|
||||||
public readonly languageId = "text";
|
|
||||||
|
|
||||||
constructor(private readonly session: EnhancedDebugSession) {}
|
|
||||||
|
|
||||||
public async evaluate({
|
|
||||||
expression,
|
|
||||||
preferredExtractorId,
|
|
||||||
frameId,
|
|
||||||
}: EvaluationArgs): Promise<
|
|
||||||
| { kind: "data"; result: DataExtractionResult }
|
|
||||||
| { kind: "error"; message: FormattedMessage }
|
|
||||||
> {
|
|
||||||
const finalExpression = this.getFinalExpression({
|
|
||||||
expression,
|
|
||||||
preferredExtractorId,
|
|
||||||
});
|
|
||||||
let reply;
|
|
||||||
try {
|
|
||||||
reply = await this.session.evaluate({
|
|
||||||
expression: finalExpression,
|
|
||||||
frameId,
|
|
||||||
context: this.getContext(),
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
return {
|
|
||||||
kind: "error",
|
|
||||||
message: {
|
|
||||||
kind: "list",
|
|
||||||
items: [
|
|
||||||
"An error occurred while evaluating the expression:",
|
|
||||||
error.message,
|
|
||||||
`Used debug adapter: ${this.session.session.configuration.type}`,
|
|
||||||
{
|
|
||||||
kind: "inlineList",
|
|
||||||
items: [
|
|
||||||
"Evaluated expression is",
|
|
||||||
{ kind: "code", content: finalExpression },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return parseEvaluationResultFromGenericDebugAdapter(reply.result, {
|
|
||||||
debugAdapterType: this.session.session.configuration.type,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected getFinalExpression(args: {
|
|
||||||
expression: string;
|
|
||||||
preferredExtractorId: DataExtractorId | undefined;
|
|
||||||
}): string {
|
|
||||||
return args.expression;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected getContext(): "watch" | "repl" {
|
|
||||||
// we will use "repl" as default so that results are not truncated.
|
|
||||||
return "repl";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
import {
|
|
||||||
getExpressionForDataExtractorApi,
|
|
||||||
DataResult,
|
|
||||||
ApiHasNotBeenInitializedCode,
|
|
||||||
getExpressionToInitializeDataExtractorApi,
|
|
||||||
DataExtractionResult,
|
|
||||||
} from "@hediet/debug-visualizer-data-extraction";
|
|
||||||
import { EnhancedDebugSession } from "../../debugger/EnhancedDebugSession";
|
|
||||||
import {
|
|
||||||
EvaluationEngine,
|
|
||||||
Evaluator,
|
|
||||||
EvaluationArgs,
|
|
||||||
} from "./EvaluationEngine";
|
|
||||||
import { FormattedMessage } from "../../webviewContract";
|
|
||||||
import { registerUpdateReconciler, hotClass } from "@hediet/node-reload";
|
|
||||||
|
|
||||||
registerUpdateReconciler(module);
|
|
||||||
|
|
||||||
@hotClass(module)
|
|
||||||
export class JsEvaluationEngine implements EvaluationEngine {
|
|
||||||
createEvaluator(session: EnhancedDebugSession): Evaluator | undefined {
|
|
||||||
const supportedDebugAdapters = [
|
|
||||||
"node",
|
|
||||||
"node2",
|
|
||||||
"extensionHost",
|
|
||||||
"chrome",
|
|
||||||
"pwa-chrome",
|
|
||||||
"pwa-node",
|
|
||||||
];
|
|
||||||
if (supportedDebugAdapters.indexOf(session.session.type) !== -1) {
|
|
||||||
return new JsEvaluator(session);
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class JsEvaluator implements Evaluator {
|
|
||||||
public readonly languageId = "javascript";
|
|
||||||
|
|
||||||
constructor(private readonly session: EnhancedDebugSession) {}
|
|
||||||
|
|
||||||
private getContext(): "copy" | "repl" {
|
|
||||||
if (this.session.session.type.startsWith("pwa-")) {
|
|
||||||
return "copy";
|
|
||||||
}
|
|
||||||
return "repl";
|
|
||||||
}
|
|
||||||
|
|
||||||
public async evaluate({
|
|
||||||
expression,
|
|
||||||
preferredExtractorId,
|
|
||||||
frameId,
|
|
||||||
}: EvaluationArgs): Promise<
|
|
||||||
| { kind: "data"; result: DataExtractionResult }
|
|
||||||
| { kind: "error"; message: FormattedMessage }
|
|
||||||
> {
|
|
||||||
while (true) {
|
|
||||||
try {
|
|
||||||
const preferredExtractorExpr = preferredExtractorId
|
|
||||||
? `"${preferredExtractorId}"`
|
|
||||||
: "undefined";
|
|
||||||
|
|
||||||
const body = `${getExpressionForDataExtractorApi()}.getData(
|
|
||||||
e => (${expression}),
|
|
||||||
expr => eval(expr),
|
|
||||||
${preferredExtractorExpr}
|
|
||||||
)`;
|
|
||||||
|
|
||||||
const wrappedExpr = `
|
|
||||||
(() => {
|
|
||||||
try {
|
|
||||||
return ${body};
|
|
||||||
} catch (e) {
|
|
||||||
return JSON.stringify({
|
|
||||||
kind: "Error",
|
|
||||||
message: e.message,
|
|
||||||
stack: e.stack
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
`;
|
|
||||||
|
|
||||||
const reply = await this.session.evaluate({
|
|
||||||
expression: wrappedExpr,
|
|
||||||
frameId,
|
|
||||||
context: this.getContext(),
|
|
||||||
});
|
|
||||||
const resultStr = reply.result;
|
|
||||||
const jsonData =
|
|
||||||
this.getContext() === "copy"
|
|
||||||
? resultStr
|
|
||||||
: resultStr.substr(1, resultStr.length - 2);
|
|
||||||
const result = JSON.parse(jsonData) as DataResult;
|
|
||||||
|
|
||||||
if (result.kind === "NoExtractors") {
|
|
||||||
throw new Error("No extractors");
|
|
||||||
} else if (result.kind === "Error") {
|
|
||||||
throw new Error(result.message);
|
|
||||||
} else if (result.kind === "Data") {
|
|
||||||
return {
|
|
||||||
kind: "data",
|
|
||||||
result: result.extractionResult,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
throw new Error("Invalid Data");
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
const msg = error.message as string | undefined;
|
|
||||||
if (msg && msg.includes(ApiHasNotBeenInitializedCode)) {
|
|
||||||
if (await this.initializeApi(frameId)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
kind: "error",
|
|
||||||
message: error.message,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async initializeApi(frameId: number | undefined): Promise<boolean> {
|
|
||||||
try {
|
|
||||||
// prefer existing is true, so that manually registered (possibly newer) extractors are not overwritten.
|
|
||||||
const expression = `${getExpressionToInitializeDataExtractorApi()}.registerDefaultExtractors(true);`;
|
|
||||||
|
|
||||||
await this.session.evaluate({
|
|
||||||
expression,
|
|
||||||
frameId,
|
|
||||||
context: this.getContext(),
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
export * from "./EvaluationEngine";
|
|
||||||
|
|
||||||
export { ComposedEvaluationEngine } from "./ComposedEvaluationEngine";
|
|
||||||
export { JsEvaluationEngine } from "./JsEvaluationEngine";
|
|
||||||
export { GenericEvaluationEngine } from "./GenericEvaluationEngine";
|
|
||||||
export { ConfiguredEvaluationEngine } from "./ConfiguredEvaluationEngine";
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
import {
|
|
||||||
EvaluationWatchService,
|
|
||||||
EvaluationWatcher,
|
|
||||||
EvaluationWatcherOptions,
|
|
||||||
} from "./EvaluationWatchService";
|
|
||||||
import { observable, autorun, action } from "mobx";
|
|
||||||
import { Disposable } from "@hediet/std/disposable";
|
|
||||||
import { DataExtractorId } from "@hediet/debug-visualizer-data-extraction";
|
|
||||||
import { DataExtractionState, CompletionItem } from "../webviewContract";
|
|
||||||
import { hotClass } from "@hediet/node-reload";
|
|
||||||
import { VsCodeDebuggerView } from "../debugger/VsCodeDebuggerView";
|
|
||||||
import { EvaluationEngine } from "./EvaluationEngine/EvaluationEngine";
|
|
||||||
|
|
||||||
@hotClass(module)
|
|
||||||
export class EvaluationWatchServiceImpl implements EvaluationWatchService {
|
|
||||||
public readonly dispose = Disposable.fn();
|
|
||||||
private readonly watchers = new Set<ObservableEvaluationWatcher>();
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private readonly vsCodeDebuggerView: VsCodeDebuggerView,
|
|
||||||
private readonly evaluationEngine: EvaluationEngine
|
|
||||||
) {
|
|
||||||
this.dispose.track({
|
|
||||||
dispose: autorun(() => {
|
|
||||||
if (
|
|
||||||
vsCodeDebuggerView.activeDebugSession &&
|
|
||||||
vsCodeDebuggerView.activeFrameId !== undefined
|
|
||||||
) {
|
|
||||||
for (const w of this.watchers) {
|
|
||||||
w.refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public createEvaluationWatcher(
|
|
||||||
expression: string,
|
|
||||||
options: EvaluationWatcherOptions
|
|
||||||
): EvaluationWatcher {
|
|
||||||
const w = new ObservableEvaluationWatcher(expression, this, options);
|
|
||||||
this.watchers.add(w);
|
|
||||||
this.refresh(w);
|
|
||||||
return w;
|
|
||||||
}
|
|
||||||
|
|
||||||
public removeWatcher(w: ObservableEvaluationWatcher) {
|
|
||||||
this.watchers.delete(w);
|
|
||||||
}
|
|
||||||
|
|
||||||
private lastLanguageId: string | undefined = undefined;
|
|
||||||
|
|
||||||
get languageId(): string | undefined {
|
|
||||||
const session = this.vsCodeDebuggerView.activeDebugSession;
|
|
||||||
if (!session) {
|
|
||||||
return this.lastLanguageId;
|
|
||||||
}
|
|
||||||
const evaluator = this.evaluationEngine.createEvaluator(session);
|
|
||||||
if (!evaluator) {
|
|
||||||
return this.lastLanguageId;
|
|
||||||
}
|
|
||||||
this.lastLanguageId = evaluator.languageId;
|
|
||||||
return evaluator.languageId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async refresh(w: ObservableEvaluationWatcher): Promise<void> {
|
|
||||||
const session = this.vsCodeDebuggerView.activeDebugSession;
|
|
||||||
if (!session) {
|
|
||||||
w._state = { kind: "noDebugSession" };
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const frameId = this.vsCodeDebuggerView.activeFrameId;
|
|
||||||
|
|
||||||
w._state = { kind: "loading" };
|
|
||||||
|
|
||||||
const evaluator = this.evaluationEngine.createEvaluator(session);
|
|
||||||
if (!evaluator) {
|
|
||||||
w._state = {
|
|
||||||
kind: "error",
|
|
||||||
message: `The debug adapter "${session.session.type}" is not supported.`,
|
|
||||||
};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await evaluator.evaluate({
|
|
||||||
expression: w.expression,
|
|
||||||
frameId,
|
|
||||||
preferredExtractorId: w.preferredDataExtractor,
|
|
||||||
});
|
|
||||||
|
|
||||||
w._state = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getCompletions(
|
|
||||||
text: string,
|
|
||||||
column: number
|
|
||||||
): Promise<CompletionItem[]> {
|
|
||||||
const session = this.vsCodeDebuggerView.activeDebugSession;
|
|
||||||
if (!session) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
return await session.getCompletions({
|
|
||||||
text,
|
|
||||||
frameId: this.vsCodeDebuggerView.activeFrameId,
|
|
||||||
column,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ObservableEvaluationWatcher implements EvaluationWatcher {
|
|
||||||
constructor(
|
|
||||||
public readonly expression: string,
|
|
||||||
private readonly source: EvaluationWatchServiceImpl,
|
|
||||||
options: EvaluationWatcherOptions
|
|
||||||
) {
|
|
||||||
this._preferredDataExtractor = options.preferredDataExtractor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@observable
|
|
||||||
private _preferredDataExtractor: DataExtractorId | undefined = undefined;
|
|
||||||
|
|
||||||
public get preferredDataExtractor(): DataExtractorId | undefined {
|
|
||||||
return this._preferredDataExtractor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
public setPreferredDataExtractor(id: DataExtractorId | undefined): void {
|
|
||||||
this._preferredDataExtractor = id;
|
|
||||||
this.refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
public refresh(): void {
|
|
||||||
this.source.refresh(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@observable
|
|
||||||
public _state: DataExtractionState = { kind: "loading" };
|
|
||||||
public get state(): DataExtractionState {
|
|
||||||
return this._state;
|
|
||||||
}
|
|
||||||
|
|
||||||
public dispose(): void {
|
|
||||||
this.source.removeWatcher(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export * from "./EvaluationWatchServiceImpl";
|
|
||||||
export * from "./EvaluationWatchService";
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import {
|
||||||
|
DebugSessionVisualizationSupport,
|
||||||
|
VisualizationBackend,
|
||||||
|
} from "./VisualizationBackend";
|
||||||
|
import { DebugSessionProxy } from "../proxies/DebugSessionProxy";
|
||||||
|
|
||||||
|
export class ComposedVisualizationSupport
|
||||||
|
implements DebugSessionVisualizationSupport {
|
||||||
|
constructor(public readonly engines: DebugSessionVisualizationSupport[]) {}
|
||||||
|
|
||||||
|
createBackend(
|
||||||
|
session: DebugSessionProxy
|
||||||
|
): VisualizationBackend | undefined {
|
||||||
|
for (const f of this.engines) {
|
||||||
|
const evaluator = f.createBackend(session);
|
||||||
|
if (evaluator) {
|
||||||
|
return evaluator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import { DataExtractorId } from "@hediet/debug-visualizer-data-extraction";
|
||||||
|
import { DebugSessionProxy } from "../proxies/DebugSessionProxy";
|
||||||
|
import {
|
||||||
|
DebugSessionVisualizationSupport,
|
||||||
|
VisualizationBackend,
|
||||||
|
} from "./VisualizationBackend";
|
||||||
|
import { Config, DebugAdapterConfig } from "../Config";
|
||||||
|
import { GenericVisualizationBackend } from "./GenericVisualizationSupport";
|
||||||
|
import { registerUpdateReconciler, hotClass } from "@hediet/node-reload";
|
||||||
|
import { DebuggerViewProxy } from "../proxies/DebuggerViewProxy";
|
||||||
|
|
||||||
|
registerUpdateReconciler(module);
|
||||||
|
|
||||||
|
@hotClass(module)
|
||||||
|
export class ConfigurableVisualizationSupport
|
||||||
|
implements DebugSessionVisualizationSupport {
|
||||||
|
constructor(
|
||||||
|
private readonly config: Config,
|
||||||
|
private readonly debuggerView: DebuggerViewProxy
|
||||||
|
) {}
|
||||||
|
|
||||||
|
createBackend(
|
||||||
|
session: DebugSessionProxy
|
||||||
|
): VisualizationBackend | undefined {
|
||||||
|
const config = this.config.getDebugAdapterConfig(session.session.type);
|
||||||
|
if (!config) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return new ConfiguredVisualizationBackend(
|
||||||
|
session,
|
||||||
|
this.debuggerView,
|
||||||
|
config
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConfiguredVisualizationBackend extends GenericVisualizationBackend {
|
||||||
|
constructor(
|
||||||
|
debugSession: DebugSessionProxy,
|
||||||
|
debuggerView: DebuggerViewProxy,
|
||||||
|
private readonly config: DebugAdapterConfig
|
||||||
|
) {
|
||||||
|
super(debugSession, debuggerView);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getContext() {
|
||||||
|
return this.config.context;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getFinalExpression({
|
||||||
|
expression,
|
||||||
|
preferredExtractorId,
|
||||||
|
}: {
|
||||||
|
expression: string;
|
||||||
|
preferredExtractorId: DataExtractorId | undefined;
|
||||||
|
}) {
|
||||||
|
return this.config.getFinalExpression({
|
||||||
|
expression,
|
||||||
|
preferredExtractorId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
import { DataExtractionResult } from "@hediet/debug-visualizer-data-extraction";
|
||||||
|
import { CompletionItem, FormattedMessage } from "../webviewContract";
|
||||||
|
import {
|
||||||
|
DebugSessionVisualizationSupport,
|
||||||
|
GetVisualizationDataArgs,
|
||||||
|
VisualizationBackend,
|
||||||
|
} from "./VisualizationBackend";
|
||||||
|
import { EventEmitter, EventSource } from "@hediet/std/events";
|
||||||
|
import { debug } from "vscode";
|
||||||
|
import { DebugSessionProxy } from "../proxies/DebugSessionProxy";
|
||||||
|
import { Disposable } from "@hediet/std/disposable";
|
||||||
|
import { DebuggerViewProxy } from "../proxies/DebuggerViewProxy";
|
||||||
|
import { autorun, reaction } from "mobx";
|
||||||
|
|
||||||
|
export class DispatchingVisualizationBackend implements VisualizationBackend {
|
||||||
|
public readonly dispose = Disposable.fn();
|
||||||
|
private readonly visualizationBackends = new Map<
|
||||||
|
DebugSessionProxy,
|
||||||
|
VisualizationBackend
|
||||||
|
>();
|
||||||
|
|
||||||
|
protected readonly onChangeEmitter = new EventEmitter();
|
||||||
|
public readonly onChange = this.onChangeEmitter;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly visualizationSupport: DebugSessionVisualizationSupport,
|
||||||
|
private readonly debuggerView: DebuggerViewProxy
|
||||||
|
) {
|
||||||
|
this.dispose.track(
|
||||||
|
debug.onDidTerminateDebugSession(session => {
|
||||||
|
const existing = [...this.visualizationBackends].find(
|
||||||
|
v => v[0].session === session
|
||||||
|
);
|
||||||
|
if (existing) {
|
||||||
|
this.visualizationBackends.delete(existing[0]);
|
||||||
|
existing[1].dispose();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
this.dispose.track({
|
||||||
|
dispose: () => {
|
||||||
|
for (const backend of this.visualizationBackends.values()) {
|
||||||
|
backend.dispose();
|
||||||
|
}
|
||||||
|
this.visualizationBackends.clear();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
this.dispose.track({
|
||||||
|
dispose: reaction(
|
||||||
|
() => this.debuggerView.activeDebugSession,
|
||||||
|
debugSession => {
|
||||||
|
if (debugSession !== undefined) {
|
||||||
|
this.onChangeEmitter.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private getVisualizationBackend(
|
||||||
|
debugSession: DebugSessionProxy
|
||||||
|
): VisualizationBackend | undefined {
|
||||||
|
const existing = this.visualizationBackends.get(debugSession);
|
||||||
|
if (existing) {
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newBackend = this.visualizationSupport.createBackend(
|
||||||
|
debugSession
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!newBackend) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
newBackend.onChange.sub(() => {
|
||||||
|
this.onChangeEmitter.emit();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.visualizationBackends.set(debugSession, newBackend);
|
||||||
|
|
||||||
|
return newBackend;
|
||||||
|
}
|
||||||
|
|
||||||
|
private get activeVisualizationBackend(): VisualizationBackend | undefined {
|
||||||
|
const activeDebugSession = this.debuggerView.activeDebugSession;
|
||||||
|
if (!activeDebugSession) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const backend = this.getVisualizationBackend(activeDebugSession);
|
||||||
|
return backend;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getVisualizationData(
|
||||||
|
args: GetVisualizationDataArgs
|
||||||
|
): Promise<
|
||||||
|
| { kind: "data"; result: DataExtractionResult }
|
||||||
|
| { kind: "error"; message: FormattedMessage }
|
||||||
|
> {
|
||||||
|
const activeDebugSession = this.debuggerView.activeDebugSession;
|
||||||
|
if (!activeDebugSession) {
|
||||||
|
return {
|
||||||
|
kind: "error",
|
||||||
|
message: "No active debug session.",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const backend = this.getVisualizationBackend(activeDebugSession);
|
||||||
|
if (!backend) {
|
||||||
|
return {
|
||||||
|
kind: "error",
|
||||||
|
message: `The debug adapter "${activeDebugSession.session.type}" is not supported.`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return await backend.getVisualizationData(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get expressionLanguageId(): string | undefined {
|
||||||
|
return this.activeVisualizationBackend?.expressionLanguageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getCompletions(
|
||||||
|
text: string,
|
||||||
|
column: number
|
||||||
|
): Promise<CompletionItem[]> {
|
||||||
|
return (
|
||||||
|
(await this.activeVisualizationBackend?.getCompletions(
|
||||||
|
text,
|
||||||
|
column
|
||||||
|
)) || []
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
import {
|
||||||
|
DataExtractionResult,
|
||||||
|
DataExtractorId,
|
||||||
|
GraphNode,
|
||||||
|
GraphVisualizationData,
|
||||||
|
} from "@hediet/debug-visualizer-data-extraction";
|
||||||
|
import { DebugSessionProxy } from "../proxies/DebugSessionProxy";
|
||||||
|
import {
|
||||||
|
DebugSessionVisualizationSupport,
|
||||||
|
VisualizationBackend,
|
||||||
|
GetVisualizationDataArgs,
|
||||||
|
VisualizationBackendBase,
|
||||||
|
} from "./VisualizationBackend";
|
||||||
|
import { parseEvaluationResultFromGenericDebugAdapter } from "./parseEvaluationResultFromGenericDebugAdapter";
|
||||||
|
import { FormattedMessage } from "../webviewContract";
|
||||||
|
import { hotClass, registerUpdateReconciler } from "@hediet/node-reload";
|
||||||
|
import { DebuggerViewProxy } from "../proxies/DebuggerViewProxy";
|
||||||
|
|
||||||
|
registerUpdateReconciler(module);
|
||||||
|
|
||||||
|
@hotClass(module)
|
||||||
|
export class GenericVisualizationSupport
|
||||||
|
implements DebugSessionVisualizationSupport {
|
||||||
|
constructor(private readonly debuggerView: DebuggerViewProxy) {}
|
||||||
|
|
||||||
|
createBackend(
|
||||||
|
session: DebugSessionProxy
|
||||||
|
): VisualizationBackend | undefined {
|
||||||
|
return new GenericVisualizationBackend(session, this.debuggerView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class GenericVisualizationBackend extends VisualizationBackendBase {
|
||||||
|
public readonly expressionLanguageId = "text";
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
debugSession: DebugSessionProxy,
|
||||||
|
debuggerView: DebuggerViewProxy
|
||||||
|
) {
|
||||||
|
super(debugSession, debuggerView);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getVisualizationData({
|
||||||
|
expression,
|
||||||
|
preferredExtractorId,
|
||||||
|
}: GetVisualizationDataArgs): Promise<
|
||||||
|
| { kind: "data"; result: DataExtractionResult }
|
||||||
|
| { kind: "error"; message: FormattedMessage }
|
||||||
|
> {
|
||||||
|
const frameId = this.debuggerView.getActiveStackFrameId(
|
||||||
|
this.debugSession
|
||||||
|
);
|
||||||
|
|
||||||
|
const finalExpression = this.getFinalExpression({
|
||||||
|
expression,
|
||||||
|
preferredExtractorId,
|
||||||
|
});
|
||||||
|
let reply: { result: string; variablesReference: number };
|
||||||
|
try {
|
||||||
|
reply = await this.debugSession.evaluate({
|
||||||
|
expression: finalExpression,
|
||||||
|
frameId,
|
||||||
|
context: this.getContext(),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Use structural information about variables
|
||||||
|
// from the evaluation response if present.
|
||||||
|
if (reply.variablesReference) {
|
||||||
|
const graph = await this.constructGraphFromVariablesReference(
|
||||||
|
reply.result,
|
||||||
|
reply.variablesReference
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
kind: "data",
|
||||||
|
result: {
|
||||||
|
availableExtractors: [],
|
||||||
|
usedExtractor: {
|
||||||
|
id: "generic" as any,
|
||||||
|
name: "Generic",
|
||||||
|
priority: 1,
|
||||||
|
},
|
||||||
|
data: graph,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return parseEvaluationResultFromGenericDebugAdapter(
|
||||||
|
reply.result,
|
||||||
|
{
|
||||||
|
debugAdapterType: this.debugSession.session
|
||||||
|
.configuration.type,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
kind: "error",
|
||||||
|
message: {
|
||||||
|
kind: "list",
|
||||||
|
items: [
|
||||||
|
"An error occurred while evaluating the expression:",
|
||||||
|
error.message,
|
||||||
|
`Used debug adapter: ${this.debugSession.session.configuration.type}`,
|
||||||
|
{
|
||||||
|
kind: "inlineList",
|
||||||
|
items: [
|
||||||
|
"Evaluated expression is",
|
||||||
|
{ kind: "code", content: finalExpression },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs GraphVisualizationData from a DAP variables
|
||||||
|
* reference by successively querying the debug adapter for
|
||||||
|
* variables. Objects are considered to be equivalent if
|
||||||
|
* they share the same variables reference (this is important
|
||||||
|
* for representing cyclic relationships).
|
||||||
|
*
|
||||||
|
* @param rootLabel - The root object's label
|
||||||
|
* @param rootVariablesReference - The root object's DAP variables reference
|
||||||
|
* @param maxDepth - The maximum depth to search at
|
||||||
|
* @param maxKnownNodes - The maximum number of nodes
|
||||||
|
*/
|
||||||
|
private async constructGraphFromVariablesReference(
|
||||||
|
rootLabel: string,
|
||||||
|
rootVariablesReference: number,
|
||||||
|
maxDepth: number = 30,
|
||||||
|
maxKnownNodes: number = 50
|
||||||
|
): Promise<GraphVisualizationData> {
|
||||||
|
// Perform a breadth-first search on the object to construct the graph
|
||||||
|
|
||||||
|
const graph: GraphVisualizationData = {
|
||||||
|
kind: { graph: true },
|
||||||
|
nodes: [],
|
||||||
|
edges: [],
|
||||||
|
};
|
||||||
|
const knownNodeIds: { [ref: number]: string } = {};
|
||||||
|
const bfsQueue: {
|
||||||
|
source: { id: string; name: string } | undefined;
|
||||||
|
label: string;
|
||||||
|
variablesReference: number;
|
||||||
|
depth: number;
|
||||||
|
}[] = [
|
||||||
|
{
|
||||||
|
source: undefined,
|
||||||
|
label: rootLabel,
|
||||||
|
variablesReference: rootVariablesReference,
|
||||||
|
depth: 0,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
let knownCount: number = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
const variable = bfsQueue.shift()!;
|
||||||
|
const hasChilds = variable.variablesReference > 0;
|
||||||
|
|
||||||
|
if (variable.depth > maxDepth) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let nodeId: string;
|
||||||
|
|
||||||
|
if (!hasChilds || !(variable.variablesReference in knownNodeIds)) {
|
||||||
|
// The variable is a leaf or an unvisited object: create the node.
|
||||||
|
|
||||||
|
const node: GraphNode = {
|
||||||
|
id: hasChilds
|
||||||
|
? `${variable.variablesReference}`
|
||||||
|
: `__${variable.label}@${knownCount}__`,
|
||||||
|
label: variable.label,
|
||||||
|
color: variable.depth == 0 ? "lightblue" : undefined,
|
||||||
|
shape: "box",
|
||||||
|
};
|
||||||
|
|
||||||
|
graph.nodes.push(node);
|
||||||
|
knownCount++;
|
||||||
|
|
||||||
|
if (hasChilds) {
|
||||||
|
knownNodeIds[variable.variablesReference] = node.id;
|
||||||
|
|
||||||
|
for (const child of await this.debugSession.getVariables({
|
||||||
|
variablesReference: variable.variablesReference,
|
||||||
|
})) {
|
||||||
|
bfsQueue.push({
|
||||||
|
source: { id: node.id, name: child.name },
|
||||||
|
label: child.value,
|
||||||
|
variablesReference: child.variablesReference,
|
||||||
|
depth: variable.depth + 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeId = node.id;
|
||||||
|
} else {
|
||||||
|
// The variable is a visited object (e.g. due to a cyclic reference)
|
||||||
|
|
||||||
|
nodeId = knownNodeIds[variable.variablesReference];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (variable.source) {
|
||||||
|
graph.edges.push({
|
||||||
|
from: variable.source.id,
|
||||||
|
to: nodeId,
|
||||||
|
label: variable.source.name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} while (bfsQueue.length > 0 && knownCount <= maxKnownNodes);
|
||||||
|
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getFinalExpression(args: {
|
||||||
|
expression: string;
|
||||||
|
preferredExtractorId: DataExtractorId | undefined;
|
||||||
|
}): string {
|
||||||
|
return args.expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getContext(): "watch" | "repl" {
|
||||||
|
// we will use "repl" as default so that results are not truncated.
|
||||||
|
return "repl";
|
||||||
|
}
|
||||||
|
}
|
||||||
395
extension/src/VisualizationBackend/JsVisualizationSupport.ts
Normal file
@@ -0,0 +1,395 @@
|
|||||||
|
import {
|
||||||
|
getExpressionForDataExtractorApi,
|
||||||
|
DataResult,
|
||||||
|
getExpressionToInitializeDataExtractorApi,
|
||||||
|
DataExtractionResult,
|
||||||
|
getExpressionToDetectDataExtractorApiPresence,
|
||||||
|
} from "@hediet/debug-visualizer-data-extraction";
|
||||||
|
import { DebugSessionProxy } from "../proxies/DebugSessionProxy";
|
||||||
|
import {
|
||||||
|
DebugSessionVisualizationSupport,
|
||||||
|
VisualizationBackend,
|
||||||
|
GetVisualizationDataArgs,
|
||||||
|
VisualizationBackendBase,
|
||||||
|
} from "./VisualizationBackend";
|
||||||
|
import { FormattedMessage } from "../webviewContract";
|
||||||
|
import { registerUpdateReconciler, hotClass } from "@hediet/node-reload";
|
||||||
|
import { Config } from "../Config";
|
||||||
|
import { DebuggerViewProxy } from "../proxies/DebuggerViewProxy";
|
||||||
|
import { readFileSync, existsSync } from "fs";
|
||||||
|
import { reaction, observable } from "mobx";
|
||||||
|
import {
|
||||||
|
workspace,
|
||||||
|
FileSystemWatcher,
|
||||||
|
CancellationTokenSource,
|
||||||
|
CancellationToken,
|
||||||
|
window,
|
||||||
|
} from "vscode";
|
||||||
|
import { ResettableTimeout } from "@hediet/std/timer";
|
||||||
|
|
||||||
|
registerUpdateReconciler(module);
|
||||||
|
|
||||||
|
@hotClass(module)
|
||||||
|
export class JsEvaluationEngine implements DebugSessionVisualizationSupport {
|
||||||
|
constructor(
|
||||||
|
private readonly debuggerView: DebuggerViewProxy,
|
||||||
|
private readonly config: Config
|
||||||
|
) {}
|
||||||
|
|
||||||
|
createBackend(
|
||||||
|
session: DebugSessionProxy
|
||||||
|
): VisualizationBackend | undefined {
|
||||||
|
const supportedDebugAdapters = [
|
||||||
|
"node",
|
||||||
|
"node2",
|
||||||
|
"extensionHost",
|
||||||
|
"chrome",
|
||||||
|
"pwa-chrome",
|
||||||
|
"pwa-node",
|
||||||
|
"pwa-extensionHost",
|
||||||
|
"node-terminal",
|
||||||
|
"pwa-msedge",
|
||||||
|
];
|
||||||
|
|
||||||
|
if (supportedDebugAdapters.indexOf(session.session.type) !== -1) {
|
||||||
|
return new JsVisualizationBackend(
|
||||||
|
session,
|
||||||
|
this.debuggerView,
|
||||||
|
this.config
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class JsVisualizationBackend extends VisualizationBackendBase {
|
||||||
|
public readonly expressionLanguageId = "javascript";
|
||||||
|
private apiInitialized = false;
|
||||||
|
private initializedPromise: Promise<void> | undefined = undefined;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
debugSession: DebugSessionProxy,
|
||||||
|
debuggerView: DebuggerViewProxy,
|
||||||
|
private readonly config: Config
|
||||||
|
) {
|
||||||
|
super(debugSession, debuggerView);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getContext(): "copy" | "repl" {
|
||||||
|
if (this.debugSession.session.type.startsWith("pwa-")) {
|
||||||
|
return "copy";
|
||||||
|
}
|
||||||
|
return "repl";
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getVisualizationData({
|
||||||
|
expression,
|
||||||
|
preferredExtractorId,
|
||||||
|
}: GetVisualizationDataArgs): Promise<
|
||||||
|
| { kind: "data"; result: DataExtractionResult }
|
||||||
|
| { kind: "error"; message: FormattedMessage }
|
||||||
|
> {
|
||||||
|
try {
|
||||||
|
await this.ensureRuntimeIsInjected();
|
||||||
|
|
||||||
|
const frameId = this.debuggerView.getActiveStackFrameId(
|
||||||
|
this.debugSession
|
||||||
|
);
|
||||||
|
|
||||||
|
const variableNames = new Array<string>();
|
||||||
|
if (frameId) {
|
||||||
|
const scopes = await this.debugSession.getScopes({ frameId });
|
||||||
|
const scopeVariables = await Promise.all(
|
||||||
|
scopes
|
||||||
|
.filter(s => !s.expensive)
|
||||||
|
.map(s =>
|
||||||
|
this.debugSession.getVariables({
|
||||||
|
variablesReference: s.variablesReference,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
for (const variables of scopeVariables) {
|
||||||
|
variableNames.push(
|
||||||
|
...variables
|
||||||
|
.filter(v => v.value !== "undefined")
|
||||||
|
.map(v => v.name)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (variableNames.length > 100) {
|
||||||
|
variableNames.length = 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const preferredExtractorExpr = preferredExtractorId
|
||||||
|
? `"${preferredExtractorId}"`
|
||||||
|
: "undefined";
|
||||||
|
|
||||||
|
const body = `${getExpressionForDataExtractorApi()}.getData(
|
||||||
|
e => (${expression}),
|
||||||
|
expr => eval(expr),
|
||||||
|
${preferredExtractorExpr},
|
||||||
|
{${variableNames.map(n => `${n}: ${n}`).join(",")}},
|
||||||
|
)`;
|
||||||
|
|
||||||
|
const wrappedExpr = `
|
||||||
|
(() => {
|
||||||
|
try {
|
||||||
|
return ${body};
|
||||||
|
} catch (e) {
|
||||||
|
return JSON.stringify({
|
||||||
|
kind: "Error",
|
||||||
|
message: e.message,
|
||||||
|
stack: e.stack
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
`;
|
||||||
|
|
||||||
|
const reply = await this.debugSession.evaluate({
|
||||||
|
expression: wrappedExpr,
|
||||||
|
frameId,
|
||||||
|
context: this.getContext(),
|
||||||
|
});
|
||||||
|
const resultStr = reply.result;
|
||||||
|
const jsonData =
|
||||||
|
this.getContext() === "copy"
|
||||||
|
? resultStr
|
||||||
|
: resultStr.substr(1, resultStr.length - 2);
|
||||||
|
const result = JSON.parse(jsonData) as DataResult;
|
||||||
|
|
||||||
|
if (result.kind === "NoExtractors") {
|
||||||
|
throw new Error("No extractors");
|
||||||
|
} else if (result.kind === "Error") {
|
||||||
|
throw new Error(result.message);
|
||||||
|
} else if (result.kind === "Data") {
|
||||||
|
return {
|
||||||
|
kind: "data",
|
||||||
|
result: result.extractionResult,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
throw new Error("Invalid Data");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
kind: "error",
|
||||||
|
message: error.message,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ensureRuntimeIsInjected(): Promise<void> | undefined {
|
||||||
|
if (this.apiInitialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.initializedPromise) {
|
||||||
|
return this.initializedPromise;
|
||||||
|
} else {
|
||||||
|
this.initializedPromise = this._ensureRuntimeIsInjected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _ensureRuntimeIsInjected(): Promise<void> {
|
||||||
|
const body = getExpressionToDetectDataExtractorApiPresence();
|
||||||
|
|
||||||
|
const reply = await this.debugSession.evaluate({
|
||||||
|
expression: body,
|
||||||
|
frameId: undefined,
|
||||||
|
context: this.getContext(),
|
||||||
|
});
|
||||||
|
const isApiInitialized = reply.result === "true";
|
||||||
|
|
||||||
|
if (!isApiInitialized) {
|
||||||
|
await this.initializeApi();
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.initializeCustomScripts();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async initializeApi(): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
// prefer existing is true, so that manually registered (possibly newer) extractors are not overwritten.
|
||||||
|
const expression = `${getExpressionToInitializeDataExtractorApi()}.registerDefaultExtractors(true);`;
|
||||||
|
|
||||||
|
await this.debugSession.evaluate({
|
||||||
|
expression,
|
||||||
|
frameId: undefined,
|
||||||
|
context: this.getContext(),
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@observable
|
||||||
|
private filesVersionId: number = 0;
|
||||||
|
|
||||||
|
private readonly fileChangeDebouncedScheduler = new DebouncedScheduler(100);
|
||||||
|
|
||||||
|
private async initializeCustomScripts(): Promise<void> {
|
||||||
|
await this.debugSession.evaluate({
|
||||||
|
expression: `global["${injectedScriptsKey}"] = {};`,
|
||||||
|
frameId: undefined,
|
||||||
|
context: "repl",
|
||||||
|
});
|
||||||
|
|
||||||
|
const watchers = new Map<string, WatchedFile>();
|
||||||
|
this.dispose.track({
|
||||||
|
dispose: () => {
|
||||||
|
for (const w of watchers.values()) {
|
||||||
|
w.watcher.dispose();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
reaction(
|
||||||
|
() => ({
|
||||||
|
customScriptPaths: [...this.config.customScriptPaths],
|
||||||
|
version: this.filesVersionId,
|
||||||
|
}),
|
||||||
|
async ({ customScriptPaths }) => {
|
||||||
|
const promises = new Array<Promise<[Result, WatchedFile]>>();
|
||||||
|
|
||||||
|
const activePaths = new Set<string>();
|
||||||
|
for (const fsPath of customScriptPaths) {
|
||||||
|
activePaths.add(fsPath);
|
||||||
|
let entry = watchers.get(fsPath);
|
||||||
|
if (!entry) {
|
||||||
|
entry = new WatchedFile(fsPath, this.debugSession);
|
||||||
|
watchers.set(fsPath, entry);
|
||||||
|
entry.watcher.onDidChange(() => {
|
||||||
|
this.fileChangeDebouncedScheduler.run(() => {
|
||||||
|
this.filesVersionId++;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
promises.push(entry.update().then(e => [e, entry!]));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [fsPath, entry] of watchers) {
|
||||||
|
if (!activePaths.has(fsPath)) {
|
||||||
|
promises.push(entry.remove().then(e => [e, entry]));
|
||||||
|
entry.watcher.dispose();
|
||||||
|
watchers.delete(fsPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const results = await Promise.all(promises);
|
||||||
|
const errors = results.filter(([r]) => r.error);
|
||||||
|
for (const [e, watcher] of errors) {
|
||||||
|
window.showErrorMessage(
|
||||||
|
`Error while evaluating "${watcher.fsPath}": ${
|
||||||
|
e.error!.message
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (promises.length > 0) {
|
||||||
|
this.onChangeEmitter.emit();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fireImmediately: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const injectedScriptsKey = `@hediet/debug-visualizer/injectedScripts`;
|
||||||
|
|
||||||
|
interface Result {
|
||||||
|
error?: { message: string };
|
||||||
|
}
|
||||||
|
|
||||||
|
class WatchedFile {
|
||||||
|
public static nextId = 0;
|
||||||
|
public readonly watcher = workspace.createFileSystemWatcher(this.fsPath);
|
||||||
|
public readonly id = WatchedFile.nextId++;
|
||||||
|
public lastContent: string | undefined = undefined;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public readonly fsPath: string,
|
||||||
|
private readonly debugSession: DebugSessionProxy
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public async update(): Promise<Result> {
|
||||||
|
if (!existsSync(this.fsPath)) {
|
||||||
|
return {
|
||||||
|
error: { message: `File does not exist.` },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const scriptContent = readFileSync(this.fsPath, {
|
||||||
|
encoding: "utf-8",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.lastContent === scriptContent) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
this.lastContent = scriptContent;
|
||||||
|
|
||||||
|
const expression = `
|
||||||
|
(
|
||||||
|
load => {
|
||||||
|
var module = {};
|
||||||
|
load(module);
|
||||||
|
global["${injectedScriptsKey}"]["${this.id}"] = module.exports;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
(
|
||||||
|
function (module) { ${scriptContent} }
|
||||||
|
)`;
|
||||||
|
try {
|
||||||
|
await this.debugSession.evaluate({
|
||||||
|
expression,
|
||||||
|
frameId: undefined,
|
||||||
|
context: "repl",
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
return { error: { message: e.message } };
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async remove(): Promise<Result> {
|
||||||
|
const expression = `(() => { delete global["${injectedScriptsKey}"]["${this.id}"]; })()`;
|
||||||
|
try {
|
||||||
|
await this.debugSession.evaluate({
|
||||||
|
expression,
|
||||||
|
frameId: undefined,
|
||||||
|
context: "repl",
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
return { error: { message: e.message } };
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DebouncedScheduler {
|
||||||
|
private timeout: NodeJS.Timeout | undefined;
|
||||||
|
|
||||||
|
constructor(private readonly debounceTimeout: number) {}
|
||||||
|
|
||||||
|
public run(action: () => void): void {
|
||||||
|
this.clear();
|
||||||
|
this.timeout = setTimeout(action, this.debounceTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
private clear() {
|
||||||
|
if (this.timeout) {
|
||||||
|
clearTimeout(this.timeout);
|
||||||
|
this.timeout = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void {
|
||||||
|
this.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
80
extension/src/VisualizationBackend/VisualizationBackend.ts
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import {
|
||||||
|
DataExtractionResult,
|
||||||
|
DataExtractorId,
|
||||||
|
} from "@hediet/debug-visualizer-data-extraction";
|
||||||
|
import { Disposable } from "@hediet/std/disposable";
|
||||||
|
import { DebugSessionProxy } from "../proxies/DebugSessionProxy";
|
||||||
|
import { CompletionItem, FormattedMessage } from "../webviewContract";
|
||||||
|
import { reaction } from "mobx";
|
||||||
|
import { DebuggerViewProxy } from "../proxies/DebuggerViewProxy";
|
||||||
|
import { EventEmitter, EventSource } from "@hediet/std/events";
|
||||||
|
|
||||||
|
export interface DebugSessionVisualizationSupport {
|
||||||
|
createBackend(session: DebugSessionProxy): VisualizationBackend | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VisualizationBackend extends Disposable {
|
||||||
|
readonly onChange: EventSource;
|
||||||
|
|
||||||
|
getVisualizationData(
|
||||||
|
args: GetVisualizationDataArgs
|
||||||
|
): Promise<
|
||||||
|
| { kind: "data"; result: DataExtractionResult }
|
||||||
|
| { kind: "error"; message: FormattedMessage }
|
||||||
|
>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The language that expressions must be written in.
|
||||||
|
*/
|
||||||
|
readonly expressionLanguageId: string | undefined;
|
||||||
|
|
||||||
|
getCompletions(text: string, column: number): Promise<CompletionItem[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GetVisualizationDataArgs {
|
||||||
|
expression: string;
|
||||||
|
preferredExtractorId: DataExtractorId | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class VisualizationBackendBase implements VisualizationBackend {
|
||||||
|
public readonly dispose = Disposable.fn();
|
||||||
|
|
||||||
|
protected readonly onChangeEmitter = new EventEmitter();
|
||||||
|
public readonly onChange = this.onChangeEmitter;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected readonly debugSession: DebugSessionProxy,
|
||||||
|
protected readonly debuggerView: DebuggerViewProxy
|
||||||
|
) {
|
||||||
|
this.dispose.track({
|
||||||
|
dispose: reaction(
|
||||||
|
() => debuggerView.getActiveStackFrameId(debugSession),
|
||||||
|
activeStackFrameId => {
|
||||||
|
if (activeStackFrameId !== undefined) {
|
||||||
|
this.onChangeEmitter.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract readonly expressionLanguageId: string | undefined;
|
||||||
|
|
||||||
|
public abstract getVisualizationData(
|
||||||
|
args: GetVisualizationDataArgs
|
||||||
|
): Promise<
|
||||||
|
| { kind: "data"; result: DataExtractionResult }
|
||||||
|
| { kind: "error"; message: FormattedMessage }
|
||||||
|
>;
|
||||||
|
|
||||||
|
public async getCompletions(
|
||||||
|
text: string,
|
||||||
|
column: number
|
||||||
|
): Promise<CompletionItem[]> {
|
||||||
|
return await this.debugSession.getCompletions({
|
||||||
|
text,
|
||||||
|
frameId: this.debuggerView.getActiveStackFrameId(this.debugSession),
|
||||||
|
column,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
6
extension/src/VisualizationBackend/index.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export * from "./VisualizationBackend";
|
||||||
|
|
||||||
|
export { ComposedVisualizationSupport } from "./ComposedVisualizationSupport";
|
||||||
|
export { JsEvaluationEngine } from "./JsVisualizationSupport";
|
||||||
|
export { GenericVisualizationSupport } from "./GenericVisualizationSupport";
|
||||||
|
export { ConfigurableVisualizationSupport } from "./ConfigurableVisualizationSupport";
|
||||||
@@ -2,7 +2,7 @@ import {
|
|||||||
DataExtractionResult,
|
DataExtractionResult,
|
||||||
isVisualizationData,
|
isVisualizationData,
|
||||||
} from "@hediet/debug-visualizer-data-extraction";
|
} from "@hediet/debug-visualizer-data-extraction";
|
||||||
import { FormattedMessage } from "../../webviewContract";
|
import { FormattedMessage } from "../webviewContract";
|
||||||
|
|
||||||
export interface ParseEvaluationResultContext {
|
export interface ParseEvaluationResultContext {
|
||||||
debugAdapterType: string;
|
debugAdapterType: string;
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import { DataExtractorId } from "@hediet/debug-visualizer-data-extraction";
|
import { DataExtractorId } from "@hediet/debug-visualizer-data-extraction";
|
||||||
import { DataExtractionState, CompletionItem } from "../webviewContract";
|
import { DataExtractionState, CompletionItem } from "../webviewContract";
|
||||||
|
|
||||||
export interface EvaluationWatchService {
|
export interface VisualizationWatchModel {
|
||||||
createEvaluationWatcher(
|
createWatch(
|
||||||
expression: string,
|
expression: string,
|
||||||
options: EvaluationWatcherOptions
|
options: VisualizationWatchOptions
|
||||||
): EvaluationWatcher;
|
): VisualizationWatch;
|
||||||
|
|
||||||
getCompletions(text: string, column: number): Promise<CompletionItem[]>;
|
getCompletions(text: string, column: number): Promise<CompletionItem[]>;
|
||||||
|
|
||||||
@@ -17,14 +17,17 @@ export interface EvaluationWatchService {
|
|||||||
readonly languageId: string | undefined;
|
readonly languageId: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EvaluationWatcherOptions {
|
export interface VisualizationWatchOptions {
|
||||||
preferredDataExtractor?: DataExtractorId | undefined;
|
preferredDataExtractor?: DataExtractorId | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EvaluationWatcher {
|
export interface VisualizationWatch {
|
||||||
|
/** This field is constant. */
|
||||||
readonly expression: string;
|
readonly expression: string;
|
||||||
|
|
||||||
/** This field is observable */
|
/** This field is observable */
|
||||||
readonly state: DataExtractionState;
|
readonly state: DataExtractionState;
|
||||||
|
|
||||||
/** This field is observable */
|
/** This field is observable */
|
||||||
readonly preferredDataExtractor: DataExtractorId | undefined;
|
readonly preferredDataExtractor: DataExtractorId | undefined;
|
||||||
|
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
import { DataExtractorId } from "@hediet/debug-visualizer-data-extraction";
|
||||||
|
import { hotClass } from "@hediet/node-reload";
|
||||||
|
import { Disposable } from "@hediet/std/disposable";
|
||||||
|
import { EventEmitter } from "@hediet/std/events";
|
||||||
|
import { wait } from "@hediet/std/timer";
|
||||||
|
import { action, observable } from "mobx";
|
||||||
|
import { CancellationToken, CancellationTokenSource } from "vscode";
|
||||||
|
import { VisualizationBackend } from "../VisualizationBackend/VisualizationBackend";
|
||||||
|
import { CompletionItem, DataExtractionState } from "../webviewContract";
|
||||||
|
import {
|
||||||
|
VisualizationWatch,
|
||||||
|
VisualizationWatchModel,
|
||||||
|
VisualizationWatchOptions,
|
||||||
|
} from "./VisualizationWatchModel";
|
||||||
|
|
||||||
|
@hotClass(module)
|
||||||
|
export class VisualizationWatchModelImpl implements VisualizationWatchModel {
|
||||||
|
public readonly dispose = Disposable.fn();
|
||||||
|
private readonly watchers = new Set<ObservableVisualizationWatch>();
|
||||||
|
|
||||||
|
constructor(private readonly visualizationBackend: VisualizationBackend) {
|
||||||
|
this.dispose.track(
|
||||||
|
visualizationBackend.onChange.sub(() => {
|
||||||
|
if (visualizationBackend.expressionLanguageId !== undefined) {
|
||||||
|
this.lastLanguageId =
|
||||||
|
visualizationBackend.expressionLanguageId;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
this.lastLanguageId = visualizationBackend.expressionLanguageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public createWatch(
|
||||||
|
expression: string,
|
||||||
|
options: VisualizationWatchOptions
|
||||||
|
): VisualizationWatch {
|
||||||
|
const w = new ObservableVisualizationWatch(
|
||||||
|
expression,
|
||||||
|
options,
|
||||||
|
this.visualizationBackend
|
||||||
|
);
|
||||||
|
w.onDispose.sub(() => {
|
||||||
|
this.watchers.delete(w);
|
||||||
|
});
|
||||||
|
this.watchers.add(w);
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
@observable
|
||||||
|
private lastLanguageId: string | undefined = undefined;
|
||||||
|
|
||||||
|
get languageId(): string | undefined {
|
||||||
|
return this.lastLanguageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCompletions(
|
||||||
|
text: string,
|
||||||
|
column: number
|
||||||
|
): Promise<CompletionItem[]> {
|
||||||
|
return this.visualizationBackend.getCompletions(text, column);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ObservableVisualizationWatch implements VisualizationWatch {
|
||||||
|
public readonly dispose = Disposable.fn();
|
||||||
|
private readonly onDisposeEmitter = new EventEmitter();
|
||||||
|
public readonly onDispose = this.onDisposeEmitter.asEvent();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public readonly expression: string,
|
||||||
|
options: VisualizationWatchOptions,
|
||||||
|
private readonly visualizationBackend: VisualizationBackend
|
||||||
|
) {
|
||||||
|
this._preferredDataExtractor = options.preferredDataExtractor;
|
||||||
|
|
||||||
|
this.dispose.track(
|
||||||
|
visualizationBackend.onChange.sub(() => {
|
||||||
|
this.refresh();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
this.dispose.track({
|
||||||
|
dispose: () => {
|
||||||
|
this.onDisposeEmitter.emit();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
this.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _preferredDataExtractor: DataExtractorId | undefined = undefined;
|
||||||
|
|
||||||
|
public get preferredDataExtractor(): DataExtractorId | undefined {
|
||||||
|
return this._preferredDataExtractor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
public setPreferredDataExtractor(id: DataExtractorId | undefined): void {
|
||||||
|
this._preferredDataExtractor = id;
|
||||||
|
this.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
private runningRefreshOperation: Disposable | undefined;
|
||||||
|
|
||||||
|
public refresh(): void {
|
||||||
|
if (this.runningRefreshOperation) {
|
||||||
|
this.runningRefreshOperation.dispose();
|
||||||
|
}
|
||||||
|
const tokenSource = new CancellationTokenSource();
|
||||||
|
this.runningRefreshOperation = {
|
||||||
|
dispose: () => {
|
||||||
|
tokenSource.cancel();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
this._refresh(tokenSource.token);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _refresh(token: CancellationToken): Promise<void> {
|
||||||
|
/*const session = this.debuggerView.activeDebugSession;
|
||||||
|
if (!session) {
|
||||||
|
this._state = { kind: "noDebugSession" };
|
||||||
|
return;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
//const frameId = this.debuggerView.activeFrameId;
|
||||||
|
|
||||||
|
this._state = { kind: "loading" };
|
||||||
|
|
||||||
|
/*
|
||||||
|
const visualizationBackend = this.getVisualizationBackend();
|
||||||
|
if (!visualizationBackend) {
|
||||||
|
this._state = {
|
||||||
|
kind: "error",
|
||||||
|
message: `The debug adapter "${session.session.type}" is not supported.`,
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
const result = await this.visualizationBackend.getVisualizationData({
|
||||||
|
expression: this.expression,
|
||||||
|
//frameId,
|
||||||
|
preferredExtractorId: this.preferredDataExtractor,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.kind === "error") {
|
||||||
|
// give cancellation requested more time in case of errors
|
||||||
|
await wait(330);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.isCancellationRequested) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._state = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@observable
|
||||||
|
public _state: DataExtractionState = { kind: "loading" };
|
||||||
|
public get state(): DataExtractionState {
|
||||||
|
return this._state;
|
||||||
|
}
|
||||||
|
}
|
||||||
2
extension/src/VisualizationWatchModel/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from "./VisualizationWatchModelImpl";
|
||||||
|
export * from "./VisualizationWatchModel";
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
import { Disposable } from "@hediet/std/disposable";
|
|
||||||
import { debug, DebugSession } from "vscode";
|
|
||||||
import { observable, action } from "mobx";
|
|
||||||
import { VsCodeDebugger } from "./VsCodeDebugger";
|
|
||||||
import { EnhancedDebugSession } from "./EnhancedDebugSession";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tracks the currently active debug session and its currently active stack frame.
|
|
||||||
* This is currently all faked. A proper API would be nice.
|
|
||||||
*/
|
|
||||||
export class VsCodeDebuggerView {
|
|
||||||
public readonly dispose = Disposable.fn();
|
|
||||||
|
|
||||||
@observable private _activeDebugSession: EnhancedDebugSession | undefined;
|
|
||||||
|
|
||||||
public get activeDebugSession(): EnhancedDebugSession | undefined {
|
|
||||||
return this._activeDebugSession;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get activeFrameId(): number | undefined {
|
|
||||||
if (!this._activeDebugSession) {
|
|
||||||
return undefined;
|
|
||||||
} else {
|
|
||||||
return this._activeDebugSession["activeStackFrame"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(private vsCodeDebugger: VsCodeDebugger) {
|
|
||||||
this.dispose.track(
|
|
||||||
debug.onDidChangeActiveDebugSession(activeSession => {
|
|
||||||
this.updateActiveDebugSession(activeSession);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
this.updateActiveDebugSession(debug.activeDebugSession);
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
private updateActiveDebugSession(activeSession: DebugSession | undefined) {
|
|
||||||
if (!activeSession) {
|
|
||||||
this._activeDebugSession = undefined;
|
|
||||||
} else {
|
|
||||||
const s = this.vsCodeDebugger.getEnhancedDebugSession(
|
|
||||||
activeSession
|
|
||||||
);
|
|
||||||
this._activeDebugSession = s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,15 +15,16 @@ registerUpdateReconciler(module);
|
|||||||
import { InternalWebviewManager } from "./webview/InternalWebviewManager";
|
import { InternalWebviewManager } from "./webview/InternalWebviewManager";
|
||||||
import { WebviewServer } from "./webview/WebviewServer";
|
import { WebviewServer } from "./webview/WebviewServer";
|
||||||
import { Config } from "./Config";
|
import { Config } from "./Config";
|
||||||
import { VsCodeDebugger } from "./debugger/VsCodeDebugger";
|
import { DebuggerProxy } from "./proxies/DebuggerProxy";
|
||||||
import { VsCodeDebuggerView } from "./debugger/VsCodeDebuggerView";
|
import { DebuggerViewProxy } from "./proxies/DebuggerViewProxy";
|
||||||
import { EvaluationWatchServiceImpl } from "./EvaluationWatchService";
|
import { VisualizationWatchModelImpl } from "./VisualizationWatchModel";
|
||||||
import {
|
import {
|
||||||
ComposedEvaluationEngine,
|
ComposedVisualizationSupport,
|
||||||
JsEvaluationEngine,
|
JsEvaluationEngine,
|
||||||
GenericEvaluationEngine,
|
GenericVisualizationSupport,
|
||||||
ConfiguredEvaluationEngine,
|
ConfigurableVisualizationSupport,
|
||||||
} from "./EvaluationWatchService/EvaluationEngine";
|
} from "./VisualizationBackend";
|
||||||
|
import { DispatchingVisualizationBackend } from "./VisualizationBackend/DispatchingVisualizationBackend";
|
||||||
|
|
||||||
export function activate(context: ExtensionContext) {
|
export function activate(context: ExtensionContext) {
|
||||||
context.subscriptions.push(
|
context.subscriptions.push(
|
||||||
@@ -37,18 +38,23 @@ export class Extension {
|
|||||||
public readonly dispose = Disposable.fn();
|
public readonly dispose = Disposable.fn();
|
||||||
|
|
||||||
private readonly config = new Config();
|
private readonly config = new Config();
|
||||||
private readonly debugger = this.dispose.track(new VsCodeDebugger());
|
private readonly debugger = this.dispose.track(new DebuggerProxy());
|
||||||
private readonly debuggerView = this.dispose.track(
|
private readonly debuggerView = this.dispose.track(
|
||||||
new VsCodeDebuggerView(this.debugger)
|
new DebuggerViewProxy(this.debugger)
|
||||||
);
|
);
|
||||||
|
|
||||||
public readonly dataSource = new EvaluationWatchServiceImpl(
|
public readonly dataSource = new VisualizationWatchModelImpl(
|
||||||
this.debuggerView,
|
new DispatchingVisualizationBackend(
|
||||||
new ComposedEvaluationEngine([
|
new ComposedVisualizationSupport([
|
||||||
new ConfiguredEvaluationEngine(this.config),
|
new ConfigurableVisualizationSupport(
|
||||||
new JsEvaluationEngine(),
|
this.config,
|
||||||
new GenericEvaluationEngine(),
|
this.debuggerView
|
||||||
])
|
),
|
||||||
|
new JsEvaluationEngine(this.debuggerView, this.config),
|
||||||
|
new GenericVisualizationSupport(this.debuggerView),
|
||||||
|
]),
|
||||||
|
this.debuggerView
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
private readonly server = new WebviewServer(this.dataSource, this.config);
|
private readonly server = new WebviewServer(this.dataSource, this.config);
|
||||||
@@ -82,7 +88,26 @@ export class Extension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const selection = editor.selection;
|
const selection = editor.selection;
|
||||||
const selectedText = editor.document.getText(selection);
|
|
||||||
|
let selectedText;
|
||||||
|
if (selection.isEmpty) {
|
||||||
|
const lineText = editor.document.lineAt(selection.start)
|
||||||
|
.text;
|
||||||
|
const regexp = /`(.*)`/g;
|
||||||
|
selectedText = "";
|
||||||
|
let match;
|
||||||
|
while ((match = regexp.exec(lineText))) {
|
||||||
|
if (
|
||||||
|
match.index <= selection.start.character &&
|
||||||
|
selection.start.character <=
|
||||||
|
match.index + match[0].length
|
||||||
|
) {
|
||||||
|
selectedText = match[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
selectedText = editor.document.getText(selection);
|
||||||
|
}
|
||||||
|
|
||||||
if (!selectedText) {
|
if (!selectedText) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import { DebugSession } from "vscode";
|
|||||||
import { CompletionItem } from "../webviewContract";
|
import { CompletionItem } from "../webviewContract";
|
||||||
import { observable } from "mobx";
|
import { observable } from "mobx";
|
||||||
|
|
||||||
export class EnhancedDebugSession {
|
export class DebugSessionProxy {
|
||||||
@observable protected activeStackFrame: number | undefined;
|
@observable private _activeStackFrameId: number | undefined;
|
||||||
|
|
||||||
constructor(public readonly session: DebugSession) {}
|
constructor(public readonly session: DebugSession) {}
|
||||||
|
|
||||||
@@ -46,6 +46,38 @@ export class EnhancedDebugSession {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async getScopes(args: { frameId: number }): Promise<Scope[]> {
|
||||||
|
try {
|
||||||
|
const reply = await this.session.customRequest("scopes", {
|
||||||
|
frameId: args.frameId,
|
||||||
|
});
|
||||||
|
if (!reply) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return reply.scopes;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getVariables(args: {
|
||||||
|
variablesReference: number;
|
||||||
|
}): Promise<Variable[]> {
|
||||||
|
try {
|
||||||
|
const reply = await this.session.customRequest("variables", {
|
||||||
|
variablesReference: args.variablesReference,
|
||||||
|
});
|
||||||
|
if (!reply) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return reply.variables;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates the given expression.
|
* Evaluates the given expression.
|
||||||
* If context is "watch", long results are usually shortened.
|
* If context is "watch", long results are usually shortened.
|
||||||
@@ -55,15 +87,31 @@ export class EnhancedDebugSession {
|
|||||||
expression: string;
|
expression: string;
|
||||||
frameId: number | undefined;
|
frameId: number | undefined;
|
||||||
context: "watch" | "repl" | "copy";
|
context: "watch" | "repl" | "copy";
|
||||||
}): Promise<{ result: string }> {
|
}): Promise<{ result: string; variablesReference: number }> {
|
||||||
const reply = await this.session.customRequest("evaluate", {
|
const reply = await this.session.customRequest("evaluate", {
|
||||||
expression: args.expression,
|
expression: args.expression,
|
||||||
frameId: args.frameId,
|
frameId: args.frameId,
|
||||||
context: args.context,
|
context: args.context,
|
||||||
});
|
});
|
||||||
return { result: reply.result };
|
return {
|
||||||
|
result: reply.result,
|
||||||
|
variablesReference: reply.variablesReference,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Scope {
|
||||||
|
name: string;
|
||||||
|
expensive: boolean;
|
||||||
|
variablesReference: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Variable {
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
variablesReference: number;
|
||||||
|
}
|
||||||
|
|
||||||
interface StackFrame {
|
interface StackFrame {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
@@ -2,26 +2,24 @@ import { Disposable } from "@hediet/std/disposable";
|
|||||||
import { debug, DebugSession } from "vscode";
|
import { debug, DebugSession } from "vscode";
|
||||||
import { EventEmitter } from "@hediet/std/events";
|
import { EventEmitter } from "@hediet/std/events";
|
||||||
import { runInAction } from "mobx";
|
import { runInAction } from "mobx";
|
||||||
import { EnhancedDebugSession } from "./EnhancedDebugSession";
|
import { DebugSessionProxy } from "./DebugSessionProxy";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decorates DebugSession instances and emits an event for new debug sessions.
|
* Decorates DebugSession instances and emits an event for new debug sessions.
|
||||||
*/
|
*/
|
||||||
export class VsCodeDebugger {
|
export class DebuggerProxy {
|
||||||
public readonly dispose = Disposable.fn();
|
public readonly dispose = Disposable.fn();
|
||||||
private readonly sessions = new Map<DebugSession, EnhancedDebugSession>();
|
private readonly sessions = new Map<DebugSession, DebugSessionProxy>();
|
||||||
|
|
||||||
private readonly _onDidStartDebugSession = new EventEmitter<{
|
private readonly _onDidStartDebugSession = new EventEmitter<{
|
||||||
session: EnhancedDebugSession;
|
session: DebugSessionProxy;
|
||||||
}>();
|
}>();
|
||||||
public readonly onDidStartDebugSession = this._onDidStartDebugSession.asEvent();
|
public readonly onDidStartDebugSession = this._onDidStartDebugSession.asEvent();
|
||||||
|
|
||||||
public getEnhancedDebugSession(
|
public getDebugSessionProxy(session: DebugSession): DebugSessionProxy {
|
||||||
session: DebugSession
|
|
||||||
): EnhancedDebugSession {
|
|
||||||
let result = this.sessions.get(session);
|
let result = this.sessions.get(session);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
result = new EnhancedDebugSession(session);
|
result = new DebugSessionProxy(session);
|
||||||
this.sessions.set(session, result);
|
this.sessions.set(session, result);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -38,9 +36,7 @@ export class VsCodeDebugger {
|
|||||||
}),
|
}),
|
||||||
debug.registerDebugAdapterTrackerFactory("*", {
|
debug.registerDebugAdapterTrackerFactory("*", {
|
||||||
createDebugAdapterTracker: session => {
|
createDebugAdapterTracker: session => {
|
||||||
const extendedSession = this.getEnhancedDebugSession(
|
const extendedSession = this.getDebugSessionProxy(session);
|
||||||
session
|
|
||||||
);
|
|
||||||
return {
|
return {
|
||||||
onDidSendMessage: async msg => {
|
onDidSendMessage: async msg => {
|
||||||
type Message =
|
type Message =
|
||||||
@@ -90,7 +86,7 @@ export class VsCodeDebugger {
|
|||||||
startFrame: 0,
|
startFrame: 0,
|
||||||
levels: 1,
|
levels: 1,
|
||||||
});
|
});
|
||||||
extendedSession["activeStackFrame"] =
|
extendedSession["_activeStackFrameId"] =
|
||||||
r.stackFrames.length > 0
|
r.stackFrames.length > 0
|
||||||
? r.stackFrames[0].id
|
? r.stackFrames[0].id
|
||||||
: undefined;
|
: undefined;
|
||||||
@@ -103,7 +99,7 @@ export class VsCodeDebugger {
|
|||||||
m.command === "stepOut"
|
m.command === "stepOut"
|
||||||
) {
|
) {
|
||||||
extendedSession[
|
extendedSession[
|
||||||
"activeStackFrame"
|
"_activeStackFrameId"
|
||||||
] = undefined;
|
] = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
41
extension/src/proxies/DebuggerViewProxy.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { Disposable } from "@hediet/std/disposable";
|
||||||
|
import { debug, DebugSession } from "vscode";
|
||||||
|
import { observable, action } from "mobx";
|
||||||
|
import { DebuggerProxy } from "./DebuggerProxy";
|
||||||
|
import { DebugSessionProxy } from "./DebugSessionProxy";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks the currently active debug session and its currently active stack frame.
|
||||||
|
* This is currently all faked. A proper API would be nice.
|
||||||
|
*/
|
||||||
|
export class DebuggerViewProxy {
|
||||||
|
public readonly dispose = Disposable.fn();
|
||||||
|
|
||||||
|
@observable private _activeDebugSession: DebugSessionProxy | undefined;
|
||||||
|
|
||||||
|
public get activeDebugSession(): DebugSessionProxy | undefined {
|
||||||
|
return this._activeDebugSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getActiveStackFrameId(
|
||||||
|
session: DebugSessionProxy
|
||||||
|
): number | undefined {
|
||||||
|
return session["_activeStackFrameId"];
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(private debuggerProxy: DebuggerProxy) {
|
||||||
|
this.dispose.track(
|
||||||
|
debug.onDidChangeActiveDebugSession(activeSession => {
|
||||||
|
this.updateActiveDebugSession(activeSession);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
this.updateActiveDebugSession(debug.activeDebugSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
private updateActiveDebugSession(activeSession: DebugSession | undefined) {
|
||||||
|
this._activeDebugSession = activeSession
|
||||||
|
? this.debuggerProxy.getDebugSessionProxy(activeSession)
|
||||||
|
: undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -90,11 +90,11 @@ function getDebugVisualizerWebviewHtml(
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta http-equiv="Content-Security-Policy" content="default-src * 'unsafe-inline' 'unsafe-eval'; script-src * 'unsafe-inline' 'unsafe-eval'; connect-src * 'unsafe-inline'; img-src * data: blob: 'unsafe-inline'; frame-src *; style-src * 'unsafe-inline'; worker-src * data: 'unsafe-inline' 'unsafe-eval'; font-src * 'unsafe-inline' 'unsafe-eval';">
|
<meta http-equiv="Content-Security-Policy" content="default-src * 'unsafe-inline' 'unsafe-eval'; script-src * 'unsafe-inline' 'unsafe-eval'; connect-src * 'unsafe-inline'; img-src * data: blob: 'unsafe-inline'; frame-src *; style-src * 'unsafe-inline'; worker-src * data: blob: data: 'unsafe-inline' 'unsafe-eval'; font-src * 'unsafe-inline' 'unsafe-eval' 'self' data: blob:;">
|
||||||
<style>
|
<style>
|
||||||
html { height: 100%; width: 100%; padding: 0; margin: 0; }
|
html { height: 100%; width: 100%; padding: 0; margin: 0; }
|
||||||
body { height: 100%; width: 100%; padding: 0; margin: 0; }
|
body { height: 100%; width: 100%; padding: 0; margin: 0; }
|
||||||
iframe { height: 100%; width: 100%; padding: 0; margin: 0; border: 0; display: block; }
|
iframe { height: 100%; width: 100%; padding: 0; margin: 0; border: 0; display: block; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -112,11 +112,11 @@ function getDebugVisualizerWebviewHtml(
|
|||||||
window.addEventListener('message', event => {
|
window.addEventListener('message', event => {
|
||||||
if (event.source === window.frames[0]) {
|
if (event.source === window.frames[0]) {
|
||||||
if (event.data.command === "setState") {
|
if (event.data.command === "setState") {
|
||||||
console.log("setState", event.data.state);
|
// console.log("setState", event.data.state);
|
||||||
api.setState(event.data.state);
|
api.setState(event.data.state);
|
||||||
}
|
}
|
||||||
if (event.data.command === "getState") {
|
if (event.data.command === "getState") {
|
||||||
console.log("getState, sent ", api.getState());
|
// console.log("getState, sent ", api.getState());
|
||||||
window.frames[0].postMessage({ command: "getStateResult", state: api.getState() }, "*");
|
window.frames[0].postMessage({ command: "getStateResult", state: api.getState() }, "*");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import { Disposable } from "@hediet/std/disposable";
|
|||||||
import { webviewContract } from "../webviewContract";
|
import { webviewContract } from "../webviewContract";
|
||||||
import { ConsoleRpcLogger, RequestHandlingError } from "@hediet/typed-json-rpc";
|
import { ConsoleRpcLogger, RequestHandlingError } from "@hediet/typed-json-rpc";
|
||||||
import {
|
import {
|
||||||
EvaluationWatcher,
|
VisualizationWatch,
|
||||||
EvaluationWatchService,
|
VisualizationWatchModel,
|
||||||
} from "../EvaluationWatchService";
|
} from "../VisualizationWatchModel";
|
||||||
import { WebSocketStream } from "@hediet/typed-json-rpc-websocket";
|
import { WebSocketStream } from "@hediet/typed-json-rpc-websocket";
|
||||||
import { observable, autorun } from "mobx";
|
import { observable, autorun } from "mobx";
|
||||||
import { WebviewServer } from "./WebviewServer";
|
import { WebviewServer } from "./WebviewServer";
|
||||||
@@ -15,12 +15,12 @@ import { Config } from "../Config";
|
|||||||
export class WebviewConnection {
|
export class WebviewConnection {
|
||||||
public readonly dispose = Disposable.fn();
|
public readonly dispose = Disposable.fn();
|
||||||
@observable
|
@observable
|
||||||
private watcher: EvaluationWatcher | undefined = undefined;
|
private watcher: VisualizationWatch | undefined = undefined;
|
||||||
|
|
||||||
private readonly client: typeof webviewContract["TClientInterface"];
|
private readonly client: typeof webviewContract["TClientInterface"];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
evaluationWatchService: EvaluationWatchService,
|
evaluationWatchService: VisualizationWatchModel,
|
||||||
stream: WebSocketStream,
|
stream: WebSocketStream,
|
||||||
server: WebviewServer,
|
server: WebviewServer,
|
||||||
config: Config,
|
config: Config,
|
||||||
@@ -55,19 +55,16 @@ export class WebviewConnection {
|
|||||||
setExpression: async ({ newExpression }) => {
|
setExpression: async ({ newExpression }) => {
|
||||||
throwIfNotAuthenticated();
|
throwIfNotAuthenticated();
|
||||||
|
|
||||||
let oldPreferredDataExtractor: EvaluationWatcher["preferredDataExtractor"];
|
let oldPreferredDataExtractor: VisualizationWatch["preferredDataExtractor"];
|
||||||
if (this.watcher) {
|
if (this.watcher) {
|
||||||
oldPreferredDataExtractor = this.watcher
|
oldPreferredDataExtractor = this.watcher
|
||||||
.preferredDataExtractor;
|
.preferredDataExtractor;
|
||||||
this.dispose.untrack(this.watcher).dispose();
|
this.dispose.untrack(this.watcher).dispose();
|
||||||
}
|
}
|
||||||
this.watcher = this.dispose.track(
|
this.watcher = this.dispose.track(
|
||||||
evaluationWatchService.createEvaluationWatcher(
|
evaluationWatchService.createWatch(newExpression, {
|
||||||
newExpression,
|
preferredDataExtractor: oldPreferredDataExtractor,
|
||||||
{
|
})
|
||||||
preferredDataExtractor: oldPreferredDataExtractor,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
openInBrowser: async ({}) => {
|
openInBrowser: async ({}) => {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import * as serveStatic from "serve-static";
|
|||||||
import { Config } from "../Config";
|
import { Config } from "../Config";
|
||||||
import cryptoRandomString = require("crypto-random-string");
|
import cryptoRandomString = require("crypto-random-string");
|
||||||
import { distPath } from "debug-visualizer-webview";
|
import { distPath } from "debug-visualizer-webview";
|
||||||
import { EvaluationWatchService } from "../EvaluationWatchService/EvaluationWatchService";
|
import { VisualizationWatchModel } from "../VisualizationWatchModel/VisualizationWatchModel";
|
||||||
import { URLSearchParams } from "url";
|
import { URLSearchParams } from "url";
|
||||||
import { autorun, reaction } from "mobx";
|
import { autorun, reaction } from "mobx";
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ export class WebviewServer {
|
|||||||
public readonly connections = new Set<WebviewConnection>();
|
public readonly connections = new Set<WebviewConnection>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
dataSource: EvaluationWatchService,
|
dataSource: VisualizationWatchModel,
|
||||||
private readonly config: Config
|
private readonly config: Config
|
||||||
) {
|
) {
|
||||||
const app = express();
|
const app = express();
|
||||||
@@ -28,11 +28,13 @@ export class WebviewServer {
|
|||||||
|
|
||||||
this.server = app.listen();
|
this.server = app.listen();
|
||||||
|
|
||||||
|
/*
|
||||||
console.log(
|
console.log(
|
||||||
`Serving "${distPath}" on port ${
|
`Serving "${distPath}" on port ${
|
||||||
(this.server.address() as AddressInfo).port
|
(this.server.address() as AddressInfo).port
|
||||||
}`
|
}`
|
||||||
);
|
);
|
||||||
|
*/
|
||||||
|
|
||||||
const wss = new WebSocket.Server({ server: this.server });
|
const wss = new WebSocket.Server({ server: this.server });
|
||||||
wss.on("connection", async ws => {
|
wss.on("connection", async ws => {
|
||||||
|
|||||||
@@ -20,8 +20,8 @@
|
|||||||
"react-dom": "^16.12.0",
|
"react-dom": "^16.12.0",
|
||||||
"react-measure": "^2.3.0",
|
"react-measure": "^2.3.0",
|
||||||
"@hediet/debug-visualizer-data-extraction": "*",
|
"@hediet/debug-visualizer-data-extraction": "*",
|
||||||
"@hediet/visualization-bundle": "^0.1.1",
|
"@hediet/visualization-bundle": "^0.2.1",
|
||||||
"@hediet/visualization-core": "^0.1.0",
|
"@hediet/visualization-core": "^0.2.0",
|
||||||
"@knuddels/mobx-logger": "^1.1.1",
|
"@knuddels/mobx-logger": "^1.1.1",
|
||||||
"less-loader": "^6.2.0"
|
"less-loader": "^6.2.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ export class App extends React.Component {
|
|||||||
require("../vscode-dark.scss");
|
require("../vscode-dark.scss");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(this.model.theme);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ export class ExpressionInput extends React.Component<{ model: Model }> {
|
|||||||
@action.bound
|
@action.bound
|
||||||
submit() {
|
submit() {
|
||||||
const val = this.model.getValue();
|
const val = this.model.getValue();
|
||||||
console.log(val);
|
//console.log(val);
|
||||||
this.props.model.setExpression(val);
|
this.props.model.setExpression(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ export class MonacoBridge {
|
|||||||
);
|
);
|
||||||
|
|
||||||
for (const file of commonTypes.keys()) {
|
for (const file of commonTypes.keys()) {
|
||||||
console.log(file);
|
|
||||||
this.dispose.track(
|
this.dispose.track(
|
||||||
monaco.languages.typescript.javascriptDefaults.addExtraLib(
|
monaco.languages.typescript.javascriptDefaults.addExtraLib(
|
||||||
commonTypes(file).default,
|
commonTypes(file).default,
|
||||||
|
|||||||
382
yarn.lock
@@ -487,10 +487,10 @@
|
|||||||
stacktracey "^1.2.112"
|
stacktracey "^1.2.112"
|
||||||
ws "^7.0.0"
|
ws "^7.0.0"
|
||||||
|
|
||||||
"@hediet/monaco-editor-react@^0.1.0":
|
"@hediet/monaco-editor-react@^0.1.1":
|
||||||
version "0.1.0"
|
version "0.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/@hediet/monaco-editor-react/-/monaco-editor-react-0.1.0.tgz#b00dfa28e2ffa09ecc748e35f4befc0e887947f2"
|
resolved "https://registry.yarnpkg.com/@hediet/monaco-editor-react/-/monaco-editor-react-0.1.1.tgz#041f805aeb188403c7876f0f364d2a429e706031"
|
||||||
integrity sha512-EFAmKW1u9ks2iqTP63qqLPUezKMAnK+UvZrvoRmUMCpRRxG9uduYGPQfASaHcIQYzOqzWaVKvCQN5wQQ+lSxIQ==
|
integrity sha512-0DZZfLcFNuc3Wrn+2eztnRloCBe6GV8zIrGT3LPdZlWYEigJT+Qh7ANvRHF0tCS5YPAFGQNZJcfzKbBfqRGo4w==
|
||||||
|
|
||||||
"@hediet/node-reload@^0.7.3":
|
"@hediet/node-reload@^0.7.3":
|
||||||
version "0.7.3"
|
version "0.7.3"
|
||||||
@@ -507,10 +507,10 @@
|
|||||||
stack-trace "^0.0.10"
|
stack-trace "^0.0.10"
|
||||||
ws "^7.0.0"
|
ws "^7.0.0"
|
||||||
|
|
||||||
"@hediet/semantic-json@^0.3.11":
|
"@hediet/semantic-json@^0.3.15":
|
||||||
version "0.3.11"
|
version "0.3.15"
|
||||||
resolved "https://registry.yarnpkg.com/@hediet/semantic-json/-/semantic-json-0.3.11.tgz#9420a89d30645ba333dfd4f3f2c120f973297ee2"
|
resolved "https://registry.yarnpkg.com/@hediet/semantic-json/-/semantic-json-0.3.15.tgz#e38f799b1a7dd2624a3ee2e05bca58cfe76cb58d"
|
||||||
integrity sha512-KKw6ZcYHiyfhanNmln/WlG4KvZnMi/Ojy8O6HB6sqfDC5XCcNYjccUMMtaX23F/Hox0dWJPFqXYs54KJAA5itg==
|
integrity sha512-8t1NXiYDF2wqIt1jEknxNnpucdtgFAI2MGSWnnewDhaYqWOJLMY/MxH60gDX03vycf2ySb6vEYpEwsiB6r0O3Q==
|
||||||
|
|
||||||
"@hediet/std@^0.6.0":
|
"@hediet/std@^0.6.0":
|
||||||
version "0.6.0"
|
version "0.6.0"
|
||||||
@@ -550,16 +550,16 @@
|
|||||||
"@hediet/std" "^0.6.0"
|
"@hediet/std" "^0.6.0"
|
||||||
io-ts "^1.8.6"
|
io-ts "^1.8.6"
|
||||||
|
|
||||||
"@hediet/visualization-bundle@^0.1.1":
|
"@hediet/visualization-bundle@^0.2.1":
|
||||||
version "0.1.1"
|
version "0.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/@hediet/visualization-bundle/-/visualization-bundle-0.1.1.tgz#dc36d772def977cb97292890afb3b369760c620b"
|
resolved "https://registry.yarnpkg.com/@hediet/visualization-bundle/-/visualization-bundle-0.2.1.tgz#397a6bff0ea12018a7a1cb1c182ef8c5de87328f"
|
||||||
integrity sha512-X0Y0MQQHpZkMDSM9naLC5F3LVlSq+nQ6dNYkNz+3sF6PdvSf6xxUbRL4qbum2QCLqNRoiEu/HO6fjCU/gBvysA==
|
integrity sha512-Qfyn8WbWGwuE5J1z8U7l8E5VKuG3DpS2JJOtKhlW1QW/rhqBWOLd5avifxqjWxiMIfqh3NTShp9gLHpmI2Bysw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@finos/perspective-viewer" "^0.5.2"
|
"@finos/perspective-viewer" "^0.5.2"
|
||||||
"@finos/perspective-viewer-d3fc" "^0.5.2"
|
"@finos/perspective-viewer-d3fc" "^0.5.2"
|
||||||
"@finos/perspective-viewer-datagrid" "^0.5.2"
|
"@finos/perspective-viewer-datagrid" "^0.5.2"
|
||||||
"@hediet/monaco-editor-react" "^0.1.0"
|
"@hediet/monaco-editor-react" "^0.1.1"
|
||||||
"@hediet/semantic-json" "^0.3.11"
|
"@hediet/semantic-json" "^0.3.15"
|
||||||
"@hediet/std" "^0.6.0"
|
"@hediet/std" "^0.6.0"
|
||||||
classnames "^2.2.6"
|
classnames "^2.2.6"
|
||||||
line-column "^1.0.2"
|
line-column "^1.0.2"
|
||||||
@@ -576,12 +576,12 @@
|
|||||||
vis-network "^8.0.0"
|
vis-network "^8.0.0"
|
||||||
viz.js "^2.1.2"
|
viz.js "^2.1.2"
|
||||||
|
|
||||||
"@hediet/visualization-core@^0.1.0":
|
"@hediet/visualization-core@^0.2.0":
|
||||||
version "0.1.0"
|
version "0.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/@hediet/visualization-core/-/visualization-core-0.1.0.tgz#f23706cbc6a9ffd411c300767077ca4c0c494c15"
|
resolved "https://registry.yarnpkg.com/@hediet/visualization-core/-/visualization-core-0.2.0.tgz#8fca0044d5d91e8c45354984ae9c131ef7850a76"
|
||||||
integrity sha512-v7aZnyJ0ax09x6mBqhVaJQVwos1X7nyEfymr85/wbvLuleDjisKUuLHBxGpmWYSBRFMZUKIHllaY48DEHjP8Ug==
|
integrity sha512-r/SYDUipaUSdu1JXL1X0Le5ZkBXVGbKXo6jkX0jFq3NPz/60+B4MnIQnk8D7TCWLXftGFtE6MSFejrE+miup4w==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@hediet/semantic-json" "^0.3.11"
|
"@hediet/semantic-json" "^0.3.15"
|
||||||
"@hediet/std" "^0.6.0"
|
"@hediet/std" "^0.6.0"
|
||||||
react "^16.12.0"
|
react "^16.12.0"
|
||||||
react-dom "^16.12.0"
|
react-dom "^16.12.0"
|
||||||
@@ -1623,6 +1623,14 @@ aws4@^1.8.0:
|
|||||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
|
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
|
||||||
integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
|
integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
|
||||||
|
|
||||||
|
azure-devops-node-api@^10.2.2:
|
||||||
|
version "10.2.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/azure-devops-node-api/-/azure-devops-node-api-10.2.2.tgz#9f557e622dd07bbaa9bd5e7e84e17c761e2151b2"
|
||||||
|
integrity sha512-4TVv2X7oNStT0vLaEfExmy3J4/CzfuXolEcQl/BRUmvGySqKStTG2O55/hUQ0kM7UJlZBLgniM0SBq4d/WkKow==
|
||||||
|
dependencies:
|
||||||
|
tunnel "0.0.6"
|
||||||
|
typed-rest-client "^1.8.4"
|
||||||
|
|
||||||
babel-code-frame@^6.22.0:
|
babel-code-frame@^6.22.0:
|
||||||
version "6.26.0"
|
version "6.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
|
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
|
||||||
@@ -1789,7 +1797,7 @@ bonjour@^3.5.0:
|
|||||||
multicast-dns "^6.0.1"
|
multicast-dns "^6.0.1"
|
||||||
multicast-dns-service-types "^1.1.0"
|
multicast-dns-service-types "^1.1.0"
|
||||||
|
|
||||||
boolbase@~1.0.0:
|
boolbase@^1.0.0, boolbase@~1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
|
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
|
||||||
integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
|
integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
|
||||||
@@ -1930,6 +1938,11 @@ bubleify@^1.1.0, bubleify@^1.2.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
buble "^0.19.3"
|
buble "^0.19.3"
|
||||||
|
|
||||||
|
buffer-crc32@~0.2.3:
|
||||||
|
version "0.2.13"
|
||||||
|
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
|
||||||
|
integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
|
||||||
|
|
||||||
buffer-from@^1.0.0:
|
buffer-from@^1.0.0:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
|
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
|
||||||
@@ -2020,6 +2033,14 @@ caching-transform@^4.0.0:
|
|||||||
package-hash "^4.0.0"
|
package-hash "^4.0.0"
|
||||||
write-file-atomic "^3.0.0"
|
write-file-atomic "^3.0.0"
|
||||||
|
|
||||||
|
call-bind@^1.0.0:
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
|
||||||
|
integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
|
||||||
|
dependencies:
|
||||||
|
function-bind "^1.1.1"
|
||||||
|
get-intrinsic "^1.0.2"
|
||||||
|
|
||||||
camel-case@3.0.x:
|
camel-case@3.0.x:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73"
|
resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73"
|
||||||
@@ -2096,6 +2117,30 @@ check-error@^1.0.2:
|
|||||||
resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
|
resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
|
||||||
integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=
|
integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=
|
||||||
|
|
||||||
|
cheerio-select@^1.5.0:
|
||||||
|
version "1.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-1.5.0.tgz#faf3daeb31b17c5e1a9dabcee288aaf8aafa5823"
|
||||||
|
integrity sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==
|
||||||
|
dependencies:
|
||||||
|
css-select "^4.1.3"
|
||||||
|
css-what "^5.0.1"
|
||||||
|
domelementtype "^2.2.0"
|
||||||
|
domhandler "^4.2.0"
|
||||||
|
domutils "^2.7.0"
|
||||||
|
|
||||||
|
cheerio@^1.0.0-rc.9:
|
||||||
|
version "1.0.0-rc.10"
|
||||||
|
resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.10.tgz#2ba3dcdfcc26e7956fc1f440e61d51c643379f3e"
|
||||||
|
integrity sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==
|
||||||
|
dependencies:
|
||||||
|
cheerio-select "^1.5.0"
|
||||||
|
dom-serializer "^1.3.2"
|
||||||
|
domhandler "^4.2.0"
|
||||||
|
htmlparser2 "^6.1.0"
|
||||||
|
parse5 "^6.0.1"
|
||||||
|
parse5-htmlparser2-tree-adapter "^6.0.1"
|
||||||
|
tslib "^2.2.0"
|
||||||
|
|
||||||
chevrotain@^6.5.0:
|
chevrotain@^6.5.0:
|
||||||
version "6.5.0"
|
version "6.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/chevrotain/-/chevrotain-6.5.0.tgz#dcbef415516b0af80fd423cc0d96b28d3f11374e"
|
resolved "https://registry.yarnpkg.com/chevrotain/-/chevrotain-6.5.0.tgz#dcbef415516b0af80fd423cc0d96b28d3f11374e"
|
||||||
@@ -2431,6 +2476,11 @@ commander@^2.12.1, commander@^2.20.0:
|
|||||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
|
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
|
||||||
integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
|
integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
|
||||||
|
|
||||||
|
commander@^6.1.0:
|
||||||
|
version "6.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c"
|
||||||
|
integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==
|
||||||
|
|
||||||
commander@~2.19.0:
|
commander@~2.19.0:
|
||||||
version "2.19.0"
|
version "2.19.0"
|
||||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
|
resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
|
||||||
@@ -2813,6 +2863,17 @@ css-select@^1.1.0:
|
|||||||
domutils "1.5.1"
|
domutils "1.5.1"
|
||||||
nth-check "~1.0.1"
|
nth-check "~1.0.1"
|
||||||
|
|
||||||
|
css-select@^4.1.3:
|
||||||
|
version "4.1.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067"
|
||||||
|
integrity sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==
|
||||||
|
dependencies:
|
||||||
|
boolbase "^1.0.0"
|
||||||
|
css-what "^5.0.0"
|
||||||
|
domhandler "^4.2.0"
|
||||||
|
domutils "^2.6.0"
|
||||||
|
nth-check "^2.0.0"
|
||||||
|
|
||||||
css-system-font-keywords@^1.0.0:
|
css-system-font-keywords@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/css-system-font-keywords/-/css-system-font-keywords-1.0.0.tgz#85c6f086aba4eb32c571a3086affc434b84823ed"
|
resolved "https://registry.yarnpkg.com/css-system-font-keywords/-/css-system-font-keywords-1.0.0.tgz#85c6f086aba4eb32c571a3086affc434b84823ed"
|
||||||
@@ -2823,6 +2884,11 @@ css-what@2.1:
|
|||||||
resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2"
|
resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2"
|
||||||
integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==
|
integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==
|
||||||
|
|
||||||
|
css-what@^5.0.0, css-what@^5.0.1:
|
||||||
|
version "5.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.0.1.tgz#3efa820131f4669a8ac2408f9c32e7c7de9f4cad"
|
||||||
|
integrity sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==
|
||||||
|
|
||||||
csscolorparser@~1.0.3:
|
csscolorparser@~1.0.3:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/csscolorparser/-/csscolorparser-1.0.3.tgz#b34f391eea4da8f3e98231e2ccd8df9c041f171b"
|
resolved "https://registry.yarnpkg.com/csscolorparser/-/csscolorparser-1.0.3.tgz#b34f391eea4da8f3e98231e2ccd8df9c041f171b"
|
||||||
@@ -3396,6 +3462,11 @@ delegates@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
|
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
|
||||||
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
|
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
|
||||||
|
|
||||||
|
denodeify@^1.2.1:
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/denodeify/-/denodeify-1.2.1.tgz#3a36287f5034e699e7577901052c2e6c94251631"
|
||||||
|
integrity sha1-OjYof1A05pnnV3kBBSwubJQlFjE=
|
||||||
|
|
||||||
depd@~1.1.2:
|
depd@~1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
|
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
|
||||||
@@ -3507,6 +3578,15 @@ dom-serializer@0:
|
|||||||
domelementtype "^1.3.0"
|
domelementtype "^1.3.0"
|
||||||
entities "^1.1.1"
|
entities "^1.1.1"
|
||||||
|
|
||||||
|
dom-serializer@^1.0.1, dom-serializer@^1.3.2:
|
||||||
|
version "1.3.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91"
|
||||||
|
integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==
|
||||||
|
dependencies:
|
||||||
|
domelementtype "^2.0.1"
|
||||||
|
domhandler "^4.2.0"
|
||||||
|
entities "^2.0.0"
|
||||||
|
|
||||||
dom4@^2.1.5:
|
dom4@^2.1.5:
|
||||||
version "2.1.5"
|
version "2.1.5"
|
||||||
resolved "https://registry.yarnpkg.com/dom4/-/dom4-2.1.5.tgz#f98a94eb67b340f0fa5b42b0ee9c38cda035428e"
|
resolved "https://registry.yarnpkg.com/dom4/-/dom4-2.1.5.tgz#f98a94eb67b340f0fa5b42b0ee9c38cda035428e"
|
||||||
@@ -3522,6 +3602,11 @@ domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1:
|
|||||||
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f"
|
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f"
|
||||||
integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==
|
integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==
|
||||||
|
|
||||||
|
domelementtype@^2.0.1, domelementtype@^2.2.0:
|
||||||
|
version "2.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57"
|
||||||
|
integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==
|
||||||
|
|
||||||
domhandler@^2.3.0:
|
domhandler@^2.3.0:
|
||||||
version "2.4.2"
|
version "2.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803"
|
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803"
|
||||||
@@ -3529,6 +3614,13 @@ domhandler@^2.3.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
domelementtype "1"
|
domelementtype "1"
|
||||||
|
|
||||||
|
domhandler@^4.0.0, domhandler@^4.2.0:
|
||||||
|
version "4.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.0.tgz#f9768a5f034be60a89a27c2e4d0f74eba0d8b059"
|
||||||
|
integrity sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==
|
||||||
|
dependencies:
|
||||||
|
domelementtype "^2.2.0"
|
||||||
|
|
||||||
domutils@1.5.1:
|
domutils@1.5.1:
|
||||||
version "1.5.1"
|
version "1.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf"
|
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf"
|
||||||
@@ -3545,6 +3637,15 @@ domutils@^1.5.1:
|
|||||||
dom-serializer "0"
|
dom-serializer "0"
|
||||||
domelementtype "1"
|
domelementtype "1"
|
||||||
|
|
||||||
|
domutils@^2.5.2, domutils@^2.6.0, domutils@^2.7.0:
|
||||||
|
version "2.7.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.7.0.tgz#8ebaf0c41ebafcf55b0b72ec31c56323712c5442"
|
||||||
|
integrity sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==
|
||||||
|
dependencies:
|
||||||
|
dom-serializer "^1.0.1"
|
||||||
|
domelementtype "^2.2.0"
|
||||||
|
domhandler "^4.2.0"
|
||||||
|
|
||||||
dotignore@~0.1.2:
|
dotignore@~0.1.2:
|
||||||
version "0.1.2"
|
version "0.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/dotignore/-/dotignore-0.1.2.tgz#f942f2200d28c3a76fbdd6f0ee9f3257c8a2e905"
|
resolved "https://registry.yarnpkg.com/dotignore/-/dotignore-0.1.2.tgz#f942f2200d28c3a76fbdd6f0ee9f3257c8a2e905"
|
||||||
@@ -3681,6 +3782,16 @@ entities@^1.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
|
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
|
||||||
integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==
|
integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==
|
||||||
|
|
||||||
|
entities@^2.0.0:
|
||||||
|
version "2.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
|
||||||
|
integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
|
||||||
|
|
||||||
|
entities@~2.0.0:
|
||||||
|
version "2.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f"
|
||||||
|
integrity sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==
|
||||||
|
|
||||||
errno@^0.1.1, errno@^0.1.3, errno@~0.1.7:
|
errno@^0.1.1, errno@^0.1.3, errno@~0.1.7:
|
||||||
version "0.1.7"
|
version "0.1.7"
|
||||||
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
|
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
|
||||||
@@ -4054,6 +4165,13 @@ faye-websocket@~0.11.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
websocket-driver ">=0.5.1"
|
websocket-driver ">=0.5.1"
|
||||||
|
|
||||||
|
fd-slicer@~1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e"
|
||||||
|
integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=
|
||||||
|
dependencies:
|
||||||
|
pend "~1.2.0"
|
||||||
|
|
||||||
figgy-pudding@^3.5.1:
|
figgy-pudding@^3.5.1:
|
||||||
version "3.5.1"
|
version "3.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790"
|
resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790"
|
||||||
@@ -4387,6 +4505,15 @@ get-func-name@^2.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
|
resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
|
||||||
integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=
|
integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=
|
||||||
|
|
||||||
|
get-intrinsic@^1.0.2:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6"
|
||||||
|
integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==
|
||||||
|
dependencies:
|
||||||
|
function-bind "^1.1.1"
|
||||||
|
has "^1.0.3"
|
||||||
|
has-symbols "^1.0.1"
|
||||||
|
|
||||||
get-node-dimensions@^1.2.1:
|
get-node-dimensions@^1.2.1:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/get-node-dimensions/-/get-node-dimensions-1.2.1.tgz#fb7b4bb57060fb4247dd51c9d690dfbec56b0823"
|
resolved "https://registry.yarnpkg.com/get-node-dimensions/-/get-node-dimensions-1.2.1.tgz#fb7b4bb57060fb4247dd51c9d690dfbec56b0823"
|
||||||
@@ -4837,6 +4964,18 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4:
|
|||||||
once "^1.3.0"
|
once "^1.3.0"
|
||||||
path-is-absolute "^1.0.0"
|
path-is-absolute "^1.0.0"
|
||||||
|
|
||||||
|
glob@^7.0.6:
|
||||||
|
version "7.1.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90"
|
||||||
|
integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==
|
||||||
|
dependencies:
|
||||||
|
fs.realpath "^1.0.0"
|
||||||
|
inflight "^1.0.4"
|
||||||
|
inherits "2"
|
||||||
|
minimatch "^3.0.4"
|
||||||
|
once "^1.3.0"
|
||||||
|
path-is-absolute "^1.0.0"
|
||||||
|
|
||||||
glob@^7.1.6, glob@~7.1.6:
|
glob@^7.1.6, glob@~7.1.6:
|
||||||
version "7.1.6"
|
version "7.1.6"
|
||||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
|
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
|
||||||
@@ -5305,6 +5444,16 @@ htmlparser2@^3.3.0:
|
|||||||
inherits "^2.0.1"
|
inherits "^2.0.1"
|
||||||
readable-stream "^3.1.1"
|
readable-stream "^3.1.1"
|
||||||
|
|
||||||
|
htmlparser2@^6.1.0:
|
||||||
|
version "6.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7"
|
||||||
|
integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==
|
||||||
|
dependencies:
|
||||||
|
domelementtype "^2.0.1"
|
||||||
|
domhandler "^4.0.0"
|
||||||
|
domutils "^2.5.2"
|
||||||
|
entities "^2.0.0"
|
||||||
|
|
||||||
http-deceiver@^1.2.7:
|
http-deceiver@^1.2.7:
|
||||||
version "1.2.7"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87"
|
resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87"
|
||||||
@@ -5416,6 +5565,11 @@ ignore@^3.3.5:
|
|||||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043"
|
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043"
|
||||||
integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==
|
integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==
|
||||||
|
|
||||||
|
ignore@^5.1.8:
|
||||||
|
version "5.1.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
|
||||||
|
integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
|
||||||
|
|
||||||
image-palette@^2.1.0:
|
image-palette@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/image-palette/-/image-palette-2.1.0.tgz#d976525a1df75964ca125d2dba2741e92905547f"
|
resolved "https://registry.yarnpkg.com/image-palette/-/image-palette-2.1.0.tgz#d976525a1df75964ca125d2dba2741e92905547f"
|
||||||
@@ -6132,6 +6286,11 @@ less@^3.11.3:
|
|||||||
native-request "^1.0.5"
|
native-request "^1.0.5"
|
||||||
source-map "~0.6.0"
|
source-map "~0.6.0"
|
||||||
|
|
||||||
|
leven@^3.1.0:
|
||||||
|
version "3.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
|
||||||
|
integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==
|
||||||
|
|
||||||
levn@~0.3.0:
|
levn@~0.3.0:
|
||||||
version "0.3.0"
|
version "0.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
|
resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
|
||||||
@@ -6156,6 +6315,13 @@ line-column@^1.0.2:
|
|||||||
isarray "^1.0.0"
|
isarray "^1.0.0"
|
||||||
isobject "^2.0.0"
|
isobject "^2.0.0"
|
||||||
|
|
||||||
|
linkify-it@^2.0.0:
|
||||||
|
version "2.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.2.0.tgz#e3b54697e78bf915c70a38acd78fd09e0058b1cf"
|
||||||
|
integrity sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==
|
||||||
|
dependencies:
|
||||||
|
uc.micro "^1.0.1"
|
||||||
|
|
||||||
lit-html@^1.1.2:
|
lit-html@^1.1.2:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-1.2.1.tgz#1fb933dc1e2ddc095f60b8086277d4fcd9d62cc8"
|
resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-1.2.1.tgz#1fb933dc1e2ddc095f60b8086277d4fcd9d62cc8"
|
||||||
@@ -6368,6 +6534,17 @@ marching-simplex-table@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
convex-hull "^1.0.3"
|
convex-hull "^1.0.3"
|
||||||
|
|
||||||
|
markdown-it@^10.0.0:
|
||||||
|
version "10.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-10.0.0.tgz#abfc64f141b1722d663402044e43927f1f50a8dc"
|
||||||
|
integrity sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==
|
||||||
|
dependencies:
|
||||||
|
argparse "^1.0.7"
|
||||||
|
entities "~2.0.0"
|
||||||
|
linkify-it "^2.0.0"
|
||||||
|
mdurl "^1.0.1"
|
||||||
|
uc.micro "^1.0.5"
|
||||||
|
|
||||||
marky@^1.2.0:
|
marky@^1.2.0:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/marky/-/marky-1.2.1.tgz#a3fcf82ffd357756b8b8affec9fdbf3a30dc1b02"
|
resolved "https://registry.yarnpkg.com/marky/-/marky-1.2.1.tgz#a3fcf82ffd357756b8b8affec9fdbf3a30dc1b02"
|
||||||
@@ -6423,6 +6600,11 @@ md5.js@^1.3.4:
|
|||||||
inherits "^2.0.1"
|
inherits "^2.0.1"
|
||||||
safe-buffer "^5.1.2"
|
safe-buffer "^5.1.2"
|
||||||
|
|
||||||
|
mdurl@^1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
|
||||||
|
integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=
|
||||||
|
|
||||||
media-typer@0.3.0:
|
media-typer@0.3.0:
|
||||||
version "0.3.0"
|
version "0.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
||||||
@@ -6507,7 +6689,7 @@ mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24:
|
|||||||
dependencies:
|
dependencies:
|
||||||
mime-db "1.40.0"
|
mime-db "1.40.0"
|
||||||
|
|
||||||
mime@1.6.0, mime@^1.4.1:
|
mime@1.6.0, mime@^1.3.4, mime@^1.4.1:
|
||||||
version "1.6.0"
|
version "1.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
|
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
|
||||||
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
|
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
|
||||||
@@ -6776,6 +6958,11 @@ murmurhash-js@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/murmurhash-js/-/murmurhash-js-1.0.0.tgz#b06278e21fc6c37fa5313732b0412bcb6ae15f51"
|
resolved "https://registry.yarnpkg.com/murmurhash-js/-/murmurhash-js-1.0.0.tgz#b06278e21fc6c37fa5313732b0412bcb6ae15f51"
|
||||||
integrity sha1-sGJ44h/Gw3+lMTcysEEry2rhX1E=
|
integrity sha1-sGJ44h/Gw3+lMTcysEEry2rhX1E=
|
||||||
|
|
||||||
|
mute-stream@~0.0.4:
|
||||||
|
version "0.0.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
|
||||||
|
integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
|
||||||
|
|
||||||
nan@^2.12.1:
|
nan@^2.12.1:
|
||||||
version "2.14.0"
|
version "2.14.0"
|
||||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
|
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
|
||||||
@@ -7053,6 +7240,13 @@ npmlog@^4.0.2:
|
|||||||
gauge "~2.7.3"
|
gauge "~2.7.3"
|
||||||
set-blocking "~2.0.0"
|
set-blocking "~2.0.0"
|
||||||
|
|
||||||
|
nth-check@^2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.0.tgz#1bb4f6dac70072fc313e8c9cd1417b5074c0a125"
|
||||||
|
integrity sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==
|
||||||
|
dependencies:
|
||||||
|
boolbase "^1.0.0"
|
||||||
|
|
||||||
nth-check@~1.0.1:
|
nth-check@~1.0.1:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c"
|
resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c"
|
||||||
@@ -7135,6 +7329,11 @@ object-inspect@^1.7.0, object-inspect@~1.7.0:
|
|||||||
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67"
|
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67"
|
||||||
integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==
|
integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==
|
||||||
|
|
||||||
|
object-inspect@^1.9.0:
|
||||||
|
version "1.10.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.3.tgz#c2aa7d2d09f50c99375704f7a0adf24c5782d369"
|
||||||
|
integrity sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==
|
||||||
|
|
||||||
object-is@^1.0.1:
|
object-is@^1.0.1:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.2.tgz#6b80eb84fe451498f65007982f035a5b445edec4"
|
resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.2.tgz#6b80eb84fe451498f65007982f035a5b445edec4"
|
||||||
@@ -7279,7 +7478,7 @@ os-tmpdir@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
|
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
|
||||||
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
|
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
|
||||||
|
|
||||||
osenv@^0.1.4:
|
osenv@^0.1.3, osenv@^0.1.4:
|
||||||
version "0.1.5"
|
version "0.1.5"
|
||||||
resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
|
resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
|
||||||
integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
|
integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
|
||||||
@@ -7426,6 +7625,13 @@ parse-rect@^1.2.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
pick-by-alias "^1.2.0"
|
pick-by-alias "^1.2.0"
|
||||||
|
|
||||||
|
parse-semver@^1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/parse-semver/-/parse-semver-1.1.1.tgz#9a4afd6df063dc4826f93fba4a99cf223f666cb8"
|
||||||
|
integrity sha1-mkr9bfBj3Egm+T+6SpnPIj9mbLg=
|
||||||
|
dependencies:
|
||||||
|
semver "^5.1.0"
|
||||||
|
|
||||||
parse-svg-path@^0.1.2:
|
parse-svg-path@^0.1.2:
|
||||||
version "0.1.2"
|
version "0.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/parse-svg-path/-/parse-svg-path-0.1.2.tgz#7a7ec0d1eb06fa5325c7d3e009b859a09b5d49eb"
|
resolved "https://registry.yarnpkg.com/parse-svg-path/-/parse-svg-path-0.1.2.tgz#7a7ec0d1eb06fa5325c7d3e009b859a09b5d49eb"
|
||||||
@@ -7436,6 +7642,18 @@ parse-unit@^1.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/parse-unit/-/parse-unit-1.0.1.tgz#7e1bb6d5bef3874c28e392526a2541170291eecf"
|
resolved "https://registry.yarnpkg.com/parse-unit/-/parse-unit-1.0.1.tgz#7e1bb6d5bef3874c28e392526a2541170291eecf"
|
||||||
integrity sha1-fhu21b7zh0wo45JSaiVBFwKR7s8=
|
integrity sha1-fhu21b7zh0wo45JSaiVBFwKR7s8=
|
||||||
|
|
||||||
|
parse5-htmlparser2-tree-adapter@^6.0.1:
|
||||||
|
version "6.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6"
|
||||||
|
integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==
|
||||||
|
dependencies:
|
||||||
|
parse5 "^6.0.1"
|
||||||
|
|
||||||
|
parse5@^6.0.1:
|
||||||
|
version "6.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
|
||||||
|
integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
|
||||||
|
|
||||||
parseurl@~1.3.2, parseurl@~1.3.3:
|
parseurl@~1.3.2, parseurl@~1.3.3:
|
||||||
version "1.3.3"
|
version "1.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
|
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
|
||||||
@@ -7534,6 +7752,11 @@ pbkdf2@^3.0.3:
|
|||||||
safe-buffer "^5.0.1"
|
safe-buffer "^5.0.1"
|
||||||
sha.js "^2.4.8"
|
sha.js "^2.4.8"
|
||||||
|
|
||||||
|
pend@~1.2.0:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
|
||||||
|
integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
|
||||||
|
|
||||||
performance-now@^2.1.0:
|
performance-now@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
||||||
@@ -7981,6 +8204,13 @@ qs@6.7.0:
|
|||||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
|
||||||
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
|
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
|
||||||
|
|
||||||
|
qs@^6.9.1:
|
||||||
|
version "6.10.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.1.tgz#4931482fa8d647a5aab799c5271d2133b981fb6a"
|
||||||
|
integrity sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==
|
||||||
|
dependencies:
|
||||||
|
side-channel "^1.0.4"
|
||||||
|
|
||||||
qs@~6.5.2:
|
qs@~6.5.2:
|
||||||
version "6.5.2"
|
version "6.5.2"
|
||||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
||||||
@@ -8157,6 +8387,13 @@ react@^16.12.0:
|
|||||||
object-assign "^4.1.1"
|
object-assign "^4.1.1"
|
||||||
prop-types "^15.6.2"
|
prop-types "^15.6.2"
|
||||||
|
|
||||||
|
read@^1.0.7:
|
||||||
|
version "1.0.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4"
|
||||||
|
integrity sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=
|
||||||
|
dependencies:
|
||||||
|
mute-stream "~0.0.4"
|
||||||
|
|
||||||
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
|
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
|
||||||
version "2.3.6"
|
version "2.3.6"
|
||||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
|
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
|
||||||
@@ -8827,16 +9064,16 @@ selfsigned@^1.10.7:
|
|||||||
dependencies:
|
dependencies:
|
||||||
node-forge "0.9.0"
|
node-forge "0.9.0"
|
||||||
|
|
||||||
|
semver@^5.1.0, semver@^5.4.1, semver@^5.7.0:
|
||||||
|
version "5.7.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
||||||
|
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
||||||
|
|
||||||
semver@^5.3.0, semver@^5.5.0, semver@^5.6.0:
|
semver@^5.3.0, semver@^5.5.0, semver@^5.6.0:
|
||||||
version "5.7.0"
|
version "5.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b"
|
||||||
integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==
|
integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==
|
||||||
|
|
||||||
semver@^5.4.1, semver@^5.7.0:
|
|
||||||
version "5.7.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
|
||||||
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
|
||||||
|
|
||||||
semver@^6.0.0, semver@^6.3.0:
|
semver@^6.0.0, semver@^6.3.0:
|
||||||
version "6.3.0"
|
version "6.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
|
||||||
@@ -8981,6 +9218,15 @@ shx@^0.3.2:
|
|||||||
minimist "^1.2.0"
|
minimist "^1.2.0"
|
||||||
shelljs "^0.8.1"
|
shelljs "^0.8.1"
|
||||||
|
|
||||||
|
side-channel@^1.0.4:
|
||||||
|
version "1.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
|
||||||
|
integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
|
||||||
|
dependencies:
|
||||||
|
call-bind "^1.0.0"
|
||||||
|
get-intrinsic "^1.0.2"
|
||||||
|
object-inspect "^1.9.0"
|
||||||
|
|
||||||
signal-exit@^3.0.0, signal-exit@^3.0.2:
|
signal-exit@^3.0.0, signal-exit@^3.0.2:
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
|
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
|
||||||
@@ -9681,6 +9927,13 @@ tinyqueue@^2.0.3:
|
|||||||
resolved "https://registry.yarnpkg.com/tinyqueue/-/tinyqueue-2.0.3.tgz#64d8492ebf39e7801d7bd34062e29b45b2035f08"
|
resolved "https://registry.yarnpkg.com/tinyqueue/-/tinyqueue-2.0.3.tgz#64d8492ebf39e7801d7bd34062e29b45b2035f08"
|
||||||
integrity sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==
|
integrity sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==
|
||||||
|
|
||||||
|
tmp@^0.2.1:
|
||||||
|
version "0.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14"
|
||||||
|
integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==
|
||||||
|
dependencies:
|
||||||
|
rimraf "^3.0.0"
|
||||||
|
|
||||||
to-array-buffer@^3.0.0:
|
to-array-buffer@^3.0.0:
|
||||||
version "3.2.0"
|
version "3.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/to-array-buffer/-/to-array-buffer-3.2.0.tgz#cb684dd691a7368c3b249c2348d75227f7d4dbb4"
|
resolved "https://registry.yarnpkg.com/to-array-buffer/-/to-array-buffer-3.2.0.tgz#cb684dd691a7368c3b249c2348d75227f7d4dbb4"
|
||||||
@@ -9840,6 +10093,11 @@ tslib@^1.9.3:
|
|||||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
|
||||||
integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
|
integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
|
||||||
|
|
||||||
|
tslib@^2.2.0:
|
||||||
|
version "2.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
|
||||||
|
integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
|
||||||
|
|
||||||
tslib@~1.9.0:
|
tslib@~1.9.0:
|
||||||
version "1.9.3"
|
version "1.9.3"
|
||||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
|
||||||
@@ -9883,6 +10141,11 @@ tunnel-agent@^0.6.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer "^5.0.1"
|
safe-buffer "^5.0.1"
|
||||||
|
|
||||||
|
tunnel@0.0.6:
|
||||||
|
version "0.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c"
|
||||||
|
integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==
|
||||||
|
|
||||||
turntable-camera-controller@^3.0.0:
|
turntable-camera-controller@^3.0.0:
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/turntable-camera-controller/-/turntable-camera-controller-3.0.1.tgz#8dbd3fe00550191c65164cb888971049578afd99"
|
resolved "https://registry.yarnpkg.com/turntable-camera-controller/-/turntable-camera-controller-3.0.1.tgz#8dbd3fe00550191c65164cb888971049578afd99"
|
||||||
@@ -9947,6 +10210,15 @@ type@^2.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/type/-/type-2.0.0.tgz#5f16ff6ef2eb44f260494dae271033b29c09a9c3"
|
resolved "https://registry.yarnpkg.com/type/-/type-2.0.0.tgz#5f16ff6ef2eb44f260494dae271033b29c09a9c3"
|
||||||
integrity sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==
|
integrity sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==
|
||||||
|
|
||||||
|
typed-rest-client@^1.8.4:
|
||||||
|
version "1.8.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/typed-rest-client/-/typed-rest-client-1.8.4.tgz#ba3fb788e5b9322547406392533f12d660a5ced6"
|
||||||
|
integrity sha512-MyfKKYzk3I6/QQp6e1T50py4qg+c+9BzOEl2rBmQIpStwNUoqQ73An+Tkfy9YuV7O+o2mpVVJpe+fH//POZkbg==
|
||||||
|
dependencies:
|
||||||
|
qs "^6.9.1"
|
||||||
|
tunnel "0.0.6"
|
||||||
|
underscore "^1.12.1"
|
||||||
|
|
||||||
typed-styles@^0.0.7:
|
typed-styles@^0.0.7:
|
||||||
version "0.0.7"
|
version "0.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/typed-styles/-/typed-styles-0.0.7.tgz#93392a008794c4595119ff62dde6809dbc40a3d9"
|
resolved "https://registry.yarnpkg.com/typed-styles/-/typed-styles-0.0.7.tgz#93392a008794c4595119ff62dde6809dbc40a3d9"
|
||||||
@@ -9977,6 +10249,11 @@ typescript@^3.8.2:
|
|||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.2.tgz#91d6868aaead7da74f493c553aeff76c0c0b1d5a"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.2.tgz#91d6868aaead7da74f493c553aeff76c0c0b1d5a"
|
||||||
integrity sha512-EgOVgL/4xfVrCMbhYKUQTdF37SQn4Iw73H5BgCrF1Abdun7Kwy/QZsE/ssAy0y4LxBbvua3PIbFsbRczWWnDdQ==
|
integrity sha512-EgOVgL/4xfVrCMbhYKUQTdF37SQn4Iw73H5BgCrF1Abdun7Kwy/QZsE/ssAy0y4LxBbvua3PIbFsbRczWWnDdQ==
|
||||||
|
|
||||||
|
uc.micro@^1.0.1, uc.micro@^1.0.5:
|
||||||
|
version "1.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac"
|
||||||
|
integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==
|
||||||
|
|
||||||
uglify-js@3.4.x:
|
uglify-js@3.4.x:
|
||||||
version "3.4.10"
|
version "3.4.10"
|
||||||
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f"
|
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f"
|
||||||
@@ -9985,6 +10262,11 @@ uglify-js@3.4.x:
|
|||||||
commander "~2.19.0"
|
commander "~2.19.0"
|
||||||
source-map "~0.6.1"
|
source-map "~0.6.1"
|
||||||
|
|
||||||
|
underscore@^1.12.1:
|
||||||
|
version "1.13.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.1.tgz#0c1c6bd2df54b6b69f2314066d65b6cde6fcf9d1"
|
||||||
|
integrity sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==
|
||||||
|
|
||||||
unicode-canonical-property-names-ecmascript@^1.0.4:
|
unicode-canonical-property-names-ecmascript@^1.0.4:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818"
|
resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818"
|
||||||
@@ -10092,6 +10374,11 @@ urix@^0.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
|
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
|
||||||
integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
|
integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
|
||||||
|
|
||||||
|
url-join@^1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/url-join/-/url-join-1.1.0.tgz#741c6c2f4596c4830d6718460920d0c92202dc78"
|
||||||
|
integrity sha1-dBxsL0WWxIMNZxhGCSDQySIC3Hg=
|
||||||
|
|
||||||
url-parse@^1.4.3:
|
url-parse@^1.4.3:
|
||||||
version "1.4.7"
|
version "1.4.7"
|
||||||
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278"
|
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278"
|
||||||
@@ -10322,6 +10609,32 @@ vm-browserify@^1.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.0.tgz#bd76d6a23323e2ca8ffa12028dc04559c75f9019"
|
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.0.tgz#bd76d6a23323e2ca8ffa12028dc04559c75f9019"
|
||||||
integrity sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==
|
integrity sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==
|
||||||
|
|
||||||
|
vsce@^1.93.0:
|
||||||
|
version "1.93.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/vsce/-/vsce-1.93.0.tgz#676395f24f27f850f63240b339ed551e2e1d80db"
|
||||||
|
integrity sha512-RgmxwybXenP6tTF0PLh97b/RRLp1RkzjAHNya3QAfv1EZVg+lfoBiAaXogpmOGjYr8OskkqP5tIa3D/Q6X9lrw==
|
||||||
|
dependencies:
|
||||||
|
azure-devops-node-api "^10.2.2"
|
||||||
|
chalk "^2.4.2"
|
||||||
|
cheerio "^1.0.0-rc.9"
|
||||||
|
commander "^6.1.0"
|
||||||
|
denodeify "^1.2.1"
|
||||||
|
glob "^7.0.6"
|
||||||
|
ignore "^5.1.8"
|
||||||
|
leven "^3.1.0"
|
||||||
|
lodash "^4.17.15"
|
||||||
|
markdown-it "^10.0.0"
|
||||||
|
mime "^1.3.4"
|
||||||
|
osenv "^0.1.3"
|
||||||
|
parse-semver "^1.1.1"
|
||||||
|
read "^1.0.7"
|
||||||
|
semver "^5.1.0"
|
||||||
|
tmp "^0.2.1"
|
||||||
|
typed-rest-client "^1.8.4"
|
||||||
|
url-join "^1.1.0"
|
||||||
|
yauzl "^2.3.1"
|
||||||
|
yazl "^2.2.2"
|
||||||
|
|
||||||
vt-pbf@^3.1.1:
|
vt-pbf@^3.1.1:
|
||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/vt-pbf/-/vt-pbf-3.1.1.tgz#b0f627e39a10ce91d943b898ed2363d21899fb82"
|
resolved "https://registry.yarnpkg.com/vt-pbf/-/vt-pbf-3.1.1.tgz#b0f627e39a10ce91d943b898ed2363d21899fb82"
|
||||||
@@ -10738,6 +11051,21 @@ yargs@^15.0.2:
|
|||||||
y18n "^4.0.0"
|
y18n "^4.0.0"
|
||||||
yargs-parser "^18.1.1"
|
yargs-parser "^18.1.1"
|
||||||
|
|
||||||
|
yauzl@^2.3.1:
|
||||||
|
version "2.10.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
|
||||||
|
integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=
|
||||||
|
dependencies:
|
||||||
|
buffer-crc32 "~0.2.3"
|
||||||
|
fd-slicer "~1.1.0"
|
||||||
|
|
||||||
|
yazl@^2.2.2:
|
||||||
|
version "2.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.5.1.tgz#a3d65d3dd659a5b0937850e8609f22fffa2b5c35"
|
||||||
|
integrity sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==
|
||||||
|
dependencies:
|
||||||
|
buffer-crc32 "~0.2.3"
|
||||||
|
|
||||||
yn@3.1.1:
|
yn@3.1.1:
|
||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
|
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
|
||||||
|
|||||||