Artifact Compilation

This commit is contained in:
Chegele 2023-09-19 17:59:33 -04:00
parent 42bf560f9f
commit 5ccaa5ad3a
6 changed files with 125 additions and 19 deletions

View File

@ -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"));

View File

@ -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');
}
} }

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);