UNPKG

@remotion/renderer

Version:

Render Remotion videos using Node.js or Bun

156 lines (155 loc) • 6.06 kB
"use strict"; 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;