microsoft/vscode-react-native

Public

mirrored from https://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
transitive-dependency-serialize-javascript

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

src/debugger/sourceMap.ts

199lines · modeblame

9f036952Nisheet Jain10 years ago1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
ce5e88eeYuri Skorokhodov5 years ago4import * as url from "url";
5import * as path from "path";
70bb7c83Vladimir Kotikov8 years ago6import { RawSourceMap } from "source-map";
09f6024fHeniker4 years ago7import { SourceMapsCombinator } from "./sourceMapsCombinator";
876df2a0dlebu10 years ago8
09f6024fHeniker4 years ago9const IS_REMOTE = /^[A-z]{2,}:\/\//; // Detection remote sources or specific protocols (like "webpack:///")
66b52ec9Artem Egorov8 years ago10
70bb7c83Vladimir Kotikov8 years ago11interface ISourceMap extends RawSourceMap {
f16656e9frogcjn9 years ago12sections?: ISourceMapSection[];
13}
14interface ISourceMapSection {
15map: ISourceMap;
34472878RedMickey5 years ago16offset: { column: number; line: number };
876df2a0dlebu10 years ago17}
18
5c8365a6Artem Egorov8 years ago19export interface IStrictUrl extends url.Url {
20pathname: string;
21href: string;
22}
23
876df2a0dlebu10 years ago24export class SourceMapUtil {
09f6024fHeniker4 years ago25private static SourceMapURLGlobalRegex: RegExp =
716c1b85RedMickey4 years ago26/\/\/(#|@) sourceMappingURL=((?!data:)[^ ]+?)\s*$/gm;
27private static SourceMapURLRegex: RegExp = /\/\/(#|@) sourceMappingURL=((?!data:)[^ ]+?)\s*$/m;
32558f9eYuri Skorokhodov6 years ago28private static SourceURLRegex: RegExp = /^\/\/[#@] ?sourceURL=(.+)$/m;
4e7a6f0edlebu10 years ago29
876df2a0dlebu10 years ago30/**
31* Given a script body and URL, this method parses the body and finds the corresponding source map URL.
32* If the source map URL is not found in the body in the expected form, null is returned.
33*/
5c8365a6Artem Egorov8 years ago34public getSourceMapURL(scriptUrl: url.Url, scriptBody: string): IStrictUrl | null {
35let result: IStrictUrl | null = null;
876df2a0dlebu10 years ago36
37// scriptUrl = "http://localhost:8081/index.ios.bundle?platform=ios&dev=true"
09f6024fHeniker4 years ago38const sourceMappingRelativeUrl = this.getSourceMapRelativeUrl(scriptBody); // sourceMappingRelativeUrl = "/index.ios.map?platform=ios&dev=true"
876df2a0dlebu10 years ago39if (sourceMappingRelativeUrl) {
09f6024fHeniker4 years ago40const sourceMappingUrl = url.parse(sourceMappingRelativeUrl);
876df2a0dlebu10 years ago41sourceMappingUrl.protocol = scriptUrl.protocol;
42sourceMappingUrl.host = scriptUrl.host;
43// parse() repopulates all the properties of the URL
5c8365a6Artem Egorov8 years ago44result = <IStrictUrl>url.parse(url.format(sourceMappingUrl));
876df2a0dlebu10 years ago45}
46
47return result;
48}
49
50/**
51* Updates the contents of a source map file to be VS Code friendly:
52* - makes source paths unix style and relative to the sources root path
53* - updates the url of the script file
54* - deletes the script content from the source map
55*
56* @parameter sourceMapBody - body of the source map as generated by the RN Packager.
57* @parameter scriptPath - path of the script file asssociated with this source map.
58* @parameter sourcesRootPath - root path of sources
59*
60*/
34472878RedMickey5 years ago61public updateSourceMapFile(
62sourceMapBody: string,
63scriptPath: string,
64sourcesRootPath: string,
65packagerRemoteRoot?: string,
66packagerLocalRoot?: string,
67): string {
876df2a0dlebu10 years ago68try {
69let sourceMap = <ISourceMap>JSON.parse(sourceMapBody);
f16656e9frogcjn9 years ago70
71if (sourceMap.sections) {
72// TODO: there is a need to handle value.map == null, make a fake map
09f6024fHeniker4 years ago73sourceMap.sections = sourceMap.sections.filter(value => value.map != null);
f16656e9frogcjn9 years ago74
09f6024fHeniker4 years ago75// eslint-disable-next-line @typescript-eslint/no-var-requires
f16656e9frogcjn9 years ago76sourceMap = require("flatten-source-map")(sourceMap);
77}
78
09f6024fHeniker4 years ago79const sourceMapsCombinator = new SourceMapsCombinator();
48644043Dmitry Zinovyev9 years ago80sourceMap = sourceMapsCombinator.convert(sourceMap);
81
f16656e9frogcjn9 years ago82if (sourceMap.sources) {
09f6024fHeniker4 years ago83sourceMap.sources = sourceMap.sources.map(sourcePath =>
84IS_REMOTE.test(sourcePath)
34472878RedMickey5 years ago85? sourcePath
86: this.updateSourceMapPath(
87sourcePath,
88sourcesRootPath,
89packagerRemoteRoot,
90packagerLocalRoot,
09f6024fHeniker4 years ago91),
92);
f16656e9frogcjn9 years ago93}
876df2a0dlebu10 years ago94
95delete sourceMap.sourcesContent;
96sourceMap.sourceRoot = "";
97sourceMap.file = scriptPath;
98return JSON.stringify(sourceMap);
99} catch (exception) {
100return sourceMapBody;
101}
102}
103
34472878RedMickey5 years ago104public appendSourceMapPaths(scriptBody: string, sourceMappingUrl: string): string {
979d7bfemax-mironov8 years ago105scriptBody += `//# sourceMappingURL=${sourceMappingUrl}`;
106return scriptBody;
107}
108
3736c251dlebu10 years ago109/**
110* Updates source map URLs in the script body.
111*/
34472878RedMickey5 years ago112public updateScriptPaths(scriptBody: string, sourceMappingUrl: IStrictUrl): string {
716c1b85RedMickey4 years ago113const sourceMapMatch = this.searchSourceMapURL(scriptBody);
114if (sourceMapMatch) {
115// Update the body with the new location of the source map on storage.
116return scriptBody.replace(
117sourceMapMatch[0],
118`//# sourceMappingURL=${path.basename(sourceMappingUrl.pathname)}`,
119);
120}
121return scriptBody;
3736c251dlebu10 years ago122}
123
2f5c780bYuri Skorokhodov6 years ago124/**
125* Removes sourceURL from the script body since RN 0.61 because it breaks sourcemaps.
126* Example: //# sourceURL=http://localhost:8081/index.bundle?platform=android&dev=true&minify=false -> ""
127*/
34472878RedMickey5 years ago128public removeSourceURL(scriptBody: string): string {
2f5c780bYuri Skorokhodov6 years ago129return scriptBody.replace(SourceMapUtil.SourceURLRegex, "");
130}
131
4cf8fdf4Yuri Skorokhodov6 years ago132/**
133* Parses the body of a script searching for a source map URL.
134* It supports the following source map url styles:
135*
136* `//# sourceMappingURL=path/to/source/map`
137*
138* `//@ sourceMappingURL=path/to/source/map`
139*
140* Returns the last match if found, null otherwise.
141*/
34472878RedMickey5 years ago142public getSourceMapRelativeUrl(body: string): string | null {
716c1b85RedMickey4 years ago143const sourceMapMatch = this.searchSourceMapURL(body);
4cf8fdf4Yuri Skorokhodov6 years ago144// If match is null, the body doesn't contain the source map
716c1b85RedMickey4 years ago145if (sourceMapMatch) {
146// On React Native macOS 0.62 and RN Windows 0.65 sourceMappingUrl looks like:
147// # sourceMappingURL=//localhost:8081/index.map?platform=macos&dev=true&minify=false
148// Add 'http:' protocol to avoid errors in further processing
149const el = sourceMapMatch[2];
150const macOsOrWin =
151(el.includes("platform=macos") || el.includes("platform=window")) &&
152el.startsWith("//") &&
153!el.includes("http:");
154
155return macOsOrWin ? `http:${el}` : el;
4cf8fdf4Yuri Skorokhodov6 years ago156}
716c1b85RedMickey4 years ago157return null;
158}
09f6024fHeniker4 years ago159
716c1b85RedMickey4 years ago160private searchSourceMapURL(str: string): RegExpMatchArray | null {
161const matchesList = str
162.match(SourceMapUtil.SourceMapURLGlobalRegex)
163?.filter(s => !s.includes("\\n"));
164if (matchesList && matchesList.length) {
165return matchesList[matchesList.length - 1].match(SourceMapUtil.SourceMapURLRegex);
166}
09f6024fHeniker4 years ago167
716c1b85RedMickey4 years ago168return null;
4cf8fdf4Yuri Skorokhodov6 years ago169}
170
876df2a0dlebu10 years ago171/**
172* Given an absolute source path, this method does two things:
173* 1. It changes the path from absolute to be relative to the sourcesRootPath parameter.
174* 2. It changes the path separators to Unix style.
175*/
34472878RedMickey5 years ago176private updateSourceMapPath(
177sourcePath: string,
178sourcesRootPath: string,
179packagerRemoteRoot?: string,
180packagerLocalRoot?: string,
181) {
6eeec3c0Serge Svekolnikov8 years ago182if (packagerRemoteRoot && packagerLocalRoot) {
183packagerRemoteRoot = this.makeUnixStylePath(packagerRemoteRoot);
184packagerLocalRoot = this.makeUnixStylePath(packagerLocalRoot);
185sourcePath = sourcePath.replace(packagerRemoteRoot, packagerLocalRoot);
186}
09f6024fHeniker4 years ago187const relativeSourcePath = path.relative(sourcesRootPath, sourcePath);
876df2a0dlebu10 years ago188return this.makeUnixStylePath(relativeSourcePath);
189}
190
191/**
192* Visual Studio Code source mapping requires Unix style path separators.
193* This method replaces all back-slash characters in a given string with forward-slash ones.
194*/
195private makeUnixStylePath(p: string): string {
09f6024fHeniker4 years ago196const pathArgs = p.split(path.sep);
4e7a6f0edlebu10 years ago197return path.posix.join.apply(null, pathArgs);
876df2a0dlebu10 years ago198}
f16656e9frogcjn9 years ago199}