@meldscience/meld
Version:
pipeable one-shot prompt scripting toolkit
105 lines (93 loc) • 3.09 kB
text/typescript
import { readFileSync } from 'fs';
import { dirname } from 'path';
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkStringify, { Options } from 'remark-stringify';
import { remarkMeldDirectives } from './plugins/remarkMeldDirectives';
import { remarkProcessMeldNodes } from './plugins/remarkProcessMeldNodes';
import { remarkMeldDirectiveHandler } from './plugins/remarkMeldDirectiveHandler';
export interface MeldOptions {
inputPath: string;
workspacePath: string;
outputFile?: string;
dryRun?: boolean;
debug?: boolean;
}
export interface MeldResult {
content: string;
errors: string[];
}
export async function processMeldFile(options: MeldOptions): Promise<MeldResult> {
const { inputPath, workspacePath, debug } = options;
try {
const content = readFileSync(inputPath, 'utf-8');
// Process the file through our remark pipeline
const file = await unified()
.use(remarkParse)
.use(() => (tree) => {
if (debug) console.log('After parse:', JSON.stringify(tree, null, 2));
return tree;
})
.use(remarkMeldDirectives)
.use(() => (tree) => {
if (debug) console.log('After meldDirectives:', JSON.stringify(tree, null, 2));
return tree;
})
.use(remarkProcessMeldNodes, { currentFileDir: dirname(inputPath), debug })
.use(() => (tree) => {
if (debug) console.log('After processMeldNodes:', JSON.stringify(tree, null, 2));
return tree;
})
.use(remarkMeldDirectiveHandler)
.use(() => (tree) => {
if (debug) console.log('After meldDirectiveHandler:', JSON.stringify(tree, null, 2));
return tree;
})
.use(remarkStringify, {
// Disable escaping and other markdown processing
entities: false,
bullet: '-',
fence: '`',
fences: true,
incrementListMarker: true,
rule: '-',
ruleRepetition: 3,
ruleSpaces: false,
setext: false,
quote: '"',
strong: '*',
emphasis: '_'
} as Options)
.process(content);
const meldErrors = (file.data as any).meldErrors || [];
// Clean up any double newlines and trailing whitespace
let processedContent = String(file);
processedContent = processedContent.split('\n').map(line => line.trimRight()).join('\n');
processedContent = processedContent.replace(/\n{3,}/g, '\n\n');
processedContent = processedContent.replace(/\n+$/, '\n');
return {
content: processedContent,
errors: meldErrors
};
} catch (error) {
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
return {
content: '',
errors: ['Input file not found']
};
}
return {
content: '',
errors: [`Error processing file: ${(error as Error).message}`]
};
}
}
export class Meld {
private options: MeldOptions;
constructor(options: MeldOptions) {
this.options = options;
}
async process(): Promise<MeldResult> {
return processMeldFile(this.options);
}
}