| [9af201e] | 1 | /*
|
|---|
| 2 | MIT License http://www.opensource.org/licenses/mit-license.php
|
|---|
| 3 | */
|
|---|
| 4 |
|
|---|
| 5 | "use strict";
|
|---|
| 6 |
|
|---|
| 7 | /**
|
|---|
| 8 | * Utilities for building V3 source-map `mappings` strings without pulling in a
|
|---|
| 9 | * full source-map library. The shape of the input is intentionally minimal —
|
|---|
| 10 | * one slot per generated line, each holding zero, one, or many segments — so
|
|---|
| 11 | * call sites that have a "one mapping per line" structure (like the CSS-module
|
|---|
| 12 | * exports emit in `lib/css/CssGenerator.js`) can build mappings directly,
|
|---|
| 13 | * while richer call sites can pass arrays of segments.
|
|---|
| 14 | *
|
|---|
| 15 | * TODO move this encoder into `webpack-sources` and replace the body of this
|
|---|
| 16 | * file with re-exports. The public shape (`encodeVLQ`, `encodeMappings(lines)`,
|
|---|
| 17 | * `MappingSegment`, `LineMappings`) is intended to match what would land
|
|---|
| 18 | * upstream so call sites don't have to change.
|
|---|
| 19 | */
|
|---|
| 20 |
|
|---|
| 21 | const VLQ_BASE64 =
|
|---|
| 22 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|---|
| 23 |
|
|---|
| 24 | /**
|
|---|
| 25 | * Encode a signed integer as a base64 VLQ string per the source-map V3 spec.
|
|---|
| 26 | * @param {number} value signed integer to encode
|
|---|
| 27 | * @returns {string} base64 VLQ encoded value
|
|---|
| 28 | */
|
|---|
| 29 | const encodeVLQ = (value) => {
|
|---|
| 30 | let vlq = value < 0 ? (-value << 1) | 1 : value << 1;
|
|---|
| 31 | let result = "";
|
|---|
| 32 | do {
|
|---|
| 33 | let digit = vlq & 0x1f;
|
|---|
| 34 | vlq >>>= 5;
|
|---|
| 35 | if (vlq > 0) digit |= 0x20;
|
|---|
| 36 | result += VLQ_BASE64[digit];
|
|---|
| 37 | } while (vlq > 0);
|
|---|
| 38 | return result;
|
|---|
| 39 | };
|
|---|
| 40 |
|
|---|
| 41 | /**
|
|---|
| 42 | * @typedef {object} MappingSegment
|
|---|
| 43 | * @property {number=} generatedColumn 0-based generated column (defaults to 0)
|
|---|
| 44 | * @property {number=} sourceIndex index into the surrounding source map's `sources` array; omit for a generated-only segment
|
|---|
| 45 | * @property {number=} originalLine 0-based line in the original source (required when `sourceIndex` is set)
|
|---|
| 46 | * @property {number=} originalColumn 0-based column in the original source (required when `sourceIndex` is set)
|
|---|
| 47 | * @property {number=} nameIndex index into the surrounding source map's `names` array
|
|---|
| 48 | */
|
|---|
| 49 |
|
|---|
| 50 | /** @typedef {null | MappingSegment | MappingSegment[]} LineMappings */
|
|---|
| 51 |
|
|---|
| 52 | /**
|
|---|
| 53 | * Encode a V3 source-map `mappings` string from a per-generated-line
|
|---|
| 54 | * description of segments.
|
|---|
| 55 | *
|
|---|
| 56 | * Each entry of `lines` describes the mappings for one generated line:
|
|---|
| 57 | *
|
|---|
| 58 | * - `null` (or `undefined`) — the line has no mappings.
|
|---|
| 59 | * - a single `MappingSegment` — convenience for the common "one mapping at
|
|---|
| 60 | * column 0" case.
|
|---|
| 61 | * - `MappingSegment[]` — multiple segments on the same line.
|
|---|
| 62 | *
|
|---|
| 63 | * Lines are joined with `;`, segments within a line with `,`. All numeric
|
|---|
| 64 | * fields are encoded as deltas relative to the previous emitted segment, per
|
|---|
| 65 | * the V3 spec.
|
|---|
| 66 | * @param {LineMappings[]} lines per-generated-line mapping segments
|
|---|
| 67 | * @returns {string} VLQ-encoded V3 mappings string
|
|---|
| 68 | */
|
|---|
| 69 | const encodeMappings = (lines) => {
|
|---|
| 70 | let prevSourceIndex = 0;
|
|---|
| 71 | let prevOriginalLine = 0;
|
|---|
| 72 | let prevOriginalColumn = 0;
|
|---|
| 73 | let prevNameIndex = 0;
|
|---|
| 74 |
|
|---|
| 75 | const encodedLines = [];
|
|---|
| 76 |
|
|---|
| 77 | for (const line of lines) {
|
|---|
| 78 | if (line === null || line === undefined) {
|
|---|
| 79 | encodedLines.push("");
|
|---|
| 80 | continue;
|
|---|
| 81 | }
|
|---|
| 82 |
|
|---|
| 83 | const segments = Array.isArray(line) ? line : [line];
|
|---|
| 84 | let prevGeneratedColumn = 0;
|
|---|
| 85 | const encodedSegments = [];
|
|---|
| 86 |
|
|---|
| 87 | for (const segment of segments) {
|
|---|
| 88 | const generatedColumn = segment.generatedColumn || 0;
|
|---|
| 89 | let encoded = encodeVLQ(generatedColumn - prevGeneratedColumn);
|
|---|
| 90 | prevGeneratedColumn = generatedColumn;
|
|---|
| 91 |
|
|---|
| 92 | if (segment.sourceIndex !== undefined) {
|
|---|
| 93 | const originalLine = /** @type {number} */ (segment.originalLine);
|
|---|
| 94 | const originalColumn = /** @type {number} */ (segment.originalColumn);
|
|---|
| 95 | encoded += encodeVLQ(segment.sourceIndex - prevSourceIndex);
|
|---|
| 96 | encoded += encodeVLQ(originalLine - prevOriginalLine);
|
|---|
| 97 | encoded += encodeVLQ(originalColumn - prevOriginalColumn);
|
|---|
| 98 | prevSourceIndex = segment.sourceIndex;
|
|---|
| 99 | prevOriginalLine = originalLine;
|
|---|
| 100 | prevOriginalColumn = originalColumn;
|
|---|
| 101 |
|
|---|
| 102 | if (segment.nameIndex !== undefined) {
|
|---|
| 103 | encoded += encodeVLQ(segment.nameIndex - prevNameIndex);
|
|---|
| 104 | prevNameIndex = segment.nameIndex;
|
|---|
| 105 | }
|
|---|
| 106 | }
|
|---|
| 107 |
|
|---|
| 108 | encodedSegments.push(encoded);
|
|---|
| 109 | }
|
|---|
| 110 |
|
|---|
| 111 | encodedLines.push(encodedSegments.join(","));
|
|---|
| 112 | }
|
|---|
| 113 |
|
|---|
| 114 | return encodedLines.join(";");
|
|---|
| 115 | };
|
|---|
| 116 |
|
|---|
| 117 | module.exports.encodeMappings = encodeMappings;
|
|---|
| 118 | module.exports.encodeVLQ = encodeVLQ;
|
|---|