diff --git a/example-project/src/MockLanguageServiceHost.ts b/example-project/src/MockLanguageServiceHost.ts new file mode 100644 index 0000000..8e6fd01 --- /dev/null +++ b/example-project/src/MockLanguageServiceHost.ts @@ -0,0 +1,39 @@ +import * as ts from "typescript"; + +export class MockLanguageServiceHost implements ts.LanguageServiceHost { + constructor( + private readonly files: Map, + private readonly compilationSettings: ts.CompilerOptions + ) {} + + getScriptFileNames(): string[] { + return [...this.files.keys()]; + } + + getScriptVersion(fileName: string): string { + return ""; // our files don't change + } + + getScriptSnapshot(fileName: string): ts.IScriptSnapshot | undefined { + const content = this.files.get(fileName); + if (!content) { + return undefined; + } + return { + dispose() {}, + getChangeRange: () => undefined, + getLength: () => content.length, + getText: (start, end) => content.substr(start, end - start), + }; + } + + getCompilationSettings(): ts.CompilerOptions { + return this.compilationSettings; + } + getCurrentDirectory(): string { + return "/"; + } + getDefaultLibFileName(options: ts.CompilerOptions): string { + return ts.getDefaultLibFileName(options); + } +} diff --git a/example-project/src/index.ts b/example-project/src/index.ts index ecc00ac..cfb42be 100644 --- a/example-project/src/index.ts +++ b/example-project/src/index.ts @@ -7,92 +7,178 @@ import { } from "@hediet/node-reload"; enableHotReload(); -/* import { registerAll, CommonDataTypes, } from "@hediet/debug-visualizer-data-extraction"; +import { MockLanguageServiceHost } from "./MockLanguageServiceHost"; + registerAll(); -*/ registerUpdateReconciler(module); +function getClosure( + root: T, + edgeSelector: (item: T) => { item: T; edgeLabel: string }[], + labelSelector: (item: T) => string +): CommonDataTypes.GraphData { + const r: CommonDataTypes.GraphData = { + kind: { + graph: true, + }, + nodes: [], + edges: [], + }; + let idCounter = 1; + const ids = new Map(); + function getId(item: T): string { + let id = ids.get(item); + if (!id) { + id = (idCounter++).toString(); + ids.set(item, id); + } + return id; + } + + const queue = new Array(root); + const processed = new Set(); + + while (queue.length > 0) { + const item = queue.shift()!; + if (processed.has(item)) { + continue; + } + processed.add(item); + const edges = edgeSelector(item); + const fromId = getId(item); + r.nodes.push({ id: fromId, label: labelSelector(item) }); + for (const e of edges) { + const toId = getId(e.item); + r.edges.push({ + from: fromId, + to: toId, + label: e.edgeLabel, + }); + if (!processed.has(e.item)) { + queue.push(e.item); + } + } + } + return r; +} + +let id = 0; +class DoubleLinkedList { + public readonly id = (id++).toString(); + constructor(public name: string) {} + + next: DoubleLinkedList | undefined; + prev: DoubleLinkedList | undefined; + + public setNext(val: DoubleLinkedList): void { + val.prev = this; + this.next = val; + } + + toData(): CommonDataTypes.GraphData { + return getClosure( + this, + r => + [ + { item: r.next!, edgeLabel: "next" }, + { item: r.prev!, edgeLabel: "prev" }, + ].filter(r => !!r.item), + item => item.name + ); + } +} + @hotClass(module) class Main { run() { - const sf = ts.createSourceFile( - "test", - ` + const mainFile = { + name: "main.ts", + content: ` class Test1 { + public foo(a: number) { + } } -class Test2 { -} -class Test1 { -} -class Test2 { -} -class Test1 { -} -class Test2 { -} -class Test1 { -} -class Test2 { -} -class Test1 { -} -class Test2 { -} -class Test1 { -} -class Test2 { -} -class Test1 { -} -class Test2 { -} -class Test1 { -} -class Test2 { -} -class Test1 { -} -class Test2 { -} -class Test1 { -} -class Test2 { -} -class Test1 { -} -class Test2 { -} -class Test1 { -} -class Test2 { -} -class Test1 { -} -class Test2 { -} -class Test1 { -} -class Test2 { -} -`, - ts.ScriptTarget.Latest, - true + `, + }; + const files = new Map([ + [mainFile.name, mainFile.content], + ]); + const serviceHost = new MockLanguageServiceHost(files, {}); + const baseService = ts.createLanguageService( + serviceHost, + ts.createDocumentRegistry() ); - let myValue: any = sf.statements[0]; - myValue = sf.statements[1]; + const prog = baseService.getProgram()!; + + const identifiers = new Array(); + function traverse(node: ts.Node) { + if (ts.isIdentifier(node)) identifiers.push(node); + node.forEachChild(traverse); + } + traverse(prog.getSourceFiles()[0]); + + const c = prog.getTypeChecker(); + let myValue = undefined; + const sf = prog.getSourceFiles()[0]; myValue = sf.getText(); + myValue = { + sf, + fn: (n: ts.Node) => { + try { + const t = c.getTypeAtLocation(n); + return t ? c.typeToString(t) : undefined; + } catch (e) { + return "" + e; + } + }, + }; + myValue = { + sf, + fn: (n: ts.Node) => { + try { + const t = c.getSymbolAtLocation(n); + return t ? ts.SymbolFlags[t.flags] : undefined; + } catch (e) { + return "" + e; + } + }, + }; + + debugger; + for (const ident of identifiers) { + const s = c.getSymbolAtLocation(ident); + myValue = ident; + } + + const first = (myValue = new DoubleLinkedList("1")); + myValue.setNext(new DoubleLinkedList("2")); + myValue.next!.setNext(new DoubleLinkedList("3")); + myValue.next!.next!.setNext(new DoubleLinkedList("4")); + + let last: DoubleLinkedList | undefined = undefined; + while (myValue) { + myValue.prev = myValue.next; + myValue.next = last; + last = myValue; + myValue = myValue.prev; + } + myValue = first; + myValue = { kind: { text: true, svg: true }, - text: ` - - Sorry, your browser does not support inline SVG. - - `, + text: ` + + + + `, }; } }