Skip to content

Commit

Permalink
fix(sourcemaps): do not encode inline sourcemaps (#3163)
Browse files Browse the repository at this point in the history
this commit fixes a regression originally introduced in #3100, where
inline sourcemaps that are data URI's are erroneously encoded using
RFC-3986. this causes the sourcemaps for tests to not correctly map the
transpiled output back to the original source code.
  • Loading branch information
rwaskiewicz committed Dec 3, 2021
1 parent 5e2a234 commit b2eb083
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 7 deletions.
7 changes: 3 additions & 4 deletions src/compiler/transpile.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { TranspileOptions, TranspileResults, Config, TransformOptions, TransformCssToEsmInput } from '../declarations';
import { catchError, getSourceMappingUrlLinker, isString } from '@utils';
import { catchError, getInlineSourceMappingUrlLinker, isString } from '@utils';
import { getPublicCompilerMeta } from './transformers/add-component-meta-static';
import { getTranspileCssConfig, getTranspileConfig, getTranspileResults } from './config/transpile-options';
import { patchTypescript } from './sys/typescript/typescript-sys';
Expand Down Expand Up @@ -74,10 +74,9 @@ const transpileCode = (
mapObject.sources = [transpileOpts.file];
delete mapObject.sourceRoot;

const mapBase64 = Buffer.from(JSON.stringify(mapObject), 'utf8').toString('base64');
const sourceMapInlined = `data:application/json;charset=utf-8;base64,` + mapBase64;
const sourceMapComment = results.code.lastIndexOf('//#');
results.code = results.code.slice(0, sourceMapComment) + getSourceMappingUrlLinker(sourceMapInlined);
results.code =
results.code.slice(0, sourceMapComment) + getInlineSourceMappingUrlLinker(JSON.stringify(mapObject));
} catch (e) {
console.error(e);
}
Expand Down
18 changes: 16 additions & 2 deletions src/utils/sourcemaps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const JS_SOURCE_MAPPING_URL_LINKER = '//# sourceMappingURL=';
* @param filename the filename to encode
* @returns the encoded URI
*/
const encodeFilenameToRfc3986 = (filename: string): string => {
const encodeToRfc3986 = (filename: string): string => {
const encodedUri = encodeURIComponent(filename);
// replace all '!', single quotes, '(', ')', and '*' with their hexadecimal values (UTF-16)
return encodedUri.replace(/[!'()*]/g, (matchedCharacter) => {
Expand All @@ -51,7 +51,21 @@ const encodeFilenameToRfc3986 = (filename: string): string => {
* @returns a linker string, of the format {@link JS_SOURCE_MAPPING_URL_LINKER}=<url>
*/
export const getSourceMappingUrlLinker = (url: string): string => {
return `${JS_SOURCE_MAPPING_URL_LINKER}${encodeFilenameToRfc3986(url)}`;
return `${JS_SOURCE_MAPPING_URL_LINKER}${encodeToRfc3986(url)}`;
};

/**
* Generates a string used to link generated code with the original source, to be placed at the end of the generated
* code as an inline source map.
* @param sourceMapContents the sourceMapContents of the source map
* @returns a linker string, of the format {@link JS_SOURCE_MAPPING_URL_LINKER}<dataUriPrefixAndMime><sourceMapContents>
*/
export const getInlineSourceMappingUrlLinker = (sourceMapContents: string): string => {
const mapBase64 = Buffer.from(sourceMapContents, 'utf8').toString('base64');

// do not RFC-3986 encode an already valid base64 string. the sourcemaps will not resolve correctly when there is an
// allowed base64 character is encoded (because it is a disallowed RFC-3986 character)
return `${JS_SOURCE_MAPPING_URL_LINKER}data:application/json;charset=utf-8;base64,${mapBase64}`;
};

/**
Expand Down
130 changes: 129 additions & 1 deletion src/utils/test/sourcemaps.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { getSourceMappingUrlLinker, getSourceMappingUrlForEndOfFile, rollupToStencilSourceMap } from '@utils';
import {
getSourceMappingUrlLinker,
getSourceMappingUrlForEndOfFile,
rollupToStencilSourceMap,
getInlineSourceMappingUrlLinker,
} from '@utils';
import { SourceMap as RollupSourceMap } from 'rollup';
import type * as d from '../../declarations';

Expand Down Expand Up @@ -84,6 +89,129 @@ describe('sourcemaps', () => {
});
});

describe('getInlineSourceMappingUrlLinker', () => {
it('returns a correctly formatted sourcemap', () => {
expect(
getInlineSourceMappingUrlLinker(
'{"version":3,"file":"sourcemaps.js","sourceRoot":"","sources":["sourcemaps.ts"],"names":[],"mappings":";;AAAA,mCAKgB;"}'
)
).toBe(
'//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +
'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlbWFwcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInNvdXJjZW1hcHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxtQ0FLZ0I7In0='
);
});

it('handles question marks in sourcemaps', () => {
expect(
getInlineSourceMappingUrlLinker(
'{"version":3,"file":"source?maps.js","sourceRoot":"","sources":["source?maps.ts"],"names":[],"mappings":";;AAAA,mCAKgB;"}'
)
).toBe(
'//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +
'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlP21hcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2U/bWFwcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ=='
);
});

it('handles plus signs in sourcemaps', () => {
expect(
getInlineSourceMappingUrlLinker(
'{"version":3,"file":"source+maps.js","sourceRoot":"","sources":["source+maps.ts"],"names":[],"mappings":";;AAAA,mCAKgB;"}'
)
).toBe(
'//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +
'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlK21hcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2UrbWFwcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ=='
);
});

it('handles equal signs in sourcemaps', () => {
expect(
getInlineSourceMappingUrlLinker(
'{"version":3,"file":"source=maps.js","sourceRoot":"","sources":["source=maps.ts"],"names":[],"mappings":";;AAAA,mCAKgB;"}'
)
).toBe(
'//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +
'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlPW1hcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2U9bWFwcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ=='
);
});

it('handles ampersands in sourcemaps', () => {
expect(
getInlineSourceMappingUrlLinker(
'{"version":3,"file":"source&maps.js","sourceRoot":"","sources":["source&maps.ts"],"names":[],"mappings":";;AAAA,mCAKgB;"}'
)
).toBe(
'//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +
'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlJm1hcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2UmbWFwcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ=='
);
});

it('handles slashes in sourcemaps', () => {
expect(
getInlineSourceMappingUrlLinker(
'{"version":3,"file":"source/maps.js","sourceRoot":"","sources":["source/maps.js.ts"],"names":[],"mappings":";;AAAA,mCAKgB;"}'
)
).toBe(
'//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +
'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlL21hcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2UvbWFwcy5qcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ=='
);
});

it('handles exclamation points in sourcemaps', () => {
expect(
getInlineSourceMappingUrlLinker(
'{"version":3,"file":"sourcemaps!.js","sourceRoot":"","sources":["sourcemaps!.ts"],"names":[],"mappings":";;AAAA,mCAKgB;"}'
)
).toBe(
'//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +
'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlbWFwcyEuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2VtYXBzIS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ=='
);
});

it('handles single quotes in sourcemaps', () => {
expect(
getInlineSourceMappingUrlLinker(
'{"version":3,"file":"source\'maps.js","sourceRoot":"","sources":["source\'maps.ts"],"names":[],"mappings":";;AAAA,mCAKgB;"}'
)
).toBe(
'//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +
'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlJ21hcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2UnbWFwcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ=='
);
});

it('handles parenthesis in sourcemaps', () => {
expect(
getInlineSourceMappingUrlLinker(
'{"version":3,"file":"source()maps.js","sourceRoot":"","sources":["source()maps.ts"],"names":[],"mappings":";;AAAA,mCAKgB;"}'
)
).toBe(
'//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +
'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlKCltYXBzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsic291cmNlKCltYXBzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsbUNBS2dCOyJ9'
);
});

it('handles asterisks in sourcemaps', () => {
expect(
getInlineSourceMappingUrlLinker(
'{"version":3,"file":"source*maps.js","sourceRoot":"","sources":["source*maps.ts"],"names":[],"mappings":";;AAAA,mCAKgB;"}'
)
).toBe(
'//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +
'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlKm1hcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2UqbWFwcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ=='
);
});

it('encodes multiple disallowed characters at once', () => {
expect(
getInlineSourceMappingUrlLinker(
'{"version":3,"file":"!source(maps)*.js","sourceRoot":"","sources":["!source(maps)*.ts"],"names":[],"mappings":";;AAAA,mCAKgB;"}'
)
).toBe(
'//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +
'eyJ2ZXJzaW9uIjozLCJmaWxlIjoiIXNvdXJjZShtYXBzKSouanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIhc291cmNlKG1hcHMpKi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ=='
);
});
});

describe('getSourceMappingUrlLinkerWithNewline', () => {
it('returns a correctly formatted url', () => {
expect(getSourceMappingUrlForEndOfFile('some-pkg')).toBe('\n//# sourceMappingURL=some-pkg.map');
Expand Down

0 comments on commit b2eb083

Please sign in to comment.