UNPKG

@serwist/build

Version:

A module that integrates into your build process, helping you generate a manifest of local files that should be precached.

123 lines (109 loc) 3.4 kB
/* Copyright 2019 Google LLC Use of this source code is governed by an MIT-style license that can be found in the LICENSE file or at https://opensource.org/licenses/MIT. */ import type { RawSourceMap } from "source-map"; import { SourceMapConsumer, SourceMapGenerator } from "source-map"; interface ReplaceAndUpdateSourceMapOptions { /** * The name for the file whose contents * correspond to originalSource. */ jsFilename: string; /** * The sourcemap for originalSource, * prior to any replacements. */ originalMap: RawSourceMap; /** * The source code, prior to any * replacements. */ originalSource: string; /** * A string to swap in for searchString. */ replaceString: string; /** * A string in originalSource to replace. * Only the first occurrence will be replaced. */ searchString: string; } /** * Adapted from https://github.com/nsams/sourcemap-aware-replace, with modern * JavaScript updates, along with additional properties copied from originalMap. * * @param options * @returns An object containing both * originalSource with the replacement applied, and the modified originalMap. * @private */ export async function replaceAndUpdateSourceMap({ jsFilename, originalMap, originalSource, replaceString, searchString, }: ReplaceAndUpdateSourceMapOptions): Promise<{ map: string; source: string }> { const generator = new SourceMapGenerator({ file: jsFilename, }); const consumer = await new SourceMapConsumer(originalMap); let pos: number; let src = originalSource; const replacements: { line: number; column: number }[] = []; let lineNum = 0; let filePos = 0; const lines = src.split("\n"); for (let line of lines) { lineNum++; let searchPos = 0; while ((pos = line.indexOf(searchString, searchPos)) !== -1) { src = src.substring(0, filePos + pos) + replaceString + src.substring(filePos + pos + searchString.length); line = line.substring(0, pos) + replaceString + line.substring(pos + searchString.length); replacements.push({ line: lineNum, column: pos }); searchPos = pos + replaceString.length; } filePos += line.length + 1; } replacements.reverse(); consumer.eachMapping((mapping) => { for (const replacement of replacements) { if (replacement.line === mapping.generatedLine && mapping.generatedColumn > replacement.column) { const offset = searchString.length - replaceString.length; mapping.generatedColumn -= offset; } } if (mapping.source) { const newMapping = { generated: { line: mapping.generatedLine, column: mapping.generatedColumn, }, original: { line: mapping.originalLine, column: mapping.originalColumn, }, source: mapping.source, }; return generator.addMapping(newMapping); } return mapping; }); consumer.destroy(); // JSON.parse returns any. // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const updatedSourceMap: RawSourceMap = Object.assign(JSON.parse(generator.toString()), { names: originalMap.names, sourceRoot: originalMap.sourceRoot, sources: originalMap.sources, sourcesContent: originalMap.sourcesContent, }); return { map: JSON.stringify(updatedSourceMap), source: src, }; }