@emanuelsan/mosaic-js
Version:
Composable Markdown-based AI instruction engine for Node.js
76 lines • 3.25 kB
JavaScript
import { Effect, Console, Data, Context } from 'effect';
import { isValidTemplateSelector } from './utils/isValidTemplateSelector';
import { buildTemplateTree } from './utils/buildTemplateTree';
import { checkDirectory } from './utils/checkDirectory';
import { decodeVariables, } from './utils/decodeVariables';
import { decodeTemplateOverrides, } from './utils/decodeTemplateOverrides';
import { Directory } from './utils/normalizeToRelativeSelector';
// Error Types Definitions
class InvalidTemplateSelectorError extends Data.TaggedError('InvalidTemplateSelectorError') {
}
export class MosaicVariables extends Context.Tag('MosaicVariables')() {
}
// Class Definitions
export class Mosaic {
instructionsDir;
variables = {};
overrides = {};
/**
* Creates a new Mosaic instance.
* @param instructionsDir - Path to the directory containing all the markdown files to be parsed and assembled.
* This directory should contain the modular instruction templates for expansion.
*/
constructor(instructionsDir) {
this.instructionsDir = instructionsDir;
}
compose(templateSelector) {
// Create the full Effect context
const context = Context.empty().pipe(Context.add(MosaicVariables, {
templateVariables: Effect.succeed(this.variables),
templateOverrides: Effect.succeed(this.overrides),
}), Context.add(Directory, {
templateDir: Effect.succeed(this.instructionsDir),
}));
// Define the full expansion pipeline
const pipeline = Effect.gen(function* () {
const validation = yield* isValidTemplateSelector(templateSelector);
if (!validation.valid) {
yield* Console.error(`${templateSelector} is not a valid template selector. Returning empty string.`);
return yield* Effect.fail(new InvalidTemplateSelectorError({
message: 'Invalid template selector',
}));
}
// Build the template tree, recursively expand and flatten it
const finalNode = yield* buildTemplateTree(templateSelector);
return finalNode.content;
});
// Provide context and run the pipeline
const result = Effect.runSync(Effect.provide(pipeline, context));
return result;
}
/**
* Creates a new Mosaic instance from a directory of markdown files.
* @param instructionsDir - Path to the directory that this mosaic will have as a parse base.
*/
static fromDirectory(instructionsDir) {
return Effect.runSync(checkDirectory(instructionsDir));
}
provideVariables(variables) {
const decoded = Effect.runSync(decodeVariables(variables));
this.variables = {
...this.variables,
...decoded,
};
return this;
}
provideOverrides(overrides) {
const effect = Effect.provideService(decodeTemplateOverrides(overrides), Directory, { templateDir: Effect.succeed(this.instructionsDir) });
const decoded = Effect.runSync(effect);
this.overrides = {
...this.overrides,
...decoded,
};
return this;
}
}
//# sourceMappingURL=Mosaic.js.map