2024-06-04 23:00:22 +03:00
|
|
|
/**
|
|
|
|
* Module: OSS data loading and processing.
|
|
|
|
*/
|
|
|
|
|
2025-02-26 00:16:41 +03:00
|
|
|
import { type ILibraryItem } from '@/features/library';
|
2025-02-12 21:36:25 +03:00
|
|
|
|
2025-03-12 12:04:50 +03:00
|
|
|
import { Graph } from '@/models/graph';
|
2025-01-30 19:55:38 +03:00
|
|
|
|
2025-04-20 15:55:52 +03:00
|
|
|
import { type IBlock, type IOperation, type IOperationSchema, type IOperationSchemaStats } from '../models/oss';
|
2025-04-21 20:37:11 +03:00
|
|
|
import { BLOCK_NODE_MIN_HEIGHT, BLOCK_NODE_MIN_WIDTH } from '../pages/oss-page/editor-oss-graph/graph/block-node';
|
2025-02-12 21:36:25 +03:00
|
|
|
|
2025-02-21 21:15:05 +03:00
|
|
|
import { type IOperationSchemaDTO, OperationType } from './types';
|
2024-06-04 23:00:22 +03:00
|
|
|
|
2025-04-20 15:55:52 +03:00
|
|
|
/** Loads data into an {@link IOperationSchema} based on {@link IOperationSchemaDTO}. */
|
2024-06-04 23:00:22 +03:00
|
|
|
export class OssLoader {
|
2025-02-18 23:39:11 +03:00
|
|
|
private oss: IOperationSchema;
|
2024-07-21 15:19:57 +03:00
|
|
|
private graph: Graph = new Graph();
|
2025-04-20 15:55:52 +03:00
|
|
|
private hierarchy: Graph = new Graph();
|
2025-02-12 20:53:31 +03:00
|
|
|
private operationByID = new Map<number, IOperation>();
|
2025-04-20 15:55:52 +03:00
|
|
|
private blockByID = new Map<number, IBlock>();
|
2025-02-12 15:13:37 +03:00
|
|
|
private schemaIDs: number[] = [];
|
2024-08-15 23:23:45 +03:00
|
|
|
private items: ILibraryItem[];
|
2024-06-04 23:00:22 +03:00
|
|
|
|
2025-01-30 19:55:38 +03:00
|
|
|
constructor(input: IOperationSchemaDTO, items: ILibraryItem[]) {
|
2025-02-18 23:39:11 +03:00
|
|
|
this.oss = input as unknown as IOperationSchema;
|
2024-08-15 23:23:45 +03:00
|
|
|
this.items = items;
|
2024-06-04 23:00:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
produceOSS(): IOperationSchema {
|
2025-02-18 23:39:11 +03:00
|
|
|
const result = this.oss;
|
2024-07-21 15:19:57 +03:00
|
|
|
this.prepareLookups();
|
|
|
|
this.createGraph();
|
2024-07-26 00:34:08 +03:00
|
|
|
this.extractSchemas();
|
2024-08-01 20:11:32 +03:00
|
|
|
this.inferOperationAttributes();
|
2025-04-20 15:55:52 +03:00
|
|
|
this.inferBlockAttributes();
|
2024-07-21 15:19:57 +03:00
|
|
|
|
|
|
|
result.operationByID = this.operationByID;
|
2025-04-20 15:55:52 +03:00
|
|
|
result.blockByID = this.blockByID;
|
2024-07-21 15:19:57 +03:00
|
|
|
result.graph = this.graph;
|
2025-04-20 15:55:52 +03:00
|
|
|
result.hierarchy = this.hierarchy;
|
2024-08-15 23:23:45 +03:00
|
|
|
result.schemas = this.schemaIDs;
|
2024-07-26 00:34:08 +03:00
|
|
|
result.stats = this.calculateStats();
|
2024-06-04 23:00:22 +03:00
|
|
|
return result;
|
|
|
|
}
|
2024-07-21 15:19:57 +03:00
|
|
|
|
|
|
|
private prepareLookups() {
|
2025-04-06 15:49:43 +03:00
|
|
|
this.oss.operations.forEach(operation => {
|
2025-02-18 23:39:11 +03:00
|
|
|
this.operationByID.set(operation.id, operation);
|
2024-07-21 15:19:57 +03:00
|
|
|
this.graph.addNode(operation.id);
|
2025-04-20 15:55:52 +03:00
|
|
|
this.hierarchy.addNode(operation.id);
|
|
|
|
if (operation.parent) {
|
|
|
|
this.hierarchy.addEdge(-operation.parent, operation.id);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
this.oss.blocks.forEach(block => {
|
|
|
|
this.blockByID.set(block.id, block);
|
|
|
|
this.hierarchy.addNode(-block.id);
|
|
|
|
if (block.parent) {
|
2025-04-21 20:37:11 +03:00
|
|
|
this.hierarchy.addEdge(-block.parent, -block.id);
|
2025-04-20 15:55:52 +03:00
|
|
|
}
|
2024-07-21 15:19:57 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
private createGraph() {
|
|
|
|
this.oss.arguments.forEach(argument => this.graph.addEdge(argument.argument, argument.operation));
|
|
|
|
}
|
2024-07-26 00:34:08 +03:00
|
|
|
|
|
|
|
private extractSchemas() {
|
2025-04-06 15:49:43 +03:00
|
|
|
this.schemaIDs = this.oss.operations.map(operation => operation.result).filter(item => item !== null);
|
2024-07-26 00:34:08 +03:00
|
|
|
}
|
|
|
|
|
2024-08-01 20:11:32 +03:00
|
|
|
private inferOperationAttributes() {
|
|
|
|
this.graph.topologicalOrder().forEach(operationID => {
|
|
|
|
const operation = this.operationByID.get(operationID)!;
|
2024-08-15 23:23:45 +03:00
|
|
|
const schema = this.items.find(item => item.id === operation.result);
|
2025-04-06 15:49:43 +03:00
|
|
|
const position = this.oss.layout.operations.find(item => item.id === operationID);
|
|
|
|
operation.x = position?.x ?? 0;
|
|
|
|
operation.y = position?.y ?? 0;
|
2024-08-17 12:17:13 +03:00
|
|
|
operation.is_consolidation = this.inferConsolidation(operationID);
|
2024-08-15 23:23:45 +03:00
|
|
|
operation.is_owned = !schema || (schema.owner === this.oss.owner && schema.location === this.oss.location);
|
2024-08-01 20:11:32 +03:00
|
|
|
operation.substitutions = this.oss.substitutions.filter(item => item.operation === operationID);
|
|
|
|
operation.arguments = this.oss.arguments
|
|
|
|
.filter(item => item.operation === operationID)
|
|
|
|
.map(item => item.argument);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2025-04-20 15:55:52 +03:00
|
|
|
private inferBlockAttributes() {
|
|
|
|
this.oss.blocks.forEach(block => {
|
|
|
|
const geometry = this.oss.layout.blocks.find(item => item.id === block.id);
|
|
|
|
block.x = geometry?.x ?? 0;
|
|
|
|
block.y = geometry?.y ?? 0;
|
2025-04-21 20:37:11 +03:00
|
|
|
block.width = geometry?.width ?? BLOCK_NODE_MIN_WIDTH;
|
|
|
|
block.height = geometry?.height ?? BLOCK_NODE_MIN_HEIGHT;
|
2025-04-20 15:55:52 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2025-02-12 20:53:31 +03:00
|
|
|
private inferConsolidation(operationID: number): boolean {
|
2024-08-17 12:17:13 +03:00
|
|
|
const inputs = this.graph.expandInputs([operationID]);
|
|
|
|
if (inputs.length === 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const ancestors = [...inputs];
|
|
|
|
inputs.forEach(input => {
|
|
|
|
ancestors.push(...this.graph.expandAllInputs([input]));
|
|
|
|
});
|
|
|
|
const unique = new Set(ancestors);
|
|
|
|
return unique.size < ancestors.length;
|
|
|
|
}
|
|
|
|
|
2024-07-26 00:34:08 +03:00
|
|
|
private calculateStats(): IOperationSchemaStats {
|
2025-04-20 15:55:52 +03:00
|
|
|
const operations = this.oss.operations;
|
2024-07-26 00:34:08 +03:00
|
|
|
return {
|
2025-04-20 15:55:52 +03:00
|
|
|
count_all: this.oss.operations.length + this.oss.blocks.length,
|
|
|
|
count_inputs: operations.filter(item => item.operation_type === OperationType.INPUT).length,
|
|
|
|
count_synthesis: operations.filter(item => item.operation_type === OperationType.SYNTHESIS).length,
|
2024-08-23 21:29:07 +03:00
|
|
|
count_schemas: this.schemaIDs.length,
|
2025-04-20 15:55:52 +03:00
|
|
|
count_owned: operations.filter(item => !!item.result && item.is_owned).length,
|
|
|
|
count_block: this.oss.blocks.length
|
2024-07-26 00:34:08 +03:00
|
|
|
};
|
|
|
|
}
|
2024-06-04 23:00:22 +03:00
|
|
|
}
|