Skip to content

Commit

Permalink
feat: add the ability to ignore-list sources
Browse files Browse the repository at this point in the history
This adds the ability to mark sources emitted into a source map as
ignore-listed, which provides a hint that debuggers can utilize when
dealing with these sources[^1].

The `ignoreList` option can be passed to a `MagicString` now, and will
be considered when generating a source map for it. In addition that bit
will also be considered when the `MagicString` is added as source to a
`Bundle` (with the possibility to override the value via a parameter to
`addSource`). The `x_google_ignoreList` field in the source map will
only be emitted if at least one of its sources was explicitly marked
with `ignoreList: true`. Otherwise - and primarily for backwards
compatibility with the existing ecosystem - no `x_google_ignoreList`
field is emitted.

Fixes #241

[^1]: https://developer.chrome.com/blog/devtools-better-angular-debugging
  • Loading branch information
bmeurer committed Feb 20, 2023
1 parent d4e9c31 commit e80b3f8
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 5 deletions.
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ You can pass an options argument:

```js
const s = new MagicString(someCode, {
// both these options will be used if you later
// call `bundle.addSource( s )` - see below
// these options will be used if you later call `bundle.addSource( s )` - see below
filename: 'foo.js',
indentExclusionRanges: [/*...*/]
indentExclusionRanges: [/*...*/],
ignoreList: true
});
```

Expand Down Expand Up @@ -251,6 +251,15 @@ bundle.addSource({
content: new MagicString('console.log( answer )')
});

// Sources can be marked as ignore-listed, which provides a hint to debuggers
// to not step into this code and also don't show the source files depending
// on user preferences.
bundle.addSource({
filename: 'some-3rdparty-library.js',
content: new MagicString('function myLib(){}'),
ignoreList: true
})

// Advanced: a source can include an `indentExclusionRanges` property
// alongside `filename` and `content`. This will be passed to `s.indent()`
// - see documentation above
Expand Down
2 changes: 1 addition & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export class SourceMap {

export class Bundle {
constructor(options?: BundleOptions);
addSource(source: MagicString | { filename?: string, content: MagicString }): Bundle;
addSource(source: MagicString | { filename?: string, content: MagicString, ignoreList?: boolean }): Bundle;
append(str: string, options?: BundleOptions): Bundle;
clone(): Bundle;
generateMap(options?: SourceMapOptions): SourceMap;
Expand Down
11 changes: 10 additions & 1 deletion src/Bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default class Bundle {
);
}

['filename', 'indentExclusionRanges', 'separator'].forEach((option) => {
['filename', 'ignoreList', 'indentExclusionRanges', 'separator'].forEach((option) => {
if (!hasOwnProp.call(source, option)) source[option] = source.content[option];
});

Expand Down Expand Up @@ -84,6 +84,7 @@ export default class Bundle {

generateDecodedMap(options = {}) {
const names = [];
let x_google_ignoreList = undefined;
this.sources.forEach((source) => {
Object.keys(source.content.storedNames).forEach((name) => {
if (!~names.indexOf(name)) names.push(name);
Expand Down Expand Up @@ -141,6 +142,13 @@ export default class Bundle {
if (magicString.outro) {
mappings.advance(magicString.outro);
}

if (source.ignoreList && sourceIndex !== -1) {
if (x_google_ignoreList === undefined) {
x_google_ignoreList = [];
}
x_google_ignoreList.push(sourceIndex);
}
});

return {
Expand All @@ -153,6 +161,7 @@ export default class Bundle {
}),
names,
mappings: mappings.raw,
x_google_ignoreList,
};
}

Expand Down
2 changes: 2 additions & 0 deletions src/MagicString.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export default class MagicString {
sourcemapLocations: { writable: true, value: new BitSet() },
storedNames: { writable: true, value: {} },
indentStr: { writable: true, value: undefined },
ignoreList: { writable: true, value: options.ignoreList },
});

if (DEBUG) {
Expand Down Expand Up @@ -168,6 +169,7 @@ export default class MagicString {
sourcesContent: options.includeContent ? [this.original] : undefined,
names,
mappings: mappings.raw,
x_google_ignoreList: this.ignoreList ? [sourceIndex] : undefined
};
}

Expand Down
38 changes: 38 additions & 0 deletions test/MagicString.Bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,32 @@ describe('MagicString.Bundle', () => {
assert.strictEqual(b.sources[0].indentExclusionRanges, array);
});

it('should accept ignore-list hint', () => {
const b = new MagicString.Bundle();
const foo = new MagicString('foo', {filename: 'foo.js'});
const bar = new MagicString('bar', {filename: 'bar.js'});

b.addSource({content: foo, ignoreList: true});
b.addSource({content: bar, ignoreList: false});
assert.strictEqual(b.sources[0].content, foo);
assert.strictEqual(b.sources[0].ignoreList, true);
assert.strictEqual(b.sources[1].content, bar);
assert.strictEqual(b.sources[1].ignoreList, false);
});

it('respects MagicString init options with { content: source }', () => {
const b = new MagicString.Bundle();
const array = [];
const source = new MagicString('abcdefghijkl', {
filename: 'foo.js',
ignoreList: false,
indentExclusionRanges: array
});

b.addSource({ content: source });
assert.strictEqual(b.sources[0].content, source);
assert.strictEqual(b.sources[0].filename, 'foo.js');
assert.strictEqual(b.sources[0].ignoreList, false);
assert.strictEqual(b.sources[0].indentExclusionRanges, array);
});
});
Expand Down Expand Up @@ -345,6 +360,29 @@ describe('MagicString.Bundle', () => {
assert.equal(loc.source, 'three.js');
});

it('should generate x_google_ignoreList correctly', () => {
const b = new MagicString.Bundle();

const one = new MagicString('function one () {}', { filename: 'one.js' });
const two = new MagicString('function two () {}', { filename: 'two.js' });
const three = new MagicString('function three () {}', { filename: 'three.js' });
const four = new MagicString('function four () {}', { filename: 'four.js' });

b.addSource({ content: one, ignoreList: false });
b.addSource({ content: two, ignoreList: true });
b.addSource({ content: three, ignoreList: true });
b.addSource({ content: four });

const map = b.generateMap({
file: 'output.js'
});

assert.deepEqual(map.x_google_ignoreList, [
map.sources.indexOf('two.js'),
map.sources.indexOf('three.js')
]);
});

it('handles prepended content', () => {
const b = new MagicString.Bundle();

Expand Down
16 changes: 16 additions & 0 deletions test/MagicString.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ describe('MagicString', () => {

assert.equal(s.filename, 'foo.js');
});

it('stores ignore-list hint', () => {
const s = new MagicString('abc', { ignoreList: true });

assert.equal(s.ignoreList, true);
});
});

describe('append', () => {
Expand Down Expand Up @@ -418,6 +424,16 @@ describe('MagicString', () => {
const map = s.generateMap();
assert.equal(map.mappings, 'IAAA');
});

it('generates x_google_ignoreList', () => {
const s = new MagicString('function foo(){}', {
ignoreList: true
});

const map = s.generateMap({ source: 'foo.js' });
assert.deepEqual(map.sources, ['foo.js']);
assert.deepEqual(map.x_google_ignoreList, [0]);
});
});

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

0 comments on commit e80b3f8

Please sign in to comment.