Artifact Compilation
This commit is contained in:
parent
42bf560f9f
commit
5ccaa5ad3a
85
src/index.ts
85
src/index.ts
|
@ -1,11 +1,18 @@
|
||||||
|
|
||||||
import * as fs from 'fs/promises';
|
import * as fs from 'fs/promises';
|
||||||
|
|
||||||
|
import { Node } from './node-types/abstract-node';
|
||||||
import { QuestionNode } from "./node-types/question";
|
import { QuestionNode } from "./node-types/question";
|
||||||
import { ClaimNode } from './node-types/claim';
|
import { ClaimNode } from './node-types/claim';
|
||||||
import { EvidenceNode } from './node-types/evidence';
|
import { EvidenceNode } from './node-types/evidence';
|
||||||
import { SourceNode } from './node-types/source';
|
import { SourceNode } from './node-types/source';
|
||||||
|
|
||||||
|
import { Edge } from './edge-types/abstract-edge';
|
||||||
|
import { GenerateEdge } from './edge-types/generate';
|
||||||
|
import { InformEdge } from './edge-types/inform';
|
||||||
|
import { SupportEdge } from './edge-types/support';
|
||||||
|
import { OpposeEdge } from './edge-types/oppose';
|
||||||
|
|
||||||
export class Compiler {
|
export class Compiler {
|
||||||
|
|
||||||
public static nodes = [
|
public static nodes = [
|
||||||
|
@ -15,6 +22,13 @@ export class Compiler {
|
||||||
SourceNode
|
SourceNode
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public static edges = [
|
||||||
|
GenerateEdge,
|
||||||
|
InformEdge,
|
||||||
|
SupportEdge,
|
||||||
|
OpposeEdge
|
||||||
|
];
|
||||||
|
|
||||||
public static getNodeType(name: string) {
|
public static getNodeType(name: string) {
|
||||||
for (const nodeType of Compiler.nodes) {
|
for (const nodeType of Compiler.nodes) {
|
||||||
if (nodeType.TYPE_PATTERN.test(name)) return nodeType;
|
if (nodeType.TYPE_PATTERN.test(name)) return nodeType;
|
||||||
|
@ -22,14 +36,21 @@ export class Compiler {
|
||||||
throw new Error(`File name does not match any known node type \n - ${name}`);
|
throw new Error(`File name does not match any known node type \n - ${name}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static getEdgeType(name: string) {
|
||||||
|
for (const edgeType of Compiler.edges) {
|
||||||
|
if (name.includes(edgeType.EDGE_TYPE)) return edgeType;
|
||||||
|
}
|
||||||
|
throw new Error(`Edge name does not match any known edge types \n - ${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
static async loadNodes(directory: string) {
|
public static async loadNodes(directory: string) {
|
||||||
console.log('Loading nodes...');
|
console.log('\nLoading nodes...');
|
||||||
const nodes = [];
|
const nodes = [];
|
||||||
const files = await fs.readdir(directory);
|
const files = await fs.readdir(directory);
|
||||||
for (const file of files) try {
|
for (const file of files) try {
|
||||||
|
const data = await fs.readFile(`${directory}/${file}`, 'utf-8');
|
||||||
const NodeType = Compiler.getNodeType(file);
|
const NodeType = Compiler.getNodeType(file);
|
||||||
const node = NodeType.load(file, "");
|
const node = NodeType.load(file, data);
|
||||||
nodes.push(node);
|
nodes.push(node);
|
||||||
console.log(`Loaded ${NodeType.TYPE} node "${node.name}"`);
|
console.log(`Loaded ${NodeType.TYPE} node "${node.name}"`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -38,8 +59,62 @@ export class Compiler {
|
||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static loadEdges(nodes: Node[]) {
|
||||||
|
console.log('\nLoading edges...');
|
||||||
|
const edges = [];
|
||||||
|
for (const node of nodes) {
|
||||||
|
const references = node.parseDataEdges();
|
||||||
|
for (const reference of references) try {
|
||||||
|
const source = node;
|
||||||
|
const destination = nodes.find(node => node.name === reference.referenceName);
|
||||||
|
if (!destination) throw new Error(`Could not find referenced node "${reference.referenceName}"`);
|
||||||
|
const EdgeClass = Compiler.getEdgeType(reference.edgeType);
|
||||||
|
const edge = EdgeClass.createEdge(source, destination);
|
||||||
|
edges.push(edge);
|
||||||
|
console.log(`Loaded ${EdgeClass.EDGE_TYPE} edge from "${edge.source.name}" to "${edge.reference.name}"`);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return edges;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static registerEdges(edges: Edge[]) {
|
||||||
|
console.log('\nRegistering edges...');
|
||||||
|
for (const edge of edges) try {
|
||||||
|
edge.source.registerEdge(edge);
|
||||||
|
edge.reference.registerEdge(edge);
|
||||||
|
console.log(`Registered ${edge.constructor.name} from "${edge.source.name}" to "${edge.reference.name}"`);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static traverseGraph(node: Node, relationship: string | null, indent: number = 0) {
|
||||||
|
const currentIndent = ' '.repeat(indent);
|
||||||
|
const nodeType = node.constructor as typeof Node;
|
||||||
|
const bullet = relationship ? '> ' + relationship : '-';
|
||||||
|
console.log(`${currentIndent}${bullet} ${nodeType.SYMBOL} ${node.name}`);
|
||||||
|
for (const edge of node.incomingReferences) {
|
||||||
|
if (edge.source instanceof QuestionNode) continue;
|
||||||
|
const edgeType = edge.constructor as typeof Edge;
|
||||||
|
Compiler.traverseGraph(edge.source, edgeType.RELATIONSHIP, indent + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const graphPath = "./example_graph";
|
async function runTest() {
|
||||||
Compiler.loadNodes(graphPath);
|
console.log("Running Test");
|
||||||
|
const graphPath = "./example_graph";
|
||||||
|
const nodes = await Compiler.loadNodes(graphPath);
|
||||||
|
const edges = await Compiler.loadEdges(nodes);
|
||||||
|
Compiler.registerEdges(edges);
|
||||||
|
console.log("\nGenerating Artifact...");
|
||||||
|
const questions = nodes.filter(node => node instanceof QuestionNode);
|
||||||
|
for (const question of questions) Compiler.traverseGraph(question, null);
|
||||||
|
console.log("\nTest Complete");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
runTest().then(() => console.log("Done"));
|
|
@ -1,19 +1,46 @@
|
||||||
|
|
||||||
|
import { Edge } from "../edge-types/abstract-edge";
|
||||||
|
|
||||||
export abstract class Node {
|
export abstract class Node {
|
||||||
|
|
||||||
public static readonly TYPE: string;
|
public static readonly EDGE_PATTERN: RegExp = /^- (\S+) \[\[({.+}) (.+)\]\]$/;
|
||||||
public static readonly TYPE_PATTERN: RegExp;
|
public static readonly TYPE: string;
|
||||||
|
public static readonly TYPE_PATTERN: RegExp;
|
||||||
|
public static readonly SYMBOL: string;
|
||||||
|
|
||||||
public readonly name: string;
|
public readonly name: string;
|
||||||
public readonly data: string;
|
public readonly data: string;
|
||||||
|
public readonly outgoingReferences: Edge[] = [];
|
||||||
|
public readonly incomingReferences: Edge[] = [];
|
||||||
|
|
||||||
public constructor(name: string, data: string) {
|
public constructor(name: string, data: string) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static load(fileName: string, fileData: string): Node {
|
public static load(fileName: string, fileData: string): Node {
|
||||||
throw new Error('You must override the static parse method in specific node implementations');
|
throw new Error('You must override the static parse method in specific node implementations');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public parseDataEdges() {
|
||||||
|
type EdgeData = {edgeType: string, referenceType: string, referenceName: string};
|
||||||
|
const edges: EdgeData[] = [];
|
||||||
|
const lines = this.data.split('\n');
|
||||||
|
for (const line of lines) {
|
||||||
|
const match = line.match(Node.EDGE_PATTERN);
|
||||||
|
if (match) edges.push({
|
||||||
|
edgeType: match[1],
|
||||||
|
referenceType: match[2],
|
||||||
|
referenceName: match[3]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return edges;
|
||||||
|
}
|
||||||
|
|
||||||
|
public registerEdge(edge: Edge) {
|
||||||
|
if (edge.source === this) this.outgoingReferences.push(edge);
|
||||||
|
else if (edge.reference === this) this.incomingReferences.push(edge);
|
||||||
|
else throw new Error('Edge does not reference this node');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -5,6 +5,7 @@ export class ClaimNode extends Node{
|
||||||
|
|
||||||
public static readonly TYPE = 'claim';
|
public static readonly TYPE = 'claim';
|
||||||
public static readonly TYPE_PATTERN = /^\{CLM\}/;
|
public static readonly TYPE_PATTERN = /^\{CLM\}/;
|
||||||
|
public static readonly SYMBOL = "{CLM}";
|
||||||
|
|
||||||
public constructor(name: string, data: string) {
|
public constructor(name: string, data: string) {
|
||||||
super(name, data);
|
super(name, data);
|
||||||
|
|
|
@ -5,6 +5,7 @@ export class EvidenceNode extends Node{
|
||||||
|
|
||||||
public static readonly TYPE = 'evidence';
|
public static readonly TYPE = 'evidence';
|
||||||
public static readonly TYPE_PATTERN = /^\{EVD\}/;
|
public static readonly TYPE_PATTERN = /^\{EVD\}/;
|
||||||
|
public static readonly SYMBOL = "{EVD}";
|
||||||
|
|
||||||
public constructor(name: string, data: string) {
|
public constructor(name: string, data: string) {
|
||||||
super(name, data);
|
super(name, data);
|
||||||
|
|
|
@ -5,6 +5,7 @@ export class QuestionNode extends Node{
|
||||||
|
|
||||||
public static readonly TYPE = 'question';
|
public static readonly TYPE = 'question';
|
||||||
public static readonly TYPE_PATTERN = /^\{QUE\}/;
|
public static readonly TYPE_PATTERN = /^\{QUE\}/;
|
||||||
|
public static readonly SYMBOL = "{QUE}";
|
||||||
|
|
||||||
public constructor(name: string, data: string) {
|
public constructor(name: string, data: string) {
|
||||||
super(name, data);
|
super(name, data);
|
||||||
|
|
|
@ -5,6 +5,7 @@ export class SourceNode extends Node{
|
||||||
|
|
||||||
public static readonly TYPE = 'source';
|
public static readonly TYPE = 'source';
|
||||||
public static readonly TYPE_PATTERN = /^\{SRC\}/;
|
public static readonly TYPE_PATTERN = /^\{SRC\}/;
|
||||||
|
public static readonly SYMBOL = "{SRC}";
|
||||||
|
|
||||||
public constructor(name: string, data: string) {
|
public constructor(name: string, data: string) {
|
||||||
super(name, data);
|
super(name, data);
|
||||||
|
|
Loading…
Reference in New Issue