Implements GenericDataExtractionProviderFactory. With this, the debug visualizer can be used with every language that can be debugged in VS Code.
This commit is contained in:
@@ -1,10 +1,9 @@
|
||||
import { Disposable } from "@hediet/std/disposable";
|
||||
import { debugVisualizerUIContract } from "@hediet/debug-visualizer-vscode-shared";
|
||||
import { ConsoleRpcLogger, RequestHandlingError } from "@hediet/typed-json-rpc";
|
||||
import { EvaluationWatcher } from "./DataSource/DataSource";
|
||||
import { EvaluationWatcher, DataSource } from "./DataSource/DataSource";
|
||||
import { WebSocketStream } from "@hediet/typed-json-rpc-websocket";
|
||||
import { observable, autorun } from "mobx";
|
||||
import { Sources } from "./DataSource";
|
||||
import { Server } from "./Server";
|
||||
import * as open from "open";
|
||||
import chromeLauncher = require("chrome-launcher");
|
||||
@@ -16,7 +15,7 @@ export class ConnectionHandler {
|
||||
private watcher: EvaluationWatcher | undefined = undefined;
|
||||
|
||||
constructor(
|
||||
sources: Sources,
|
||||
dataSource: DataSource,
|
||||
stream: WebSocketStream,
|
||||
server: Server,
|
||||
config: Config,
|
||||
@@ -61,12 +60,9 @@ export class ConnectionHandler {
|
||||
this.dispose.untrack(this.watcher).dispose();
|
||||
}
|
||||
this.watcher = this.dispose.track(
|
||||
sources.jsSource.createEvaluationWatcher(
|
||||
newExpression,
|
||||
{
|
||||
preferredDataExtractor: oldPreferredDataExtractor,
|
||||
}
|
||||
)
|
||||
dataSource.createEvaluationWatcher(newExpression, {
|
||||
preferredDataExtractor: oldPreferredDataExtractor,
|
||||
})
|
||||
);
|
||||
},
|
||||
openInBrowser: async ({}) => {
|
||||
@@ -96,7 +92,7 @@ export class ConnectionHandler {
|
||||
getCompletions: async ({ text, column }) => {
|
||||
throwIfNotAuthenticated();
|
||||
|
||||
const completions = await sources.jsSource.getCompletions(
|
||||
const completions = await dataSource.getCompletions(
|
||||
text,
|
||||
column
|
||||
);
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import {
|
||||
DataExtractionProviderFactory,
|
||||
DataExtractionProvider,
|
||||
} from "./DataExtractionProvider";
|
||||
import { VsCodeDebugSession } from "../../VsCodeDebugger";
|
||||
|
||||
export class ComposedDataExtractionProviderFactory
|
||||
implements DataExtractionProviderFactory {
|
||||
constructor(public readonly factories: DataExtractionProviderFactory[]) {}
|
||||
|
||||
createDataExtractionProvider(
|
||||
session: VsCodeDebugSession
|
||||
): DataExtractionProvider | undefined {
|
||||
for (const f of this.factories) {
|
||||
const provider = f.createDataExtractionProvider(session);
|
||||
if (provider) {
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { DataExtractionResult } from "@hediet/debug-visualizer-data-extraction";
|
||||
import { VsCodeDebugSession } from "../../VsCodeDebugger";
|
||||
|
||||
export interface DataExtractionProviderFactory {
|
||||
createDataExtractionProvider(
|
||||
session: VsCodeDebugSession
|
||||
): DataExtractionProvider | undefined;
|
||||
}
|
||||
|
||||
export interface DataExtractionProvider {
|
||||
evaluate(
|
||||
args: DataExtractionProviderArgs
|
||||
): Promise<
|
||||
| { kind: "data"; result: DataExtractionResult }
|
||||
| { kind: "error"; message: string }
|
||||
>;
|
||||
}
|
||||
|
||||
export interface DataExtractionProviderArgs {
|
||||
expression: string;
|
||||
preferredExtractor: string | undefined;
|
||||
frameId: number | undefined;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import {
|
||||
DataResult,
|
||||
DataExtractionResult,
|
||||
ExtractedData,
|
||||
isExtractedData,
|
||||
} from "@hediet/debug-visualizer-data-extraction";
|
||||
import { VsCodeDebugSession } from "../../VsCodeDebugger";
|
||||
import {
|
||||
DataExtractionProviderFactory,
|
||||
DataExtractionProvider,
|
||||
DataExtractionProviderArgs,
|
||||
} from "./DataExtractionProvider";
|
||||
|
||||
export class GenericDataExtractionProviderFactory
|
||||
implements DataExtractionProviderFactory {
|
||||
createDataExtractionProvider(
|
||||
session: VsCodeDebugSession
|
||||
): DataExtractionProvider | undefined {
|
||||
return new GenericDataExtractionProvider(session);
|
||||
}
|
||||
}
|
||||
|
||||
class GenericDataExtractionProvider implements DataExtractionProvider {
|
||||
constructor(private readonly session: VsCodeDebugSession) {}
|
||||
|
||||
public async evaluate({
|
||||
expression,
|
||||
preferredExtractor,
|
||||
frameId,
|
||||
}: DataExtractionProviderArgs): Promise<
|
||||
| { kind: "data"; result: DataExtractionResult }
|
||||
| { kind: "error"; message: string }
|
||||
> {
|
||||
try {
|
||||
const reply = await this.session.evaluate({
|
||||
expression,
|
||||
frameId,
|
||||
});
|
||||
const resultStr = reply.result;
|
||||
const jsonData = resultStr.substr(1, resultStr.length - 2);
|
||||
const result = JSON.parse(jsonData) as ExtractedData;
|
||||
|
||||
if (!isExtractedData(result)) {
|
||||
throw new Error("Invalid Data");
|
||||
}
|
||||
|
||||
return {
|
||||
kind: "data",
|
||||
result: {
|
||||
availableExtractors: [],
|
||||
usedExtractor: {
|
||||
id: "generic" as any,
|
||||
name: "Generic",
|
||||
priority: 1,
|
||||
},
|
||||
data: result,
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
kind: "error",
|
||||
message: error.message,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
import {
|
||||
getExpressionForDataExtractorApi,
|
||||
DataResult,
|
||||
ApiHasNotBeenInitializedCode,
|
||||
getExpressionToInitializeDataExtractorApi,
|
||||
DataExtractionResult,
|
||||
} from "@hediet/debug-visualizer-data-extraction";
|
||||
import { VsCodeDebugSession } from "../../VsCodeDebugger";
|
||||
import {
|
||||
DataExtractionProviderFactory,
|
||||
DataExtractionProvider,
|
||||
DataExtractionProviderArgs,
|
||||
} from "./DataExtractionProvider";
|
||||
|
||||
export class JsDataExtractionProviderFactory
|
||||
implements DataExtractionProviderFactory {
|
||||
createDataExtractionProvider(
|
||||
session: VsCodeDebugSession
|
||||
): DataExtractionProvider | undefined {
|
||||
const supportedDebugAdapters = [
|
||||
"node",
|
||||
"node2",
|
||||
"extensionHost",
|
||||
"chrome",
|
||||
];
|
||||
if (supportedDebugAdapters.indexOf(session.session.type) !== -1) {
|
||||
return new JsDataEvaluator(session);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
class JsDataEvaluator implements DataExtractionProvider {
|
||||
constructor(private readonly session: VsCodeDebugSession) {}
|
||||
|
||||
public async evaluate({
|
||||
expression,
|
||||
preferredExtractor,
|
||||
frameId,
|
||||
}: DataExtractionProviderArgs): Promise<
|
||||
| { kind: "data"; result: DataExtractionResult }
|
||||
| { kind: "error"; message: string }
|
||||
> {
|
||||
while (true) {
|
||||
try {
|
||||
const preferredExtractorExpr = preferredExtractor
|
||||
? `"${preferredExtractor}"`
|
||||
: "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,
|
||||
});
|
||||
const resultStr = reply.result;
|
||||
const jsonData = 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,
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
extension/src/DataSource/DataExtractionProvider/index.ts
Normal file
12
extension/src/DataSource/DataExtractionProvider/index.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export * from "./DataExtractionProvider";
|
||||
|
||||
import { ComposedDataExtractionProviderFactory } from "./ComposedDataExtractionProviderFactory";
|
||||
import { JsDataExtractionProviderFactory } from "./JsDataExtractionProviderFactory";
|
||||
import { GenericDataExtractionProviderFactory } from "./GenericDataExtractionProviderFactory";
|
||||
|
||||
export const defaultDataExtractionProviderFactory = new ComposedDataExtractionProviderFactory(
|
||||
[
|
||||
new JsDataExtractionProviderFactory(),
|
||||
new GenericDataExtractionProviderFactory(),
|
||||
]
|
||||
);
|
||||
@@ -4,30 +4,27 @@ import {
|
||||
CompletionItem,
|
||||
} from "@hediet/debug-visualizer-vscode-shared";
|
||||
|
||||
export interface EvaluationWatcherOptions {
|
||||
preferredDataExtractor?: DataExtractorId | undefined;
|
||||
}
|
||||
|
||||
export interface DataSource {
|
||||
createEvaluationWatcher(
|
||||
expression: string,
|
||||
options: EvaluationWatcherOptions
|
||||
): EvaluationWatcher;
|
||||
|
||||
getCompletions(text: string, column: number): Promise<CompletionItem[]>;
|
||||
}
|
||||
|
||||
export interface EvaluationWatcherOptions {
|
||||
preferredDataExtractor?: DataExtractorId | undefined;
|
||||
}
|
||||
|
||||
export interface EvaluationWatcher {
|
||||
readonly expression: string;
|
||||
|
||||
// is observable
|
||||
/** This field is observable */
|
||||
readonly state: DataExtractionState;
|
||||
/** This field is observable */
|
||||
readonly preferredDataExtractor: DataExtractorId | undefined;
|
||||
|
||||
setPreferredDataExtractor(id: DataExtractorId | undefined): void;
|
||||
|
||||
refresh(): void;
|
||||
|
||||
// is observable
|
||||
state: DataExtractionState;
|
||||
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
136
extension/src/DataSource/DataSourceImpl.ts
Normal file
136
extension/src/DataSource/DataSourceImpl.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import {
|
||||
DataSource,
|
||||
EvaluationWatcher,
|
||||
EvaluationWatcherOptions,
|
||||
} from "./DataSource";
|
||||
import { observable, autorun, action } from "mobx";
|
||||
import { Disposable } from "@hediet/std/disposable";
|
||||
import { DataExtractorId } from "@hediet/debug-visualizer-data-extraction";
|
||||
import {
|
||||
DataExtractionState,
|
||||
CompletionItem,
|
||||
} from "@hediet/debug-visualizer-vscode-shared";
|
||||
import { hotClass } from "@hediet/node-reload";
|
||||
import { VsCodeDebuggerView } from "../VsCodeDebugger";
|
||||
import { DataExtractionProviderFactory } from "./DataExtractionProvider/DataExtractionProvider";
|
||||
|
||||
@hotClass(module)
|
||||
export class DataSourceImpl implements DataSource {
|
||||
public readonly dispose = Disposable.fn();
|
||||
private readonly watchers = new Set<ObservableEvaluationWatcher>();
|
||||
|
||||
constructor(
|
||||
private readonly vsCodeDebuggerView: VsCodeDebuggerView,
|
||||
private readonly dataExtractionProviderFactory: DataExtractionProviderFactory
|
||||
) {
|
||||
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);
|
||||
}
|
||||
|
||||
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 extractionProvider = this.dataExtractionProviderFactory.createDataExtractionProvider(
|
||||
session
|
||||
);
|
||||
if (!extractionProvider) {
|
||||
w._state = {
|
||||
kind: "error",
|
||||
message: `The debug adapter "${session.session.type}" is not supported.`,
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await extractionProvider.evaluate({
|
||||
expression: w.expression,
|
||||
frameId,
|
||||
preferredExtractor: 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: DataSourceImpl,
|
||||
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,213 +0,0 @@
|
||||
import {
|
||||
DataSource,
|
||||
EvaluationWatcher,
|
||||
EvaluationWatcherOptions,
|
||||
} from "./DataSource";
|
||||
import { observable, autorun, action } from "mobx";
|
||||
import { Disposable } from "@hediet/std/disposable";
|
||||
import {
|
||||
getExpressionForDataExtractorApi,
|
||||
DataResult,
|
||||
DataExtractorId,
|
||||
ApiHasNotBeenInitializedCode,
|
||||
getExpressionToInitializeDataExtractorApi,
|
||||
} from "@hediet/debug-visualizer-data-extraction";
|
||||
import {
|
||||
DataExtractionState,
|
||||
CompletionItem,
|
||||
} from "@hediet/debug-visualizer-vscode-shared";
|
||||
import { hotClass } from "@hediet/node-reload";
|
||||
import { VsCodeDebuggerView, VsCodeDebugSession } from "../VsCodeDebugger";
|
||||
|
||||
export function createJsDebuggerSource(args: {
|
||||
vsCodeDebuggerView: VsCodeDebuggerView;
|
||||
}): JsDataSource {
|
||||
return new JsDebuggerSourceImplementation(args.vsCodeDebuggerView);
|
||||
}
|
||||
|
||||
export interface JsCode extends String {
|
||||
__brand: "JsCode";
|
||||
}
|
||||
|
||||
export interface JsDataSource extends DataSource {
|
||||
registerDataExtractor(classExpression: JsCode): void;
|
||||
}
|
||||
|
||||
@hotClass(module)
|
||||
export class JsDebuggerSourceImplementation implements JsDataSource {
|
||||
public readonly dispose = Disposable.fn();
|
||||
private readonly watchers = new Set<ObservableEvaluationWatcher>();
|
||||
|
||||
constructor(private readonly vsCodeDebuggerView: VsCodeDebuggerView) {
|
||||
this.dispose.track({
|
||||
dispose: autorun(() => {
|
||||
if (
|
||||
vsCodeDebuggerView.activeDebugSession &&
|
||||
vsCodeDebuggerView.activeFrameId !== undefined
|
||||
) {
|
||||
for (const w of this.watchers) {
|
||||
w.refresh();
|
||||
}
|
||||
}
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
registerDataExtractor(classExpression: JsCode): void {
|
||||
// TODO implement
|
||||
}
|
||||
|
||||
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,
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public async refresh(w: ObservableEvaluationWatcher): Promise<void> {
|
||||
const session = this.vsCodeDebuggerView.activeDebugSession;
|
||||
if (!session) {
|
||||
w._state = { kind: "noDebugSession" };
|
||||
return;
|
||||
}
|
||||
|
||||
const frameId = this.vsCodeDebuggerView.activeFrameId;
|
||||
|
||||
try {
|
||||
w._state = { kind: "loading" };
|
||||
|
||||
const preferredExtractor = w.preferredDataExtractor
|
||||
? `"${w.preferredDataExtractor}"`
|
||||
: "undefined";
|
||||
|
||||
const body = `${getExpressionForDataExtractorApi()}.getData(
|
||||
e => (${w.expression}),
|
||||
expr => eval(expr),
|
||||
${preferredExtractor}
|
||||
)`;
|
||||
|
||||
const expression = `
|
||||
(() => {
|
||||
try {
|
||||
return ${body};
|
||||
} catch (e) {
|
||||
return JSON.stringify({
|
||||
kind: "Error",
|
||||
message: e.message,
|
||||
stack: e.stack
|
||||
});
|
||||
}
|
||||
})()
|
||||
`;
|
||||
|
||||
const reply = await session.evaluate({
|
||||
expression,
|
||||
frameId,
|
||||
});
|
||||
const resultStr = reply.result;
|
||||
const jsonData = 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);
|
||||
}
|
||||
|
||||
w._state = {
|
||||
kind: "data",
|
||||
result: result.extractionResult,
|
||||
};
|
||||
} catch (error) {
|
||||
const msg = error.message as string | undefined;
|
||||
if (msg && msg.includes(ApiHasNotBeenInitializedCode)) {
|
||||
if (await this.initializeApi(session, frameId)) {
|
||||
await this.refresh(w);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
w._state = {
|
||||
kind: "error",
|
||||
message: error.message,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private async initializeApi(
|
||||
session: VsCodeDebugSession,
|
||||
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 session.evaluate({
|
||||
expression,
|
||||
frameId,
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ObservableEvaluationWatcher implements EvaluationWatcher {
|
||||
constructor(
|
||||
public readonly expression: string,
|
||||
private readonly source: JsDebuggerSourceImplementation,
|
||||
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,6 +1,7 @@
|
||||
import { Disposable } from "@hediet/std/disposable";
|
||||
import { VsCodeDebugger, VsCodeDebuggerView } from "../VsCodeDebugger";
|
||||
import { createJsDebuggerSource } from "./JsDebuggerSource";
|
||||
import { DataSourceImpl } from "./DataSourceImpl";
|
||||
import { defaultDataExtractionProviderFactory } from "./DataExtractionProvider";
|
||||
|
||||
export class Sources {
|
||||
public readonly dispose = Disposable.fn();
|
||||
@@ -9,7 +10,8 @@ export class Sources {
|
||||
new VsCodeDebuggerView(this.debugger)
|
||||
);
|
||||
|
||||
public readonly jsSource = createJsDebuggerSource({
|
||||
vsCodeDebuggerView: this.debuggerView,
|
||||
});
|
||||
public readonly dataSource = new DataSourceImpl(
|
||||
this.debuggerView,
|
||||
defaultDataExtractionProviderFactory
|
||||
);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,13 @@ export class Server {
|
||||
const wss = new WebSocket.Server({ server: this.server });
|
||||
wss.on("connection", ws => {
|
||||
const stream = new WebSocketStream(ws);
|
||||
new ConnectionHandler(sources, stream, this, config, this.secret);
|
||||
new ConnectionHandler(
|
||||
sources.dataSource,
|
||||
stream,
|
||||
this,
|
||||
config,
|
||||
this.secret
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user