microsoft/vscode-react-native

Public

mirrored fromhttps://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
c0b32993595df760282a903082cf37d59de18ea8

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/debugger/sourceMapsCombinator.ts

121lines · modecode

1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
4/// <reference path="./../typings/debugger/sourceMapsCombinator.d.ts" />
5
6import * as fs from "fs";
7import * as path from "path";
8import { SourceMapConsumer, RawSourceMap, SourceMapGenerator, MappingItem, Mapping, Position, NullableMappedPosition } from "source-map";
9import sourceMapResolve = require("source-map-resolve");
10
11const DISK_LETTER_RE: RegExp = /^(?:[a-z]{2,}:\/\/\/)?[a-z]:/i;
12
13export class SourceMapsCombinator {
14
15 public convert(rawBundleSourcemap: RawSourceMap): RawSourceMap {
16
17 // Find user files from bundle files list
18 const consumers: { [key: string]: SourceMapConsumer } = rawBundleSourcemap.sources
19 .reduce((result: { [key: string]: SourceMapConsumer }, file) => {
20 // Skip files inside node_modules
21 if (file.indexOf("node_modules") >= 0) return result;
22
23 try {
24 let consumer: SourceMapConsumer | null = this.getSourceMapConsumerFrom(file);
25 if (consumer)
26 result[file] = consumer;
27 } finally {
28 return result;
29 }
30 }, {});
31
32 if (Object.keys(consumers).length === 0) {
33 // Sourcemaps not found, so return original bundle sourcemap
34 return rawBundleSourcemap;
35 }
36
37 const generator = new SourceMapGenerator();
38 const bundleConsumer = new SourceMapConsumer(rawBundleSourcemap);
39
40 bundleConsumer.eachMapping((item: MappingItem) => {
41 if (item.source === null) {
42 // Some mappings in react native bundle have no sources
43 return;
44 }
45
46 // Copy mappings
47 let mapping: Mapping = {
48 generated: { line: item.generatedLine, column: item.generatedColumn },
49 original: { line: item.originalLine, column: item.originalColumn },
50 source: item.source,
51 name: item.name,
52 };
53
54 if (consumers[item.source]) {
55 let jsPosition: Position = { line: item.originalLine, column: item.originalColumn };
56 let tsPosition: NullableMappedPosition = consumers[item.source].originalPositionFor(jsPosition);
57
58 if (tsPosition.source === null) {
59 // Some positions from react native generated bundle can not translate to TS source positions
60 // skip them
61 return;
62 }
63
64 // Resolve TS source path to absolute because it might be relative to generated JS
65 // (this depends on whether "sourceRoot" option is specified in tsconfig.json)
66 if (!tsPosition.source.match(DISK_LETTER_RE)) { // This check for Windows tests which were run on MacOs
67 tsPosition.source = path.resolve(
68 <string>rawBundleSourcemap.sourceRoot,
69 path.dirname(item.source),
70 tsPosition.source
71 );
72 }
73
74 // Update mapping w/ mapped position values
75 mapping.source = tsPosition.source;
76 mapping.name = tsPosition.name || mapping.name;
77 if (tsPosition.line !== null && tsPosition.column !== null) {
78 mapping.original = { line: tsPosition.line, column: tsPosition.column};
79 }
80 }
81
82 try {
83 generator.addMapping(mapping);
84 } catch (err) {
85
86 }
87 });
88
89 return generator.toJSON();
90 }
91
92 private getSourceMapConsumerFrom(generatedFile: string): SourceMapConsumer | null {
93 let code = fs.readFileSync(generatedFile);
94
95 let consumer = this.readSourcemap(generatedFile, code.toString());
96 return consumer;
97 }
98
99 private readSourcemap(file: string, code: string): SourceMapConsumer | null {
100 let result = sourceMapResolve.resolveSync(code, file, readFileSync.bind(null, getDiskLetter(file)));
101 if (result === null) {
102 return null;
103 }
104 return new SourceMapConsumer(result.map);
105 }
106}
107
108// Hack for source-map-resolve and cutted disk letter
109// https://github.com/lydell/source-map-resolve/issues/9
110function readFileSync(diskLetter: string, filePath: string) {
111 if (filePath.match(DISK_LETTER_RE)) {
112 return fs.readFileSync(filePath);
113 } else {
114 return fs.readFileSync(`${diskLetter}${filePath}`);
115 }
116}
117
118function getDiskLetter(filePath: string): string {
119 const matched = filePath.match(DISK_LETTER_RE);
120 return matched ? matched[0] : "";
121}
122