source-map-explorer 2.3.1 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,18 +1,10 @@
1
1
  'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', {
4
- value: true,
5
- });
6
- exports.getErrorMessage = getErrorMessage;
7
- exports.SOURCE_MAP_INFO_URL = exports.AppError = void 0;
8
-
9
- var _helpers = require('./helpers');
10
-
11
- // If we need advanced error consider using https://github.com/joyent/node-verror
2
+ Object.defineProperty(exports, '__esModule', { value: true });
3
+ exports.getErrorMessage = exports.SOURCE_MAP_INFO_URL = exports.AppError = void 0;
4
+ const helpers_1 = require('./helpers');
12
5
  class AppError extends Error {
13
6
  constructor(errorContext, error) {
14
- super(); // https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work
15
-
7
+ super();
16
8
  Object.setPrototypeOf(this, AppError.prototype);
17
9
  const message = getErrorMessage(errorContext);
18
10
  this.message = error ? `${message}: ${error.message}` : message;
@@ -20,69 +12,57 @@ class AppError extends Error {
20
12
  Error.captureStackTrace(this, AppError);
21
13
  }
22
14
  }
23
-
24
15
  exports.AppError = AppError;
25
- const SOURCE_MAP_INFO_URL =
16
+ exports.SOURCE_MAP_INFO_URL =
26
17
  'https://github.com/danvk/source-map-explorer/blob/master/README.md#generating-source-maps';
27
- exports.SOURCE_MAP_INFO_URL = SOURCE_MAP_INFO_URL;
28
-
29
18
  function getErrorMessage(context) {
30
19
  switch (context.code) {
31
20
  case 'NoBundles':
32
21
  return 'No file(s) provided';
33
-
34
22
  case 'NoSourceMap':
35
23
  return `Unable to find a source map.
36
- See ${SOURCE_MAP_INFO_URL}`;
37
-
24
+ See ${exports.SOURCE_MAP_INFO_URL}`;
38
25
  case 'OneSourceSourceMap': {
39
26
  return `Your source map only contains one source (${context.filename}).
40
27
  This can happen if you use browserify+uglifyjs, for example, and don't set the --in-source-map flag to uglify.
41
- See ${SOURCE_MAP_INFO_URL}`;
28
+ See ${exports.SOURCE_MAP_INFO_URL}`;
42
29
  }
43
-
44
30
  case 'UnmappedBytes': {
45
31
  const { unmappedBytes, totalBytes } = context;
46
- const bytesString = (0, _helpers.formatPercent)(unmappedBytes, totalBytes, 2);
32
+ const bytesString = helpers_1.formatPercent(unmappedBytes, totalBytes, 2);
47
33
  return `Unable to map ${unmappedBytes}/${totalBytes} bytes (${bytesString}%)`;
48
34
  }
49
-
50
35
  case 'InvalidMappingLine': {
51
36
  const { generatedLine, maxLine } = context;
52
37
  return `Your source map refers to generated line ${generatedLine}, but the source only contains ${maxLine} line(s).
53
38
  Check that you are using the correct source map.`;
54
39
  }
55
-
56
40
  case 'InvalidMappingColumn': {
57
- const { generatedLine, generatedColumn, maxColumn } = context; // Add 1 since generatedColumn is 0-based
58
-
59
- return `Your source map refers to generated column ${generatedColumn +
60
- 1} on line ${generatedLine}, but the source only contains ${maxColumn} column(s) on that line.
41
+ const { generatedLine, generatedColumn, maxColumn } = context;
42
+ return `Your source map refers to generated column ${
43
+ generatedColumn + 1
44
+ } on line ${generatedLine}, but the source only contains ${maxColumn} column(s) on that line.
61
45
  Check that you are using the correct source map.`;
62
46
  }
63
-
64
47
  case 'CannotSaveFile':
65
48
  return 'Unable to save HTML to file';
66
-
67
49
  case 'CannotCreateTempFile':
68
50
  return 'Unable to create a temporary HTML file';
69
-
70
51
  case 'CannotOpenTempFile': {
71
52
  const { error, tempFile } = context;
72
53
  return `Unable to open web browser. ${error.toString().trim()}
73
54
  Either run with --html, --json, --tsv, --file, or view HTML for the visualization at:
74
55
  ${tempFile}`;
75
56
  }
76
-
77
57
  case 'CannotOpenCoverageFile': {
78
58
  return 'Unable to open/parse coverage file';
79
59
  }
80
-
81
60
  case 'NoCoverageMatches': {
82
61
  return 'No matched bundles found for coverages';
83
62
  }
84
-
85
63
  default:
86
64
  return 'Unknown error';
87
65
  }
88
66
  }
67
+ exports.getErrorMessage = getErrorMessage;
68
+ //# sourceMappingURL=app-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-error.js","sourceRoot":"","sources":["../src/lib/app-error.ts"],"names":[],"mappings":";;;AAAA,uCAA0C;AAK1C,MAAa,QAAS,SAAQ,KAAK;IAIjC,YAAY,YAA0B,EAAE,KAA6B;QACnE,KAAK,EAAE,CAAC;QAER,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;QAEhD,MAAM,OAAO,GAAG,eAAe,CAAC,YAAY,CAAC,CAAC;QAE9C,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;QAChE,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC;QAE9B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC1C,CAAC;CACF;AAhBD,4BAgBC;AAEY,QAAA,mBAAmB,GAC9B,2FAA2F,CAAC;AAmD9F,SAAgB,eAAe,CAAC,OAAqB;IACnD,QAAQ,OAAO,CAAC,IAAI,EAAE;QACpB,KAAK,WAAW;YACd,OAAO,qBAAqB,CAAC;QAE/B,KAAK,aAAa;YAChB,OAAO;MACP,2BAAmB,EAAE,CAAC;QAExB,KAAK,oBAAoB,CAAC,CAAC;YACzB,OAAO,6CAA6C,OAAO,CAAC,QAAQ;;MAEpE,2BAAmB,EAAE,CAAC;SACvB;QAED,KAAK,eAAe,CAAC,CAAC;YACpB,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;YAE9C,MAAM,WAAW,GAAG,uBAAa,CAAC,aAAa,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC;YAEhE,OAAO,iBAAiB,aAAa,IAAI,UAAU,WAAW,WAAW,IAAI,CAAC;SAC/E;QAED,KAAK,oBAAoB,CAAC,CAAC;YACzB,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;YAE3C,OAAO,4CAA4C,aAAa,kCAAkC,OAAO;iDAC9D,CAAC;SAC7C;QAED,KAAK,sBAAsB,CAAC,CAAC;YAC3B,MAAM,EAAE,aAAa,EAAE,eAAe,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;YAG9D,OAAO,8CACL,eAAe,GAAG,CACpB,YAAY,aAAa,kCAAkC,SAAS;iDACzB,CAAC;SAC7C;QAED,KAAK,gBAAgB;YACnB,OAAO,6BAA6B,CAAC;QAEvC,KAAK,sBAAsB;YACzB,OAAO,wCAAwC,CAAC;QAElD,KAAK,oBAAoB,CAAC,CAAC;YACzB,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;YAEpC,OAAO,+BAA+B,KAAK,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE;;EAEjE,QAAQ,EAAE,CAAC;SACR;QAED,KAAK,wBAAwB,CAAC,CAAC;YAC7B,OAAO,oCAAoC,CAAC;SAC7C;QAED,KAAK,mBAAmB,CAAC,CAAC;YACxB,OAAO,wCAAwC,CAAC;SACjD;QAED;YACE,OAAO,eAAe,CAAC;KAC1B;AACH,CAAC;AAjED,0CAiEC","sourcesContent":["import { formatPercent } from './helpers';\n\nimport type { ErrorCode } from './types';\n\n// If we need advanced error consider using https://github.com/joyent/node-verror\nexport class AppError extends Error {\n code?: ErrorCode;\n cause?: Error;\n\n constructor(errorContext: ErrorContext, error?: NodeJS.ErrnoException) {\n super();\n // https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work\n Object.setPrototypeOf(this, AppError.prototype);\n\n const message = getErrorMessage(errorContext);\n\n this.message = error ? `${message}: ${error.message}` : message;\n this.code = errorContext.code;\n\n Error.captureStackTrace(this, AppError);\n }\n}\n\nexport const SOURCE_MAP_INFO_URL =\n 'https://github.com/danvk/source-map-explorer/blob/master/README.md#generating-source-maps';\n\ninterface CommonErrorContext {\n code:\n | 'NoBundles'\n | 'NoSourceMap'\n | 'CannotSaveFile'\n | 'CannotCreateTempFile'\n | 'CannotOpenCoverageFile'\n | 'NoCoverageMatches'\n | 'Unknown';\n}\n\ninterface OneSourceSourceMapErrorContext {\n code: 'OneSourceSourceMap';\n filename: string;\n}\n\ninterface UnmappedBytesErrorContext {\n code: 'UnmappedBytes';\n totalBytes: number;\n unmappedBytes: number;\n}\n\ninterface InvalidMappingLineErrorContext {\n code: 'InvalidMappingLine';\n generatedLine: number;\n maxLine: number;\n}\n\ninterface InvalidMappingColumnErrorContext {\n code: 'InvalidMappingColumn';\n generatedLine: number;\n generatedColumn: number;\n maxColumn: number;\n}\n\ninterface CannotOpenTempFileErrorContext {\n code: 'CannotOpenTempFile';\n error: Buffer;\n tempFile: string;\n}\n\nexport type ErrorContext =\n | CommonErrorContext\n | OneSourceSourceMapErrorContext\n | UnmappedBytesErrorContext\n | InvalidMappingLineErrorContext\n | InvalidMappingColumnErrorContext\n | CannotOpenTempFileErrorContext;\n\nexport function getErrorMessage(context: ErrorContext): string {\n switch (context.code) {\n case 'NoBundles':\n return 'No file(s) provided';\n\n case 'NoSourceMap':\n return `Unable to find a source map.\nSee ${SOURCE_MAP_INFO_URL}`;\n\n case 'OneSourceSourceMap': {\n return `Your source map only contains one source (${context.filename}).\nThis can happen if you use browserify+uglifyjs, for example, and don't set the --in-source-map flag to uglify.\nSee ${SOURCE_MAP_INFO_URL}`;\n }\n\n case 'UnmappedBytes': {\n const { unmappedBytes, totalBytes } = context;\n\n const bytesString = formatPercent(unmappedBytes, totalBytes, 2);\n\n return `Unable to map ${unmappedBytes}/${totalBytes} bytes (${bytesString}%)`;\n }\n\n case 'InvalidMappingLine': {\n const { generatedLine, maxLine } = context;\n\n return `Your source map refers to generated line ${generatedLine}, but the source only contains ${maxLine} line(s).\nCheck that you are using the correct source map.`;\n }\n\n case 'InvalidMappingColumn': {\n const { generatedLine, generatedColumn, maxColumn } = context;\n\n // Add 1 since generatedColumn is 0-based\n return `Your source map refers to generated column ${\n generatedColumn + 1\n } on line ${generatedLine}, but the source only contains ${maxColumn} column(s) on that line.\nCheck that you are using the correct source map.`;\n }\n\n case 'CannotSaveFile':\n return 'Unable to save HTML to file';\n\n case 'CannotCreateTempFile':\n return 'Unable to create a temporary HTML file';\n\n case 'CannotOpenTempFile': {\n const { error, tempFile } = context;\n\n return `Unable to open web browser. ${error.toString().trim()}\nEither run with --html, --json, --tsv, --file, or view HTML for the visualization at:\n${tempFile}`;\n }\n\n case 'CannotOpenCoverageFile': {\n return 'Unable to open/parse coverage file';\n }\n\n case 'NoCoverageMatches': {\n return 'No matched bundles found for coverages';\n }\n\n default:\n return 'Unknown error';\n }\n}\n"]}
@@ -1,13 +1,4 @@
1
- import { Bundle, ColumnsRange, MappingRange, FileDataMap } from './index';
2
- /**
3
- * Match coverages' ranges to bundles by comparing coverage URL and bundle filename
4
- */
1
+ import type { Bundle, ColumnsRange, MappingRange, FileDataMap } from './types';
5
2
  export declare function addCoverageRanges(bundles: Bundle[], coverageFilename?: string): Bundle[];
6
- /**
7
- * Set covered size for files
8
- */
9
3
  export declare function setCoveredSizes(line: string, files: FileDataMap, mappingRanges: MappingRange[], coveredRanges: ColumnsRange[]): FileDataMap;
10
- /**
11
- * Get heat map color by coverage percent
12
- */
13
4
  export declare function getColorByPercent(percent: number): string;
@@ -1,116 +1,71 @@
1
1
  'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', {
4
- value: true,
5
- });
6
- exports.addCoverageRanges = addCoverageRanges;
7
- exports.setCoveredSizes = setCoveredSizes;
8
- exports.getColorByPercent = getColorByPercent;
9
-
10
- var _helpers = require('./helpers');
11
-
12
- var _appError = require('./app-error');
13
-
14
- /**
15
- * Convert one-line coverage ranges (exclusive) into per line ranges (inclusive)
16
- */
2
+ Object.defineProperty(exports, '__esModule', { value: true });
3
+ exports.getColorByPercent = exports.setCoveredSizes = exports.addCoverageRanges = void 0;
4
+ const url_1 = require('url');
5
+ const helpers_1 = require('./helpers');
6
+ const app_error_1 = require('./app-error');
17
7
  function convertRangesToLinesRanges(coverage) {
18
8
  const { ranges, text } = coverage;
19
- const eol = (0, _helpers.detectEOL)(text);
9
+ const eol = helpers_1.detectEOL(text);
20
10
  const eolLength = eol.length;
21
- const lines = text.split(eol); // Current line offset
22
-
11
+ const lines = text.split(eol);
23
12
  let offset = 0;
24
- const lineRanges = lines.map(line => {
13
+ const lineRanges = lines.map((line) => {
25
14
  const lineLength = line.length;
26
-
27
15
  if (lineLength === 0) {
28
16
  return [];
29
- } // Exclusive line start/end
30
-
17
+ }
31
18
  const lineStart = offset;
32
19
  const lineEnd = offset + lineLength;
33
20
  const lineRanges = ranges.reduce((result, { start, end }) => {
34
- // Inclusive range start/end within the line
35
21
  const startIndex = start - lineStart;
36
22
  const endIndex = end - lineStart - 1;
37
23
  const lineEndIndex = lineLength - 1;
38
-
39
24
  if (start <= lineStart && lineEnd <= end) {
40
- // Range includes line range
41
- result.push({
42
- start: 0,
43
- end: lineEndIndex,
44
- });
25
+ result.push({ start: 0, end: lineEndIndex });
45
26
  } else if (lineStart <= start && end <= lineEnd) {
46
- // Line range includes range
47
- result.push({
48
- start: startIndex,
49
- end: endIndex,
50
- });
27
+ result.push({ start: startIndex, end: endIndex });
51
28
  } else if (lineStart <= start && start <= lineEnd) {
52
- // Range starts within line range
53
- result.push({
54
- start: startIndex,
55
- end: lineEndIndex,
56
- });
29
+ result.push({ start: startIndex, end: lineEndIndex });
57
30
  } else if (lineStart <= end && end <= lineEnd) {
58
- // Range ends within line range
59
- result.push({
60
- start: 0,
61
- end: endIndex,
62
- });
31
+ result.push({ start: 0, end: endIndex });
63
32
  }
64
-
65
33
  return result;
66
- }, []); // Move to next line jumping over EOL character
67
-
34
+ }, []);
68
35
  offset = lineEnd + eolLength;
69
36
  return lineRanges;
70
37
  });
71
38
  return lineRanges;
72
39
  }
73
-
74
40
  const PATH_SEPARATOR_REGEX = /[/\\]/;
75
-
76
41
  function getPathParts(path) {
77
42
  return path.split(PATH_SEPARATOR_REGEX).filter(Boolean);
78
43
  }
79
- /**
80
- * Match coverages' ranges to bundles by comparing coverage URL and bundle filename
81
- */
82
-
83
44
  function addCoverageRanges(bundles, coverageFilename) {
84
45
  if (!coverageFilename) {
85
46
  return bundles;
86
47
  }
87
-
88
48
  try {
89
- const coverages = JSON.parse((0, _helpers.getFileContent)(coverageFilename));
49
+ const coverages = JSON.parse(helpers_1.getFileContent(coverageFilename));
90
50
  const bundlesPaths = bundles.reduce((result, { code }, index) => {
91
51
  if (!Buffer.isBuffer(code)) {
92
52
  result.push([getPathParts(code).reverse(), index]);
93
53
  }
94
-
95
54
  return result;
96
55
  }, []);
97
- coverages // pathname contains filename
98
- .map(({ url }) => getPathParts(new URL(url).pathname).reverse())
56
+ coverages
57
+ .map(({ url }) => getPathParts(new url_1.URL(url).pathname).reverse())
99
58
  .forEach((partsA, coverageIndex) => {
100
- // Exclude coverages for inlined code (URL doesn't contain a filename)
101
59
  if (!partsA.length) return;
102
- let matchingBundles = [...bundlesPaths]; // Start from filename and go up to path root
103
-
60
+ let matchingBundles = [...bundlesPaths];
104
61
  for (let i = 0; i < partsA.length; i++) {
105
62
  matchingBundles = matchingBundles.filter(
106
63
  ([partsB]) => i < partsB.length && partsB[i] === partsA[i]
107
- ); // Stop when exact (among bundles) match found or no matches found
108
-
64
+ );
109
65
  if (matchingBundles.length <= 1) {
110
66
  break;
111
67
  }
112
68
  }
113
-
114
69
  if (matchingBundles.length === 1) {
115
70
  const [[, bundleIndex]] = matchingBundles;
116
71
  bundles[bundleIndex].coverageRanges = convertRangesToLinesRanges(
@@ -119,38 +74,22 @@ function addCoverageRanges(bundles, coverageFilename) {
119
74
  }
120
75
  });
121
76
  } catch (error) {
122
- throw new _appError.AppError(
123
- {
124
- code: 'CannotOpenCoverageFile',
125
- },
126
- error
127
- );
77
+ throw new app_error_1.AppError({ code: 'CannotOpenCoverageFile' }, error);
128
78
  }
129
-
130
79
  if (bundles.every(({ coverageRanges }) => coverageRanges === undefined)) {
131
- throw new _appError.AppError({
132
- code: 'NoCoverageMatches',
133
- });
80
+ throw new app_error_1.AppError({ code: 'NoCoverageMatches' });
134
81
  }
135
-
136
82
  return bundles;
137
83
  }
138
- /**
139
- * Find overlaps in arrays of column ranges, using ratcheting pointers instead of nested loops for
140
- * O(n) runtime instead of O(n^2)
141
- */
142
-
84
+ exports.addCoverageRanges = addCoverageRanges;
143
85
  function findCoveredMappingRanges(mappingRanges, coveredRanges) {
144
86
  let i = 0;
145
87
  let j = 0;
146
88
  const result = [];
147
-
148
89
  while (i < mappingRanges.length && j < coveredRanges.length) {
149
90
  const mappingRange = mappingRanges[i];
150
91
  const coveredRange = coveredRanges[j];
151
-
152
92
  if (mappingRange.start <= coveredRange.end && coveredRange.start <= mappingRange.end) {
153
- // Overlaps, calculate amount, move to next coverage range
154
93
  const end = Math.min(coveredRange.end, mappingRange.end);
155
94
  const start = Math.max(mappingRange.start, coveredRange.start);
156
95
  result.push({
@@ -158,35 +97,24 @@ function findCoveredMappingRanges(mappingRanges, coveredRanges) {
158
97
  end,
159
98
  source: mappingRange.source,
160
99
  });
161
-
162
100
  if (
163
101
  mappingRanges[i + 1] !== undefined &&
164
102
  mappingRanges[i + 1].start <= coveredRange.end &&
165
103
  mappingRanges[i + 1].end >= coveredRange.start
166
104
  ) {
167
- // Next module also overlaps current coverage range, advance to next module instead of advancing coverage
168
105
  i++;
169
106
  } else {
170
- // Check next coverage range, it may also overlap this module range
171
107
  j++;
172
108
  }
173
109
  } else if (mappingRange.end < coveredRange.start) {
174
- // Module comes entirely before coverageRange, check next module range
175
110
  i++;
176
111
  }
177
-
178
112
  if (coveredRange.end < mappingRange.start) {
179
- // Module range comes entirely after coverage range, check next coverage range
180
113
  j++;
181
114
  }
182
115
  }
183
-
184
116
  return result;
185
117
  }
186
- /**
187
- * Set covered size for files
188
- */
189
-
190
118
  function setCoveredSizes(line, files, mappingRanges, coveredRanges) {
191
119
  findCoveredMappingRanges(mappingRanges, coveredRanges).forEach(({ start, end, source }) => {
192
120
  const rangeByteLength = Buffer.byteLength(line.substring(start, end + 1));
@@ -196,46 +124,19 @@ function setCoveredSizes(line, files, mappingRanges, coveredRanges) {
196
124
  });
197
125
  return files;
198
126
  }
199
-
127
+ exports.setCoveredSizes = setCoveredSizes;
200
128
  const percentColors = [
201
- {
202
- percent: 0.0,
203
- color: {
204
- r: 0xff,
205
- g: 0x00,
206
- b: 0,
207
- },
208
- },
209
- {
210
- percent: 0.5,
211
- color: {
212
- r: 0xff,
213
- g: 0xff,
214
- b: 0,
215
- },
216
- },
217
- {
218
- percent: 1.0,
219
- color: {
220
- r: 0x00,
221
- g: 0xff,
222
- b: 0,
223
- },
224
- },
129
+ { percent: 0.0, color: { r: 0xff, g: 0x00, b: 0 } },
130
+ { percent: 0.5, color: { r: 0xff, g: 0xff, b: 0 } },
131
+ { percent: 1.0, color: { r: 0x00, g: 0xff, b: 0 } },
225
132
  ];
226
- /**
227
- * Get heat map color by coverage percent
228
- */
229
-
230
133
  function getColorByPercent(percent) {
231
134
  let i = 1;
232
-
233
135
  for (; i < percentColors.length - 1; i++) {
234
136
  if (percent < percentColors[i].percent) {
235
137
  break;
236
138
  }
237
139
  }
238
-
239
140
  const lowerColor = percentColors[i - 1];
240
141
  const upperColor = percentColors[i];
241
142
  const rangeWithinColors = upperColor.percent - lowerColor.percent;
@@ -247,3 +148,5 @@ function getColorByPercent(percent) {
247
148
  const b = Math.floor(lowerColor.color.b * percentLower + upperColor.color.b * percentUpper);
248
149
  return `rgb(${r}, ${g}, ${b})`;
249
150
  }
151
+ exports.getColorByPercent = getColorByPercent;
152
+ //# sourceMappingURL=coverage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverage.js","sourceRoot":"","sources":["../src/lib/coverage.ts"],"names":[],"mappings":"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","sourcesContent":["import { URL } from 'url';\n\nimport { getFileContent, detectEOL } from './helpers';\nimport { AppError } from './app-error';\n\nimport type { Bundle, Coverage, ColumnsRange, MappingRange, FileDataMap } from './types';\n\n/**\n * Convert one-line coverage ranges (exclusive) into per line ranges (inclusive)\n */\nfunction convertRangesToLinesRanges(coverage: Coverage): ColumnsRange[][] {\n const { ranges, text } = coverage;\n\n const eol = detectEOL(text);\n const eolLength = eol.length;\n const lines = text.split(eol);\n\n // Current line offset\n let offset = 0;\n\n const lineRanges = lines.map((line) => {\n const lineLength = line.length;\n\n if (lineLength === 0) {\n return [];\n }\n\n // Exclusive line start/end\n const lineStart = offset;\n const lineEnd = offset + lineLength;\n\n const lineRanges = ranges.reduce<ColumnsRange[]>((result, { start, end }) => {\n // Inclusive range start/end within the line\n const startIndex = start - lineStart;\n const endIndex = end - lineStart - 1;\n const lineEndIndex = lineLength - 1;\n\n if (start <= lineStart && lineEnd <= end) {\n // Range includes line range\n result.push({ start: 0, end: lineEndIndex });\n } else if (lineStart <= start && end <= lineEnd) {\n // Line range includes range\n result.push({ start: startIndex, end: endIndex });\n } else if (lineStart <= start && start <= lineEnd) {\n // Range starts within line range\n result.push({ start: startIndex, end: lineEndIndex });\n } else if (lineStart <= end && end <= lineEnd) {\n // Range ends within line range\n result.push({ start: 0, end: endIndex });\n }\n\n return result;\n }, []);\n\n // Move to next line jumping over EOL character\n offset = lineEnd + eolLength;\n\n return lineRanges;\n });\n\n return lineRanges;\n}\n\nconst PATH_SEPARATOR_REGEX = /[/\\\\]/;\n\nfunction getPathParts(path: string): string[] {\n return path.split(PATH_SEPARATOR_REGEX).filter(Boolean);\n}\n\n/**\n * Match coverages' ranges to bundles by comparing coverage URL and bundle filename\n */\nexport function addCoverageRanges(bundles: Bundle[], coverageFilename?: string): Bundle[] {\n if (!coverageFilename) {\n return bundles;\n }\n\n try {\n const coverages: Coverage[] = JSON.parse(getFileContent(coverageFilename));\n\n const bundlesPaths = bundles.reduce<[string[], number][]>((result, { code }, index) => {\n if (!Buffer.isBuffer(code)) {\n result.push([getPathParts(code).reverse(), index]);\n }\n\n return result;\n }, []);\n\n coverages\n // pathname contains filename\n .map(({ url }) => getPathParts(new URL(url).pathname).reverse())\n .forEach((partsA, coverageIndex) => {\n // Exclude coverages for inlined code (URL doesn't contain a filename)\n if (!partsA.length) return;\n let matchingBundles = [...bundlesPaths];\n\n // Start from filename and go up to path root\n for (let i = 0; i < partsA.length; i++) {\n matchingBundles = matchingBundles.filter(\n ([partsB]) => i < partsB.length && partsB[i] === partsA[i]\n );\n\n // Stop when exact (among bundles) match found or no matches found\n if (matchingBundles.length <= 1) {\n break;\n }\n }\n\n if (matchingBundles.length === 1) {\n const [[, bundleIndex]] = matchingBundles;\n\n bundles[bundleIndex].coverageRanges = convertRangesToLinesRanges(\n coverages[coverageIndex]\n );\n }\n });\n } catch (error) {\n throw new AppError({ code: 'CannotOpenCoverageFile' }, error);\n }\n\n if (bundles.every(({ coverageRanges }) => coverageRanges === undefined)) {\n throw new AppError({ code: 'NoCoverageMatches' });\n }\n\n return bundles;\n}\n\n/**\n * Find overlaps in arrays of column ranges, using ratcheting pointers instead of nested loops for\n * O(n) runtime instead of O(n^2)\n */\nfunction findCoveredMappingRanges(\n mappingRanges: MappingRange[],\n coveredRanges: ColumnsRange[]\n): MappingRange[] {\n let i = 0;\n let j = 0;\n\n const result: MappingRange[] = [];\n\n while (i < mappingRanges.length && j < coveredRanges.length) {\n const mappingRange = mappingRanges[i];\n const coveredRange = coveredRanges[j];\n\n if (mappingRange.start <= coveredRange.end && coveredRange.start <= mappingRange.end) {\n // Overlaps, calculate amount, move to next coverage range\n const end = Math.min(coveredRange.end, mappingRange.end);\n const start = Math.max(mappingRange.start, coveredRange.start);\n\n result.push({\n start,\n end,\n source: mappingRange.source,\n });\n\n if (\n mappingRanges[i + 1] !== undefined &&\n mappingRanges[i + 1].start <= coveredRange.end &&\n mappingRanges[i + 1].end >= coveredRange.start\n ) {\n // Next module also overlaps current coverage range, advance to next module instead of advancing coverage\n i++;\n } else {\n // Check next coverage range, it may also overlap this module range\n j++;\n }\n } else if (mappingRange.end < coveredRange.start) {\n // Module comes entirely before coverageRange, check next module range\n i++;\n }\n if (coveredRange.end < mappingRange.start) {\n // Module range comes entirely after coverage range, check next coverage range\n j++;\n }\n }\n\n return result;\n}\n\n/**\n * Set covered size for files\n */\nexport function setCoveredSizes(\n line: string,\n files: FileDataMap,\n mappingRanges: MappingRange[],\n coveredRanges: ColumnsRange[]\n): FileDataMap {\n findCoveredMappingRanges(mappingRanges, coveredRanges).forEach(({ start, end, source }) => {\n const rangeByteLength = Buffer.byteLength(line.substring(start, end + 1));\n\n let coveredSize = files[source].coveredSize || 0;\n\n coveredSize += rangeByteLength;\n\n files[source].coveredSize = coveredSize;\n });\n\n return files;\n}\n\nconst percentColors = [\n { percent: 0.0, color: { r: 0xff, g: 0x00, b: 0 } },\n { percent: 0.5, color: { r: 0xff, g: 0xff, b: 0 } },\n { percent: 1.0, color: { r: 0x00, g: 0xff, b: 0 } },\n];\n\n/**\n * Get heat map color by coverage percent\n */\nexport function getColorByPercent(percent: number): string {\n let i = 1;\n\n for (; i < percentColors.length - 1; i++) {\n if (percent < percentColors[i].percent) {\n break;\n }\n }\n\n const lowerColor = percentColors[i - 1];\n const upperColor = percentColors[i];\n const rangeWithinColors = upperColor.percent - lowerColor.percent;\n const rangePercent = (percent - lowerColor.percent) / rangeWithinColors;\n const percentLower = 1 - rangePercent;\n const percentUpper = rangePercent;\n\n const r = Math.floor(lowerColor.color.r * percentLower + upperColor.color.r * percentUpper);\n const g = Math.floor(lowerColor.color.g * percentLower + upperColor.color.g * percentUpper);\n const b = Math.floor(lowerColor.color.b * percentLower + upperColor.color.b * percentUpper);\n\n return `rgb(${r}, ${g}, ${b})`;\n}\n"]}
@@ -1,11 +1,8 @@
1
- import { Bundle, ExploreOptions, ExploreBundleResult, FileDataMap } from './index';
1
+ import type { Bundle, ExploreBundleResult, ExploreOptions, FileDataMap } from './types';
2
2
  export declare const UNMAPPED_KEY = "[unmapped]";
3
3
  export declare const SOURCE_MAP_COMMENT_KEY = "[sourceMappingURL]";
4
4
  export declare const NO_SOURCE_KEY = "[no source]";
5
5
  export declare const EOL_KEY = "[EOLs]";
6
6
  export declare const SPECIAL_FILENAMES: string[];
7
- /**
8
- * Analyze a bundle
9
- */
10
7
  export declare function exploreBundle(bundle: Bundle, options: ExploreOptions): Promise<ExploreBundleResult>;
11
8
  export declare function adjustSourcePaths(fileSizeMap: FileDataMap, options: ExploreOptions): FileDataMap;
package/lib/explore.js ADDED
@@ -0,0 +1,227 @@
1
+ 'use strict';
2
+ var __importDefault =
3
+ (this && this.__importDefault) ||
4
+ function (mod) {
5
+ return mod && mod.__esModule ? mod : { default: mod };
6
+ };
7
+ Object.defineProperty(exports, '__esModule', { value: true });
8
+ exports.adjustSourcePaths = exports.exploreBundle = exports.SPECIAL_FILENAMES = exports.EOL_KEY = exports.NO_SOURCE_KEY = exports.SOURCE_MAP_COMMENT_KEY = exports.UNMAPPED_KEY = void 0;
9
+ const convert_source_map_1 = __importDefault(require('convert-source-map'));
10
+ const path_1 = __importDefault(require('path'));
11
+ const source_map_1 = require('source-map');
12
+ const gzip_size_1 = __importDefault(require('gzip-size'));
13
+ const lodash_1 = require('lodash');
14
+ const api_1 = require('./api');
15
+ const helpers_1 = require('./helpers');
16
+ const app_error_1 = require('./app-error');
17
+ const coverage_1 = require('./coverage');
18
+ exports.UNMAPPED_KEY = '[unmapped]';
19
+ exports.SOURCE_MAP_COMMENT_KEY = '[sourceMappingURL]';
20
+ exports.NO_SOURCE_KEY = '[no source]';
21
+ exports.EOL_KEY = '[EOLs]';
22
+ exports.SPECIAL_FILENAMES = [
23
+ exports.UNMAPPED_KEY,
24
+ exports.SOURCE_MAP_COMMENT_KEY,
25
+ exports.NO_SOURCE_KEY,
26
+ exports.EOL_KEY,
27
+ ];
28
+ async function exploreBundle(bundle, options) {
29
+ const { code, map, coverageRanges } = bundle;
30
+ const sourceMapData = await loadSourceMap(code, map);
31
+ const sizes = computeFileSizes(sourceMapData, options, coverageRanges);
32
+ const files = adjustSourcePaths(sizes.files, options);
33
+ sourceMapData.consumer.destroy();
34
+ return {
35
+ bundleName: api_1.getBundleName(bundle),
36
+ ...sizes,
37
+ files,
38
+ };
39
+ }
40
+ exports.exploreBundle = exploreBundle;
41
+ async function loadSourceMap(codeFile, sourceMapFile) {
42
+ const codeFileContent = helpers_1.getFileContent(codeFile);
43
+ let consumer;
44
+ if (sourceMapFile) {
45
+ const sourceMapFileContent = helpers_1.getFileContent(sourceMapFile);
46
+ consumer = await new source_map_1.SourceMapConsumer(sourceMapFileContent);
47
+ } else {
48
+ let converter = convert_source_map_1.default.fromSource(codeFileContent);
49
+ if (!converter && !Buffer.isBuffer(codeFile)) {
50
+ converter = convert_source_map_1.default.fromMapFileSource(
51
+ codeFileContent,
52
+ path_1.default.dirname(codeFile)
53
+ );
54
+ }
55
+ if (!converter) {
56
+ throw new app_error_1.AppError({ code: 'NoSourceMap' });
57
+ }
58
+ consumer = await new source_map_1.SourceMapConsumer(converter.toJSON());
59
+ }
60
+ if (!consumer) {
61
+ throw new app_error_1.AppError({ code: 'NoSourceMap' });
62
+ }
63
+ return {
64
+ consumer,
65
+ codeFileContent,
66
+ };
67
+ }
68
+ const COMMENT_REGEX = convert_source_map_1.default.commentRegex;
69
+ const MAP_FILE_COMMENT_REGEX = convert_source_map_1.default.mapFileCommentRegex;
70
+ function getSourceMapComment(fileContent) {
71
+ const sourceMapComment =
72
+ helpers_1.getFirstRegexMatch(COMMENT_REGEX, fileContent) ||
73
+ helpers_1.getFirstRegexMatch(MAP_FILE_COMMENT_REGEX, fileContent) ||
74
+ '';
75
+ return sourceMapComment.trim();
76
+ }
77
+ function isReferencingEOL(context, maxColumnIndex) {
78
+ const { generatedLine, generatedColumn, source, consumer } = context;
79
+ if (maxColumnIndex - generatedColumn > 2) {
80
+ return false;
81
+ }
82
+ if (!source) {
83
+ return false;
84
+ }
85
+ if (context.mapReferenceEOLSources.has(source)) {
86
+ return true;
87
+ }
88
+ const content = consumer.sourceContentFor(source, true);
89
+ if (!content) {
90
+ return false;
91
+ }
92
+ const { line, column } = consumer.originalPositionFor({
93
+ line: generatedLine,
94
+ column: generatedColumn,
95
+ });
96
+ if (line === null || column === null) {
97
+ return false;
98
+ }
99
+ if (helpers_1.isEOLAtPosition(content, [line, column])) {
100
+ context.mapReferenceEOLSources.add(source);
101
+ return true;
102
+ }
103
+ return false;
104
+ }
105
+ function checkInvalidMappingColumn(context) {
106
+ const { line, generatedLine, generatedColumn } = context;
107
+ const maxColumnIndex = line.length - 1;
108
+ if (generatedColumn > maxColumnIndex) {
109
+ if (isReferencingEOL(context, maxColumnIndex)) {
110
+ return;
111
+ }
112
+ throw new app_error_1.AppError({
113
+ code: 'InvalidMappingColumn',
114
+ generatedLine,
115
+ generatedColumn,
116
+ maxColumn: line.length,
117
+ });
118
+ }
119
+ }
120
+ function computeFileSizes(sourceMapData, options, coverageRanges) {
121
+ const { consumer, codeFileContent: fileContent } = sourceMapData;
122
+ const sourceMapComment = getSourceMapComment(fileContent);
123
+ const sourceContent = fileContent.replace(sourceMapComment, '').trim();
124
+ const eol = helpers_1.detectEOL(fileContent);
125
+ const lines = sourceContent.split(eol);
126
+ const mappingRanges = [];
127
+ const context = {
128
+ generatedLine: -1,
129
+ generatedColumn: -1,
130
+ line: '',
131
+ source: null,
132
+ consumer,
133
+ mapReferenceEOLSources: new Set(),
134
+ };
135
+ consumer.computeColumnSpans();
136
+ consumer.eachMapping(({ source, generatedLine, generatedColumn, lastGeneratedColumn }) => {
137
+ const lineIndex = generatedLine - 1;
138
+ const line = lines[lineIndex];
139
+ if (line === undefined) {
140
+ if (options.noBorderChecks) {
141
+ return;
142
+ }
143
+ throw new app_error_1.AppError({
144
+ code: 'InvalidMappingLine',
145
+ generatedLine,
146
+ maxLine: lines.length,
147
+ });
148
+ }
149
+ context.generatedLine = generatedLine;
150
+ context.generatedColumn = lastGeneratedColumn || generatedColumn;
151
+ context.line = line;
152
+ context.source = source;
153
+ if (!options.noBorderChecks) {
154
+ checkInvalidMappingColumn(context);
155
+ }
156
+ const start = generatedColumn;
157
+ const end = lastGeneratedColumn === null ? line.length - 1 : lastGeneratedColumn;
158
+ const lineRanges = mappingRanges[lineIndex] || [];
159
+ lineRanges.push({
160
+ start,
161
+ end,
162
+ source: source === null ? exports.NO_SOURCE_KEY : source,
163
+ });
164
+ mappingRanges[lineIndex] = lineRanges;
165
+ });
166
+ let files = {};
167
+ let mappedBytes = 0;
168
+ const getSize = options.gzip ? gzip_size_1.default.sync : Buffer.byteLength;
169
+ mappingRanges.forEach((lineRanges, lineIndex) => {
170
+ const line = lines[lineIndex];
171
+ const mergedRanges = helpers_1.mergeRanges(lineRanges);
172
+ mergedRanges.forEach(({ start, end, source }) => {
173
+ const rangeString = line.substring(start, end + 1);
174
+ const rangeByteLength = getSize(rangeString);
175
+ if (!files[source]) {
176
+ files[source] = { size: 0 };
177
+ }
178
+ files[source].size += rangeByteLength;
179
+ mappedBytes += rangeByteLength;
180
+ });
181
+ if (coverageRanges) {
182
+ files = coverage_1.setCoveredSizes(line, files, mergedRanges, coverageRanges[lineIndex]);
183
+ }
184
+ });
185
+ const sourceMapCommentBytes = getSize(sourceMapComment);
186
+ const eolBytes = helpers_1.getOccurrencesCount(eol, fileContent) * Buffer.byteLength(eol);
187
+ const totalBytes = getSize(fileContent);
188
+ let unmappedBytes;
189
+ if (!options.excludeSourceMapComment) {
190
+ files[exports.SOURCE_MAP_COMMENT_KEY] = { size: sourceMapCommentBytes };
191
+ }
192
+ if (!options.onlyMapped) {
193
+ unmappedBytes = totalBytes - mappedBytes - sourceMapCommentBytes - eolBytes;
194
+ files[exports.UNMAPPED_KEY] = { size: unmappedBytes };
195
+ }
196
+ if (eolBytes > 0) {
197
+ files[exports.EOL_KEY] = { size: eolBytes };
198
+ }
199
+ return {
200
+ ...(options.excludeSourceMapComment
201
+ ? { totalBytes: totalBytes - sourceMapCommentBytes }
202
+ : { totalBytes }),
203
+ mappedBytes,
204
+ ...(!options.onlyMapped && { unmappedBytes }),
205
+ eolBytes,
206
+ sourceMapCommentBytes,
207
+ files,
208
+ };
209
+ }
210
+ function adjustSourcePaths(fileSizeMap, options) {
211
+ if (!options.noRoot) {
212
+ const prefix = helpers_1.getCommonPathPrefix(Object.keys(fileSizeMap));
213
+ const length = prefix.length;
214
+ if (length) {
215
+ fileSizeMap = lodash_1.mapKeys(fileSizeMap, (size, source) => source.slice(length));
216
+ }
217
+ }
218
+ if (options.replaceMap) {
219
+ fileSizeMap = Object.entries(options.replaceMap).reduce((result, [before, after]) => {
220
+ const regexp = new RegExp(before, 'g');
221
+ return lodash_1.mapKeys(result, (size, source) => source.replace(regexp, after));
222
+ }, fileSizeMap);
223
+ }
224
+ return fileSizeMap;
225
+ }
226
+ exports.adjustSourcePaths = adjustSourcePaths;
227
+ //# sourceMappingURL=explore.js.map