v0.9.0
This commit is contained in:
@@ -19,9 +19,9 @@ export type CommonDataType =
|
||||
| CommonDataTypes.Svg
|
||||
| CommonDataTypes.Html
|
||||
| CommonDataTypes.DotGraph
|
||||
| CommonDataTypes.TreeNodeData
|
||||
| CommonDataTypes.AstData
|
||||
| CommonDataTypes.GraphData;
|
||||
| CommonDataTypes.Tree
|
||||
| CommonDataTypes.Ast
|
||||
| CommonDataTypes.Graph;
|
||||
|
||||
export module CommonDataTypes {
|
||||
export interface Text {
|
||||
@@ -31,34 +31,31 @@ export module CommonDataTypes {
|
||||
fileName?: string;
|
||||
}
|
||||
|
||||
export interface GraphData {
|
||||
export interface Graph {
|
||||
kind: { graph: true };
|
||||
nodes: { id: string; label: string }[];
|
||||
edges: { from: string; to: string; label: string }[];
|
||||
nodes: NodeGraphData[];
|
||||
edges: EdgeGraphData[];
|
||||
}
|
||||
|
||||
export interface Svg extends Text {
|
||||
kind: { text: true; svg: true };
|
||||
text: string;
|
||||
}
|
||||
|
||||
export interface Html extends Text {
|
||||
kind: { text: true; html: true };
|
||||
text: string;
|
||||
}
|
||||
|
||||
export interface DotGraph extends Text {
|
||||
kind: { text: true; dotGraph: true };
|
||||
text: string;
|
||||
}
|
||||
|
||||
export interface TreeNodeData<TData = unknown> {
|
||||
export interface Tree<TData = unknown> {
|
||||
kind: { tree: true };
|
||||
root: TreeNode<TData>;
|
||||
}
|
||||
|
||||
export interface AstData
|
||||
extends TreeNodeData<{
|
||||
export interface Ast
|
||||
extends Tree<{
|
||||
position: number;
|
||||
length: number;
|
||||
}>,
|
||||
@@ -68,11 +65,26 @@ export module CommonDataTypes {
|
||||
}
|
||||
|
||||
export interface TreeNode<TExtraData> {
|
||||
id: string | undefined;
|
||||
name: string;
|
||||
value: string | undefined;
|
||||
emphasizedValue: string | undefined;
|
||||
children: TreeNode<TExtraData>[];
|
||||
data: TExtraData;
|
||||
isMarked: boolean;
|
||||
id?: string;
|
||||
value?: string;
|
||||
emphasizedValue?: string;
|
||||
isMarked?: boolean;
|
||||
}
|
||||
|
||||
export interface NodeGraphData {
|
||||
id: string;
|
||||
label: string;
|
||||
color?: string;
|
||||
}
|
||||
|
||||
export interface EdgeGraphData {
|
||||
from: string;
|
||||
to: string;
|
||||
label: string;
|
||||
id?: string;
|
||||
color?: string;
|
||||
weight?: number;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ declare const window: any;
|
||||
|
||||
export function selfContainedInitDataExtractorApi(): boolean {
|
||||
const obj = typeof window === "object" ? (window as any) : (global as any);
|
||||
const key = "@hediet/data-extractor";
|
||||
const key = "@hediet/data-extractor/v1";
|
||||
const prefix = key + "::";
|
||||
|
||||
let api: DataExtractorApi | undefined = obj[key];
|
||||
@@ -135,7 +135,7 @@ export const ApiHasNotBeenInitializedCode = "EgH0cybXij1jYUozyakO" as const;
|
||||
|
||||
export function selfContainedGetInitializedDataExtractorApi(): DataExtractorApi {
|
||||
const obj = typeof window === "object" ? (window as any) : (global as any);
|
||||
const key = "@hediet/data-extractor";
|
||||
const key = "@hediet/data-extractor/v1";
|
||||
let api: DataExtractorApi | undefined = obj[key];
|
||||
if (!api) {
|
||||
const code: typeof ApiHasNotBeenInitializedCode =
|
||||
|
||||
@@ -4,12 +4,12 @@ import { CommonDataTypes } from "../../CommonDataTypes";
|
||||
|
||||
// This class is self contained and can be injected into both nodejs and browser environments.
|
||||
export class TypeScriptAstDataExtractor
|
||||
implements DataExtractor<CommonDataTypes.AstData> {
|
||||
implements DataExtractor<CommonDataTypes.Ast> {
|
||||
readonly id = "TypeScriptAst";
|
||||
|
||||
getExtractions(
|
||||
data: unknown,
|
||||
collector: ExtractionCollector<CommonDataTypes.AstData>,
|
||||
collector: ExtractionCollector<CommonDataTypes.Ast>,
|
||||
evalFn: <TEval>(expression: string) => TEval
|
||||
): void {
|
||||
if (!data) {
|
||||
@@ -63,7 +63,7 @@ export class TypeScriptAstDataExtractor
|
||||
memberName: string,
|
||||
marked: Set<ts.Node>,
|
||||
emphasizedValueFn: (node: ts.Node) => string | undefined
|
||||
): CommonDataTypes.AstData["root"] {
|
||||
): CommonDataTypes.Ast["root"] {
|
||||
const name = tsApi.SyntaxKind[node.kind];
|
||||
const children = getChildren(node)
|
||||
.map((childNode, idx) => {
|
||||
|
||||
105
data-extraction/src/js/createGraph.ts
Normal file
105
data-extraction/src/js/createGraph.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import {
|
||||
CommonDataTypes,
|
||||
EdgeGraphData,
|
||||
NodeGraphData,
|
||||
} from "../CommonDataTypes";
|
||||
|
||||
export function createGraphFromPointers<T>(
|
||||
roots: Record<string, T | undefined | null>,
|
||||
infoSelector: (
|
||||
item: T
|
||||
) => {
|
||||
id?: string | number;
|
||||
edges: ({ to: T } & Omit<EdgeGraphData, "from" | "to">)[];
|
||||
} & Omit<NodeGraphData, "id">
|
||||
): CommonDataTypes.Graph {
|
||||
const marker = {};
|
||||
|
||||
interface Pointer {
|
||||
marker: {};
|
||||
name: string;
|
||||
value: T | null | undefined;
|
||||
}
|
||||
|
||||
const items = Object.entries(roots).map<Pointer>(([name, value]) => ({
|
||||
marker,
|
||||
name,
|
||||
value,
|
||||
}));
|
||||
|
||||
const includeLabelInName = false;
|
||||
|
||||
return createGraph<T | Pointer>(items, item => {
|
||||
if ("marker" in item && item["marker"] === marker) {
|
||||
return {
|
||||
id: "label____" + item.name,
|
||||
color: "orange",
|
||||
label: item.name,
|
||||
edges: [{ to: item.value!, color: "orange", label: "" }].filter(
|
||||
t => !!t.to
|
||||
),
|
||||
};
|
||||
} else {
|
||||
return infoSelector(item as T);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function createGraph<T>(
|
||||
roots: T[],
|
||||
infoSelector: (
|
||||
item: T
|
||||
) => {
|
||||
id?: string | number;
|
||||
edges: ({ to: T } & Omit<EdgeGraphData, "from" | "to">)[];
|
||||
} & Omit<NodeGraphData, "id">
|
||||
): CommonDataTypes.Graph {
|
||||
const r: CommonDataTypes.Graph = {
|
||||
kind: {
|
||||
graph: true,
|
||||
},
|
||||
nodes: [],
|
||||
edges: [],
|
||||
};
|
||||
let idCounter = 1;
|
||||
const ids = new Map<T, string>();
|
||||
function getId(item: T): string {
|
||||
const _id = infoSelector(item).id;
|
||||
if (_id !== undefined) {
|
||||
return "" + _id;
|
||||
}
|
||||
|
||||
let id = ids.get(item);
|
||||
if (!id) {
|
||||
id = (idCounter++).toString();
|
||||
ids.set(item, id);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
const queue = new Array<T>(...roots);
|
||||
const processed = new Set<T>();
|
||||
|
||||
while (queue.length > 0) {
|
||||
const item = queue.shift()!;
|
||||
if (processed.has(item)) {
|
||||
continue;
|
||||
}
|
||||
processed.add(item);
|
||||
const nodeInfo = infoSelector(item);
|
||||
const fromId = getId(item);
|
||||
r.nodes.push({ ...nodeInfo, id: fromId, ["edges" as any]: undefined });
|
||||
for (const e of nodeInfo.edges) {
|
||||
const toId = getId(e.to);
|
||||
r.edges.push({
|
||||
...e,
|
||||
from: fromId,
|
||||
to: toId,
|
||||
});
|
||||
if (!processed.has(e.to)) {
|
||||
queue.push(e.to);
|
||||
}
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
import { CommonDataTypes } from "../CommonDataTypes";
|
||||
|
||||
export function getClosureObj<T>(
|
||||
roots: Record<string, T | undefined | null>,
|
||||
edgeSelector: (item: T) => { item: T; edgeLabel: string }[],
|
||||
labelSelector: (item: T) => string,
|
||||
idSelector?: (item: T) => string | number
|
||||
): CommonDataTypes.GraphData {
|
||||
const items = Object.entries(roots).map(([k, v]) => v);
|
||||
return getClosure<T>(
|
||||
items.filter(i => !!i) as T[],
|
||||
edgeSelector,
|
||||
item => {
|
||||
const names = new Array<string>();
|
||||
for (const [key, val] of Object.entries(roots)) {
|
||||
if (val === item) {
|
||||
names.push(key);
|
||||
}
|
||||
}
|
||||
const base = labelSelector(item);
|
||||
return names.length === 0 ? base : `${names.join(", ")}: ${base}`;
|
||||
},
|
||||
idSelector
|
||||
);
|
||||
}
|
||||
|
||||
export function getClosure<T>(
|
||||
roots: T[],
|
||||
edgeSelector: (item: T) => { item: T; edgeLabel: string }[],
|
||||
labelSelector: (item: T) => string,
|
||||
idSelector?: (item: T) => string | number
|
||||
): CommonDataTypes.GraphData {
|
||||
const r: CommonDataTypes.GraphData = {
|
||||
kind: {
|
||||
graph: true,
|
||||
},
|
||||
nodes: [],
|
||||
edges: [],
|
||||
};
|
||||
let idCounter = 1;
|
||||
const ids = new Map<T, string>();
|
||||
function getId(item: T): string {
|
||||
if (idSelector) {
|
||||
return "" + idSelector(item);
|
||||
}
|
||||
|
||||
let id = ids.get(item);
|
||||
if (!id) {
|
||||
id = (idCounter++).toString();
|
||||
ids.set(item, id);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
const queue = new Array<T>(...roots);
|
||||
const processed = new Set<T>();
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
export * from "./Extractors";
|
||||
export * from "./DataExtractor";
|
||||
export * from "./DataExtractorApi";
|
||||
export * from "./getClosure";
|
||||
export * from "./createGraph";
|
||||
|
||||
Reference in New Issue
Block a user