Skip to content

Commit b2eb083

Browse files
authored
fix(sourcemaps): do not encode inline sourcemaps (#3163)
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.
1 parent 5e2a234 commit b2eb083

File tree

3 files changed

+148
-7
lines changed

3 files changed

+148
-7
lines changed

src/compiler/transpile.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { TranspileOptions, TranspileResults, Config, TransformOptions, TransformCssToEsmInput } from '../declarations';
2-
import { catchError, getSourceMappingUrlLinker, isString } from '@utils';
2+
import { catchError, getInlineSourceMappingUrlLinker, isString } from '@utils';
33
import { getPublicCompilerMeta } from './transformers/add-component-meta-static';
44
import { getTranspileCssConfig, getTranspileConfig, getTranspileResults } from './config/transpile-options';
55
import { patchTypescript } from './sys/typescript/typescript-sys';
@@ -74,10 +74,9 @@ const transpileCode = (
7474
mapObject.sources = [transpileOpts.file];
7575
delete mapObject.sourceRoot;
7676

77-
const mapBase64 = Buffer.from(JSON.stringify(mapObject), 'utf8').toString('base64');
78-
const sourceMapInlined = `data:application/json;charset=utf-8;base64,` + mapBase64;
7977
const sourceMapComment = results.code.lastIndexOf('//#');
80-
results.code = results.code.slice(0, sourceMapComment) + getSourceMappingUrlLinker(sourceMapInlined);
78+
results.code =
79+
results.code.slice(0, sourceMapComment) + getInlineSourceMappingUrlLinker(JSON.stringify(mapObject));
8180
} catch (e) {
8281
console.error(e);
8382
}

src/utils/sourcemaps.ts

+16-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const JS_SOURCE_MAPPING_URL_LINKER = '//# sourceMappingURL=';
3636
* @param filename the filename to encode
3737
* @returns the encoded URI
3838
*/
39-
const encodeFilenameToRfc3986 = (filename: string): string => {
39+
const encodeToRfc3986 = (filename: string): string => {
4040
const encodedUri = encodeURIComponent(filename);
4141
// replace all '!', single quotes, '(', ')', and '*' with their hexadecimal values (UTF-16)
4242
return encodedUri.replace(/[!'()*]/g, (matchedCharacter) => {
@@ -51,7 +51,21 @@ const encodeFilenameToRfc3986 = (filename: string): string => {
5151
* @returns a linker string, of the format {@link JS_SOURCE_MAPPING_URL_LINKER}=<url>
5252
*/
5353
export const getSourceMappingUrlLinker = (url: string): string => {
54-
return `${JS_SOURCE_MAPPING_URL_LINKER}${encodeFilenameToRfc3986(url)}`;
54+
return `${JS_SOURCE_MAPPING_URL_LINKER}${encodeToRfc3986(url)}`;
55+
};
56+
57+
/**
58+
* Generates a string used to link generated code with the original source, to be placed at the end of the generated
59+
* code as an inline source map.
60+
* @param sourceMapContents the sourceMapContents of the source map
61+
* @returns a linker string, of the format {@link JS_SOURCE_MAPPING_URL_LINKER}<dataUriPrefixAndMime><sourceMapContents>
62+
*/
63+
export const getInlineSourceMappingUrlLinker = (sourceMapContents: string): string => {
64+
const mapBase64 = Buffer.from(sourceMapContents, 'utf8').toString('base64');
65+
66+
// do not RFC-3986 encode an already valid base64 string. the sourcemaps will not resolve correctly when there is an
67+
// allowed base64 character is encoded (because it is a disallowed RFC-3986 character)
68+
return `${JS_SOURCE_MAPPING_URL_LINKER}data:application/json;charset=utf-8;base64,${mapBase64}`;
5569
};
5670

5771
/**

src/utils/test/sourcemaps.spec.ts

+129-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import { getSourceMappingUrlLinker, getSourceMappingUrlForEndOfFile, rollupToStencilSourceMap } from '@utils';
1+
import {
2+
getSourceMappingUrlLinker,
3+
getSourceMappingUrlForEndOfFile,
4+
rollupToStencilSourceMap,
5+
getInlineSourceMappingUrlLinker,
6+
} from '@utils';
27
import { SourceMap as RollupSourceMap } from 'rollup';
38
import type * as d from '../../declarations';
49

@@ -84,6 +89,129 @@ describe('sourcemaps', () => {
8489
});
8590
});
8691

92+
describe('getInlineSourceMappingUrlLinker', () => {
93+
it('returns a correctly formatted sourcemap', () => {
94+
expect(
95+
getInlineSourceMappingUrlLinker(
96+
'{"version":3,"file":"sourcemaps.js","sourceRoot":"","sources":["sourcemaps.ts"],"names":[],"mappings":";;AAAA,mCAKgB;"}'
97+
)
98+
).toBe(
99+
'//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +
100+
'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlbWFwcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInNvdXJjZW1hcHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxtQ0FLZ0I7In0='
101+
);
102+
});
103+
104+
it('handles question marks in sourcemaps', () => {
105+
expect(
106+
getInlineSourceMappingUrlLinker(
107+
'{"version":3,"file":"source?maps.js","sourceRoot":"","sources":["source?maps.ts"],"names":[],"mappings":";;AAAA,mCAKgB;"}'
108+
)
109+
).toBe(
110+
'//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +
111+
'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlP21hcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2U/bWFwcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ=='
112+
);
113+
});
114+
115+
it('handles plus signs in sourcemaps', () => {
116+
expect(
117+
getInlineSourceMappingUrlLinker(
118+
'{"version":3,"file":"source+maps.js","sourceRoot":"","sources":["source+maps.ts"],"names":[],"mappings":";;AAAA,mCAKgB;"}'
119+
)
120+
).toBe(
121+
'//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +
122+
'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlK21hcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2UrbWFwcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ=='
123+
);
124+
});
125+
126+
it('handles equal signs in sourcemaps', () => {
127+
expect(
128+
getInlineSourceMappingUrlLinker(
129+
'{"version":3,"file":"source=maps.js","sourceRoot":"","sources":["source=maps.ts"],"names":[],"mappings":";;AAAA,mCAKgB;"}'
130+
)
131+
).toBe(
132+
'//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +
133+
'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlPW1hcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2U9bWFwcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ=='
134+
);
135+
});
136+
137+
it('handles ampersands in sourcemaps', () => {
138+
expect(
139+
getInlineSourceMappingUrlLinker(
140+
'{"version":3,"file":"source&maps.js","sourceRoot":"","sources":["source&maps.ts"],"names":[],"mappings":";;AAAA,mCAKgB;"}'
141+
)
142+
).toBe(
143+
'//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +
144+
'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlJm1hcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2UmbWFwcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ=='
145+
);
146+
});
147+
148+
it('handles slashes in sourcemaps', () => {
149+
expect(
150+
getInlineSourceMappingUrlLinker(
151+
'{"version":3,"file":"source/maps.js","sourceRoot":"","sources":["source/maps.js.ts"],"names":[],"mappings":";;AAAA,mCAKgB;"}'
152+
)
153+
).toBe(
154+
'//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +
155+
'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlL21hcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2UvbWFwcy5qcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ=='
156+
);
157+
});
158+
159+
it('handles exclamation points in sourcemaps', () => {
160+
expect(
161+
getInlineSourceMappingUrlLinker(
162+
'{"version":3,"file":"sourcemaps!.js","sourceRoot":"","sources":["sourcemaps!.ts"],"names":[],"mappings":";;AAAA,mCAKgB;"}'
163+
)
164+
).toBe(
165+
'//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +
166+
'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlbWFwcyEuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2VtYXBzIS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ=='
167+
);
168+
});
169+
170+
it('handles single quotes in sourcemaps', () => {
171+
expect(
172+
getInlineSourceMappingUrlLinker(
173+
'{"version":3,"file":"source\'maps.js","sourceRoot":"","sources":["source\'maps.ts"],"names":[],"mappings":";;AAAA,mCAKgB;"}'
174+
)
175+
).toBe(
176+
'//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +
177+
'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlJ21hcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2UnbWFwcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ=='
178+
);
179+
});
180+
181+
it('handles parenthesis in sourcemaps', () => {
182+
expect(
183+
getInlineSourceMappingUrlLinker(
184+
'{"version":3,"file":"source()maps.js","sourceRoot":"","sources":["source()maps.ts"],"names":[],"mappings":";;AAAA,mCAKgB;"}'
185+
)
186+
).toBe(
187+
'//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +
188+
'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlKCltYXBzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsic291cmNlKCltYXBzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsbUNBS2dCOyJ9'
189+
);
190+
});
191+
192+
it('handles asterisks in sourcemaps', () => {
193+
expect(
194+
getInlineSourceMappingUrlLinker(
195+
'{"version":3,"file":"source*maps.js","sourceRoot":"","sources":["source*maps.ts"],"names":[],"mappings":";;AAAA,mCAKgB;"}'
196+
)
197+
).toBe(
198+
'//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +
199+
'eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlKm1hcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzb3VyY2UqbWFwcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ=='
200+
);
201+
});
202+
203+
it('encodes multiple disallowed characters at once', () => {
204+
expect(
205+
getInlineSourceMappingUrlLinker(
206+
'{"version":3,"file":"!source(maps)*.js","sourceRoot":"","sources":["!source(maps)*.ts"],"names":[],"mappings":";;AAAA,mCAKgB;"}'
207+
)
208+
).toBe(
209+
'//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +
210+
'eyJ2ZXJzaW9uIjozLCJmaWxlIjoiIXNvdXJjZShtYXBzKSouanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIhc291cmNlKG1hcHMpKi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLG1DQUtnQjsifQ=='
211+
);
212+
});
213+
});
214+
87215
describe('getSourceMappingUrlLinkerWithNewline', () => {
88216
it('returns a correctly formatted url', () => {
89217
expect(getSourceMappingUrlForEndOfFile('some-pkg')).toBe('\n//# sourceMappingURL=some-pkg.map');

0 commit comments

Comments
 (0)