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