Skip to content

Commit

Permalink
Merge pull request #97 from ampproject/return-decoded-mapping
Browse files Browse the repository at this point in the history
Allow returning SourceMap with decoded mappings
  • Loading branch information
jridgewell authored Dec 19, 2020
2 parents 273beb4 + 4342d23 commit 60e9144
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 18 deletions.
15 changes: 10 additions & 5 deletions src/remapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import buildSourceMapTree from './build-source-map-tree';
import SourceMap from './source-map';

import type { SourceMapInput, SourceMapLoader } from './types';
import type { SourceMapInput, SourceMapLoader, Options } from './types';

/**
* Traces through all the mappings in the root sourcemap, through the sources
Expand All @@ -28,14 +28,19 @@ import type { SourceMapInput, SourceMapLoader } from './types';
* it returns a falsey value, that source file is treated as an original,
* unmodified source file.
*
* Pass `excludeContent` content to exclude any self-containing source file
* content from the output sourcemap.
* Pass `excludeContent` to exclude any self-containing source file content
* from the output sourcemap.
*
* Pass `decodedMappings` to receive a SourceMap with decoded (instead of
* VLQ encoded) mappings.
*/
export default function remapping(
input: SourceMapInput | SourceMapInput[],
loader: SourceMapLoader,
excludeContent?: boolean
options?: boolean | Options
): SourceMap {
const opts =
typeof options === 'object' ? options : { excludeContent: !!options, decodedMappings: false };
const graph = buildSourceMapTree(input, loader);
return new SourceMap(graph.traceMappings(), !!excludeContent);
return new SourceMap(graph.traceMappings(), opts);
}
14 changes: 8 additions & 6 deletions src/source-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,35 @@

import { encode } from 'sourcemap-codec';

import type { DecodedSourceMap, RawSourceMap } from './types';
import type { DecodedSourceMap, RawSourceMap, Options } from './types';

/**
* A SourceMap v3 compatible sourcemap, which only includes fields that were
* provided to it.
*/
export default class SourceMap implements RawSourceMap {
export default class SourceMap implements SourceMap {
file?: string | null;
mappings: string;
mappings: RawSourceMap['mappings'] | DecodedSourceMap['mappings'];
sourceRoot?: string;
names: string[];
sources: (string | null)[];
sourcesContent?: (string | null)[];
version: 3;

constructor(map: DecodedSourceMap, excludeContent: boolean) {
constructor(map: DecodedSourceMap, options: Options) {
this.version = 3; // SourceMap spec says this should be first.
if ('file' in map) this.file = map.file;
this.mappings = encode(map.mappings);
this.mappings = options.decodedMappings ? map.mappings : encode(map.mappings);
this.names = map.names;

// TODO: We first need to make all source URIs relative to the sourceRoot
// before we can support a sourceRoot.
// if ('sourceRoot' in map) this.sourceRoot = map.sourceRoot;

this.sources = map.sources;
if (!excludeContent && 'sourcesContent' in map) this.sourcesContent = map.sourcesContent;
if (!options.excludeContent && 'sourcesContent' in map) {
this.sourcesContent = map.sourcesContent;
}
}

toString(): string {
Expand Down
5 changes: 5 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,8 @@ export interface SourceMapSegmentObject {
export type SourceMapInput = string | RawSourceMap | DecodedSourceMap;

export type SourceMapLoader = (file: string) => SourceMapInput | null | undefined;

export type Options = {
excludeContent: boolean;
decodedMappings: boolean;
};
24 changes: 17 additions & 7 deletions test/unit/source-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,50 +24,60 @@ describe('SourceMap', () => {
sources: ['file.js'],
version: 3,
};
const opts = {
excludeContent: false,
decodedMappings: false,
};

test('it is a compliant, v3 sourcemap', () => {
const map = new SourceMap(decoded, false);
const map = new SourceMap(decoded, opts);
expect(map).toHaveProperty('mappings', 'AAAA');
expect(map).toHaveProperty('names', decoded.names);
expect(map).toHaveProperty('sources', decoded.sources);
expect(map).toHaveProperty('version', 3);
});

test('it does not include properties missing from input', () => {
const map = new SourceMap(decoded, false);
const map = new SourceMap(decoded, opts);
expect(map).not.toHaveProperty('file');
expect(map).not.toHaveProperty('sourceRoot');
expect(map).not.toHaveProperty('sourcesContent');
});

test('it can include a file', () => {
const file = 'foobar.js';
const map = new SourceMap({ ...decoded, file }, false);
const map = new SourceMap({ ...decoded, file }, opts);
expect(map).toHaveProperty('file', file);
});

// TODO: support sourceRoot
test.skip('it can include a sourceRoot', () => {
const sourceRoot = 'https://foo.com/';
const map = new SourceMap({ ...decoded, sourceRoot }, false);
const map = new SourceMap({ ...decoded, sourceRoot }, opts);
expect(map).toHaveProperty('sourceRoot', sourceRoot);
});

test('it can include a sourcesContent', () => {
const sourcesContent = ['1 + 1'];
const map = new SourceMap({ ...decoded, sourcesContent }, false);
const map = new SourceMap({ ...decoded, sourcesContent }, opts);
expect(map).toHaveProperty('sourcesContent', sourcesContent);
});

test('sourcesContent can be manually excluded', () => {
const sourcesContent = ['1 + 1'];
const map = new SourceMap({ ...decoded, sourcesContent }, true);
const map = new SourceMap({ ...decoded, sourcesContent }, { ...opts, excludeContent: true });
expect(map).not.toHaveProperty('sourcesContent');
});

test('mappings can be decoded', () => {
const sourcesContent = ['1 + 1'];
const map = new SourceMap({ ...decoded, sourcesContent }, { ...opts, decodedMappings: true });
expect(map).toHaveProperty('mappings', [[[0, 0, 0, 0]]]);
});

describe('toString()', () => {
test('returns the sourcemap in JSON', () => {
const map = new SourceMap(decoded, false);
const map = new SourceMap(decoded, opts);
expect(JSON.parse(map.toString())).toEqual(map);
});
});
Expand Down

0 comments on commit 60e9144

Please sign in to comment.