myst-cli
Version:
Command line tools for MyST
70 lines (69 loc) • 2.69 kB
JavaScript
import path from 'node:path';
import fs from 'node:fs';
import { RuleId, fileError } from 'myst-common';
import { SourceFileKind } from 'myst-spec-ext';
import { includeDirectiveTransform } from 'myst-transforms';
import { watch } from '../store/reducers.js';
import { loadMdFile, loadNotebookFile, loadTexFile } from '../process/file.js';
/**
* Return resolveFile function
*
* If `sourceFile` is format .tex, `relativeFile` will be resolved relative to the
* original baseFile; otherwise, it will be resolved relative to `sourceFile`.
*
* The returned function will resolve the file as described above, and return it if
* it exists or log an error and return undefined otherwise.
*/
export const makeFileResolver = (baseFile) => (relativeFile, sourceFile, vfile) => {
const base = sourceFile.toLowerCase().endsWith('.tex') ? baseFile : sourceFile;
const fullFile = path.resolve(path.dirname(base), relativeFile);
if (!fs.existsSync(fullFile)) {
fileError(vfile, `Include Directive: Could not find "${relativeFile}" relative to "${base}"`, {
ruleId: RuleId.includeContentLoads,
});
return;
}
return fullFile;
};
/**
* Return loadFile function
*
* Loaded file is added to original baseFile's dependencies.
*/
export const makeFileLoader = (session, baseFile) => (fullFile) => {
session.store.dispatch(watch.actions.addLocalDependency({
path: baseFile,
dependency: fullFile,
}));
return fs.readFileSync(fullFile).toString();
};
/**
* Return paresContent function
*
* Handles html and tex files separately; all other files are treated as MyST md.
*/
export const makeContentParser = (session, file) => async (filename, content) => {
if (filename.toLowerCase().endsWith('.html')) {
const mdast = { type: 'root', children: [{ type: 'html', value: content }] };
return { mdast, kind: SourceFileKind.Article };
}
const opts = { keepTitleNode: true };
if (filename.toLowerCase().endsWith('.tex')) {
return loadTexFile(session, content, file, opts);
}
if (filename.toLowerCase().endsWith('.ipynb')) {
return loadNotebookFile(session, content, file, opts);
}
return loadMdFile(session, content, file, opts);
};
export async function includeFilesTransform(session, baseFile, tree, frontmatter, vfile) {
const parseContent = makeContentParser(session, baseFile);
const loadFile = makeFileLoader(session, baseFile);
const resolveFile = makeFileResolver(baseFile);
await includeDirectiveTransform(tree, frontmatter, vfile, {
resolveFile,
loadFile,
parseContent,
sourceFile: baseFile,
});
}