// Copyright 2014-2025 Jesper Larsson
//
// This file is part of Klipspringer, <https://klipspringer.avadeaux.net/>
//
// Klipspringer is free software: you can redistribute it and/or modify it under the terms of the
// GNU General Public License as published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// Klipspringer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with Klipspringer. If
// not, see <https://www.gnu.org/licenses/>.

import { readFile } from 'fs/promises';
import * as path from 'path';

export const expand = (input, dir, values, deps) => {
    const r = /\$(\$|\(([A-Za-z_.]+)(|:[A-Za-z_]*)\))/g;

    // Recursive function: appends one expansion, finds next macro. (It's done
    // with recursion so that it works both in "then" and in direct call.)
    // Returns a promise that resolves to the expanded text.
    const appendAndMatch = (expansion, output) => {
        output += expansion;
        const p = r.lastIndex;
        const  m = r.exec(input);

        if (!m) {
            // No more match, done.
            return Promise.resolve(output + input.substring(p));
        } else {
            output += input.substring(p, m.index);
            if (m[1] === '$') {
                return appendAndMatch("$", output);
            } else if (m[3] === ':file') {
                if (deps) { deps.push(m[2]); }
                return readFile(path.join(dir, m[2]))
                    .then(s => s.toString().replace(/^\/\/.*\n/gm, '').replace(/^\s*<!--[\s\S]*?-->/gm, ''))
                    .then(s => expand(s, dir, values))
                    .then(s => appendAndMatch(s, output));
            } else {
                return Promise.resolve(values[m[2]+m[3]])
                    .then(s => s === undefined ? "" : expand(s.toString(), dir, values))
                    .then(s => appendAndMatch(s, output));
            }
        }
    }

    return appendAndMatch("", "");
}

export const expandFile = (fileName, dir, values, deps) => readFile(path.join(dir, fileName))
    .then(s => expand(s.toString(), dir, values, deps));

Version: v4.3.2.2 (2026-05-16T17:03:34+02:00)
Raw file
Source code overview
Klipspringer home