All files / src/pipeline/rfcxml assemble-markdown.js

88.23% Statements 45/51
62.96% Branches 17/27
83.33% Functions 5/6
88.23% Lines 45/51

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93          2x 2x 2x 2x 2x     4x     4x 4x 1x   3x     3x       4x 4x 4x 1x 1x 1x 1x 1x             3x 3x 1x   2x 2x 2x 2x 2x           3x 3x 2x   1x 1x             2x 2x 2x 2x   2x 5x 5x       5x     2x 2x 2x 2x     2x            
/**
 * Load and concatenate Spec-Up-T markdown sources the same way the HTML renderer does,
 * without mutating files or requiring a prior HTML render.
 */
 
const fs = require('fs-extra');
const path = require('node:path');
const { shouldProcessFile } = require('../../utils/file-filter');
const { processEscapedTags } = require('../preprocessing/escape-placeholder-utils');
const { applyReplacers } = require('../rendering/render-utils');
 
function listTermFiles(specDir, termsDirName) {
    Iif (!termsDirName) {
        return [];
    }
    const termsDir = path.join(specDir, termsDirName);
    if (!fs.existsSync(termsDir)) {
        return [];
    }
    return fs.readdirSync(termsDir)
        .filter(shouldProcessFile)
        .sort((a, b) => a.localeCompare(b))
        .map(file => path.join(termsDirName, file));
}
 
function resolveMarkdownPaths(spec, cwd = process.cwd()) {
    const paths = [...(spec.markdown_paths || ['spec.md'])];
    const generatedPath = path.join(cwd, '.cache', 'specs-generated.json');
    if (fs.existsSync(generatedPath)) {
        try {
            const generated = fs.readJsonSync(generatedPath);
            const generatedPaths = generated?.specs?.[0]?.markdown_paths;
            Eif (Array.isArray(generatedPaths) && generatedPaths.length) {
                return generatedPaths;
            }
        } catch {
            // Fall through to local resolution.
        }
    }
 
    const termFiles = listTermFiles(path.resolve(cwd, spec.spec_directory || '.'), spec.spec_terms_directory);
    if (!termFiles.length) {
        return paths;
    }
    const introIndex = paths.indexOf('terms-and-definitions-intro.md');
    Eif (introIndex !== -1) {
        const next = [...paths];
        next.splice(introIndex + 1, 0, ...termFiles);
        return next;
    }
    return [...paths, ...termFiles];
}
 
function loadXtrefs(cwd = process.cwd()) {
    const xtrefsPath = path.join(cwd, '.cache', 'xtrefs-data.json');
    if (!fs.existsSync(xtrefsPath)) {
        return { xtrefs: [] };
    }
    try {
        return fs.readJsonSync(xtrefsPath);
    } catch {
        return { xtrefs: [] };
    }
}
 
function assembleMarkdown(spec, cwd = process.cwd()) {
    const specDir = path.resolve(cwd, spec.spec_directory || '.');
    const relPaths = resolveMarkdownPaths(spec, cwd);
    const docs = [];
    const missing = [];
 
    for (const rel of relPaths) {
        const full = path.join(specDir, rel);
        Iif (!fs.existsSync(full)) {
            missing.push(rel);
            continue;
        }
        docs.push(fs.readFileSync(full, 'utf8'));
    }
 
    let markdown = docs.join('\n\n');
    markdown = processEscapedTags(markdown);
    markdown = applyReplacers(markdown);
    return { markdown, paths: relPaths, missing };
}
 
module.exports = {
    listTermFiles,
    resolveMarkdownPaths,
    loadXtrefs,
    assembleMarkdown
};