Skip to content

Commit

Permalink
Merge e37fe62 into 2f8535b
Browse files Browse the repository at this point in the history
  • Loading branch information
nikolay-borzov committed Nov 10, 2019
2 parents 2f8535b + e37fe62 commit 113d5db
Show file tree
Hide file tree
Showing 9 changed files with 498 additions and 392 deletions.
76 changes: 55 additions & 21 deletions src/explore.ts
Expand Up @@ -21,7 +21,7 @@ export async function exploreBundle(

const sourceMapData = await loadSourceMap(code, map);

const sizes = computeFileSizeMapOptimized(sourceMapData);
const sizes = computeFileSizes(sourceMapData);

const files = adjustSourcePaths(sizes.files, options);

Expand Down Expand Up @@ -85,10 +85,45 @@ async function loadSourceMap(codeFile: File, sourceMapFile?: File): Promise<Sour
};
}

function detectEOL(content: string): string {
const lineBreakIndex = content.indexOf('\n', 1);

return content[lineBreakIndex - 1] === '\r' ? '\r\n' : '\n';
}

interface ComputeFileSizesContext {
generatedLine: number;
generatedColumn: number;
line: string;
eol: string;
}

function checkInvalidMappingColumn({
generatedLine,
generatedColumn,
line,
eol,
}: ComputeFileSizesContext): void {
const maxColumnIndex = line.length - 1;

// Ignore case when source map references EOL character (e.g. when generated by typescript)
if (generatedColumn > maxColumnIndex && `${line}${eol}`.lastIndexOf(eol) !== generatedColumn) {
throw new AppError({
code: 'InvalidMappingColumn',
generatedLine,
generatedColumn,
maxColumn: line.length,
});
}
}

/** Calculate the number of bytes contributed by each source file */
function computeFileSizeMapOptimized(sourceMapData: SourceMapData): FileSizes {
function computeFileSizes(sourceMapData: SourceMapData): FileSizes {
const { consumer, codeFileContent } = sourceMapData;
const lines = codeFileContent.split('\n');
const eol = detectEOL(codeFileContent);
// Assume only one EOL is used
const lines = codeFileContent.split(eol);

const files: FileSizeMap = {};
let mappedBytes = 0;

Expand All @@ -97,38 +132,37 @@ function computeFileSizeMapOptimized(sourceMapData: SourceMapData): FileSizes {
consumer.eachMapping(({ source, generatedLine, generatedColumn, lastGeneratedColumn }) => {
// Lines are 1-based
const line = lines[generatedLine - 1];
if (line === null) {

if (line === undefined) {
throw new AppError({
code: 'InvalidMappingLine',
generatedLine: generatedLine,
generatedLine,
maxLine: lines.length,
});
}

// Columns are 0-based
if (generatedColumn >= line.length) {
throw new AppError({
code: 'InvalidMappingColumn',
generatedLine: generatedLine,
generatedColumn: generatedColumn,
maxColumn: line.length,
});
}
checkInvalidMappingColumn({
generatedLine,
generatedColumn,
line,
eol,
});

let mappingLength = 0;
if (lastGeneratedColumn !== null) {
if (lastGeneratedColumn >= line.length) {
throw new AppError({
code: 'InvalidMappingColumn',
generatedLine: generatedLine,
generatedColumn: lastGeneratedColumn,
maxColumn: line.length,
});
}
checkInvalidMappingColumn({
generatedLine,
generatedColumn: lastGeneratedColumn,
line,
eol,
});

mappingLength = lastGeneratedColumn - generatedColumn + 1;
} else {
mappingLength = line.length - generatedColumn;
}

files[source] = (files[source] || 0) + mappingLength;
mappedBytes += mappingLength;
});
Expand Down
19 changes: 19 additions & 0 deletions tests/api.test.ts
Expand Up @@ -228,6 +228,16 @@ describe('api', () => {
expect(error.code).to.equal('OneSourceSourceMap');
});

it('should throw if source map reference column beyond generated last column in line', async function() {
try {
await explore('data/invalid-map-column.js');
} catch (errorResult) {
const error = errorResult.errors[0];

expect(error.code).to.equal('InvalidMappingColumn');
}
});

it('should add warning about unmapped bytes', async function() {
const result = await explore('data/with-unmapped.js');

Expand Down Expand Up @@ -289,6 +299,15 @@ describe('api', () => {
code: 'data/inline-map.js',
map: undefined,
},
{
code: 'data/invalid-map-column.js',
map: undefined,
},
{
code: 'data/invalid-map-line.js',
map: undefined,
},
{ code: 'data/map-reference-eol.js', map: undefined },
{
code: 'data/no-map.js',
map: 'data/no-map.js.map',
Expand Down
3 changes: 3 additions & 0 deletions tests/data/invalid-map-column.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions tests/data/invalid-map-line.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions tests/data/map-reference-eol.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 34 additions & 0 deletions tests/generate-data/README.md
@@ -0,0 +1,34 @@
# How to generate

## `invalid-map-column.js`

1. Create `src/invalid-map-column.ts` with content
```
console.log('goodbye cruel world');
console.log('goodbye man');
```
2. Run `tsc --inlineSourceMap src/invalid-map-column.ts --outFile ../data/invalid-map-column.js`
3. Save source map comment from `../data/invalid-map-column.js`
4. Replace `src/invalid-map-column.ts` content with
```
console.log('hello happy world');
console.log('hello man');
```
5. Run `.2` again
6. Replace source map comment of `../data/invalid-map-column.js` with one from `.3`

## `invalid-map-line.js`

1. Create `src/invalid-map-line.ts` with content
```
console.log('hello happy world');
console.log('hello man');
```
2. Run `tsc --inlineSourceMap src/invalid-map-line.ts --outFile ../data/invalid-map-line.js`
3. Save source map comment from `../data/invalid-map-line.js`
4. Replace `src/invalid-map-line.ts` content with
```
console.log('hello happy world');
```
5. Run `.2` again
6. Replace source map comment of `../data/invalid-map-line.js` with one from `.3`

0 comments on commit 113d5db

Please sign in to comment.