monocart-coverage-reports 2.5.9 → 2.6.1

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,737 +1,737 @@
1
- const Util = require('../utils/util.js');
2
- const EC = Util.EC;
3
-
4
- const findMapping = (list, offset) => {
5
- let start = 0;
6
- let end = list.length - 1;
7
- while (end - start > 1) {
8
- const i = Math.floor((start + end) * 0.5);
9
- const item = list[i];
10
- if (offset < item.generatedOffset) {
11
- end = i;
12
- continue;
13
- }
14
- if (offset > item.generatedOffset) {
15
- start = i;
16
- continue;
17
- }
18
- return list[i];
19
- }
20
- // last two items, less is start
21
- const startItem = list[start];
22
- if (offset === startItem.generatedOffset) {
23
- return startItem;
24
- }
25
- const endItem = list[end];
26
- if (offset === endItem.generatedOffset) {
27
- return endItem;
28
- }
29
-
30
- // between two mappings
31
- if (offset > startItem.generatedOffset && offset < endItem.generatedOffset) {
32
- return [startItem, endItem];
33
- }
34
-
35
- // not found the mappings
36
-
37
- };
38
-
39
- // ========================================================================================================
40
-
41
- const getBlockStartPosition = (originalLineText) => {
42
- // originalText: 'argument) {',
43
- // generatedLeft: 'o',
44
- // generatedRight: '&&'
45
-
46
- // function/block could be started with {(
47
- const startBlockIndex = originalLineText.search(/[<{(]/);
48
- if (startBlockIndex !== -1) {
49
- return {
50
- pos: startBlockIndex
51
- };
52
- }
53
-
54
- // end a block
55
- const list = ['>', '}', ')'];
56
- for (const s of list) {
57
- const endBlockIndex = originalLineText.lastIndexOf(s);
58
- if (endBlockIndex !== -1) {
59
- return {
60
- pos: endBlockIndex + 1
61
- };
62
- }
63
- }
64
-
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
-
84
- };
85
-
86
- const getBlockEndPosition = (originalLineText) => {
87
-
88
- // generatedText: 'e),',
89
- // generatedPos: 2,
90
- // originalText: 'prop))'
91
-
92
- // generatedText: ' = false)',
93
- // generatedPos: 8,
94
- // originalText: '=false"'
95
-
96
- // generatedText: '), 1 /* TEXT */)])])) : (0,vue__...)("v-if", true)], 6 /* CLASS, STYLE */);',
97
- // generatedPos: 17,
98
- // originalText: ' }}</slot>'
99
-
100
- const list = ['>', '}', ')'];
101
- for (const s of list) {
102
- const endBlockIndex = originalLineText.lastIndexOf(s);
103
- if (endBlockIndex !== -1) {
104
- return {
105
- pos: endBlockIndex + 1
106
- };
107
- }
108
- }
109
-
110
- const startBlockIndex = originalLineText.search(/[<{(]/);
111
- if (startBlockIndex !== -1) {
112
- return {
113
- pos: startBlockIndex
114
- };
115
- }
116
-
117
- };
118
-
119
- const getComparedPosition = (gt, gp, ot, direction) => {
120
-
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
- };
139
- }
140
-
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
- };
157
- }
158
-
159
- // ============================
160
- // left matched
161
-
162
- // originalText: '1;',
163
- // generatedText: '1;else',
164
- // generatedLeft: '1;'
165
-
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
- };
174
- }
175
-
176
- // ============================
177
- // right matched
178
-
179
- const right = gt.slice(gp);
180
- if (ot.endsWith(right)) {
181
- return {
182
- pos: ot.length - right.length
183
- };
184
- }
185
-
186
- };
187
-
188
- const getSimilarPosition = (info, direction) => {
189
-
190
- const {
191
- generatedText, generatedPos, originalText
192
- } = info;
193
-
194
- const textPos = getComparedPosition(generatedText, generatedPos, originalText, direction);
195
- if (textPos) {
196
- return textPos;
197
- }
198
-
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
- }
207
-
208
- const originalLineText = originalLines[0].trimEnd();
209
- info.originalLineText = originalLineText;
210
-
211
- // generatedPos not in first line
212
- if (generatedPos > originalLineText.length) {
213
- return;
214
- }
215
-
216
- const linePos = getComparedPosition(generatedText, generatedPos, originalLineText, direction);
217
- if (linePos) {
218
- return linePos;
219
- }
220
-
221
- // console.log('====================================================================');
222
- // console.log(`${EC.magenta(direction)} similar position can NOT be fixed`);
223
- // console.log({
224
- // sourcePath: info.originalState.sourcePath,
225
- // generatedText,
226
- // generatedPos,
227
- // originalText
228
- // });
229
-
230
- };
231
-
232
- const getFixedPosition = (info, direction) => {
233
-
234
- const similarPos = getSimilarPosition(info, direction);
235
- if (similarPos) {
236
- return similarPos.pos;
237
- }
238
-
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;
250
- }
251
-
252
- const blockPos = getBlockEndPosition(originalLineText);
253
- if (blockPos) {
254
- return blockPos.pos;
255
- }
256
- return originalLineText.length;
257
- };
258
-
259
- // ========================================================================================================
260
-
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;
267
- };
268
-
269
- const getOriginalText = (m1, m2, rangeInfo, direction) => {
270
- const originalLocator = rangeInfo.originalState.locator;
271
-
272
- const o1 = m1.originalOffset;
273
- const o2 = m2.originalOffset;
274
-
275
- // o1 < o2: most of time
276
- if (o1 < o2) {
277
- // could be multiple lines for original text
278
- return {
279
- originalOffset: o1,
280
- originalText: originalLocator.getSlice(o1, o2)
281
- };
282
- }
283
-
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
- }
293
-
294
- // o1 > o2: should be wrong sourcemap
295
-
296
- // just reverse offsets if few cross lines
297
- const crossLines = m1.originalLine - m2.originalLine;
298
- if (crossLines < 2) {
299
- return {
300
- originalOffset: o2,
301
- originalText: originalLocator.getSlice(o2, o1)
302
- };
303
- }
304
-
305
- // if (direction === 'start') {
306
- // should be m2 ?
307
- // console.log(direction, rangeInfo.originalState.sourcePath);
308
- // console.log(m1, m2);
309
- // }
310
-
311
- // should be wrong, ignore m2
312
- const originalEndOffset = getOriginalEndOffset(m1, rangeInfo);
313
- return {
314
- originalOffset: o1,
315
- originalText: originalLocator.getSlice(o1, originalEndOffset)
316
- };
317
-
318
- };
319
-
320
- const getGeneratedText = (m1, m2, state, offset) => {
321
- const generatedLocator = state.locator;
322
-
323
- const o1 = m1.generatedOffset;
324
- const o2 = m2.generatedOffset;
325
-
326
- // same line
327
- if (m1.generatedLine === m2.generatedLine) {
328
- return {
329
- generatedText: generatedLocator.getSlice(o1, o2),
330
- generatedPos: offset - o1
331
- };
332
- }
333
-
334
- // =======================================
335
- // different lines
336
- // never cross lines
337
-
338
- // 1-base
339
- const lineInfo = generatedLocator.offsetToLocation(offset);
340
- // 0-base
341
- const targetLine = lineInfo.line - 1;
342
-
343
- // m1 p (case 1, right to end)
344
- // p (case 2, mid line)
345
- // p (case 3) m2
346
-
347
- // case 1
348
- if (targetLine === m1.generatedLine) {
349
- return {
350
- generatedText: generatedLocator.getSlice(o1, lineInfo.end),
351
- generatedPos: offset - o1
352
- };
353
- }
354
-
355
- // case 3
356
- if (targetLine === m2.generatedLine) {
357
- return {
358
- generatedText: generatedLocator.getSlice(lineInfo.start, o2),
359
- generatedPos: offset - lineInfo.start
360
- };
361
- }
362
-
363
- // case 2
364
- return {
365
- generatedText: lineInfo.text,
366
- generatedPos: offset - lineInfo.start
367
- };
368
-
369
- };
370
-
371
- // ========================================================================================================
372
-
373
- const getFixedOriginalStart = (start, mappings, state, rangeInfo) => {
374
-
375
- const [m1, m2] = mappings;
376
- const { originalState, crossStart } = rangeInfo;
377
-
378
- // cross file from start of line
379
- if (crossStart) {
380
- return {
381
- originalStart: m2.originalOffset
382
- };
383
- }
384
-
385
- const direction = 'start';
386
- const { originalText, originalOffset } = getOriginalText(m1, m2, rangeInfo, direction);
387
- const { generatedText, generatedPos } = getGeneratedText(m1, m2, state, start);
388
-
389
- const originalPos = getFixedPosition({
390
- generatedText,
391
- generatedPos,
392
- originalText,
393
- originalState
394
- }, direction);
395
-
396
- // if (start === 2660) {
397
- // console.log('=====================================================');
398
- // console.log('fixed start', originalState.sourcePath);
399
- // console.log({
400
- // generatedText,
401
- // generatedPos,
402
- // originalText,
403
- // originalPos
404
- // });
405
- // }
406
-
407
- return {
408
- originalStart: originalOffset + originalPos
409
- };
410
- };
411
-
412
- const getFixedOriginalEnd = (end, mappings, state, rangeInfo) => {
413
-
414
- const [m1, m2] = mappings;
415
- const { originalState, crossEnd } = rangeInfo;
416
-
417
- // cross file until e1 line end (not file end)
418
- if (crossEnd) {
419
- const originalEndOffset = getOriginalEndOffset(m1, rangeInfo);
420
- return {
421
- originalEnd: originalEndOffset
422
- };
423
- }
424
-
425
- // end is exclusive
426
- // quick check previous one if exact match
427
- // most of case is matching "}"
428
- if (m1.generatedOffset === end - 1) {
429
- return {
430
- originalEnd: m1.originalOffset + 1
431
- };
432
- }
433
-
434
- // quick check next one if exact match
435
- // most of case is same string
436
- if (m2.generatedOffset === end + 1) {
437
- const gt = state.locator.source[end];
438
- const oi = m2.originalOffset - 1;
439
- const ot = originalState.locator.source[oi];
440
- if (gt === ot) {
441
- return {
442
- originalEnd: oi
443
- };
444
- }
445
-
446
- // Not applicable
447
- // console.log('==================================');
448
- // console.log({
449
- // gp: state.sourcePath,
450
- // g: end,
451
- // gt,
452
- // op: originalState.sourcePath,
453
- // o: oi,
454
- // ot
455
- // });
456
- }
457
-
458
- const direction = 'end';
459
- const { originalText, originalOffset } = getOriginalText(m1, m2, rangeInfo, direction);
460
- const { generatedText, generatedPos } = getGeneratedText(m1, m2, state, end);
461
-
462
- const originalPos = getFixedPosition({
463
- generatedText,
464
- generatedPos,
465
- originalText,
466
- originalState
467
- }, direction);
468
-
469
- // if (end === 2858) {
470
- // console.log('=====================================================');
471
- // console.log('fixed end', originalState.sourcePath);
472
- // console.log({
473
- // generatedText,
474
- // generatedPos,
475
- // originalText,
476
- // originalPos
477
- // });
478
- // }
479
-
480
- return {
481
- originalEnd: originalOffset + originalPos
482
- };
483
- };
484
-
485
- // ========================================================================================================
486
-
487
- const getOriginalStart = (start, startMapping, state, rangeInfo) => {
488
- if (Array.isArray(startMapping)) {
489
- return getFixedOriginalStart(start, startMapping, state, rangeInfo);
490
- }
491
- // Exact match
492
- return {
493
- originalStart: startMapping.originalOffset
494
- };
495
- };
496
-
497
- const getOriginalEnd = (end, endMapping, state, rangeInfo) => {
498
- if (Array.isArray(endMapping)) {
499
- return getFixedOriginalEnd(end, endMapping, state, rangeInfo);
500
- }
501
- // Exact match
502
- return {
503
- originalEnd: endMapping.originalOffset
504
- };
505
- };
506
-
507
- // ========================================================================================================
508
-
509
- const checkSourceFileIndexes = (startIndexes, endIndexes) => {
510
-
511
- const checkIndex11 = (s1, e1) => {
512
- if (s1 === e1) {
513
- return {
514
- sourceIndex: s1
515
- };
516
- }
517
- return {
518
- error: true
519
- };
520
- };
521
-
522
- const checkIndex21 = (s1, s2, e1) => {
523
- if (s1 === e1 || s2 === e1) {
524
- if (s1 === s2) {
525
- return {
526
- sourceIndex: e1
527
- };
528
- }
529
- return {
530
- crossStart: true,
531
- sourceIndex: e1
532
- };
533
- }
534
- return {
535
- error: true
536
- };
537
- };
538
-
539
- const checkIndex12 = (s1, e1, e2) => {
540
- if (s1 === e1 || s1 === e2) {
541
- if (e1 === e2) {
542
- return {
543
- sourceIndex: s1
544
- };
545
- }
546
- return {
547
- crossEnd: true,
548
- sourceIndex: s1
549
- };
550
- }
551
- return {
552
- error: true
553
- };
554
- };
555
-
556
- const checkIndex22 = (s1, s2, e1, e2) => {
557
- // 4 same
558
- if (s1 === s2 && e1 === e2 && s1 === e1) {
559
- return {
560
- sourceIndex: s1
561
- };
562
- }
563
-
564
- if (e1 === e2) {
565
- return checkIndex21(s1, s2, e1);
566
- }
567
-
568
- if (s1 === s2) {
569
- return checkIndex12(s1, e1, e2);
570
- }
571
-
572
- if (s2 === e1) {
573
- return {
574
- crossStart: true,
575
- crossEnd: true,
576
- sourceIndex: s2
577
- };
578
- }
579
-
580
- // both between two mappings: 38,39 ~ 38,39
581
- // if (s1 === e1 && s2 === e2) {
582
- // }
583
-
584
- return {
585
- error: true
586
- };
587
- };
588
-
589
- // both exact matched
590
- if (startIndexes.length === 1 && endIndexes.length === 1) {
591
- return checkIndex11(startIndexes[0], endIndexes[0]);
592
- }
593
-
594
- if (startIndexes.length === 2 && endIndexes.length === 1) {
595
- return checkIndex21(startIndexes[0], startIndexes[1], endIndexes[0]);
596
- }
597
-
598
- if (startIndexes.length === 1 && endIndexes.length === 2) {
599
- return checkIndex12(startIndexes[0], endIndexes[0], endIndexes[1]);
600
- }
601
-
602
- // both 2 mappings
603
- return checkIndex22(startIndexes[0], startIndexes[1], endIndexes[0], endIndexes[1]);
604
-
605
- };
606
-
607
- const getOriginalState = (startMappings, endMappings, originalMap) => {
608
-
609
- // check source file indexes
610
- const startIndexes = [].concat(startMappings).map((it) => it.sourceIndex);
611
- const endIndexes = [].concat(endMappings).map((it) => it.sourceIndex);
612
- const rangeInfo = checkSourceFileIndexes(startIndexes, endIndexes);
613
- if (rangeInfo.error) {
614
- return {
615
- error: true,
616
- errors: [`invalid source indexes: ${EC.yellow(`${startIndexes} ~ ${endIndexes}`)}`]
617
- };
618
- }
619
-
620
- const {
621
- sourceIndex, crossStart, crossEnd
622
- } = rangeInfo;
623
-
624
- // if (crossStart || crossEnd) {
625
- // console.log(EC.magenta('cross file'), EC.yellow(`${startIndexes} ~ ${endIndexes}`));
626
- // }
627
-
628
- const originalState = originalMap.get(sourceIndex);
629
- if (!originalState) {
630
- return {
631
- error: true,
632
- errors: [`not found original file: ${EC.yellow(sourceIndex)}`]
633
- };
634
- }
635
-
636
- return {
637
- // for debug
638
- // startIndexes,
639
- // endIndexes,
640
-
641
- sourceIndex,
642
- crossStart,
643
- crossEnd,
644
- originalState
645
- };
646
- };
647
-
648
- const getMappingInfo = (decodedMappings, start, end) => {
649
- // possible no length
650
- if (decodedMappings.length < 2) {
651
- return {
652
- error: true,
653
- errors: ['invalid decoded mappings (length < 2)']
654
- };
655
- }
656
-
657
- // start: inclusive
658
- // end: exclusive
659
- // could be 4 mappings found
660
-
661
- const startMappings = findMapping(decodedMappings, start);
662
- if (!startMappings) {
663
- return {
664
- error: true,
665
- errors: ['not found start mappings']
666
- };
667
- }
668
-
669
- const endMappings = findMapping(decodedMappings, end);
670
- if (!endMappings) {
671
- return {
672
- error: true,
673
- errors: ['not found end mappings']
674
- };
675
- }
676
-
677
- return {
678
- startMappings,
679
- endMappings
680
- };
681
- };
682
-
683
- const findOriginalRange = (start, end, state, originalMap) => {
684
-
685
- const { sourcePath, decodedMappings } = state;
686
-
687
- const createMappingError = (errors) => {
688
- return {
689
- error: true,
690
- start,
691
- end,
692
- sourcePath,
693
- errors
694
- };
695
- };
696
-
697
- const mappingInfo = getMappingInfo(decodedMappings, start, end);
698
- if (mappingInfo.error) {
699
- return createMappingError(mappingInfo.errors);
700
- }
701
-
702
- const { startMappings, endMappings } = mappingInfo;
703
-
704
- const rangeInfo = getOriginalState(startMappings, endMappings, originalMap);
705
- if (rangeInfo.error) {
706
- return createMappingError(rangeInfo.errors);
707
- }
708
-
709
- const originalStartResult = getOriginalStart(start, startMappings, state, rangeInfo);
710
- if (originalStartResult.error) {
711
- return createMappingError(originalStartResult.errors);
712
- }
713
-
714
- const originalEndResult = getOriginalEnd(end, endMappings, state, rangeInfo);
715
- if (originalEndResult.error) {
716
- return createMappingError(originalEndResult.errors);
717
- }
718
-
719
- const { originalStart } = originalStartResult;
720
- const { originalEnd } = originalEndResult;
721
-
722
- // range start > end
723
- if (originalStart > originalEnd) {
724
- return createMappingError([`invalid original start > end: ${EC.yellow(originalStart)} > ${EC.yellow(originalEnd)}`]);
725
- }
726
-
727
- const { originalState } = rangeInfo;
728
-
729
- return {
730
- start: originalStart,
731
- end: originalEnd,
732
- originalState
733
- };
734
-
735
- };
736
-
737
- module.exports = findOriginalRange;
1
+ const Util = require('../utils/util.js');
2
+ const EC = Util.EC;
3
+
4
+ const findMapping = (list, offset) => {
5
+ let start = 0;
6
+ let end = list.length - 1;
7
+ while (end - start > 1) {
8
+ const i = Math.floor((start + end) * 0.5);
9
+ const item = list[i];
10
+ if (offset < item.generatedOffset) {
11
+ end = i;
12
+ continue;
13
+ }
14
+ if (offset > item.generatedOffset) {
15
+ start = i;
16
+ continue;
17
+ }
18
+ return list[i];
19
+ }
20
+ // last two items, less is start
21
+ const startItem = list[start];
22
+ if (offset === startItem.generatedOffset) {
23
+ return startItem;
24
+ }
25
+ const endItem = list[end];
26
+ if (offset === endItem.generatedOffset) {
27
+ return endItem;
28
+ }
29
+
30
+ // between two mappings
31
+ if (offset > startItem.generatedOffset && offset < endItem.generatedOffset) {
32
+ return [startItem, endItem];
33
+ }
34
+
35
+ // not found the mappings
36
+
37
+ };
38
+
39
+ // ========================================================================================================
40
+
41
+ const getBlockStartPosition = (originalLineText) => {
42
+ // originalText: 'argument) {',
43
+ // generatedLeft: 'o',
44
+ // generatedRight: '&&'
45
+
46
+ // function/block could be started with {(
47
+ const startBlockIndex = originalLineText.search(/[<{(]/);
48
+ if (startBlockIndex !== -1) {
49
+ return {
50
+ pos: startBlockIndex
51
+ };
52
+ }
53
+
54
+ // end a block
55
+ const list = ['>', '}', ')'];
56
+ for (const s of list) {
57
+ const endBlockIndex = originalLineText.lastIndexOf(s);
58
+ if (endBlockIndex !== -1) {
59
+ return {
60
+ pos: endBlockIndex + 1
61
+ };
62
+ }
63
+ }
64
+
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
+
84
+ };
85
+
86
+ const getBlockEndPosition = (originalLineText) => {
87
+
88
+ // generatedText: 'e),',
89
+ // generatedPos: 2,
90
+ // originalText: 'prop))'
91
+
92
+ // generatedText: ' = false)',
93
+ // generatedPos: 8,
94
+ // originalText: '=false"'
95
+
96
+ // generatedText: '), 1 /* TEXT */)])])) : (0,vue__...)("v-if", true)], 6 /* CLASS, STYLE */);',
97
+ // generatedPos: 17,
98
+ // originalText: ' }}</slot>'
99
+
100
+ const list = ['>', '}', ')'];
101
+ for (const s of list) {
102
+ const endBlockIndex = originalLineText.lastIndexOf(s);
103
+ if (endBlockIndex !== -1) {
104
+ return {
105
+ pos: endBlockIndex + 1
106
+ };
107
+ }
108
+ }
109
+
110
+ const startBlockIndex = originalLineText.search(/[<{(]/);
111
+ if (startBlockIndex !== -1) {
112
+ return {
113
+ pos: startBlockIndex
114
+ };
115
+ }
116
+
117
+ };
118
+
119
+ const getComparedPosition = (gt, gp, ot, direction) => {
120
+
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
+ };
139
+ }
140
+
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
+ };
157
+ }
158
+
159
+ // ============================
160
+ // left matched
161
+
162
+ // originalText: '1;',
163
+ // generatedText: '1;else',
164
+ // generatedLeft: '1;'
165
+
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
+ };
174
+ }
175
+
176
+ // ============================
177
+ // right matched
178
+
179
+ const right = gt.slice(gp);
180
+ if (ot.endsWith(right)) {
181
+ return {
182
+ pos: ot.length - right.length
183
+ };
184
+ }
185
+
186
+ };
187
+
188
+ const getSimilarPosition = (info, direction) => {
189
+
190
+ const {
191
+ generatedText, generatedPos, originalText
192
+ } = info;
193
+
194
+ const textPos = getComparedPosition(generatedText, generatedPos, originalText, direction);
195
+ if (textPos) {
196
+ return textPos;
197
+ }
198
+
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
+ }
207
+
208
+ const originalLineText = originalLines[0].trimEnd();
209
+ info.originalLineText = originalLineText;
210
+
211
+ // generatedPos not in first line
212
+ if (generatedPos > originalLineText.length) {
213
+ return;
214
+ }
215
+
216
+ const linePos = getComparedPosition(generatedText, generatedPos, originalLineText, direction);
217
+ if (linePos) {
218
+ return linePos;
219
+ }
220
+
221
+ // console.log('====================================================================');
222
+ // console.log(`${EC.magenta(direction)} similar position can NOT be fixed`);
223
+ // console.log({
224
+ // sourcePath: info.originalState.sourcePath,
225
+ // generatedText,
226
+ // generatedPos,
227
+ // originalText
228
+ // });
229
+
230
+ };
231
+
232
+ const getFixedPosition = (info, direction) => {
233
+
234
+ const similarPos = getSimilarPosition(info, direction);
235
+ if (similarPos) {
236
+ return similarPos.pos;
237
+ }
238
+
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;
250
+ }
251
+
252
+ const blockPos = getBlockEndPosition(originalLineText);
253
+ if (blockPos) {
254
+ return blockPos.pos;
255
+ }
256
+ return originalLineText.length;
257
+ };
258
+
259
+ // ========================================================================================================
260
+
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;
267
+ };
268
+
269
+ const getOriginalText = (m1, m2, rangeInfo, direction) => {
270
+ const originalLocator = rangeInfo.originalState.locator;
271
+
272
+ const o1 = m1.originalOffset;
273
+ const o2 = m2.originalOffset;
274
+
275
+ // o1 < o2: most of time
276
+ if (o1 < o2) {
277
+ // could be multiple lines for original text
278
+ return {
279
+ originalOffset: o1,
280
+ originalText: originalLocator.getSlice(o1, o2)
281
+ };
282
+ }
283
+
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
+ }
293
+
294
+ // o1 > o2: should be wrong sourcemap
295
+
296
+ // just reverse offsets if few cross lines
297
+ const crossLines = m1.originalLine - m2.originalLine;
298
+ if (crossLines < 2) {
299
+ return {
300
+ originalOffset: o2,
301
+ originalText: originalLocator.getSlice(o2, o1)
302
+ };
303
+ }
304
+
305
+ // if (direction === 'start') {
306
+ // should be m2 ?
307
+ // console.log(direction, rangeInfo.originalState.sourcePath);
308
+ // console.log(m1, m2);
309
+ // }
310
+
311
+ // should be wrong, ignore m2
312
+ const originalEndOffset = getOriginalEndOffset(m1, rangeInfo);
313
+ return {
314
+ originalOffset: o1,
315
+ originalText: originalLocator.getSlice(o1, originalEndOffset)
316
+ };
317
+
318
+ };
319
+
320
+ const getGeneratedText = (m1, m2, state, offset) => {
321
+ const generatedLocator = state.locator;
322
+
323
+ const o1 = m1.generatedOffset;
324
+ const o2 = m2.generatedOffset;
325
+
326
+ // same line
327
+ if (m1.generatedLine === m2.generatedLine) {
328
+ return {
329
+ generatedText: generatedLocator.getSlice(o1, o2),
330
+ generatedPos: offset - o1
331
+ };
332
+ }
333
+
334
+ // =======================================
335
+ // different lines
336
+ // never cross lines
337
+
338
+ // 1-base
339
+ const lineInfo = generatedLocator.offsetToLocation(offset);
340
+ // 0-base
341
+ const targetLine = lineInfo.line - 1;
342
+
343
+ // m1 p (case 1, right to end)
344
+ // p (case 2, mid line)
345
+ // p (case 3) m2
346
+
347
+ // case 1
348
+ if (targetLine === m1.generatedLine) {
349
+ return {
350
+ generatedText: generatedLocator.getSlice(o1, lineInfo.end),
351
+ generatedPos: offset - o1
352
+ };
353
+ }
354
+
355
+ // case 3
356
+ if (targetLine === m2.generatedLine) {
357
+ return {
358
+ generatedText: generatedLocator.getSlice(lineInfo.start, o2),
359
+ generatedPos: offset - lineInfo.start
360
+ };
361
+ }
362
+
363
+ // case 2
364
+ return {
365
+ generatedText: lineInfo.text,
366
+ generatedPos: offset - lineInfo.start
367
+ };
368
+
369
+ };
370
+
371
+ // ========================================================================================================
372
+
373
+ const getFixedOriginalStart = (start, mappings, state, rangeInfo) => {
374
+
375
+ const [m1, m2] = mappings;
376
+ const { originalState, crossStart } = rangeInfo;
377
+
378
+ // cross file from start of line
379
+ if (crossStart) {
380
+ return {
381
+ originalStart: m2.originalOffset
382
+ };
383
+ }
384
+
385
+ const direction = 'start';
386
+ const { originalText, originalOffset } = getOriginalText(m1, m2, rangeInfo, direction);
387
+ const { generatedText, generatedPos } = getGeneratedText(m1, m2, state, start);
388
+
389
+ const originalPos = getFixedPosition({
390
+ generatedText,
391
+ generatedPos,
392
+ originalText,
393
+ originalState
394
+ }, direction);
395
+
396
+ // if (start === 2660) {
397
+ // console.log('=====================================================');
398
+ // console.log('fixed start', originalState.sourcePath);
399
+ // console.log({
400
+ // generatedText,
401
+ // generatedPos,
402
+ // originalText,
403
+ // originalPos
404
+ // });
405
+ // }
406
+
407
+ return {
408
+ originalStart: originalOffset + originalPos
409
+ };
410
+ };
411
+
412
+ const getFixedOriginalEnd = (end, mappings, state, rangeInfo) => {
413
+
414
+ const [m1, m2] = mappings;
415
+ const { originalState, crossEnd } = rangeInfo;
416
+
417
+ // cross file until e1 line end (not file end)
418
+ if (crossEnd) {
419
+ const originalEndOffset = getOriginalEndOffset(m1, rangeInfo);
420
+ return {
421
+ originalEnd: originalEndOffset
422
+ };
423
+ }
424
+
425
+ // end is exclusive
426
+ // quick check previous one if exact match
427
+ // most of case is matching "}"
428
+ if (m1.generatedOffset === end - 1) {
429
+ return {
430
+ originalEnd: m1.originalOffset + 1
431
+ };
432
+ }
433
+
434
+ // quick check next one if exact match
435
+ // most of case is same string
436
+ if (m2.generatedOffset === end + 1) {
437
+ const gt = state.locator.source[end];
438
+ const oi = m2.originalOffset - 1;
439
+ const ot = originalState.locator.source[oi];
440
+ if (gt === ot) {
441
+ return {
442
+ originalEnd: oi
443
+ };
444
+ }
445
+
446
+ // Not applicable
447
+ // console.log('==================================');
448
+ // console.log({
449
+ // gp: state.sourcePath,
450
+ // g: end,
451
+ // gt,
452
+ // op: originalState.sourcePath,
453
+ // o: oi,
454
+ // ot
455
+ // });
456
+ }
457
+
458
+ const direction = 'end';
459
+ const { originalText, originalOffset } = getOriginalText(m1, m2, rangeInfo, direction);
460
+ const { generatedText, generatedPos } = getGeneratedText(m1, m2, state, end);
461
+
462
+ const originalPos = getFixedPosition({
463
+ generatedText,
464
+ generatedPos,
465
+ originalText,
466
+ originalState
467
+ }, direction);
468
+
469
+ // if (end === 2858) {
470
+ // console.log('=====================================================');
471
+ // console.log('fixed end', originalState.sourcePath);
472
+ // console.log({
473
+ // generatedText,
474
+ // generatedPos,
475
+ // originalText,
476
+ // originalPos
477
+ // });
478
+ // }
479
+
480
+ return {
481
+ originalEnd: originalOffset + originalPos
482
+ };
483
+ };
484
+
485
+ // ========================================================================================================
486
+
487
+ const getOriginalStart = (start, startMapping, state, rangeInfo) => {
488
+ if (Array.isArray(startMapping)) {
489
+ return getFixedOriginalStart(start, startMapping, state, rangeInfo);
490
+ }
491
+ // Exact match
492
+ return {
493
+ originalStart: startMapping.originalOffset
494
+ };
495
+ };
496
+
497
+ const getOriginalEnd = (end, endMapping, state, rangeInfo) => {
498
+ if (Array.isArray(endMapping)) {
499
+ return getFixedOriginalEnd(end, endMapping, state, rangeInfo);
500
+ }
501
+ // Exact match
502
+ return {
503
+ originalEnd: endMapping.originalOffset
504
+ };
505
+ };
506
+
507
+ // ========================================================================================================
508
+
509
+ const checkSourceFileIndexes = (startIndexes, endIndexes) => {
510
+
511
+ const checkIndex11 = (s1, e1) => {
512
+ if (s1 === e1) {
513
+ return {
514
+ sourceIndex: s1
515
+ };
516
+ }
517
+ return {
518
+ error: true
519
+ };
520
+ };
521
+
522
+ const checkIndex21 = (s1, s2, e1) => {
523
+ if (s1 === e1 || s2 === e1) {
524
+ if (s1 === s2) {
525
+ return {
526
+ sourceIndex: e1
527
+ };
528
+ }
529
+ return {
530
+ crossStart: true,
531
+ sourceIndex: e1
532
+ };
533
+ }
534
+ return {
535
+ error: true
536
+ };
537
+ };
538
+
539
+ const checkIndex12 = (s1, e1, e2) => {
540
+ if (s1 === e1 || s1 === e2) {
541
+ if (e1 === e2) {
542
+ return {
543
+ sourceIndex: s1
544
+ };
545
+ }
546
+ return {
547
+ crossEnd: true,
548
+ sourceIndex: s1
549
+ };
550
+ }
551
+ return {
552
+ error: true
553
+ };
554
+ };
555
+
556
+ const checkIndex22 = (s1, s2, e1, e2) => {
557
+ // 4 same
558
+ if (s1 === s2 && e1 === e2 && s1 === e1) {
559
+ return {
560
+ sourceIndex: s1
561
+ };
562
+ }
563
+
564
+ if (e1 === e2) {
565
+ return checkIndex21(s1, s2, e1);
566
+ }
567
+
568
+ if (s1 === s2) {
569
+ return checkIndex12(s1, e1, e2);
570
+ }
571
+
572
+ if (s2 === e1) {
573
+ return {
574
+ crossStart: true,
575
+ crossEnd: true,
576
+ sourceIndex: s2
577
+ };
578
+ }
579
+
580
+ // both between two mappings: 38,39 ~ 38,39
581
+ // if (s1 === e1 && s2 === e2) {
582
+ // }
583
+
584
+ return {
585
+ error: true
586
+ };
587
+ };
588
+
589
+ // both exact matched
590
+ if (startIndexes.length === 1 && endIndexes.length === 1) {
591
+ return checkIndex11(startIndexes[0], endIndexes[0]);
592
+ }
593
+
594
+ if (startIndexes.length === 2 && endIndexes.length === 1) {
595
+ return checkIndex21(startIndexes[0], startIndexes[1], endIndexes[0]);
596
+ }
597
+
598
+ if (startIndexes.length === 1 && endIndexes.length === 2) {
599
+ return checkIndex12(startIndexes[0], endIndexes[0], endIndexes[1]);
600
+ }
601
+
602
+ // both 2 mappings
603
+ return checkIndex22(startIndexes[0], startIndexes[1], endIndexes[0], endIndexes[1]);
604
+
605
+ };
606
+
607
+ const getOriginalState = (startMappings, endMappings, originalMap) => {
608
+
609
+ // check source file indexes
610
+ const startIndexes = [].concat(startMappings).map((it) => it.sourceIndex);
611
+ const endIndexes = [].concat(endMappings).map((it) => it.sourceIndex);
612
+ const rangeInfo = checkSourceFileIndexes(startIndexes, endIndexes);
613
+ if (rangeInfo.error) {
614
+ return {
615
+ error: true,
616
+ errors: [`invalid source indexes: ${EC.yellow(`${startIndexes} ~ ${endIndexes}`)}`]
617
+ };
618
+ }
619
+
620
+ const {
621
+ sourceIndex, crossStart, crossEnd
622
+ } = rangeInfo;
623
+
624
+ // if (crossStart || crossEnd) {
625
+ // console.log(EC.magenta('cross file'), EC.yellow(`${startIndexes} ~ ${endIndexes}`));
626
+ // }
627
+
628
+ const originalState = originalMap.get(sourceIndex);
629
+ if (!originalState) {
630
+ return {
631
+ error: true,
632
+ errors: [`not found original file: ${EC.yellow(sourceIndex)}`]
633
+ };
634
+ }
635
+
636
+ return {
637
+ // for debug
638
+ // startIndexes,
639
+ // endIndexes,
640
+
641
+ sourceIndex,
642
+ crossStart,
643
+ crossEnd,
644
+ originalState
645
+ };
646
+ };
647
+
648
+ const getMappingInfo = (decodedMappings, start, end) => {
649
+ // possible no length
650
+ if (decodedMappings.length < 2) {
651
+ return {
652
+ error: true,
653
+ errors: ['invalid decoded mappings (length < 2)']
654
+ };
655
+ }
656
+
657
+ // start: inclusive
658
+ // end: exclusive
659
+ // could be 4 mappings found
660
+
661
+ const startMappings = findMapping(decodedMappings, start);
662
+ if (!startMappings) {
663
+ return {
664
+ error: true,
665
+ errors: ['not found start mappings']
666
+ };
667
+ }
668
+
669
+ const endMappings = findMapping(decodedMappings, end);
670
+ if (!endMappings) {
671
+ return {
672
+ error: true,
673
+ errors: ['not found end mappings']
674
+ };
675
+ }
676
+
677
+ return {
678
+ startMappings,
679
+ endMappings
680
+ };
681
+ };
682
+
683
+ const findOriginalRange = (start, end, state, originalMap) => {
684
+
685
+ const { sourcePath, decodedMappings } = state;
686
+
687
+ const createMappingError = (errors) => {
688
+ return {
689
+ error: true,
690
+ start,
691
+ end,
692
+ sourcePath,
693
+ errors
694
+ };
695
+ };
696
+
697
+ const mappingInfo = getMappingInfo(decodedMappings, start, end);
698
+ if (mappingInfo.error) {
699
+ return createMappingError(mappingInfo.errors);
700
+ }
701
+
702
+ const { startMappings, endMappings } = mappingInfo;
703
+
704
+ const rangeInfo = getOriginalState(startMappings, endMappings, originalMap);
705
+ if (rangeInfo.error) {
706
+ return createMappingError(rangeInfo.errors);
707
+ }
708
+
709
+ const originalStartResult = getOriginalStart(start, startMappings, state, rangeInfo);
710
+ if (originalStartResult.error) {
711
+ return createMappingError(originalStartResult.errors);
712
+ }
713
+
714
+ const originalEndResult = getOriginalEnd(end, endMappings, state, rangeInfo);
715
+ if (originalEndResult.error) {
716
+ return createMappingError(originalEndResult.errors);
717
+ }
718
+
719
+ const { originalStart } = originalStartResult;
720
+ const { originalEnd } = originalEndResult;
721
+
722
+ // range start > end
723
+ if (originalStart > originalEnd) {
724
+ return createMappingError([`invalid original start > end: ${EC.yellow(originalStart)} > ${EC.yellow(originalEnd)}`]);
725
+ }
726
+
727
+ const { originalState } = rangeInfo;
728
+
729
+ return {
730
+ start: originalStart,
731
+ end: originalEnd,
732
+ originalState
733
+ };
734
+
735
+ };
736
+
737
+ module.exports = findOriginalRange;