source-map-explorer 2.3.0 → 2.4.2

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.
package/dist/cli.js CHANGED
@@ -1,41 +1,27 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
-
4
- Object.defineProperty(exports, '__esModule', {
5
- value: true,
6
- });
7
- exports.logError = logError;
8
- exports.logWarn = logWarn;
9
- exports.logInfo = logInfo;
10
-
11
- var _yargs = _interopRequireDefault(require('yargs'));
12
-
13
- var _fs = _interopRequireDefault(require('fs'));
14
-
15
- var _temp = _interopRequireDefault(require('temp'));
16
-
17
- var _open = _interopRequireDefault(require('open'));
18
-
19
- var _chalk = _interopRequireDefault(require('chalk'));
20
-
21
- var _lodash = require('lodash');
22
-
23
- var _api = require('./api');
24
-
25
- var _appError = require('./app-error');
26
-
27
- function _interopRequireDefault(obj) {
28
- return obj && obj.__esModule ? obj : { default: obj };
29
- }
30
-
3
+ var __importDefault =
4
+ (this && this.__importDefault) ||
5
+ function (mod) {
6
+ return mod && mod.__esModule ? mod : { default: mod };
7
+ };
8
+ Object.defineProperty(exports, '__esModule', { value: true });
9
+ const yargs_1 = __importDefault(require('yargs'));
10
+ const fs_1 = __importDefault(require('fs'));
11
+ const temp_1 = __importDefault(require('temp'));
12
+ const open_1 = __importDefault(require('open'));
13
+ const chalk_1 = __importDefault(require('chalk'));
14
+ const lodash_1 = require('lodash');
15
+ const api_1 = require('./api');
16
+ const app_error_1 = require('./app-error');
31
17
  function parseArguments() {
32
- const argv = _yargs.default
18
+ const argv = yargs_1.default
33
19
  .strict()
34
20
  .scriptName('source-map-explorer')
35
21
  .usage('Analyze and debug space usage through source maps.')
36
22
  .usage('Usage:')
37
23
  .usage(
38
- '$0 script.js [script.js.map] [--json [result.json] | --html [result.html] | --tsv [result.csv]] [-m | --only-mapped] [--exclude-source-map] [--gzip] [--replace=BEFORE_1 BEFORE_2 --with=AFTER_1 AFTER_2] [--no-root] [--coverage coverage.json] [--version] [--help | -h]'
24
+ '$0 script.js [script.js.map] [--json [result.json] | --html [result.html] | --tsv [result.csv]] [-m | --only-mapped] [--exclude-source-map] [--no-border-checks] [--gzip] [--sort] [--replace=BEFORE_1 BEFORE_2 --with=AFTER_1 AFTER_2] [--no-root] [--coverage coverage.json] [--version] [--help | -h]'
39
25
  )
40
26
  .example('$0 script.js script.js.map', 'Explore bundle')
41
27
  .example('$0 script.js', 'Explore bundle with inline source map')
@@ -90,6 +76,10 @@ function parseArguments() {
90
76
  description: 'See --replace.',
91
77
  implies: 'replace',
92
78
  },
79
+ 'no-border-checks': {
80
+ type: 'boolean',
81
+ description: 'Disable invalid mapping column/line checks.',
82
+ },
93
83
  coverage: {
94
84
  type: 'string',
95
85
  normalize: true,
@@ -101,53 +91,50 @@ function parseArguments() {
101
91
  description: 'Calculate gzip size. It also sets onlyMapped flag',
102
92
  conflicts: ['only-mapped'],
103
93
  },
94
+ sort: {
95
+ type: 'boolean',
96
+ description: 'Sort filenames',
97
+ },
104
98
  })
105
99
  .group(['json', 'tsv', 'html'], 'Output:')
106
100
  .group(['replace', 'with'], 'Replace:')
107
101
  .help('h')
108
102
  .alias('h', 'help')
109
103
  .showHelpOnFail(false, 'Specify --help for available options')
110
- .wrap(null) // Do not limit line length
104
+ .wrap(null)
111
105
  .parserConfiguration({
112
- 'boolean-negation': false, // Allow --no-root
106
+ 'boolean-negation': false,
113
107
  })
