@remotion/renderer
Version:
Render Remotion videos using Node.js or Bun
156 lines (155 loc) • 6.06 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getSourceMapFromLocalFile = exports.getSourceMapFromRemoteFile = exports.symbolicateStackFrame = exports.symbolicateFromSources = exports.symbolicateStackTraceFromRemoteFrames = exports.getSourceMapFromRemoteUrl = void 0;
const fs_1 = require("fs");
const path_1 = __importDefault(require("path"));
const source_map_1 = require("source-map");
const read_file_1 = require("./assets/read-file");
const truthy_1 = require("./truthy");
function extractSourceMapUrl(fileContents) {
const regex = /\/\/[#@] ?sourceMappingURL=([^\s'"]+)\s*$/gm;
let match = null;
for (;;) {
const next = regex.exec(fileContents);
if (next === null || next === undefined) {
break;
}
match = next;
}
if (!(match === null || match === void 0 ? void 0 : match[1])) {
return null;
}
return match[1].toString();
}
const getSourceMapFromRemoteUrl = async (url) => {
if (!url.endsWith('.js.map')) {
return Promise.reject(new Error(`The URL ${url} does not seem to be a valid source map URL.`));
}
const obj = await fetchUrl(url);
return new source_map_1.SourceMapConsumer(obj);
};
exports.getSourceMapFromRemoteUrl = getSourceMapFromRemoteUrl;
const getSourceMap = (filePath, fileContents, type) => {
const sm = extractSourceMapUrl(fileContents);
if (sm === null) {
return Promise.resolve(null);
}
if (sm.indexOf('data:') === 0) {
const base64 = /^data:application\/json;([\w=:"-]+;)*base64,/;
const match2 = sm.match(base64);
if (!match2) {
throw new Error('Sorry, non-base64 inline source-map encoding is not supported.');
}
const converted = window.atob(sm.substring(match2[0].length));
try {
const sourceMapConsumer = new source_map_1.SourceMapConsumer(JSON.parse(converted));
return Promise.resolve(sourceMapConsumer);
}
catch (_a) {
return Promise.resolve(null);
}
}
if (type === 'local') {
// Find adjacent file: bundle.js -> bundle.js.map
const newFilePath = path_1.default.join(path_1.default.dirname(filePath), sm);
return Promise.resolve(new source_map_1.SourceMapConsumer((0, fs_1.readFileSync)(newFilePath, 'utf8')));
}
const index = filePath.lastIndexOf('/');
const url = filePath.substring(0, index + 1) + sm;
return (0, exports.getSourceMapFromRemoteUrl)(url);
};
const fetchUrl = async (url) => {
const { request, response } = await (0, read_file_1.readFile)(url);
return new Promise((resolve, reject) => {
let downloaded = '';
response.on('data', (d) => {
downloaded += d;
});
response.on('end', () => {
request.destroy();
response.destroy();
resolve(downloaded);
});
response.on('error', (err) => {
request.destroy();
response.destroy();
return reject(err);
});
});
};
function getLinesAround(line, count, lines) {
const result = [];
for (let index = Math.max(0, line - 1 - count) + 1; index <= Math.min(lines.length - 1, line - 1 + count); ++index) {
result.push({
lineNumber: index + 1,
content: lines[index],
highlight: index + 1 === line,
});
}
return result;
}
const getOriginalPosition = (source_map, line, column) => {
const result = source_map.originalPositionFor({
line,
column,
});
return { line: result.line, column: result.column, source: result.source };
};
const symbolicateStackTraceFromRemoteFrames = async (frames) => {
const uniqueFileNames = [
...new Set(frames
.map((f) => f.fileName)
.filter((f) => f.startsWith('http://') || f.startsWith('https://'))
.filter(truthy_1.truthy)),
];
const maps = await Promise.all(uniqueFileNames.map((fileName) => {
return (0, exports.getSourceMapFromRemoteFile)(fileName);
}));
const mapValues = {};
for (let i = 0; i < uniqueFileNames.length; i++) {
mapValues[uniqueFileNames[i]] = maps[i];
}
return (0, exports.symbolicateFromSources)(frames, mapValues);
};
exports.symbolicateStackTraceFromRemoteFrames = symbolicateStackTraceFromRemoteFrames;
const symbolicateFromSources = (frames, mapValues) => {
return frames
.map((frame) => {
const map = mapValues[frame.fileName];
if (!map) {
return null;
}
return (0, exports.symbolicateStackFrame)(frame, map);
})
.filter(truthy_1.truthy)
.filter((f) => f.originalScriptCode !== null);
};
exports.symbolicateFromSources = symbolicateFromSources;
const symbolicateStackFrame = (frame, map) => {
const pos = getOriginalPosition(map, frame.lineNumber, frame.columnNumber);
const hasSource = pos.source ? map.sourceContentFor(pos.source, false) : null;
const scriptCode = hasSource && pos.line
? getLinesAround(pos.line, 3, hasSource.split('\n'))
: null;
return {
originalColumnNumber: pos.column,
originalFileName: pos.source,
originalFunctionName: frame.functionName,
originalLineNumber: pos.line,
originalScriptCode: scriptCode,
};
};
exports.symbolicateStackFrame = symbolicateStackFrame;
const getSourceMapFromRemoteFile = async (fileName) => {
const fileContents = await fetchUrl(fileName);
return getSourceMap(fileName, fileContents, 'remote');
};
exports.getSourceMapFromRemoteFile = getSourceMapFromRemoteFile;
const getSourceMapFromLocalFile = (fileName) => {
const fileContents = (0, fs_1.readFileSync)(fileName, 'utf8');
return getSourceMap(fileName, fileContents, 'local');
};
exports.getSourceMapFromLocalFile = getSourceMapFromLocalFile;