• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import stream from "stream";
2import ts from "../../lib/typescript.js";
3import fs from "fs";
4import { base64VLQFormatEncode } from "./sourcemaps.mjs";
5
6/**
7 * @param {string | ((file: import("vinyl")) => string)} data
8 */
9export function prepend(data) {
10    return new stream.Transform({
11        objectMode: true,
12        /**
13         * @param {string | Buffer | import("vinyl")} input
14         * @param {(error: Error | null, data?: any) => void} cb
15         */
16        transform(input, _, cb) {
17            if (typeof input === "string" || Buffer.isBuffer(input)) return cb(new Error("Only Vinyl files are supported."));
18            if (!input.isBuffer()) return cb(new Error("Streams not supported."));
19            try {
20                const output = input.clone();
21                const prependContent = typeof data === "function" ? data(input) : data;
22                output.contents = Buffer.concat([Buffer.from(prependContent, "utf8"), input.contents]);
23                if (input.sourceMap) {
24                    if (typeof input.sourceMap === "string") input.sourceMap = /**@type {import("./sourcemaps.mjs").RawSourceMap}*/(JSON.parse(input.sourceMap));
25                    const lineStarts = /**@type {*}*/(ts).computeLineStarts(prependContent);
26                    let prependMappings = "";
27                    for (let i = 1; i < lineStarts.length; i++) {
28                        prependMappings += ";";
29                    }
30                    const offset = prependContent.length - lineStarts[lineStarts.length - 1];
31                    if (offset > 0) {
32                        prependMappings += base64VLQFormatEncode(offset) + ",";
33                    }
34                    output.sourceMap = {
35                        version: input.sourceMap.version,
36                        file: input.sourceMap.file,
37                        sources: input.sourceMap.sources,
38                        sourceRoot: input.sourceMap.sourceRoot,
39                        mappings: prependMappings + input.sourceMap.mappings,
40                        names: input.names,
41                        sourcesContent: input.sourcesContent
42                    };
43                }
44                // eslint-disable-next-line local/boolean-trivia, no-null/no-null
45                return cb(null, output);
46            }
47            catch (e) {
48                return cb(/** @type {Error} */(e));
49            }
50        }
51    });
52}
53
54/**
55 * @param {string | ((file: import("vinyl")) => string)} file
56 */
57export function prependFile(file) {
58    const data = typeof file === "string" ? fs.readFileSync(file, "utf8") :
59        (/** @type {import("vinyl")} */ vinyl) => fs.readFileSync(file(vinyl), "utf8");
60    return prepend(data);
61}
62