114
- .check(argv => {
108
+ .check((argv) => {
115
109
  if (argv.replace && argv.with && argv.replace.length !== argv.with.length) {
116
110
  throw new Error('--replace flags must be paired with --with flags');
117
111
  }
118
-
119
112
  return true;
120
113
  })
121
- .parse(); // Trim extra quotes
122
-
114
+ .parse();
123
115
  const quoteRegex = /'/g;
124
- argv._ = argv._.map(path => path.replace(quoteRegex, ''));
116
+ argv._ = argv._.map((path) => path.replace(quoteRegex, ''));
125
117
  return argv;
126
118
  }
127
-
128
119
  function logError(message, error) {
129
- if (!(0, _lodash.isString)(message)) {
130
- message = (0, _appError.getErrorMessage)(message);
120
+ if (!lodash_1.isString(message)) {
121
+ message = app_error_1.getErrorMessage(message);
131
122
  }
132
-
133
123
  if (error) {
134
- console.error(_chalk.default.red(message), error);
124
+ console.error(chalk_1.default.red(message), error);
135
125
  } else {
136
- console.error(_chalk.default.red(message));
126
+ console.error(chalk_1.default.red(message));
137
127
  }
138
128
  }
139
-
129
+ exports.logError = logError;
140
130
  function logWarn(message) {
141
- console.warn(_chalk.default.yellow(message));
131
+ console.warn(chalk_1.default.yellow(message));
142
132
  }
143
-
133
+ exports.logWarn = logWarn;
144
134
  function logInfo(message) {
145
- console.log(_chalk.default.green(message));
135
+ console.log(chalk_1.default.green(message));
146
136
  }
147
- /**
148
- * Create options object for `explore` method
149
- */
150
-
137
+ exports.logInfo = logInfo;
151
138
  function getExploreOptions(argv) {
152
139
  const {
153
140
  json,
@@ -158,83 +145,60 @@ function getExploreOptions(argv) {
158
145
  onlyMapped,
159
146
  excludeSourceMap: excludeSourceMapComment,
160
147
  noRoot,
148
+ noBorderChecks,
161
149
  coverage,
162
150
  gzip,
151
+ sort,
163
152
  } = argv;
164
153
  let replaceMap;
165
-
166
154
  if (replaceItems && withItems) {
167
155
  replaceMap = replaceItems.reduce((result, item, index) => {
168
156
  result[item] = withItems[index];
169
157
  return result;
170
158
  }, {});
171
159
  }
172
-
173
160
  return {
174
161
  output: {
175
- // By default CLI needs result in HTML in order to create a temporary file
176
- format: (0, _lodash.isString)(json) ? 'json' : (0, _lodash.isString)(tsv) ? 'tsv' : 'html',
162
+ format: lodash_1.isString(json) ? 'json' : lodash_1.isString(tsv) ? 'tsv' : 'html',
177
163
  filename: json || tsv || html,
178
164
  },
179
165
  replaceMap,
180
166
  onlyMapped,
181
167
  excludeSourceMapComment,
182
168
  noRoot,
169
+ noBorderChecks,
183
170
  coverage,
184
171
  gzip,
172
+ sort,
185
173
  };
186
174
  }
187
- /**
188
- * Write HTML content to a temporary file and open the file in a browser
189
- */
190
-
191
175
  async function writeHtmlToTempFile(html) {
192
176
  if (!html) {
193
177
  return;
194
178
  }
195
-
196
179
  try {
197
- const tempFile = _temp.default.path({
198
- prefix: 'sme-result-',
199
- suffix: '.html',
200
- });
201
-
202
- _fs.default.writeFileSync(tempFile, html);
203
-
204
- const childProcess = await (0, _open.default)(tempFile);
205
-
180
+ const tempFile = temp_1.default.path({ prefix: 'sme-result-', suffix: '.html' });
181
+ fs_1.default.writeFileSync(tempFile, html);
182
+ const childProcess = await open_1.default(tempFile);
206
183
  if (childProcess.stderr) {
207
- // Catch error output from child process
208
- childProcess.stderr.once('data', error => {
209
- logError({
210
- code: 'CannotOpenTempFile',
211
- tempFile,
212
- error,
213
- });
184
+ childProcess.stderr.once('data', (error) => {
185
+ logError({ code: 'CannotOpenTempFile', tempFile, error });
214
186
  });
215
187
  }
216
188
  } catch (error) {
217
- throw new _appError.AppError(
218
- {
219
- code: 'CannotCreateTempFile',
220
- },
221
- error
222
- );
189
+ throw new app_error_1.AppError({ code: 'CannotCreateTempFile' }, error);
223
190
  }
224
191
  }
225
-
226
192
  function outputErrors({ errors }) {
227
193
  if (errors.length === 0) {
228
194
  return;
229
- } // Group errors by bundle name
230
-
231
- const groupedErrors = (0, _lodash.groupBy)(errors, 'bundleName');
195
+ }
196
+ const groupedErrors = lodash_1.groupBy(errors, 'bundleName');
232
197
  Object.entries(groupedErrors).forEach(([bundleName, errors]) => {
233
198
  console.group(bundleName);
234
199
  const hasManyErrors = errors.length > 1;
235
200
  errors.forEach((error, index) => {
236
201
  const message = `${hasManyErrors ? `${index + 1}. ` : ''}${error.message}`;
237
-
238
202
  if (error.isWarning) {
239
203
  logWarn(message);
240
204
  } else {
@@ -244,16 +208,15 @@ function outputErrors({ errors }) {
244
208
  console.groupEnd();
245
209
  });
246
210
  }
247
-
248
211
  if (require.main === module) {
249
212
  const argv = parseArguments();
250
- const isOutputFormatSpecified = [argv.json, argv.tsv, argv.html].some(_lodash.isString);
213
+ const isOutputFormatSpecified = [argv.json, argv.tsv, argv.html].some(lodash_1.isString);
251
214
  const options = getExploreOptions(argv);
252
- (0, _api.explore)(argv._, options)
253
- .then(result => {
215
+ api_1
216
+ .explore(argv._, options)
217
+ .then((result) => {
254
218
  if (isOutputFormatSpecified && options.output) {
255
219
  const filename = options.output.filename;
256
-
257
220
  if (filename) {
258
221
  logInfo(`Output saved to ${filename}`);
259
222
  outputErrors(result);
@@ -266,11 +229,13 @@ if (require.main === module) {
266
229
  });
267
230
  }
268
231
  })
269
- .catch(error => {
232
+ .catch((error) => {
270
233
  if (error.errors) {
271
234
  outputErrors(error);
272
235
  } else {
273
236
  logError('Failed to explore', error);
274
237
  }
238
+ process.exitCode = 1;
275
239
  });
276
240
  }
241
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n\nimport yargs from 'yargs';\nimport fs from 'fs';\nimport temp from 'temp';\nimport open from 'open';\nimport chalk from 'chalk';\nimport { groupBy, isString } from 'lodash';\n\nimport { explore } from './api';\nimport { AppError, getErrorMessage } from './app-error';\n\nimport type { ErrorContext } from './app-error';\nimport type { ExploreOptions, ReplaceMap, ExploreResult } from './types';\n\n/** Parsed CLI arguments */\ninterface Arguments {\n _: string[];\n json?: string;\n tsv?: string;\n html?: string;\n onlyMapped?: boolean;\n excludeSourceMap?: boolean;\n noRoot?: boolean;\n replace?: string[];\n with?: string[];\n noBorderChecks?: boolean;\n coverage?: string;\n gzip?: boolean;\n sort?: boolean;\n}\n\nfunction parseArguments(): Arguments {\n const argv = yargs\n .strict()\n .scriptName('source-map-explorer')\n .usage('Analyze and debug space usage through source maps.')\n .usage('Usage:')\n .usage(\n '$0 script.js [script.js.map] [--json [result.json] | --html [result.html] | --tsv [result.csv]] [-m | --only-mapped] [--exclude-source-map] [--no-border-checks] [--gzip] [--sort] [--replace=BEFORE_1 BEFORE_2 --with=AFTER_1 AFTER_2] [--no-root] [--coverage coverage.json] [--version] [--help | -h]'\n )\n .example('$0 script.js script.js.map', 'Explore bundle')\n .example('$0 script.js', 'Explore bundle with inline source map')\n .example('$0 dist/js/*.*', 'Explore all bundles inside dist/js folder')\n .example('$0 script.js --tsv', 'Explore and output result as TSV to stdout')\n .example('$0 script.js --json result.json', 'Explore and save result as JSON to the file')\n .demandCommand(1, 'At least one js file must be specified')\n .options({\n json: {\n type: 'string',\n description:\n 'If filename specified save output as JSON to specified file otherwise output to stdout.',\n conflicts: ['tsv', 'html'],\n },\n tsv: {\n type: 'string',\n description:\n 'If filename specified save output as TSV to specified file otherwise output to stdout.',\n conflicts: ['json', 'html'],\n },\n html: {\n type: 'string',\n description:\n 'If filename specified save output as HTML to specified file otherwise output to stdout rather than opening a browser.',\n conflicts: ['json', 'tsv'],\n },\n\n 'only-mapped': {\n alias: 'm',\n type: 'boolean',\n description:\n 'Exclude \"unmapped\" bytes from the output. This will result in total counts less than the file size',\n },\n\n 'exclude-source-map': {\n type: 'boolean',\n description: 'Exclude source map comment size from output',\n },\n\n 'no-root': {\n type: 'boolean',\n description:\n 'To simplify the visualization, source-map-explorer will remove any prefix shared by all sources. If you wish to disable this behavior, set --no-root.',\n },\n\n replace: {\n type: 'string',\n array: true,\n description:\n 'Apply a simple find/replace on source file names. This can be used to fix some oddities with paths that appear in the source map generation process. Accepts regular expressions.',\n implies: 'with',\n },\n with: {\n type: 'string',\n array: true,\n description: 'See --replace.',\n implies: 'replace',\n },\n\n 'no-border-checks': {\n type: 'boolean',\n description: 'Disable invalid mapping column/line checks.',\n },\n\n coverage: {\n type: 'string',\n normalize: true,\n description:\n 'If the path to a valid a chrome code coverage JSON export is supplied, the tree map will be colorized according to which percentage of the modules code was executed',\n },\n\n gzip: {\n type: 'boolean',\n description: 'Calculate gzip size. It also sets onlyMapped flag',\n conflicts: ['only-mapped'],\n },\n\n sort: {\n type: 'boolean',\n description: 'Sort filenames',\n },\n })\n .group(['json', 'tsv', 'html'], 'Output:')\n .group(['replace', 'with'], 'Replace:')\n .help('h')\n .alias('h', 'help')\n .showHelpOnFail(false, 'Specify --help for available options')\n .wrap(null) // Do not limit line length\n .parserConfiguration({\n 'boolean-negation': false, // Allow --no-root\n })\n .check((argv) => {\n if (argv.replace && argv.with && argv.replace.length !== argv.with.length) {\n throw new Error('--replace flags must be paired with --with flags');\n }\n\n return true;\n })\n .parse();\n\n // Trim extra quotes\n const quoteRegex = /'/g;\n\n argv._ = argv._.map((path) => path.replace(quoteRegex, ''));\n\n return argv;\n}\n\nexport function logError(message: string | ErrorContext, error?: Error): void {\n if (!isString(message)) {\n message = getErrorMessage(message);\n }\n\n if (error) {\n console.error(chalk.red(message), error);\n } else {\n console.error(chalk.red(message));\n }\n}\n\nexport function logWarn(message: string): void {\n console.warn(chalk.yellow(message));\n}\n\nexport function logInfo(message: string): void {\n console.log(chalk.green(message));\n}\n\n/**\n * Create options object for `explore` method\n */\nfunction getExploreOptions(argv: Arguments): ExploreOptions {\n const {\n json,\n tsv,\n html,\n replace: replaceItems,\n with: withItems,\n onlyMapped,\n excludeSourceMap: excludeSourceMapComment,\n noRoot,\n noBorderChecks,\n coverage,\n gzip,\n sort,\n } = argv;\n\n let replaceMap: ReplaceMap | undefined;\n\n if (replaceItems && withItems) {\n replaceMap = replaceItems.reduce<ReplaceMap>((result, item, index) => {\n result[item] = withItems[index];\n\n return result;\n }, {});\n }\n\n return {\n output: {\n // By default CLI needs result in HTML in order to create a temporary file\n format: isString(json) ? 'json' : isString(tsv) ? 'tsv' : 'html',\n filename: json || tsv || html,\n },\n replaceMap,\n onlyMapped,\n excludeSourceMapComment,\n noRoot,\n noBorderChecks,\n coverage,\n gzip,\n sort,\n };\n}\n\n/**\n * Write HTML content to a temporary file and open the file in a browser\n */\nasync function writeHtmlToTempFile(html?: string): Promise<void> {\n if (!html) {\n return;\n }\n\n try {\n const tempFile = temp.path({ prefix: 'sme-result-', suffix: '.html' });\n\n fs.writeFileSync(tempFile, html);\n\n const childProcess = await open(tempFile);\n\n if (childProcess.stderr) {\n // Catch error output from child process\n childProcess.stderr.once('data', (error: Buffer) => {\n logError({ code: 'CannotOpenTempFile', tempFile, error });\n });\n }\n } catch (error) {\n throw new AppError({ code: 'CannotCreateTempFile' }, error);\n }\n}\n\nfunction outputErrors({ errors }: ExploreResult): void {\n if (errors.length === 0) {\n return;\n }\n\n // Group errors by bundle name\n const groupedErrors = groupBy(errors, 'bundleName');\n\n Object.entries(groupedErrors).forEach(([bundleName, errors]) => {\n console.group(bundleName);\n\n const hasManyErrors = errors.length > 1;\n\n errors.forEach((error, index) => {\n const message = `${hasManyErrors ? `${index + 1}. ` : ''}${error.message}`;\n\n if (error.isWarning) {\n logWarn(message);\n } else {\n logError(message);\n }\n });\n\n console.groupEnd();\n });\n}\n\nif (require.main === module) {\n const argv = parseArguments();\n\n const isOutputFormatSpecified = [argv.json, argv.tsv, argv.html].some(isString);\n\n const options = getExploreOptions(argv);\n\n explore(argv._, options)\n .then((result) => {\n if (isOutputFormatSpecified && options.output) {\n const filename = options.output.filename;\n\n if (filename) {\n logInfo(`Output saved to ${filename}`);\n outputErrors(result);\n } else {\n console.log(result.output);\n }\n } else {\n writeHtmlToTempFile(result.output).then(() => {\n outputErrors(result);\n });\n }\n })\n .catch((error) => {\n if (error.errors) {\n outputErrors(error);\n } else {\n logError('Failed to explore', error);\n }\n\n process.exitCode = 1;\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;
package/dist/coverage.js CHANGED
@@ -1,116 +1,70 @@
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
+ const url_1 = require('url');
4
+ const helpers_1 = require('./helpers');
5
+ const app_error_1 = require('./app-error');
17
6
  function convertRangesToLinesRanges(coverage) {
18
7
  const { ranges, text } = coverage;
19
- const eol = (0, _helpers.detectEOL)(text);
8
+ const eol = helpers_1.detectEOL(text);
20
9
  const eolLength = eol.length;
21
- const lines = text.split(eol); // Current line offset
22
-
10
+ const lines = text.split(eol);
23
11
  let offset = 0;
24
- const lineRanges = lines.map(line => {
12
+ const lineRanges = lines.map((line) => {
25
13
  const lineLength = line.length;
26
-
27
14
  if (lineLength === 0) {
28
15
  return [];
29
- } // Exclusive line start/end
30
-
16
+ }
31
17
  const lineStart = offset;
32
18
  const lineEnd = offset + lineLength;
33
19
  const lineRanges = ranges.reduce((result, { start, end }) => {
34
- // Inclusive range start/end within the line
35
20
  const startIndex = start - lineStart;
36
21
  const endIndex = end - lineStart - 1;
37
22
  const lineEndIndex = lineLength - 1;
38
-
39
23
  if (start <= lineStart && lineEnd <= end) {
40
- // Range includes line range
41
- result.push({
42
- start: 0,
43
- end: lineEndIndex,
44
- });
24
+ result.push({ start: 0, end: lineEndIndex });
45
25
  } else if (lineStart <= start && end <= lineEnd) {
46
- // Line range includes range
47
- result.push({
48
- start: startIndex,
49
- end: endIndex,
50
- });
26
+ result.push({ start: startIndex, end: endIndex });
51
27
  } else if (lineStart <= start && start <= lineEnd) {
52
- // Range starts within line range
53
- result.push({
54
- start: startIndex,
55
- end: lineEndIndex,
56
- });
28
+ result.push({ start: startIndex, end: lineEndIndex });
57
29
  } else if (lineStart <= end && end <= lineEnd) {
58
- // Range ends within line range
59
- result.push({
60
- start: 0,
61
- end: endIndex,
62
- });
30
+ result.push({ start: 0, end: endIndex });
63
31
  }
64
-
65
32
  return result;
66
- }, []); // Move to next line jumping over EOL character
67
-
33
+ }, []);
68
34
  offset = lineEnd + eolLength;
69
35
  return lineRanges;
70
36
  });
71
37
  return lineRanges;
72
38
  }
73
-
74
39
  const PATH_SEPARATOR_REGEX = /[/\\]/;
75
-
76
40
  function getPathParts(path) {
77
41
  return path.split(PATH_SEPARATOR_REGEX).filter(Boolean);
78
42
  }
79
- /**
80
- * Match coverages' ranges to bundles by comparing coverage URL and bundle filename
81
- */
82
-
83
43
  function addCoverageRanges(bundles, coverageFilename) {
84
44
  if (!coverageFilename) {
85
45
  return bundles;
86
46
  }
87
-
88
47
  try {
89
- const coverages = JSON.parse((0, _helpers.getFileContent)(coverageFilename));
48
+ const coverages = JSON.parse(helpers_1.getFileContent(coverageFilename));
90
49
  const bundlesPaths = bundles.reduce((result, { code }, index) => {
91
50
  if (!Buffer.isBuffer(code)) {
92
51
  result.push([getPathParts(code).reverse(), index]);
93
52
  }
94
-
95
53
  return result;
96
54
  }, []);
97
- coverages // pathname contains filename
98
- .map(({ url }) => getPathParts(new URL(url).pathname).reverse())
55
+ coverages
56
+ .map(({ url }) => getPathParts(new url_1.URL(url).pathname).reverse())
99
57
  .forEach((partsA, coverageIndex) => {
100
- // Exclude coverages for inlined code (URL doesn't contain a filename)
101
58
  if (!partsA.length) return;
102
- let matchingBundles = [...bundlesPaths]; // Start from filename and go up to path root
103
-
59
+ let matchingBundles = [...bundlesPaths];
104
60
  for (let i = 0; i < partsA.length; i++) {
105
61
  matchingBundles = matchingBundles.filter(
106
62
  ([partsB]) => i < partsB.length && partsB[i] === partsA[i]
107
- ); // Stop when exact (among bundles) match found or no matches found
108
-
63
+ );
109
64
  if (matchingBundles.length <= 1) {
110
65
  break;
111
66
  }
112
67
  }
113
-
114
68
  if (matchingBundles.length === 1) {
115
69
  const [[, bundleIndex]] = matchingBundles;
116
70
  bundles[bundleIndex].coverageRanges = convertRangesToLinesRanges(
@@ -119,38 +73,22 @@ function addCoverageRanges(bundles, coverageFilename) {
119
73
  }
120
74
  });
121
75
  } catch (error) {
122
- throw new _appError.AppError(
123
- {
124
- code: 'CannotOpenCoverageFile',
125
- },
126
- error
127
- );
76
+ throw new app_error_1.AppError({ code: 'CannotOpenCoverageFile' }, error);
128
77
  }
129
-
130
78
  if (bundles.every(({ coverageRanges }) => coverageRanges === undefined)) {
131
- throw new _appError.AppError({
132
- code: 'NoCoverageMatches',
133
- });
79
+ throw new app_error_1.AppError({ code: 'NoCoverageMatches' });
134
80
  }
135
-
136
81
  return bundles;
137
82
  }
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
-
83
+ exports.addCoverageRanges = addCoverageRanges;
143
84
  function findCoveredMappingRanges(mappingRanges, coveredRanges) {
144
85
  let i = 0;
145
86
  let j = 0;
146
87
  const result = [];
147
-
148
88
  while (i < mappingRanges.length && j < coveredRanges.length) {
149
89
  const mappingRange = mappingRanges[i];
150
90
  const coveredRange = coveredRanges[j];
151
-
152
91
  if (mappingRange.start <= coveredRange.end && coveredRange.start <= mappingRange.end) {
153
- // Overlaps, calculate amount, move to next coverage range
154
92
  const end = Math.min(coveredRange.end, mappingRange.end);
155
93
  const start = Math.max(mappingRange.start, coveredRange.start);
156
94
  result.push({
@@ -158,35 +96,24 @@ function findCoveredMappingRanges(mappingRanges, coveredRanges) {
158
96
  end,
159
97
  source: mappingRange.source,
160
98
  });
161
-
162
99
  if (
163
100
  mappingRanges[i + 1] !== undefined &&
164
101
  mappingRanges[i + 1].start <= coveredRange.end &&
165
102
  mappingRanges[i + 1].end >= coveredRange.start
166
103
  ) {
167
- // Next module also overlaps current coverage range, advance to next module instead of advancing coverage
168
104
  i++;
169
105
  } else {
170
- // Check next coverage range, it may also overlap this module range
171
106
  j++;
172
107
  }
173
108
  } else if (mappingRange.end < coveredRange.start) {
174
- // Module comes entirely before coverageRange, check next module range
175
109
  i++;
176
110
  }
177
-
178
111
  if (coveredRange.end < mappingRange.start) {
179
- // Module range comes entirely after coverage range, check next coverage range
180
112
  j++;
181
113
  }
182
114
  }
183
-
184
115
  return result;
185
116
  }
186
- /**
187
- * Set covered size for files
188
- */
189
-
190
117
  function setCoveredSizes(line, files, mappingRanges, coveredRanges) {
191
118
  findCoveredMappingRanges(mappingRanges, coveredRanges).forEach(({ start, end, source }) => {
192
119
  const rangeByteLength = Buffer.byteLength(line.substring(start, end + 1));
@@ -196,46 +123,19 @@ function setCoveredSizes(line, files, mappingRanges, coveredRanges) {
196
123
  });
197
124
  return files;
198
125
  }
199
-
126
+ exports.setCoveredSizes = setCoveredSizes;
200
127
  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
- },
128
+ { percent: 0.0, color: { r: 0xff, g: 0x00, b: 0 } },
129
+ { percent: 0.5, color: { r: 0xff, g: 0xff, b: 0 } },
130
+ { percent: 1.0, color: { r: 0x00, g: 0xff, b: 0 } },
225
131
  ];
226
- /**
227
- * Get heat map color by coverage percent
228
- */
229
-
230
132
  function getColorByPercent(percent) {
231
133
  let i = 1;
232
-
233
134
  for (; i < percentColors.length - 1; i++) {
234
135
  if (percent < percentColors[i].percent) {
235
136
  break;
236
137
  }
237
138
  }
238
-
239
139
  const lowerColor = percentColors[i - 1];
240
140
  const upperColor = percentColors[i];
241
141
  const rangeWithinColors = upperColor.percent - lowerColor.percent;
@@ -247,3 +147,5 @@ function getColorByPercent(percent) {
247
147
  const b = Math.floor(lowerColor.color.b * percentLower + upperColor.color.b * percentUpper);
248
148
  return `rgb(${r}, ${g}, ${b})`;
249
149
  }
150
+ exports.getColorByPercent = getColorByPercent;
151
+ //# sourceMappingURL=coverage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverage.js","sourceRoot":"","sources":["../src/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"]}
package/dist/explore.d.ts CHANGED
@@ -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;