@comyata/fe
Version:
Execute YAML and JSON files like programs and get clean data to work with as result.
107 lines (106 loc) • 5.74 kB
TypeScript
import { DataFile } from '@comyata/fe/DataFile';
import { DataFileRegistry } from '@comyata/fe/DataFileRegistry';
import { Importers } from '@comyata/fe/Importers';
import { Parser } from '@comyata/run/Parser';
import { DataNode, IDataNode } from '@comyata/run/DataNode';
import { ComputeStats, runtime, IComputeStatsBase, NodeRuntimeBaggage, NodeRuntimeBaggageComplete, NodeComputeEngines, ComputeFn } from '@comyata/run/Runtime';
export interface Resolver {
id: string;
/**
* @todo most pure-loaders shouldn't need to specify resolveRelative,
* but only with real-data, for filtering/sorting, (and not just a string as $load arg) something like 'genFileIdFromArgs" would make sense
*/
scopes: string[];
resolveDirectory?: (baseUrl: string) => ResolveContext;
resolveFile: (fileUrl: string) => FileResolveContext;
}
export interface ResolveContext {
/**
* @todo maybe support a Symbol based id, to distinguish importers with same ID
* @todo make import context required? would make the in-memory files complexer - or depending on their actual importer
*/
importer?: string;
resolveRelative?: ((relPath: string) => string);
}
export interface FileResolveContext extends ResolveContext {
load: () => Promise<unknown> | unknown;
}
export interface FileComputeStats extends IComputeStatsBase {
step: 'computeFile';
file: string;
stats: (FileComputeStats | ComputeStats)[];
cached?: 0 | 1 | 2;
usages?: Map<DataFile, Set<IDataNode>>;
}
export type ImportContext = ResolveContext | FileResolveContext;
export type RuntimeContext<TNode extends IDataNode = IDataNode> = {
registry: DataFileRegistry<TNode>;
/**
* Either an object containing the computed result for an file in the current run,
* or a subscriber function if currently already running computations, which resolves with the computed data.
*
* Used as a runtime cache, as each file will always be executed with the same "context" the resulted computations are expected to be stable within one run.
* This guarantees that multiple `$import/$load` on the same URL will always have the same data inside a single run.
*/
fileEvals: Map<DataFile, {
result: unknown;
} | ((requestingFilesChain: Set<DataFile>, requestingNodesChain: Set<IDataNode>) => Promise<unknown>)>;
fileEvalsAwaiter: Map<DataFile, Set<DataFile>>;
fileListener: Map<DataFile, ((result: unknown, err?: any) => void)[]>;
/**
* map which DataFile is used by which DataFile in which DataNode
*/
usages: Map<DataFile, Map<DataFile, Set<IDataNode>>>;
};
export interface FileRuntimeBaggage<TNode extends IDataNode> extends NodeRuntimeBaggage<TNode> {
dataFile: DataFile<TNode | IDataNode>;
filesChain: Set<DataFile<TNode | IDataNode>>;
computeStats: FileComputeStats;
runtimeContext: RuntimeContext<TNode | IDataNode>;
fileEngine: Pick<FileEngine<any>, 'run' | 'fetchFile'>;
}
export type FileComputeFn<TNode extends IDataNode, C = unknown, TBaggage extends FileRuntimeBaggage<TNode> = FileRuntimeBaggage<TNode>> = ComputeFn<TNode, C, TBaggage & NodeRuntimeBaggageComplete<TNode | IDataNode>>;
export type FileComputeFn2<TNode extends IDataNode, C = unknown> = (dataNode: TNode, context: C, parentData: unknown[], runtimeBaggage: FileRuntimeBaggage<TNode | IDataNode> & NodeRuntimeBaggageComplete<TNode | IDataNode>) => Promise<unknown>;
type FileComputeEngines<TNode extends IDataNode, C = unknown, TBaggage extends FileRuntimeBaggage<TNode> = FileRuntimeBaggage<TNode>> = NodeComputeEngines<TNode, C, TBaggage>;
declare class SubscribeMap<K, V> extends Map<K, V> {
private readonly listeners;
set(key: K, value: V): this;
delete(key: K): boolean;
clear(): void;
onAdd(cb: (key: K, value: V) => void): () => void;
onDelete(cb: (deletedKey: K) => void): () => void;
}
export declare class FileEngine<TNode extends typeof DataNode> {
readonly parser: Parser<TNode>;
readonly files: SubscribeMap<string, DataFile<InstanceType<TNode>>>;
readonly compute: FileComputeEngines<InstanceType<TNode>>;
readonly processorOptions: Parameters<typeof runtime>[3];
private readonly importer;
constructor({ nodes, compute, importer, processorOptions, parserOptions, }: {
nodes: TNode[];
compute: FileComputeEngines<InstanceType<TNode>>;
importer?: Importers;
processorOptions?: Parameters<typeof runtime>[3];
parserOptions?: Partial<Parser<TNode>['options']>;
});
/**
* @todo risky method, only use outside of computations/runs, to not accidentally access the wrong files cache,
* safe to use outside of runs
*/
contextOf(contextBaseUrl: string): ResolveContext;
/**
* @todo maybe move into registry?
* @todo risky method, only use outside of computations/runs, to not accidentally access the wrong files cache;
* safe to use outside of runs
*/
fileRef(file: string, importContext?: ImportContext): DataFile<InstanceType<TNode>>;
register(id: string, objOrEval: unknown, importContext?: ImportContext): DataFile<InstanceType<TNode>>;
private newFile;
fetchFile(dataFile: DataFile<InstanceType<TNode>>, registry: DataFileRegistry<InstanceType<TNode>>, statsList?: any[]): Promise<unknown>;
run(dataFile: DataFile<InstanceType<TNode>>, context?: unknown, runtimeContext?: RuntimeContext<InstanceType<TNode>>, { filesChain, nodesChain, ...baggage }?: {
filesChain?: Set<DataFile<InstanceType<TNode>>>;
nodesChain?: Set<InstanceType<TNode>>;
abort?: AbortSignal;
}): Promise<[unknown, FileComputeStats, RuntimeContext<InstanceType<TNode>>]>;
}
export {};