@jridgewell/gen-mapping
Advanced tools
Comparing version 0.2.0 to 0.3.0
@@ -7,2 +7,9 @@ (function (global, factory) { | ||
const COLUMN = 0; | ||
const SOURCES_INDEX = 1; | ||
const SOURCE_LINE = 2; | ||
const SOURCE_COLUMN = 3; | ||
const NAMES_INDEX = 4; | ||
const NO_NAME = -1; | ||
/** | ||
@@ -19,2 +26,14 @@ * A low-level API to associate a generated position with an original source position. Line and | ||
/** | ||
* Same as `addSegment`, but will only add the segment if it generates useful information in the | ||
* resulting map. This only works correctly if segments are added **in order**, meaning you should | ||
* not add a segment with a lower generated line/column than one that came before. | ||
*/ | ||
exports.maybeAddSegment = void 0; | ||
/** | ||
* Same as `addMapping`, but will only add the mapping if it generates useful information in the | ||
* resulting map. This only works correctly if mappings are added **in order**, meaning you should | ||
* not add a mapping with a lower generated line/column than one that came before. | ||
*/ | ||
exports.maybeAddMapping = void 0; | ||
/** | ||
* Adds/removes the content of the source file to the source map. | ||
@@ -42,2 +61,4 @@ */ | ||
exports.allMappings = void 0; | ||
// This split declaration is only so that terser can elminiate the static initialization block. | ||
let addSegmentInternal; | ||
/** | ||
@@ -58,22 +79,13 @@ * Provides the state to generate a sourcemap. | ||
exports.addSegment = (map, genLine, genColumn, source, sourceLine, sourceColumn, name) => { | ||
const { _mappings: mappings, _sources: sources, _sourcesContent: sourcesContent, _names: names, } = map; | ||
const line = getLine(mappings, genLine); | ||
if (!source) { | ||
const seg = [genColumn]; | ||
const index = getColumnIndex(line, genColumn, seg); | ||
return insert(line, index, seg); | ||
} | ||
const sourcesIndex = setArray.put(sources, source); | ||
const seg = name | ||
? [genColumn, sourcesIndex, sourceLine, sourceColumn, setArray.put(names, name)] | ||
: [genColumn, sourcesIndex, sourceLine, sourceColumn]; | ||
const index = getColumnIndex(line, genColumn, seg); | ||
if (sourcesIndex === sourcesContent.length) | ||
sourcesContent[sourcesIndex] = null; | ||
insert(line, index, seg); | ||
return addSegmentInternal(false, map, genLine, genColumn, source, sourceLine, sourceColumn, name); | ||
}; | ||
exports.maybeAddSegment = (map, genLine, genColumn, source, sourceLine, sourceColumn, name) => { | ||
return addSegmentInternal(true, map, genLine, genColumn, source, sourceLine, sourceColumn, name); | ||
}; | ||
exports.addMapping = (map, mapping) => { | ||
const { generated, source, original, name } = mapping; | ||
return exports.addSegment(map, generated.line - 1, generated.column, source, original == null ? undefined : original.line - 1, original === null || original === void 0 ? void 0 : original.column, name); | ||
return addMappingInternal(false, map, mapping); | ||
}; | ||
exports.maybeAddMapping = (map, mapping) => { | ||
return addMappingInternal(true, map, mapping); | ||
}; | ||
exports.setSourceContent = (map, source, content) => { | ||
@@ -85,5 +97,6 @@ const { _sources: sources, _sourcesContent: sourcesContent } = map; | ||
const { file, sourceRoot, _mappings: mappings, _sources: sources, _sourcesContent: sourcesContent, _names: names, } = map; | ||
removeEmptyFinalLines(mappings); | ||
return { | ||
version: 3, | ||
file, | ||
file: file || undefined, | ||
names: names.array, | ||
@@ -107,3 +120,3 @@ sourceRoot: sourceRoot || undefined, | ||
const seg = line[j]; | ||
const generated = { line: i + 1, column: seg[0] }; | ||
const generated = { line: i + 1, column: seg[COLUMN] }; | ||
let source = undefined; | ||
@@ -113,6 +126,6 @@ let original = undefined; | ||
if (seg.length !== 1) { | ||
source = sources.array[seg[1]]; | ||
original = { line: seg[2] + 1, column: seg[3] }; | ||
source = sources.array[seg[SOURCES_INDEX]]; | ||
original = { line: seg[SOURCE_LINE] + 1, column: seg[SOURCE_COLUMN] }; | ||
if (seg.length === 5) | ||
name = names.array[seg[4]]; | ||
name = names.array[seg[NAMES_INDEX]]; | ||
} | ||
@@ -133,2 +146,23 @@ out.push({ generated, source, original, name }); | ||
}; | ||
// Internal helpers | ||
addSegmentInternal = (skipable, map, genLine, genColumn, source, sourceLine, sourceColumn, name) => { | ||
const { _mappings: mappings, _sources: sources, _sourcesContent: sourcesContent, _names: names, } = map; | ||
const line = getLine(mappings, genLine); | ||
const index = getColumnIndex(line, genColumn); | ||
if (!source) { | ||
if (skipable && skipSourceless(line, index)) | ||
return; | ||
return insert(line, index, [genColumn]); | ||
} | ||
const sourcesIndex = setArray.put(sources, source); | ||
const namesIndex = name ? setArray.put(names, name) : NO_NAME; | ||
if (sourcesIndex === sourcesContent.length) | ||
sourcesContent[sourcesIndex] = null; | ||
if (skipable && skipSource(line, index, sourcesIndex, sourceLine, sourceColumn, namesIndex)) { | ||
return; | ||
} | ||
return insert(line, index, name | ||
? [genColumn, sourcesIndex, sourceLine, sourceColumn, namesIndex] | ||
: [genColumn, sourcesIndex, sourceLine, sourceColumn]); | ||
}; | ||
})(); | ||
@@ -141,42 +175,11 @@ function getLine(mappings, index) { | ||
} | ||
function getColumnIndex(line, column, seg) { | ||
function getColumnIndex(line, genColumn) { | ||
let index = line.length; | ||
for (let i = index - 1; i >= 0; i--, index--) { | ||
for (let i = index - 1; i >= 0; index = i--) { | ||
const current = line[i]; | ||
const col = current[0]; | ||
if (col > column) | ||
continue; | ||
if (col < column) | ||
if (genColumn >= current[COLUMN]) | ||
break; | ||
const cmp = compare(current, seg); | ||
if (cmp === 0) | ||
return index; | ||
if (cmp < 0) | ||
break; | ||
} | ||
return index; | ||
} | ||
function compare(a, b) { | ||
let cmp = compareNum(a.length, b.length); | ||
if (cmp !== 0) | ||
return cmp; | ||
// We've already checked genColumn | ||
if (a.length === 1) | ||
return 0; | ||
cmp = compareNum(a[1], b[1]); | ||
if (cmp !== 0) | ||
return cmp; | ||
cmp = compareNum(a[2], b[2]); | ||
if (cmp !== 0) | ||
return cmp; | ||
cmp = compareNum(a[3], b[3]); | ||
if (cmp !== 0) | ||
return cmp; | ||
if (a.length === 4) | ||
return 0; | ||
return compareNum(a[4], b[4]); | ||
} | ||
function compareNum(a, b) { | ||
return a - b; | ||
} | ||
function insert(array, index, value) { | ||
@@ -188,2 +191,12 @@ for (let i = array.length; i > index; i--) { | ||
} | ||
function removeEmptyFinalLines(mappings) { | ||
const { length } = mappings; | ||
let len = length; | ||
for (let i = len - 1; i >= 0; len = i, i--) { | ||
if (mappings[i].length > 0) | ||
break; | ||
} | ||
if (len < length) | ||
mappings.length = len; | ||
} | ||
function putAll(strarr, array) { | ||
@@ -193,2 +206,36 @@ for (let i = 0; i < array.length; i++) | ||
} | ||
function skipSourceless(line, index) { | ||
// The start of a line is already sourceless, so adding a sourceless segment to the beginning | ||
// doesn't generate any useful information. | ||
if (index === 0) | ||
return true; | ||
const prev = line[index - 1]; | ||
// If the previous segment is also sourceless, then adding another sourceless segment doesn't | ||
// genrate any new information. Else, this segment will end the source/named segment and point to | ||
// a sourceless position, which is useful. | ||
return prev.length === 1; | ||
} | ||
function skipSource(line, index, sourcesIndex, sourceLine, sourceColumn, namesIndex) { | ||
// A source/named segment at the start of a line gives position at that genColumn | ||
if (index === 0) | ||
return false; | ||
const prev = line[index - 1]; | ||
// If the previous segment is sourceless, then we're transitioning to a source. | ||
if (prev.length === 1) | ||
return false; | ||
// If the previous segment maps to the exact same source position, then this segment doesn't | ||
// provide any new position information. | ||
return (sourcesIndex === prev[SOURCES_INDEX] && | ||
sourceLine === prev[SOURCE_LINE] && | ||
sourceColumn === prev[SOURCE_COLUMN] && | ||
namesIndex === (prev.length === 5 ? prev[NAMES_INDEX] : NO_NAME)); | ||
} | ||
function addMappingInternal(skipable, map, mapping) { | ||
const { generated, source, original, name } = mapping; | ||
if (!source) { | ||
return addSegmentInternal(skipable, map, generated.line - 1, generated.column, null, null, null, null); | ||
} | ||
const s = source; | ||
return addSegmentInternal(skipable, map, generated.line - 1, generated.column, s, original.line - 1, original.column, name); | ||
} | ||
@@ -195,0 +242,0 @@ exports.GenMapping = GenMapping; |
@@ -42,2 +42,14 @@ import type { SourceMapInput } from '@jridgewell/trace-mapping'; | ||
/** | ||
* Same as `addSegment`, but will only add the segment if it generates useful information in the | ||
* resulting map. This only works correctly if segments are added **in order**, meaning you should | ||
* not add a segment with a lower generated line/column than one that came before. | ||
*/ | ||
export declare let maybeAddSegment: typeof addSegment; | ||
/** | ||
* Same as `addMapping`, but will only add the mapping if it generates useful information in the | ||
* resulting map. This only works correctly if mappings are added **in order**, meaning you should | ||
* not add a mapping with a lower generated line/column than one that came before. | ||
*/ | ||
export declare let maybeAddMapping: typeof addMapping; | ||
/** | ||
* Adds/removes the content of the source file to the source map. | ||
@@ -44,0 +56,0 @@ */ |
{ | ||
"name": "@jridgewell/gen-mapping", | ||
"version": "0.2.0", | ||
"version": "0.3.0", | ||
"description": "Generate source maps", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -21,3 +21,3 @@ # @jridgewell/gen-mapping | ||
```typescript | ||
import { GenMapping, addMapping, setSourceContent, encodedMap } from '@jridgewell/gen-mapping'; | ||
import { GenMapping, addMapping, setSourceContent, toEncodedMap, toDecodedMap } from '@jridgewell/gen-mapping'; | ||
@@ -45,3 +45,3 @@ const map = new GenMapping({ | ||
assert.deepEqual(encodedMap(map), { | ||
assert.deepEqual(toDecodedMap(map), { | ||
version: 3, | ||
@@ -53,2 +53,14 @@ file: 'output.js', | ||
sourcesContent: ['function foo() {}'], | ||
mappings: [ | ||
[ [0, 0, 0, 0], [9, 0, 0, 9, 0] ] | ||
], | ||
}); | ||
assert.deepEqual(toEncodedMap(map), { | ||
version: 3, | ||
file: 'output.js', | ||
names: ['foo'], | ||
sourceRoot: 'https://example.com/', | ||
sources: ['input.js'], | ||
sourcesContent: ['function foo() {}'], | ||
mappings: 'AAAA,SAASA', | ||
@@ -58,2 +70,43 @@ }); | ||
### Smaller Sourcemaps | ||
Not everything needs to be added to a sourcemap, and needless markings can cause signficantly | ||
larger file sizes. `gen-mapping` exposes `maybeAddSegment`/`maybeAddMapping` APIs that will | ||
intelligently determine if this marking adds useful information. If not, the marking will be | ||
skipped. | ||
```typescript | ||
import { maybeAddMapping } from '@jridgewell/gen-mapping'; | ||
const map = new GenMapping(); | ||
// Adding a sourceless marking at the beginning of a line isn't useful. | ||
maybeAddMapping(map, { | ||
generated: { line: 1, column: 0 }, | ||
}); | ||
// Adding a new source marking is useful. | ||
maybeAddMapping(map, { | ||
generated: { line: 1, column: 0 }, | ||
source: 'input.js', | ||
original: { line: 1, column: 0 }, | ||
}); | ||
// But adding another marking pointing to the exact same original location isn't, even if the | ||
// generated column changed. | ||
maybeAddMapping(map, { | ||
generated: { line: 1, column: 9 }, | ||
source: 'input.js', | ||
original: { line: 1, column: 0 }, | ||
}); | ||
assert.deepEqual(toEncodedMap(map), { | ||
version: 3, | ||
names: [], | ||
sources: ['input.js'], | ||
sourcesContent: [null], | ||
mappings: 'AAAA', | ||
}); | ||
``` | ||
## Benchmarks | ||
@@ -60,0 +113,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
76203
592
182