monocart-coverage-reports 2.3.4 → 2.4.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,3 +1,5 @@
1
+ const Util = require('../utils/util.js');
2
+ const EC = Util.EC;
1
3
 
2
4
  const findMapping = (list, offset) => {
3
5
  let start = 0;
@@ -16,166 +18,73 @@ const findMapping = (list, offset) => {
16
18
  return list[i];
17
19
  }
18
20
  // last two items, less is start
19
- const endItem = list[end];
20
- if (offset < endItem.generatedOffset) {
21
- return list[start];
22
- }
23
- return list[end];
24
-
25
- };
26
-
27
- const findOffsetMapping = (state, offset) => {
28
-
29
- const decodedMappings = state.decodedMappings;
30
-
31
- // possible no length
32
- if (!decodedMappings.length) {
33
- return {
34
- error: true,
35
- errors: [`not found decoded mappings for offset: ${offset}`]
36
- };
37
- }
38
-
39
- const mapping = findMapping(decodedMappings, offset);
40
-
41
- const generatedOffset = mapping.generatedOffset;
42
-
43
- // not found, allow > last, not allow < first
44
- if (offset < generatedOffset) {
45
- return {
46
- error: true,
47
- errors: [`not found generated offset: ${offset}`]
48
- };
49
- }
50
-
51
- // exact matched no need fix
52
- const exact = generatedOffset === offset;
53
-
54
- return {
55
- ... mapping,
56
- // could be fixed if not exact matched
57
- column: mapping.originalColumn,
58
- exact
59
- };
60
- };
61
-
62
- const findNextOriginalDiffMapping = (originalState, mapping) => {
63
- const decodedMappings = originalState.decodedMappings;
64
- const { originalIndex, originalOffset } = mapping;
65
-
66
- let i = originalIndex + 1;
67
- const l = decodedMappings.length;
68
- while (i < l) {
69
- const item = decodedMappings[i];
70
- // sometimes next is same line/column
71
- if (item.originalOffset > originalOffset) {
72
- return item;
73
- }
74
- i += 1;
75
- }
76
- };
77
-
78
- const findNextGeneratedDiffMapping = (state, mapping) => {
79
- const decodedMappings = state.decodedMappings;
80
- const i = mapping.generatedIndex + 1;
81
- const l = decodedMappings.length;
82
- if (i < l) {
83
- return decodedMappings[i];
84
- }
85
- };
86
-
87
- const getGeneratedText = (mapping, state) => {
88
-
89
- const generatedText = mapping.generatedText;
90
- if (typeof generatedText === 'string') {
91
- return generatedText;
92
- }
93
-
94
- let text = '';
95
-
96
- const locator = state.locator;
97
- const nextMapping = findNextGeneratedDiffMapping(state, mapping);
98
- if (nextMapping) {
99
- text = locator.getSlice(mapping.generatedOffset, nextMapping.generatedOffset);
100
- } else {
101
- // to the end
102
- text = locator.getSlice(mapping.generatedOffset);
21
+ const startItem = list[start];
22
+ if (offset === startItem.generatedOffset) {
23
+ return startItem;
103
24
  }
104
-
105
- // never cross line
106
- if (mapping.generatedEndOffset) {
107
- const len = mapping.generatedEndOffset - mapping.generatedOffset;
108
- text = text.slice(0, len);
109
- }
110
-
111
- // keep cache
112
- mapping.generatedText = text;
113
-
114
- return text;
115
-
116
- };
117
-
118
- const getOriginalText = (mapping, originalState) => {
119
-
120
- const originalText = mapping.originalText;
121
- if (typeof originalText === 'string') {
122
- return originalText;
123
- }
124
-
125
- let text = '';
126
-
127
- const { locator } = originalState;
128
- const nextMapping = findNextOriginalDiffMapping(originalState, mapping);
129
- if (nextMapping) {
130
- text = locator.getSlice(mapping.originalOffset, nextMapping.originalOffset);
131
- } else {
132
- // to the end
133
- text = locator.getSlice(mapping.originalOffset);
25
+ const endItem = list[end];
26
+ if (offset === endItem.generatedOffset) {
27
+ return endItem;
134
28
  }
135
29
 
136
- // the last two items could have same line and column
137
- // so can NOT pre-calculate original end offset, just search new line with regex
138
-
139
- // never cross line
140
- const newLineIndex = text.search(/\r?\n/);
141
- if (newLineIndex !== -1) {
142
- text = text.slice(0, newLineIndex);
30
+ // between two mappings
31
+ if (offset > startItem.generatedOffset && offset < endItem.generatedOffset) {
32
+ return [startItem, endItem];
143
33
  }
144
34
 
145
- // keep cache
146
- mapping.originalText = text;
35
+ // not found the mappings
147
36
 
148
- return text;
149
37
  };
150
38
 
151
39
  // ========================================================================================================
152
40
 
153
- const getBlockStartPosition = (originalText) => {
154
- // start block characters
155
-
41
+ const getBlockStartPosition = (originalLineText) => {
156
42
  // originalText: 'argument) {',
157
43
  // generatedLeft: 'o',
158
44
  // generatedRight: '&&'
159
45
 
160
46
  // function/block could be started with {(
161
- const startBlockIndex = originalText.search(/[<{(]/);
47
+ const startBlockIndex = originalLineText.search(/[<{(]/);
162
48
  if (startBlockIndex !== -1) {
163
- return startBlockIndex;
49
+ return {
50
+ pos: startBlockIndex
51
+ };
164
52
  }
165
53
 
166
54
  // end a block
167
55
  const list = ['>', '}', ')'];
168
56
  for (const s of list) {
169
- const endBlockIndex = originalText.lastIndexOf(s);
57
+ const endBlockIndex = originalLineText.lastIndexOf(s);
170
58
  if (endBlockIndex !== -1) {
171
- return endBlockIndex + 1;
59
+ return {
60
+ pos: endBlockIndex + 1
61
+ };
172
62
  }
173
63
  }
174
64
 
175
- return -1;
65
+ // ============================
66
+ // end characters
67
+
68
+ // ends with ">" in vue
69
+ // <span v-if="data.distFile">
70
+
71
+ // originalText: '">',
72
+ // generatedText: ' ? ((0,vue__.openBlock)(), '
73
+
74
+ // originalMethod?.apply
75
+ // originalText: '?.' no ?
76
+
77
+ const indexEndBlock = originalLineText.search(/(?<=[;,:"'\s])/);
78
+ if (indexEndBlock !== -1) {
79
+ return {
80
+ pos: indexEndBlock
81
+ };
82
+ }
83
+
176
84
  };
177
85
 
178
- const getBlockEndPosition = (originalText) => {
86
+ const getBlockEndPosition = (originalLineText) => {
87
+
179
88
  // generatedText: 'e),',
180
89
  // generatedPos: 2,
181
90
  // originalText: 'prop))'
@@ -190,28 +99,61 @@ const getBlockEndPosition = (originalText) => {
190
99
 
191
100
  const list = ['>', '}', ')'];
192
101
  for (const s of list) {
193
- const endBlockIndex = originalText.lastIndexOf(s);
102
+ const endBlockIndex = originalLineText.lastIndexOf(s);
194
103
  if (endBlockIndex !== -1) {
195
- return endBlockIndex + 1;
104
+ return {
105
+ pos: endBlockIndex + 1
106
+ };
196
107
  }
197
108
  }
198
109
 
199
- const startBlockIndex = originalText.search(/[<{(]/);
110
+ const startBlockIndex = originalLineText.search(/[<{(]/);
200
111
  if (startBlockIndex !== -1) {
201
- return startBlockIndex;
112
+ return {
113
+ pos: startBlockIndex
114
+ };
202
115
  }
203
116
 
204
- return -1;
205
117
  };
206
118
 
207
- const getOriginalStartPosition = (originalText, generatedText, generatedPos) => {
119
+ const getComparedPosition = (gt, gp, ot, direction) => {
208
120
 
209
- if (!originalText.length) {
210
- return 0;
121
+ // before trim
122
+ const oLen = ot.length;
123
+
124
+ gt = gt.trimEnd();
125
+ ot = ot.trimEnd();
126
+
127
+ // no content after trim
128
+ if (!ot.length) {
129
+ return {
130
+ pos: direction === 'start' ? oLen : 0
131
+ };
132
+ }
133
+
134
+ // same content
135
+ if (gt === ot) {
136
+ return {
137
+ pos: gp
138
+ };
211
139
  }
212
140
 
213
- if (originalText === generatedText) {
214
- return generatedPos;
141
+ // =============================
142
+
143
+ // generatedText: '"false";\n',
144
+ // originalText: "'false';\r\n ",
145
+ // generatedPos: 7
146
+
147
+ // length not change, replace " to '
148
+ gt = gt.replace(/"/g, "'");
149
+ ot = ot.replace(/"/g, "'");
150
+
151
+
152
+ // same content too
153
+ if (gt === ot) {
154
+ return {
155
+ pos: gp
156
+ };
215
157
  }
216
158
 
217
159
  // ============================
@@ -221,407 +163,525 @@ const getOriginalStartPosition = (originalText, generatedText, generatedPos) =>
221
163
  // generatedText: '1;else',
222
164
  // generatedLeft: '1;'
223
165
 
224
- const generatedLeft = generatedText.slice(0, generatedPos);
225
- if (originalText.startsWith(generatedLeft)) {
226
- return generatedLeft.length;
166
+ // generatedText: ' var id = options.base ? item[0] + options.base : item[0];\r\n',
167
+ // originalText: ' var id = options.base ? item[0] + options.base : item[0];\n',
168
+
169
+ const left = gt.slice(0, gp);
170
+ if (ot.startsWith(left)) {
171
+ return {
172
+ pos: gp
173
+ };
227
174
  }
228
175
 
229
176
  // ============================
230
177
  // right matched
231
178
 
232
- // originalText: "'true' : ",
233
- // generatedText: '"true" : '
234
-
235
- const generatedRight = generatedText.slice(generatedPos);
236
- if (originalText.endsWith(generatedRight)) {
237
- return originalText.length - generatedRight.length;
179
+ const right = gt.slice(gp);
180
+ if (ot.endsWith(right)) {
181
+ return {
182
+ pos: ot.length - right.length
183
+ };
238
184
  }
239
185
 
240
- // ============================
241
- // starts with original text (few case possible useless)
242
-
243
- // generatedText "(void 0, void 0, void 0, function* () {"
244
- // originalText " {"
245
-
246
- // generatedLen: 1629,
247
- // generatedText: '__exports__);\r\n\r\n/***/ }),\r\n\r\n/***/ "./packages/v8',
248
- // generatedPos: 489,
249
- // originalText: '__exports__',
250
-
251
- // original less, generated more
252
- // const includeIndex = generatedText.indexOf(originalText);
253
- // if (includeIndex !== -1) {
254
-
255
- // console.log('=================== includeIndex', includeIndex, generatedPos);
256
- // console.log(JSON.stringify(generatedText.slice(0, originalText.length + includeIndex + 10)));
257
- // console.log(JSON.stringify(originalText));
186
+ };
258
187
 
259
- // if (includeIndex >= generatedPos) {
260
- // return 0;
261
- // }
188
+ const getSimilarPosition = (info, direction) => {
262
189
 
263
- // return originalText.length;
264
- // }
190
+ const {
191
+ generatedText, generatedPos, originalText
192
+ } = info;
265
193
 
266
- // ============================
267
- // {} () <>
268
- const blockIndex = getBlockStartPosition(originalText);
269
- if (blockIndex !== -1) {
270
- return blockIndex;
194
+ const textPos = getComparedPosition(generatedText, generatedPos, originalText, direction);
195
+ if (textPos) {
196
+ return textPos;
271
197
  }
272
198
 
273
- // ============================
274
- // end characters
275
-
276
- // ends with ">" in vue
277
- // <span v-if="data.distFile">
199
+ // never cross line, using first line of original text
200
+ // trim end remove \r\n and \n
201
+ const originalLines = originalText.split(/\n/);
202
+ if (originalLines.length === 1) {
203
+ // already single line
204
+ info.originalLineText = originalText;
205
+ return;
206
+ }
278
207
 
279
- // originalText: '">',
280
- // generatedText: ' ? ((0,vue__.openBlock)(), '
208
+ const originalLineText = originalLines[0].trimEnd();
209
+ info.originalLineText = originalLineText;
281
210
 
282
- // originalMethod?.apply
283
- // originalText: '?.' no ?
211
+ // generatedPos not in first line
212
+ if (generatedPos > originalLineText.length) {
213
+ return;
214
+ }
284
215
 
285
- const indexEndBlock = originalText.search(/(?<=[;,:"'\s])/);
286
- if (indexEndBlock !== -1) {
287
- return indexEndBlock;
216
+ const linePos = getComparedPosition(generatedText, generatedPos, originalLineText, direction);
217
+ if (linePos) {
218
+ return linePos;
288
219
  }
289
220
 
290
221
  // console.log('====================================================================');
291
- // console.log('start position can NOT be fixed');
222
+ // console.log(`${EC.magenta(direction)} similar position can NOT be fixed`);
292
223
  // console.log({
224
+ // sourcePath: info.originalState.sourcePath,
293
225
  // generatedText,
294
226
  // generatedPos,
295
227
  // originalText
296
- // // originalPos
297
228
  // });
298
229
 
299
- // ============================
300
- // can NOT be fixed
301
- // using original column
302
- return 0;
303
230
  };
304
231
 
305
- const getOriginalEndPosition = (originalText, generatedText, generatedPos) => {
232
+ const getFixedPosition = (info, direction) => {
306
233
 
307
- if (!originalText.length) {
308
- return 0;
234
+ const similarPos = getSimilarPosition(info, direction);
235
+ if (similarPos) {
236
+ return similarPos.pos;
309
237
  }
310
238
 
311
- if (originalText === generatedText) {
312
- return generatedPos;
239
+ // generatedText: never cross lines
240
+ // originalText: could be multiple lines
241
+ // originalLineText: single line originalText
242
+ const { originalLineText } = info;
243
+
244
+ if (direction === 'start') {
245
+ const blockPos = getBlockStartPosition(originalLineText);
246
+ if (blockPos) {
247
+ return blockPos.pos;
248
+ }
249
+ return 0;
313
250
  }
314
251
 
315
- // ============================
316
- // {} () <>
317
- const blockIndex = getBlockEndPosition(originalText);
318
- if (blockIndex !== -1) {
319
- return blockIndex;
252
+ const blockPos = getBlockEndPosition(originalLineText);
253
+ if (blockPos) {
254
+ return blockPos.pos;
320
255
  }
256
+ return originalLineText.length;
257
+ };
321
258
 
322
- // console.log('====================================================================');
323
- // console.log('end position can NOT be fixed');
324
- // console.log({
325
- // generatedText,
326
- // generatedPos,
327
- // originalText
328
- // // originalPos
329
- // });
259
+ // ========================================================================================================
330
260
 
331
- // ============================
332
- // can NOT be fixed
333
- // to the line end
334
- return originalText.length;
261
+ const getOriginalEndOffset = (m, rangeInfo) => {
262
+ if (!m.originalEndOffset) {
263
+ const line = rangeInfo.originalState.locator.getLine(m.originalLine + 1);
264
+ m.originalEndOffset = line ? line.end : m.originalOffset;
265
+ }
266
+ return m.originalEndOffset;
335
267
  };
336
268
 
337
- // ========================================================================================================
269
+ const getOriginalText = (m1, m2, rangeInfo) => {
270
+ const originalLocator = rangeInfo.originalState.locator;
338
271
 
339
- const fixStartColumn = (startMapping, range, state, originalState) => {
340
- // exact matched no need fix
341
- if (startMapping.exact) {
342
- // originalColumn is the column
343
- return;
272
+ const o1 = m1.originalOffset;
273
+ const o2 = m2.originalOffset;
274
+
275
+ // most of time o1 < o2
276
+ if (o1 < o2) {
277
+ // could be multiple lines for original text
278
+ return {
279
+ originalOffset: o1,
280
+ originalText: originalLocator.getSlice(o1, o2)
281
+ };
344
282
  }
345
283
 
346
- // fix column
347
- const originalColumn = startMapping.originalColumn;
284
+ // esbuild fixing two mapping have same original
285
+ // m1 to end line
286
+ if (o1 === o2) {
287
+ const originalEndOffset = getOriginalEndOffset(m1, rangeInfo);
288
+ return {
289
+ originalOffset: o1,
290
+ originalText: originalLocator.getSlice(o1, originalEndOffset)
291
+ };
292
+ }
348
293
 
349
- const originalText = getOriginalText(startMapping, originalState);
350
- const generatedText = getGeneratedText(startMapping, state);
294
+ // o1 > o2
295
+ return {
296
+ originalOffset: o2,
297
+ originalText: originalLocator.getSlice(o2, o1)
298
+ };
351
299
 
352
- // actual generatedOffset < startOffset
353
- const generatedPos = range.startOffset - startMapping.generatedOffset;
300
+ };
354
301
 
355
- const originalPos = getOriginalStartPosition(originalText, generatedText, generatedPos);
302
+ const getGeneratedText = (m1, m2, state, offset) => {
303
+ const generatedLocator = state.locator;
356
304
 
357
- // if (originalState.sourcePath.endsWith('conditional.js') && range.startOffset === 2153) {
358
- // console.log('====================================================================');
359
- // console.log('fix startMapping', originalState.sourcePath);
360
- // console.log(startMapping);
361
- // console.log({
362
- // generatedPos,
363
- // originalPos
364
- // });
365
- // }
305
+ const o1 = m1.generatedOffset;
306
+ const o2 = m2.generatedOffset;
366
307
 
367
- // failed if originalPos = 0
368
- startMapping.column = originalColumn + originalPos;
308
+ // same line
309
+ if (m1.generatedLine === m2.generatedLine) {
310
+ return {
311
+ generatedText: generatedLocator.getSlice(o1, o2),
312
+ generatedPos: offset - o1
313
+ };
314
+ }
369
315
 
370
- };
316
+ // =======================================
317
+ // different lines
318
+ // never cross lines
371
319
 
372
- // ========================================================================================================
320
+ // 1-base
321
+ const lineInfo = generatedLocator.offsetToLocation(offset);
322
+ // 0-base
323
+ const targetLine = lineInfo.line - 1;
373
324
 
374
- const fixEndColumn = (endMapping, range, startMapping, state, originalState) => {
325
+ // m1 p (case 1, right to end)
326
+ // p (case 2, mid line)
327
+ // p (case 3) m2
375
328
 
376
- const originalColumn = endMapping.originalColumn;
329
+ // case 1
330
+ if (targetLine === m1.generatedLine) {
331
+ return {
332
+ generatedText: generatedLocator.getSlice(o1, lineInfo.end),
333
+ generatedPos: offset - o1
334
+ };
335
+ }
377
336
 
378
- // exact matched, but already -1 so need +1
379
- if (endMapping.exact) {
380
- endMapping.column = originalColumn + 1;
337
+ // case 3
338
+ if (targetLine === m2.generatedLine) {
339
+ return {
340
+ generatedText: generatedLocator.getSlice(lineInfo.start, o2),
341
+ generatedPos: offset - lineInfo.start
342
+ };
343
+ }
344
+
345
+ // case 2
346
+ return {
347
+ generatedText: lineInfo.text,
348
+ generatedPos: offset - lineInfo.start
349
+ };
350
+
351
+ };
352
+
353
+ const checkOriginalMappings = (m1, m2, direction) => {
354
+ // check original offset order
355
+ if (m1.originalOffset <= m2.originalOffset) {
381
356
  return;
382
357
  }
383
358
 
384
- // ================================
385
- // diff line, to the line end
386
- // if (endMapping.originalLine !== startMapping.originalLine) {
387
- // endMapping.column = Infinity;
388
- // return;
359
+ // just reverse offsets if few cross lines
360
+ const crossLines = m1.originalLine - m2.originalLine;
361
+ if (crossLines < 2) {
362
+ return;
363
+ }
389
364
 
390
- // console.log(originalState.sourcePath, '-------------------------------diff line---------------------------------------');
391
- // console.log(range, startMapping, endMapping);
365
+ // console.log('================================================');
366
+ // console.log(crossLines);
367
+ // console.log(m1, m2);
392
368
 
393
- // }
369
+ // should be mistake
370
+ return {
371
+ error: true,
372
+ errors: [`invalid original ${direction}: ${EC.yellow(m1.originalOffset)} > ${EC.yellow(m2.originalOffset)}`]
373
+ };
374
+ };
394
375
 
395
- // ================================
396
- // in the same line
376
+ // ========================================================================================================
397
377
 
398
- const originalText = getOriginalText(endMapping, originalState);
378
+ const getFixedOriginalStart = (start, mappings, state, rangeInfo) => {
379
+ const { originalState, crossStart } = rangeInfo;
380
+ const [m1, m2] = mappings;
399
381
 
400
- // if (originalState.sourcePath.indexOf('comments.js') !== -1) {
401
- // if (range.endOffset === 1077) {
402
- // console.log('----------------------------------------------------------------------');
403
- // console.log(originalText);
404
- // console.log(range, startMapping, endMapping);
405
- // }
406
- // }
382
+ // cross file from start of line
383
+ if (crossStart) {
384
+ return {
385
+ originalStart: m2.originalOffset
386
+ };
387
+ }
407
388
 
408
- // exclusive, need exclude some end strings
409
- if (!endMapping.exclusive) {
410
- endMapping.column = originalColumn + originalText.length;
411
- return;
389
+ const direction = 'start';
390
+ const errorInfo = checkOriginalMappings(m1, m2, direction);
391
+ if (errorInfo) {
392
+ return errorInfo;
412
393
  }
413
394
 
395
+ const { originalText, originalOffset } = getOriginalText(m1, m2, rangeInfo);
396
+ const { generatedText, generatedPos } = getGeneratedText(m1, m2, state, start);
414
397
 
415
- const generatedText = getGeneratedText(endMapping, state);
398
+ const originalPos = getFixedPosition({
399
+ generatedText,
400
+ generatedPos,
401
+ originalText,
402
+ originalState
403
+ }, direction);
416
404
 
417
- // actual generatedOffset < endOffset
418
- const generatedPos = range.endOffset - endMapping.generatedOffset;
405
+ return {
406
+ originalStart: originalOffset + originalPos
407
+ };
408
+ };
419
409
 
420
- const originalPos = getOriginalEndPosition(originalText, generatedText, generatedPos);
410
+ const getFixedOriginalEnd = (end, mappings, state, rangeInfo) => {
421
411
 
422
- // if (originalState.sourcePath.endsWith('v8/src/app.vue')) {
423
- // console.log('====================================================================');
424
- // console.log('fix endMapping', originalState.sourcePath);
425
- // console.log(startMapping, endMapping);
426
- // const generatedLen = generatedText.length;
427
- // const gt = generatedLen > 50 ? generatedText.slice(0, 50) : generatedText;
428
- // console.log({
429
- // generatedLen,
430
- // generatedText: gt,
431
- // generatedPos,
432
- // originalText,
433
- // originalPos
434
- // });
435
- // }
412
+ const { decodedMappings } = state;
413
+
414
+ // end is exclusive, try previous one if exact match
415
+ const prevMapping = findMapping(decodedMappings, end - 1);
416
+ if (prevMapping && !Array.isArray(prevMapping)) {
417
+ return {
418
+ originalEnd: prevMapping.originalOffset + 1
419
+ };
420
+ }
436
421
 
437
- // failed if originalPos = 0
438
- endMapping.column = originalColumn + originalPos;
422
+ const { originalState, crossEnd } = rangeInfo;
423
+ const [m1, m2] = mappings;
439
424
 
425
+ // cross file until e1 line end (not file end)
426
+ if (crossEnd) {
427
+ const originalEndOffset = getOriginalEndOffset(m1, rangeInfo);
428
+ return {
429
+ originalEnd: originalEndOffset
430
+ };
431
+ }
432
+
433
+ const direction = 'end';
434
+ const errorInfo = checkOriginalMappings(m1, m2, direction);
435
+ if (errorInfo) {
436
+ return errorInfo;
437
+ }
438
+
439
+ const { originalText, originalOffset } = getOriginalText(m1, m2, rangeInfo);
440
+ const { generatedText, generatedPos } = getGeneratedText(m1, m2, state, end);
441
+
442
+ const originalPos = getFixedPosition({
443
+ generatedText,
444
+ generatedPos,
445
+ originalText,
446
+ originalState
447
+ }, direction);
448
+
449
+ return {
450
+ originalEnd: originalOffset + originalPos
451
+ };
440
452
  };
441
453
 
442
454
  // ========================================================================================================
443
455
 
444
- const isOffsetCrossLine = (startMapping, offset) => {
445
- const { exact, generatedEndOffset } = startMapping;
446
- if (!exact && generatedEndOffset) {
447
- if (offset >= generatedEndOffset) {
448
- return true;
449
- }
456
+ const getOriginalStart = (start, startMapping, state, rangeInfo) => {
457
+ if (Array.isArray(startMapping)) {
458
+ return getFixedOriginalStart(start, startMapping, state, rangeInfo);
459
+ }
460
+ // Exact match
461
+ return {
462
+ originalStart: startMapping.originalOffset
463
+ };
464
+ };
465
+
466
+ const getOriginalEnd = (end, endMapping, state, rangeInfo) => {
467
+ if (Array.isArray(endMapping)) {
468
+ return getFixedOriginalEnd(end, endMapping, state, rangeInfo);
450
469
  }
451
- return false;
470
+ // Exact match
471
+ return {
472
+ originalEnd: endMapping.originalOffset
473
+ };
452
474
  };
453
475
 
454
- const findStartMapping = (range, state, originalMap) => {
476
+ // ========================================================================================================
455
477
 
456
- // startOffset: inclusive
457
- const startOffset = range.startOffset;
478
+ const checkSourceFileIndexes = (startIndexes, endIndexes) => {
458
479
 
459
- const startMapping = findOffsetMapping(state, startOffset);
460
- if (startMapping.error) {
480
+ const checkIndex11 = (s1, e1) => {
481
+ if (s1 === e1) {
482
+ return {
483
+ sourceIndex: s1
484
+ };
485
+ }
461
486
  return {
462
- error: true,
463
- errors: startMapping.errors.concat(`not found start mapping: ${startOffset}`)
487
+ error: true
464
488
  };
465
- }
489
+ };
466
490
 
467
- // check end offset for start mapping only
468
- // start mapping is inclusive, do not allow cross line
469
- // but end mapping is exclusive and offset do -1, possible no mapping found, do not check it
470
- if (isOffsetCrossLine(startMapping, startOffset)) {
471
- // try next mapping if its offset in the range
472
- const nextMapping = findNextGeneratedDiffMapping(state, startMapping);
473
- if (!nextMapping) {
491
+ const checkIndex21 = (s1, s2, e1) => {
492
+ if (s1 === e1 || s2 === e1) {
493
+ if (s1 === s2) {
494
+ return {
495
+ sourceIndex: e1
496
+ };
497
+ }
474
498
  return {
475
- error: true,
476
- errors: [`not found next generated mapping: ${startMapping}`]
499
+ crossStart: true,
500
+ sourceIndex: e1
477
501
  };
478
502
  }
503
+ return {
504
+ error: true
505
+ };
506
+ };
507
+
508
+ const checkIndex12 = (s1, e1, e2) => {
509
+ if (s1 === e1 || s1 === e2) {
510
+ if (e1 === e2) {
511
+ return {
512
+ sourceIndex: s1
513
+ };
514
+ }
515
+ return {
516
+ crossEnd: true,
517
+ sourceIndex: s1
518
+ };
519
+ }
520
+ return {
521
+ error: true
522
+ };
523
+ };
479
524
 
480
- // ignore out of range
481
- if (nextMapping.generatedOffset >= range.endOffset) {
525
+ const checkIndex22 = (s1, s2, e1, e2) => {
526
+ // 4 same
527
+ if (s1 === s2 && e1 === e2 && s1 === e1) {
482
528
  return {
483
- error: true,
484
- errors: [`next generated mapping is out of end offset: ${nextMapping.generatedOffset} >= ${range.endOffset}`]
529
+ sourceIndex: s1
485
530
  };
486
531
  }
487
532
 
488
- // exact and column
489
- Object.assign(startMapping, nextMapping, {
490
- exact: true,
491
- column: nextMapping.originalColumn
492
- });
533
+ if (e1 === e2) {
534
+ return checkIndex21(s1, s2, e1);
535
+ }
493
536
 
494
- }
537
+ if (s1 === s2) {
538
+ return checkIndex12(s1, e1, e2);
539
+ }
495
540
 
541
+ if (s2 === e1) {
542
+ return {
543
+ crossStart: true,
544
+ crossEnd: true,
545
+ sourceIndex: s2
546
+ };
547
+ }
496
548
 
497
- // check source first, sourceIndex could be undefined
498
- const sourceIndex = startMapping.sourceIndex;
549
+ // both between two mappings: 38,39 ~ 38,39
550
+ // if (s1 === e1 && s2 === e2) {
551
+ // }
499
552
 
500
- const originalState = originalMap.get(sourceIndex);
501
- if (!originalState) {
502
553
  return {
503
- error: true,
504
- errors: [`not found original state by source index: ${sourceIndex}`]
554
+ error: true
505
555
  };
556
+ };
557
+
558
+ // both exact matched
559
+ if (startIndexes.length === 1 && endIndexes.length === 1) {
560
+ return checkIndex11(startIndexes[0], endIndexes[0]);
506
561
  }
507
562
 
508
- return {
509
- startMapping,
510
- originalState
511
- };
512
- };
563
+ if (startIndexes.length === 2 && endIndexes.length === 1) {
564
+ return checkIndex21(startIndexes[0], startIndexes[1], endIndexes[0]);
565
+ }
513
566
 
567
+ if (startIndexes.length === 1 && endIndexes.length === 2) {
568
+ return checkIndex12(startIndexes[0], endIndexes[0], endIndexes[1]);
569
+ }
514
570
 
515
- const findEndMapping = (range, state, startMapping) => {
571
+ // both 2 mappings
572
+ return checkIndex22(startIndexes[0], startIndexes[1], endIndexes[0], endIndexes[1]);
516
573
 
517
- // endOffset: exclusive
518
- const endOffset = range.endOffset;
574
+ };
519
575
 
520
- // there could be some comments before end mapping even exact matched
521
- const endMapping = findOffsetMapping(state, endOffset - 1);
522
- if (endMapping.error) {
576
+ const getOriginalState = (startMappings, endMappings, originalMap) => {
577
+
578
+ // check source file indexes
579
+ const startIndexes = [].concat(startMappings).map((it) => it.sourceIndex);
580
+ const endIndexes = [].concat(endMappings).map((it) => it.sourceIndex);
581
+ const rangeInfo = checkSourceFileIndexes(startIndexes, endIndexes);
582
+ if (rangeInfo.error) {
523
583
  return {
524
584
  error: true,
525
- errors: startMapping.errors.concat(`not found end mapping: ${endOffset} - 1 (exclusive)`)
585
+ errors: [`invalid source indexes: ${EC.yellow(`${startIndexes} ~ ${endIndexes}`)}`]
526
586
  };
527
587
  }
528
588
 
529
- // cross file ignore
530
- if (endMapping.sourceIndex !== startMapping.sourceIndex) {
589
+ const {
590
+ sourceIndex, crossStart, crossEnd
591
+ } = rangeInfo;
592
+
593
+ // if (crossStart || crossEnd) {
594
+ // console.log(EC.magenta('cross file'), EC.yellow(`${startIndexes} ~ ${endIndexes}`));
595
+ // }
596
+
597
+ const originalState = originalMap.get(sourceIndex);
598
+ if (!originalState) {
531
599
  return {
532
600
  error: true,
533
- errors: [`The source index of start and end are not equal: ${startMapping.sourceIndex} != ${endMapping.sourceIndex}`]
601
+ errors: [`not found original file: ${EC.yellow(sourceIndex)}`]
534
602
  };
535
603
  }
536
604
 
537
- // still exclusive
538
- const exclusiveMapping = findOffsetMapping(state, endOffset);
539
- if (exclusiveMapping && exclusiveMapping.originalOffset === endMapping.originalOffset) {
540
- endMapping.exclusive = true;
541
- }
605
+ return {
606
+ // for debug
607
+ // startIndexes,
608
+ // endIndexes,
542
609
 
543
- return endMapping;
610
+ sourceIndex,
611
+ crossStart,
612
+ crossEnd,
613
+ originalState
614
+ };
544
615
  };
545
616
 
546
- const findOriginalRange = (range, state, originalMap) => {
617
+ const findOriginalRange = (start, end, state, originalMap) => {
547
618
 
548
- // if (typeof range.startOffset !== 'number') {
549
- // console.log('=========================================================================', state.sourcePath);
550
- // console.log(range);
551
- // }
619
+ const { sourcePath, decodedMappings } = state;
552
620
 
553
- // startOffset: inclusive
554
- // endOffset: exclusive
555
- const startResult = findStartMapping(range, state, originalMap);
556
- if (startResult.error) {
621
+ const createMappingError = (errors) => {
557
622
  return {
558
623
  error: true,
559
- errors: startResult.errors.concat(`not found start mapping: ${range.startOffset}`)
624
+ start,
625
+ end,
626
+ sourcePath,
627
+ errors
560
628
  };
629
+ };
630
+
631
+ // possible no length
632
+ if (decodedMappings.length < 2) {
633
+ return createMappingError(['not found decoded mappings']);
561
634
  }
562
- const { startMapping, originalState } = startResult;
563
635
 
564
- // ==================================================================================
565
- // if (originalState.sourcePath.endsWith('conditional.js') && range.startOffset === 2153) {
566
- // console.log('============================================================', originalState.sourcePath);
567
- // console.log(range);
568
- // console.log(startMapping);
569
- // }
570
- // ==================================================================================
636
+ // start: inclusive
637
+ // end: exclusive
638
+ // could be 4 mappings found
639
+
640
+ const startMappings = findMapping(decodedMappings, start);
641
+ if (!startMappings) {
642
+ return {
643
+ error: true,
644
+ errors: ['not found start mappings']
645
+ };
646
+ }
571
647
 
572
- const endMapping = findEndMapping(range, state, startMapping);
573
- if (endMapping.error) {
648
+ const endMappings = findMapping(decodedMappings, end);
649
+ if (!endMappings) {
574
650
  return {
575
651
  error: true,
576
- errors: endMapping.errors.concat(`not found end mapping: ${range.endOffset}`)
652
+ errors: ['not found end mappings']
577
653
  };
578
654
  }
579
655
 
580
- // fix start
581
- fixStartColumn(startMapping, range, state, originalState);
656
+ const rangeInfo = getOriginalState(startMappings, endMappings, originalMap);
657
+ if (rangeInfo.error) {
658
+ return createMappingError(rangeInfo.errors);
659
+ }
582
660
 
583
- // fix end
584
- fixEndColumn(endMapping, range, startMapping, state, originalState);
661
+ const originalStartResult = getOriginalStart(start, startMappings, state, rangeInfo);
662
+ if (originalStartResult.error) {
663
+ return createMappingError(originalStartResult.errors);
664
+ }
585
665
 
586
- // after column fixed, the originalOffset could be not right
666
+ const originalEndResult = getOriginalEnd(end, endMappings, state, rangeInfo);
667
+ if (originalEndResult.error) {
668
+ return createMappingError(originalEndResult.errors);
669
+ }
587
670
 
588
- const locator = originalState.locator;
589
- const originalStart = locator.locationToOffset({
590
- line: startMapping.originalLine + 1,
591
- column: startMapping.column
592
- });
593
- const originalEnd = locator.locationToOffset({
594
- line: endMapping.originalLine + 1,
595
- column: endMapping.column
596
- });
671
+ const { originalStart } = originalStartResult;
672
+ const { originalEnd } = originalEndResult;
597
673
 
598
- // range start greater than end
674
+ // range start > end
599
675
  if (originalStart > originalEnd) {
600
- // console.log(`start > end: ${originalState.sourcePath}`);
601
- // console.log(range, originalRange);
602
- return {
603
- error: true,
604
- errors: [`original start is greater than end: ${originalStart} > ${originalEnd}`]
605
- };
676
+ return createMappingError([`invalid original start > end: ${EC.yellow(originalStart)} > ${EC.yellow(originalEnd)}`]);
606
677
  }
607
678
 
608
- const originalRange = {
609
- ... range,
610
- startOffset: originalStart,
611
- endOffset: originalEnd
612
- };
613
-
614
- // if (originalState.showLog) {
615
- // console.log('startMapping and endMapping:');
616
- // console.log(startMapping, endMapping);
617
- // console.log(originalStart, originalEnd);
618
- // }
679
+ const { originalState } = rangeInfo;
619
680
 
620
681
  return {
621
- originalRange,
622
- originalState,
623
- startMapping,
624
- endMapping
682
+ start: originalStart,
683
+ end: originalEnd,
684
+ originalState
625
685
  };
626
686
 
627
687
  };