@specs-feup/alpakka
Version:
Alpakka is a [LARA Framework](https://github.com/specs-feup/lara-framework) source-to-source compiler for Android's [smali](https://github.com/google/smali) syntax. It enables the analysis and transformation of Android apps through APK files.
135 lines (110 loc) • 3.41 kB
text/typescript
import BaseGraph from "./BaseGraph.js";
import BaseNode from "./BaseNode.js";
import { EdgeBuilder, EdgeConstructor, EdgeTypeGuard } from "./Edge.js";
import Graph from "./Graph.js";
import cytoscape from "@specs-feup/lara/api/libs/cytoscape-3.26.0.js";
namespace BaseEdge {
export class Class<
D extends Data = Data,
S extends ScratchData = ScratchData,
> {
#graph: BaseGraph.Class;
#edge: cytoscape.EdgeSingular;
// _d and _sd are a hack to force typescript to typecheck
// D and S in .as() method.
constructor(
graph: BaseGraph.Class,
edge: cytoscape.EdgeSingular,
_d: D = {} as any,
_sd: S = {} as any,
) {
this.#graph = graph;
this.#edge = edge;
}
get data(): D {
return this.#edge.data();
}
get scratchData(): S {
return this.#edge.scratch(Graph.scratchNamespace);
}
get id(): string {
return this.#edge.id();
}
get source(): BaseNode.Class {
return new BaseNode.Class(this.#graph, this.#edge.source());
}
set source(node: BaseNode.Class) {
this.#edge.move({ source: node.id });
}
get target(): BaseNode.Class {
return new BaseNode.Class(this.#graph, this.#edge.target());
}
set target(node: BaseNode.Class) {
this.#edge.move({ target: node.id });
}
is<D2 extends Data, S2 extends ScratchData>(
guard: EdgeTypeGuard<D2, S2>,
): this is BaseEdge.Class<D2, S2> {
const data = this.data;
const scratchData = this.scratchData;
const result =
guard.isDataCompatible(data) &&
guard.isScratchDataCompatible(scratchData);
// Have typescript statically check that the types are correct
// in the implementation of this function.
result && (data satisfies D2) && (scratchData satisfies S2);
return result;
}
as<E extends BaseEdge.Class<D, S>>(EdgeType: EdgeConstructor<D, S, E>): E {
return new EdgeType(this.#graph, this.#edge, this.data, this.scratchData);
}
init<D2 extends BaseEdge.Data, S2 extends BaseEdge.ScratchData>(
builder: EdgeBuilder<D2, S2>,
): BaseEdge.Class<D2, S2> {
const initedData = builder.buildData(this.data);
const initedScratchData = builder.buildScratchData(this.scratchData);
this.#edge.data(initedData);
this.#edge.scratch(Graph.scratchNamespace, initedScratchData);
return new BaseEdge.Class(
this.#graph,
this.#edge,
initedData,
initedScratchData,
);
}
remove() {
this.#edge.remove();
}
get graph(): BaseGraph.Class {
return this.#graph;
}
toCy(): cytoscape.EdgeSingular {
return this.#edge;
}
}
export class Builder implements EdgeBuilder<Data, ScratchData> {
buildData(data: BaseEdge.Data): Data {
return data;
}
buildScratchData(scratchData: BaseEdge.ScratchData): ScratchData {
return scratchData;
}
}
export const TypeGuard: EdgeTypeGuard<Data, ScratchData> = {
isDataCompatible(data: BaseEdge.Data): data is Data {
return true;
},
isScratchDataCompatible(
scratchData: BaseEdge.ScratchData,
): scratchData is ScratchData {
return true;
},
};
export interface Data {
id: string;
source: string;
target: string;
}
export interface ScratchData {}
}
export default BaseEdge;