Skip to content

Commit

Permalink
feat: hires boundary (#255)
Browse files Browse the repository at this point in the history
  • Loading branch information
bluwy committed Jul 28, 2023
1 parent 9213b45 commit a63d5f2
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 3 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -107,7 +107,7 @@ Generates a [version 3 sourcemap](https://docs.google.com/document/d/1U1RGAehQwR
* `file` - the filename where you plan to write the sourcemap
* `source` - the filename of the file containing the original source
* `includeContent` - whether to include the original content in the map's `sourcesContent` array
* `hires` - whether the mapping should be high-resolution. Hi-res mappings map every single character, meaning (for example) your devtools will always be able to pinpoint the exact location of function calls and so on. With lo-res mappings, devtools may only be able to identify the correct line - but they're quicker to generate and less bulky. If sourcemap locations have been specified with `s.addSourcemapLocation()`, they will be used here.
* `hires` - whether the mapping should be high-resolution. Hi-res mappings map every single character, meaning (for example) your devtools will always be able to pinpoint the exact location of function calls and so on. With lo-res mappings, devtools may only be able to identify the correct line - but they're quicker to generate and less bulky. You can also set `"boundary"` to generate a semi-hi-res mappings segmented per word boundary instead of per character, suitable for string semantics that are separated by words. If sourcemap locations have been specified with `s.addSourcemapLocation()`, they will be used here.

The returned sourcemap has two (non-enumerable) methods attached for convenience:

Expand Down
4 changes: 3 additions & 1 deletion src/index.d.ts
Expand Up @@ -10,9 +10,11 @@ export interface SourceMapOptions {
* be able to pinpoint the exact location of function calls and so on.
* With lo-res mappings, devtools may only be able to identify the correct
* line - but they're quicker to generate and less bulky.
* You can also set `"boundary"` to generate a semi-hi-res mappings segmented per word boundary
* instead of per character, suitable for string semantics that are separated by words.
* If sourcemap locations have been specified with s.addSourceMapLocation(), they will be used here.
*/
hires?: boolean;
hires?: boolean | 'boundary';
/**
* The filename where you plan to write the sourcemap.
*/
Expand Down
23 changes: 22 additions & 1 deletion src/utils/Mappings.js
@@ -1,3 +1,5 @@
const wordRegex = /\w/;

export default class Mappings {
constructor(hires) {
this.hires = hires;
Expand Down Expand Up @@ -26,10 +28,29 @@ export default class Mappings {
addUneditedChunk(sourceIndex, chunk, original, loc, sourcemapLocations) {
let originalCharIndex = chunk.start;
let first = true;
// when iterating each char, check if it's in a word boundary
let charInHiresBoundary = false;

while (originalCharIndex < chunk.end) {
if (this.hires || first || sourcemapLocations.has(originalCharIndex)) {
this.rawSegments.push([this.generatedCodeColumn, sourceIndex, loc.line, loc.column]);
const segment = [this.generatedCodeColumn, sourceIndex, loc.line, loc.column];

if (this.hires === 'boundary') {
// in hires "boundary", group segments per word boundary than per char
if (wordRegex.test(original[originalCharIndex])) {
// for first char in the boundary found, start the boundary by pushing a segment
if (!charInHiresBoundary) {
this.rawSegments.push(segment);
charInHiresBoundary = true;
}
} else {
// for non-word char, end the boundary by pushing a segment
this.rawSegments.push(segment);
charInHiresBoundary = false;
}
} else {
this.rawSegments.push(segment);
}
}

if (original[originalCharIndex] === '\n') {
Expand Down
35 changes: 35 additions & 0 deletions test/MagicString.js
Expand Up @@ -434,6 +434,41 @@ describe('MagicString', () => {
assert.deepEqual(map.sources, ['foo.js']);
assert.deepEqual(map.x_google_ignoreList, [0]);
});

it('generates segments per word boundary with hires "boundary"', () => {
const s = new MagicString('function foo(){ console.log("bar") }');

// rename bar to hello
s.overwrite(29, 32, 'hello');

const map = s.generateMap({
file: 'output.js',
source: 'input.js',
includeContent: true,
hires: 'boundary'
});

assert.equal(map.mappings, 'AAAA,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAG,CAAC,CAAC,CAAC');

const smc = new SourceMapConsumer(map);
let loc;

loc = smc.originalPositionFor({ line: 1, column: 3 });
assert.equal(loc.line, 1);
assert.equal(loc.column, 0);

loc = smc.originalPositionFor({ line: 1, column: 11 });
assert.equal(loc.line, 1);
assert.equal(loc.column, 9);

loc = smc.originalPositionFor({ line: 1, column: 29 });
assert.equal(loc.line, 1);
assert.equal(loc.column, 29);

loc = smc.originalPositionFor({ line: 1, column: 35 });
assert.equal(loc.line, 1);
assert.equal(loc.column, 33);
});
});

describe('getIndentString', () => {
Expand Down

0 comments on commit a63d5f2

Please sign in to comment.