@testream/dotnet-reporter 1.1.0 → 1.2.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.
package/dist/index.js CHANGED
@@ -2,15 +2,15 @@
2
2
  require('./sourcemap-register.js');/******/ (() => { // webpackBootstrap
3
3
  /******/ var __webpack_modules__ = ({
4
4
 
5
- /***/ 537:
5
+ /***/ 1537:
6
6
  /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
7
7
 
8
8
  "use strict";
9
9
 
10
10
 
11
11
  const validator = __nccwpck_require__(93);
12
- const XMLParser = __nccwpck_require__(360);
13
- const XMLBuilder = __nccwpck_require__(823);
12
+ const XMLParser = __nccwpck_require__(2360);
13
+ const XMLBuilder = __nccwpck_require__(2823);
14
14
 
15
15
  module.exports = {
16
16
  XMLParser: XMLParser,
@@ -20,7 +20,7 @@ module.exports = {
20
20
 
21
21
  /***/ }),
22
22
 
23
- /***/ 64:
23
+ /***/ 3064:
24
24
  /***/ ((module) => {
25
25
 
26
26
  function getIgnoreAttributesFn(ignoreAttributes) {
@@ -46,7 +46,7 @@ module.exports = getIgnoreAttributesFn
46
46
 
47
47
  /***/ }),
48
48
 
49
- /***/ 559:
49
+ /***/ 7559:
50
50
  /***/ ((__unused_webpack_module, exports) => {
51
51
 
52
52
  "use strict";
@@ -132,7 +132,7 @@ exports.nameRegexp = nameRegexp;
132
132
  "use strict";
133
133
 
134
134
 
135
- const util = __nccwpck_require__(559);
135
+ const util = __nccwpck_require__(7559);
136
136
 
137
137
  const defaultOptions = {
138
138
  allowBooleanAttributes: false, //A tag can have attributes without any value
@@ -559,14 +559,14 @@ function getPositionFromMatch(match) {
559
559
 
560
560
  /***/ }),
561
561
 
562
- /***/ 823:
562
+ /***/ 2823:
563
563
  /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
564
564
 
565
565
  "use strict";
566
566
 
567
567
  //parse Empty Node as self closing node
568
- const buildFromOrderedJs = __nccwpck_require__(57);
569
- const getIgnoreAttributesFn = __nccwpck_require__(64)
568
+ const buildFromOrderedJs = __nccwpck_require__(1057);
569
+ const getIgnoreAttributesFn = __nccwpck_require__(3064)
570
570
 
571
571
  const defaultOptions = {
572
572
  attributeNamePrefix: '@_',
@@ -853,7 +853,7 @@ module.exports = Builder;
853
853
 
854
854
  /***/ }),
855
855
 
856
- /***/ 57:
856
+ /***/ 1057:
857
857
  /***/ ((module) => {
858
858
 
859
859
  const EOL = "\n";
@@ -995,10 +995,10 @@ module.exports = toXml;
995
995
 
996
996
  /***/ }),
997
997
 
998
- /***/ 91:
998
+ /***/ 2091:
999
999
  /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
1000
1000
 
1001
- const util = __nccwpck_require__(559);
1001
+ const util = __nccwpck_require__(7559);
1002
1002
 
1003
1003
  //TODO: handle comments
1004
1004
  function readDocType(xmlData, i){
@@ -1209,18 +1209,18 @@ exports.defaultOptions = defaultOptions;
1209
1209
 
1210
1210
  /***/ }),
1211
1211
 
1212
- /***/ 629:
1212
+ /***/ 2629:
1213
1213
  /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
1214
1214
 
1215
1215
  "use strict";
1216
1216
 
1217
1217
  ///@ts-check
1218
1218
 
1219
- const util = __nccwpck_require__(559);
1220
- const xmlNode = __nccwpck_require__(79);
1221
- const readDocType = __nccwpck_require__(91);
1222
- const toNumber = __nccwpck_require__(236);
1223
- const getIgnoreAttributesFn = __nccwpck_require__(64)
1219
+ const util = __nccwpck_require__(7559);
1220
+ const xmlNode = __nccwpck_require__(7079);
1221
+ const readDocType = __nccwpck_require__(2091);
1222
+ const toNumber = __nccwpck_require__(6236);
1223
+ const getIgnoreAttributesFn = __nccwpck_require__(3064)
1224
1224
 
1225
1225
  // const regx =
1226
1226
  // '<((!\\[CDATA\\[([\\s\\S]*?)(]]>))|((NAME:)?(NAME))([^>]*)>|((\\/)(NAME)\\s*>))([^<]*)'
@@ -1823,12 +1823,12 @@ module.exports = OrderedObjParser;
1823
1823
 
1824
1824
  /***/ }),
1825
1825
 
1826
- /***/ 360:
1826
+ /***/ 2360:
1827
1827
  /***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
1828
1828
 
1829
1829
  const { buildOptions} = __nccwpck_require__(901);
1830
- const OrderedObjParser = __nccwpck_require__(629);
1831
- const { prettify} = __nccwpck_require__(318);
1830
+ const OrderedObjParser = __nccwpck_require__(2629);
1831
+ const { prettify} = __nccwpck_require__(5318);
1832
1832
  const validator = __nccwpck_require__(93);
1833
1833
 
1834
1834
  class XMLParser{
@@ -1887,7 +1887,7 @@ module.exports = XMLParser;
1887
1887
 
1888
1888
  /***/ }),
1889
1889
 
1890
- /***/ 318:
1890
+ /***/ 5318:
1891
1891
  /***/ ((__unused_webpack_module, exports) => {
1892
1892
 
1893
1893
  "use strict";
@@ -2008,7 +2008,7 @@ exports.prettify = prettify;
2008
2008
 
2009
2009
  /***/ }),
2010
2010
 
2011
- /***/ 79:
2011
+ /***/ 7079:
2012
2012
  /***/ ((module) => {
2013
2013
 
2014
2014
  "use strict";
@@ -2040,7 +2040,7 @@ module.exports = XmlNode;
2040
2040
 
2041
2041
  /***/ }),
2042
2042
 
2043
- /***/ 236:
2043
+ /***/ 6236:
2044
2044
  /***/ ((module) => {
2045
2045
 
2046
2046
  const hexRegex = /^[-+]?0x[a-fA-F0-9]+$/;
@@ -2157,7 +2157,7 @@ module.exports = toNumber;
2157
2157
 
2158
2158
  /***/ }),
2159
2159
 
2160
- /***/ 406:
2160
+ /***/ 2406:
2161
2161
  /***/ ((__unused_webpack_module, exports) => {
2162
2162
 
2163
2163
  "use strict";
@@ -2296,7 +2296,7 @@ function detectCIContext() {
2296
2296
 
2297
2297
  /***/ }),
2298
2298
 
2299
- /***/ 827:
2299
+ /***/ 3827:
2300
2300
  /***/ ((__unused_webpack_module, exports) => {
2301
2301
 
2302
2302
  "use strict";
@@ -2307,7 +2307,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
2307
2307
 
2308
2308
  /***/ }),
2309
2309
 
2310
- /***/ 322:
2310
+ /***/ 7322:
2311
2311
  /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
2312
2312
 
2313
2313
  "use strict";
@@ -2327,21 +2327,580 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
2327
2327
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
2328
2328
  };
2329
2329
  Object.defineProperty(exports, "__esModule", ({ value: true }));
2330
- exports.ensureReportId = exports.mapAttachmentsToTestResults = exports.uploadArtifacts = exports.uploadTestRun = exports.detectCIContext = void 0;
2330
+ exports.createTestLocationCollector = exports.enrichReportWithJsTestNameSourceSnippets = exports.resolveSourceSnippetOptions = exports.enrichReportWithSourceSnippets = exports.ensureReportId = exports.mapAttachmentsToTestResults = exports.uploadArtifacts = exports.uploadTestRun = exports.detectCIContext = void 0;
2331
2331
  // CTRF types
2332
- __exportStar(__nccwpck_require__(827), exports);
2333
- var ci_detection_1 = __nccwpck_require__(406);
2332
+ __exportStar(__nccwpck_require__(3827), exports);
2333
+ var ci_detection_1 = __nccwpck_require__(2406);
2334
2334
  Object.defineProperty(exports, "detectCIContext", ({ enumerable: true, get: function () { return ci_detection_1.detectCIContext; } }));
2335
- var upload_1 = __nccwpck_require__(969);
2335
+ var upload_1 = __nccwpck_require__(8969);
2336
2336
  Object.defineProperty(exports, "uploadTestRun", ({ enumerable: true, get: function () { return upload_1.uploadTestRun; } }));
2337
2337
  Object.defineProperty(exports, "uploadArtifacts", ({ enumerable: true, get: function () { return upload_1.uploadArtifacts; } }));
2338
2338
  Object.defineProperty(exports, "mapAttachmentsToTestResults", ({ enumerable: true, get: function () { return upload_1.mapAttachmentsToTestResults; } }));
2339
2339
  Object.defineProperty(exports, "ensureReportId", ({ enumerable: true, get: function () { return upload_1.ensureReportId; } }));
2340
+ var source_snippets_1 = __nccwpck_require__(9304);
2341
+ Object.defineProperty(exports, "enrichReportWithSourceSnippets", ({ enumerable: true, get: function () { return source_snippets_1.enrichReportWithSourceSnippets; } }));
2342
+ Object.defineProperty(exports, "resolveSourceSnippetOptions", ({ enumerable: true, get: function () { return source_snippets_1.resolveSourceSnippetOptions; } }));
2343
+ var js_test_name_snippets_1 = __nccwpck_require__(6913);
2344
+ Object.defineProperty(exports, "enrichReportWithJsTestNameSourceSnippets", ({ enumerable: true, get: function () { return js_test_name_snippets_1.enrichReportWithJsTestNameSourceSnippets; } }));
2345
+ var test_locations_1 = __nccwpck_require__(2293);
2346
+ Object.defineProperty(exports, "createTestLocationCollector", ({ enumerable: true, get: function () { return test_locations_1.createTestLocationCollector; } }));
2340
2347
  //# sourceMappingURL=index.js.map
2341
2348
 
2342
2349
  /***/ }),
2343
2350
 
2344
- /***/ 969:
2351
+ /***/ 6913:
2352
+ /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
2353
+
2354
+ "use strict";
2355
+
2356
+ var __importDefault = (this && this.__importDefault) || function (mod) {
2357
+ return (mod && mod.__esModule) ? mod : { "default": mod };
2358
+ };
2359
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
2360
+ exports.enrichReportWithJsTestNameSourceSnippets = enrichReportWithJsTestNameSourceSnippets;
2361
+ const promises_1 = __nccwpck_require__(1455);
2362
+ const node_path_1 = __importDefault(__nccwpck_require__(6760));
2363
+ const source_snippets_1 = __nccwpck_require__(9304);
2364
+ const MAX_CANDIDATES = 3;
2365
+ // Finds the start of common JS/TS test declarations, then the title is parsed
2366
+ // manually so titles can contain non-delimiting quotes like `it("doesn't")`.
2367
+ const JS_TEST_DECLARATION_PATTERN = /\b(describe|it|test)(?:\.(only|skip))?\s*\(\s*(['"`])/g;
2368
+ async function enrichReportWithJsTestNameSourceSnippets(report, options) {
2369
+ const resolved = (0, source_snippets_1.resolveSourceSnippetOptions)(options);
2370
+ const fileCandidateCache = new Map();
2371
+ await Promise.all(report.results.tests.map(async (test) => {
2372
+ if (test.snippet || !test.filePath) {
2373
+ return;
2374
+ }
2375
+ const filePath = node_path_1.default.resolve(resolved.sourceRoot, test.filePath);
2376
+ if (!isInsideSourceRoot(filePath, resolved.sourceRoot)) {
2377
+ return;
2378
+ }
2379
+ const candidates = await getCachedJsTestCandidates(filePath, fileCandidateCache);
2380
+ if (!candidates) {
2381
+ return;
2382
+ }
2383
+ const matches = rankCandidatesForTest(test, candidates).slice(0, MAX_CANDIDATES);
2384
+ if (matches.length === 0) {
2385
+ return;
2386
+ }
2387
+ test.line ?? (test.line = matches[0].line);
2388
+ test.snippet = formatCandidateSnippet(matches, resolved);
2389
+ }));
2390
+ }
2391
+ function getCachedJsTestCandidates(filePath, fileCandidateCache) {
2392
+ let cached = fileCandidateCache.get(filePath);
2393
+ if (!cached) {
2394
+ cached = (0, promises_1.readFile)(filePath, 'utf-8')
2395
+ .then((content) => scanJsTestCandidates(content))
2396
+ .catch(() => undefined);
2397
+ fileCandidateCache.set(filePath, cached);
2398
+ }
2399
+ return cached;
2400
+ }
2401
+ // This scanner intentionally handles the common JS/TS test declaration shapes
2402
+ // without adding parser dependencies to every reporter package. Exact runner
2403
+ // line metadata still wins; this fallback exists to give AI review bounded
2404
+ // source context when the reporter only emitted file path and test name.
2405
+ function scanJsTestCandidates(content) {
2406
+ const lineOffsets = buildLineOffsets(content);
2407
+ const blocks = scanJsTestBlocks(content, lineOffsets);
2408
+ const describeBlocks = blocks.filter((block) => block.kind === 'describe');
2409
+ return blocks
2410
+ .filter((block) => block.kind === 'test')
2411
+ .map((block) => {
2412
+ const describeTitles = describeBlocks
2413
+ .filter((describeBlock) => describeBlock.startIndex < block.startIndex && describeBlock.endIndex >= block.endIndex)
2414
+ .sort((left, right) => left.startIndex - right.startIndex)
2415
+ .map((describeBlock) => describeBlock.title);
2416
+ return {
2417
+ title: block.title,
2418
+ describeTitles,
2419
+ fullName: [...describeTitles, block.title].join(' ').trim(),
2420
+ line: block.startLine,
2421
+ snippet: block.snippet,
2422
+ };
2423
+ });
2424
+ }
2425
+ function scanJsTestBlocks(content, lineOffsets) {
2426
+ const blocks = [];
2427
+ JS_TEST_DECLARATION_PATTERN.lastIndex = 0;
2428
+ let match;
2429
+ while ((match = JS_TEST_DECLARATION_PATTERN.exec(content)) !== null) {
2430
+ if (isCommentedLine(content, match.index)) {
2431
+ continue;
2432
+ }
2433
+ const title = readQuotedTitle(content, match.index + match[0].length, match[3]);
2434
+ if (!title) {
2435
+ continue;
2436
+ }
2437
+ const commaIndex = skipWhitespaceAndFindComma(content, title.endIndex + 1);
2438
+ if (commaIndex == null) {
2439
+ continue;
2440
+ }
2441
+ const kind = match[1] === 'describe' ? 'describe' : 'test';
2442
+ const startIndex = match.index;
2443
+ const openBraceIndex = findCallbackOpenBrace(content, commaIndex + 1);
2444
+ if (openBraceIndex == null) {
2445
+ continue;
2446
+ }
2447
+ const closeBraceIndex = findMatchingBrace(content, openBraceIndex);
2448
+ if (closeBraceIndex == null) {
2449
+ continue;
2450
+ }
2451
+ const endIndex = findSnippetEndIndex(content, closeBraceIndex);
2452
+ const snippet = content.slice(startIndex, endIndex).trim();
2453
+ if (!snippet) {
2454
+ continue;
2455
+ }
2456
+ blocks.push({
2457
+ kind,
2458
+ title: title.value.trim(),
2459
+ startIndex,
2460
+ endIndex,
2461
+ startLine: getLineNumber(lineOffsets, startIndex),
2462
+ snippet,
2463
+ });
2464
+ }
2465
+ return blocks;
2466
+ }
2467
+ function rankCandidatesForTest(test, candidates) {
2468
+ const normalizedName = normalizeWhitespace(test.name);
2469
+ const suiteChain = normalizeDescribeChain(test.suite);
2470
+ const exactFullNameMatches = candidates.filter((candidate) => normalizeWhitespace(candidate.fullName) === normalizedName);
2471
+ if (exactFullNameMatches.length > 0) {
2472
+ return exactFullNameMatches;
2473
+ }
2474
+ if (suiteChain) {
2475
+ const suiteMatches = candidates.filter((candidate) => normalizeWhitespace(candidate.title) === normalizedName &&
2476
+ normalizeWhitespace(candidate.describeTitles.join(' ')) === suiteChain);
2477
+ if (suiteMatches.length > 0) {
2478
+ return suiteMatches;
2479
+ }
2480
+ }
2481
+ const leafTitleMatches = candidates.filter((candidate) => normalizeWhitespace(candidate.title) === normalizedName);
2482
+ if (leafTitleMatches.length > 0) {
2483
+ return leafTitleMatches;
2484
+ }
2485
+ return candidates.filter((candidate) => {
2486
+ const normalizedTitle = normalizeWhitespace(candidate.title);
2487
+ if (!normalizedName.endsWith(normalizedTitle)) {
2488
+ return false;
2489
+ }
2490
+ const prefix = normalizedName
2491
+ .slice(0, normalizedName.length - normalizedTitle.length)
2492
+ .trim();
2493
+ return prefix.length > 0 && normalizeWhitespace(candidate.describeTitles.join(' ')) === prefix;
2494
+ });
2495
+ }
2496
+ function formatCandidateSnippet(candidates, options) {
2497
+ const combined = candidates.length === 1
2498
+ ? candidates[0].snippet
2499
+ : candidates
2500
+ .map((candidate, index) => `Candidate ${index + 1} (line ${candidate.line})\n${candidate.snippet}`)
2501
+ .join('\n\n');
2502
+ const boundedLines = combined.split(/\r?\n/).slice(0, options.maxLines).join('\n').trim();
2503
+ if (boundedLines.length <= options.maxChars) {
2504
+ return boundedLines;
2505
+ }
2506
+ return boundedLines.slice(0, options.maxChars);
2507
+ }
2508
+ function findCallbackOpenBrace(content, fromIndex) {
2509
+ for (let index = fromIndex; index < content.length; index++) {
2510
+ const char = content[index];
2511
+ if (char === "'" || char === '"' || char === '`') {
2512
+ index = skipQuotedString(content, index);
2513
+ continue;
2514
+ }
2515
+ if (char === '/' && content[index + 1] === '/') {
2516
+ index = skipLineComment(content, index + 2);
2517
+ continue;
2518
+ }
2519
+ if (char === '/' && content[index + 1] === '*') {
2520
+ index = skipBlockComment(content, index + 2);
2521
+ continue;
2522
+ }
2523
+ if (content.startsWith('=>', index)) {
2524
+ return findNextBlockBrace(content, index + 2);
2525
+ }
2526
+ if (startsWithWord(content, index, 'function')) {
2527
+ return findNextBlockBrace(content, index + 'function'.length);
2528
+ }
2529
+ if (char === ';') {
2530
+ return undefined;
2531
+ }
2532
+ }
2533
+ return undefined;
2534
+ }
2535
+ function findNextBlockBrace(content, fromIndex) {
2536
+ for (let index = fromIndex; index < content.length; index++) {
2537
+ const char = content[index];
2538
+ if (char === "'" || char === '"' || char === '`') {
2539
+ index = skipQuotedString(content, index);
2540
+ continue;
2541
+ }
2542
+ if (char === '{') {
2543
+ return index;
2544
+ }
2545
+ if (char === '\n' && looksLikeLineTerminator(content, index + 1)) {
2546
+ return undefined;
2547
+ }
2548
+ }
2549
+ return undefined;
2550
+ }
2551
+ function findMatchingBrace(content, openBraceIndex) {
2552
+ let depth = 0;
2553
+ for (let index = openBraceIndex; index < content.length; index++) {
2554
+ const char = content[index];
2555
+ if (char === "'" || char === '"' || char === '`') {
2556
+ index = skipQuotedString(content, index);
2557
+ continue;
2558
+ }
2559
+ if (char === '/' && content[index + 1] === '/') {
2560
+ index = skipLineComment(content, index + 2);
2561
+ continue;
2562
+ }
2563
+ if (char === '/' && content[index + 1] === '*') {
2564
+ index = skipBlockComment(content, index + 2);
2565
+ continue;
2566
+ }
2567
+ if (char === '{') {
2568
+ depth++;
2569
+ continue;
2570
+ }
2571
+ if (char === '}') {
2572
+ depth--;
2573
+ if (depth === 0) {
2574
+ return index;
2575
+ }
2576
+ }
2577
+ }
2578
+ return undefined;
2579
+ }
2580
+ function readQuotedTitle(content, startIndex, quote) {
2581
+ let value = '';
2582
+ for (let index = startIndex; index < content.length; index++) {
2583
+ const char = content[index];
2584
+ if (char === '\\') {
2585
+ value += char;
2586
+ if (index + 1 < content.length) {
2587
+ index++;
2588
+ value += content[index];
2589
+ }
2590
+ continue;
2591
+ }
2592
+ if (char === quote) {
2593
+ return { value, endIndex: index };
2594
+ }
2595
+ if (char === '\n' && quote !== '`') {
2596
+ return undefined;
2597
+ }
2598
+ value += char;
2599
+ }
2600
+ return undefined;
2601
+ }
2602
+ function skipWhitespaceAndFindComma(content, fromIndex) {
2603
+ for (let index = fromIndex; index < content.length; index++) {
2604
+ const char = content[index];
2605
+ if (/\s/.test(char)) {
2606
+ continue;
2607
+ }
2608
+ return char === ',' ? index : undefined;
2609
+ }
2610
+ return undefined;
2611
+ }
2612
+ function findSnippetEndIndex(content, closeBraceIndex) {
2613
+ let index = closeBraceIndex + 1;
2614
+ while (index < content.length) {
2615
+ const char = content[index];
2616
+ if (char === '\r' || char === '\n') {
2617
+ return index;
2618
+ }
2619
+ index++;
2620
+ }
2621
+ return content.length;
2622
+ }
2623
+ function skipQuotedString(content, startIndex) {
2624
+ const quote = content[startIndex];
2625
+ for (let index = startIndex + 1; index < content.length; index++) {
2626
+ const char = content[index];
2627
+ if (char === '\\') {
2628
+ index++;
2629
+ continue;
2630
+ }
2631
+ if (char === quote) {
2632
+ return index;
2633
+ }
2634
+ }
2635
+ return content.length - 1;
2636
+ }
2637
+ function skipLineComment(content, startIndex) {
2638
+ for (let index = startIndex; index < content.length; index++) {
2639
+ if (content[index] === '\n') {
2640
+ return index;
2641
+ }
2642
+ }
2643
+ return content.length - 1;
2644
+ }
2645
+ function skipBlockComment(content, startIndex) {
2646
+ for (let index = startIndex; index < content.length - 1; index++) {
2647
+ if (content[index] === '*' && content[index + 1] === '/') {
2648
+ return index + 1;
2649
+ }
2650
+ }
2651
+ return content.length - 1;
2652
+ }
2653
+ function looksLikeLineTerminator(content, index) {
2654
+ for (let cursor = index; cursor < content.length; cursor++) {
2655
+ const char = content[cursor];
2656
+ if (!/\s/.test(char)) {
2657
+ return char !== '.' && char !== '(';
2658
+ }
2659
+ }
2660
+ return false;
2661
+ }
2662
+ function buildLineOffsets(content) {
2663
+ const offsets = [0];
2664
+ for (let index = 0; index < content.length; index++) {
2665
+ if (content[index] === '\n') {
2666
+ offsets.push(index + 1);
2667
+ }
2668
+ }
2669
+ return offsets;
2670
+ }
2671
+ function getLineNumber(lineOffsets, index) {
2672
+ let line = 0;
2673
+ for (let i = 0; i < lineOffsets.length; i++) {
2674
+ if (lineOffsets[i] > index) {
2675
+ break;
2676
+ }
2677
+ line = i;
2678
+ }
2679
+ return line + 1;
2680
+ }
2681
+ function isCommentedLine(content, index) {
2682
+ const lineStart = content.lastIndexOf('\n', index - 1) + 1;
2683
+ const prefix = content.slice(lineStart, index).trimStart();
2684
+ return prefix.startsWith('//') || prefix.startsWith('*');
2685
+ }
2686
+ function startsWithWord(content, index, word) {
2687
+ if (!content.startsWith(word, index)) {
2688
+ return false;
2689
+ }
2690
+ const before = index === 0 ? '' : content[index - 1];
2691
+ const after = content[index + word.length] ?? '';
2692
+ return !isIdentifierChar(before) && !isIdentifierChar(after);
2693
+ }
2694
+ function isIdentifierChar(char) {
2695
+ return /[A-Za-z0-9_$]/.test(char);
2696
+ }
2697
+ function normalizeWhitespace(value) {
2698
+ return (value ?? '').trim().replace(/\s+/g, ' ');
2699
+ }
2700
+ function normalizeDescribeChain(suite) {
2701
+ if (!suite) {
2702
+ return '';
2703
+ }
2704
+ const segments = suite
2705
+ .split('>')
2706
+ .map((segment) => segment.trim())
2707
+ .filter(Boolean);
2708
+ if (segments.length === 0) {
2709
+ return '';
2710
+ }
2711
+ const firstSegmentLooksLikeFile = segments[0].includes('.');
2712
+ const describeSegments = firstSegmentLooksLikeFile ? segments.slice(1) : segments;
2713
+ return normalizeWhitespace(describeSegments.join(' '));
2714
+ }
2715
+ function isInsideSourceRoot(filePath, sourceRoot) {
2716
+ const relative = node_path_1.default.relative(sourceRoot, filePath);
2717
+ return relative.length > 0 && !relative.startsWith('..') && !node_path_1.default.isAbsolute(relative);
2718
+ }
2719
+ //# sourceMappingURL=js-test-name-snippets.js.map
2720
+
2721
+ /***/ }),
2722
+
2723
+ /***/ 9304:
2724
+ /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
2725
+
2726
+ "use strict";
2727
+
2728
+ var __importDefault = (this && this.__importDefault) || function (mod) {
2729
+ return (mod && mod.__esModule) ? mod : { "default": mod };
2730
+ };
2731
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
2732
+ exports.resolveSourceSnippetOptions = resolveSourceSnippetOptions;
2733
+ exports.enrichReportWithSourceSnippets = enrichReportWithSourceSnippets;
2734
+ const promises_1 = __nccwpck_require__(1455);
2735
+ const node_path_1 = __importDefault(__nccwpck_require__(6760));
2736
+ const DEFAULT_MAX_CHARS = 2000;
2737
+ const DEFAULT_MAX_LINES = 40;
2738
+ function resolveSourceSnippetOptions(options) {
2739
+ return {
2740
+ sourceRoot: node_path_1.default.resolve(options?.sourceRoot ?? process.cwd()),
2741
+ maxChars: normalizePositiveInt(options?.maxChars, DEFAULT_MAX_CHARS),
2742
+ maxLines: normalizePositiveInt(options?.maxLines, DEFAULT_MAX_LINES),
2743
+ };
2744
+ }
2745
+ // This implementation only extracts JS/TS-style test()/it() blocks.
2746
+ // Other languages need reporter-specific snippet logic after that reporter
2747
+ // has supplied file/line metadata for the test.
2748
+ async function enrichReportWithSourceSnippets(report, options) {
2749
+ const resolved = resolveSourceSnippetOptions(options);
2750
+ const fileContentCache = new Map();
2751
+ await Promise.all(report.results.tests.map(async (test) => {
2752
+ if (test.snippet || !test.filePath || !test.line) {
2753
+ return;
2754
+ }
2755
+ const snippet = await tryExtractSnippet(test, resolved, fileContentCache);
2756
+ if (snippet) {
2757
+ test.snippet = snippet;
2758
+ }
2759
+ }));
2760
+ }
2761
+ async function tryExtractSnippet(test, options, fileContentCache) {
2762
+ const filePath = node_path_1.default.resolve(options.sourceRoot, test.filePath);
2763
+ if (!isInsideSourceRoot(filePath, options.sourceRoot)) {
2764
+ return undefined;
2765
+ }
2766
+ const content = await getCachedFileContent(filePath, fileContentCache);
2767
+ if (!content) {
2768
+ return undefined;
2769
+ }
2770
+ return extractEnclosingTestBlock(content, test.line, options);
2771
+ }
2772
+ function getCachedFileContent(filePath, fileContentCache) {
2773
+ let cached = fileContentCache.get(filePath);
2774
+ if (!cached) {
2775
+ cached = (0, promises_1.readFile)(filePath, 'utf-8').catch(() => undefined);
2776
+ fileContentCache.set(filePath, cached);
2777
+ }
2778
+ return cached;
2779
+ }
2780
+ function extractEnclosingTestBlock(content, lineNumber, options) {
2781
+ const lines = content.split(/\r?\n/);
2782
+ const index = Math.max(0, Math.min(lines.length - 1, lineNumber - 1));
2783
+ const start = findTestStart(lines, index);
2784
+ if (start == null) {
2785
+ return undefined;
2786
+ }
2787
+ const selected = [];
2788
+ let braceBalance = 0;
2789
+ let sawOpeningBrace = false;
2790
+ for (let i = start; i < lines.length && selected.length < options.maxLines; i++) {
2791
+ const line = lines[i];
2792
+ selected.push(line);
2793
+ for (const char of line) {
2794
+ if (char === '{') {
2795
+ braceBalance++;
2796
+ sawOpeningBrace = true;
2797
+ }
2798
+ else if (char === '}') {
2799
+ braceBalance--;
2800
+ }
2801
+ }
2802
+ if (sawOpeningBrace && braceBalance <= 0 && isJsTestBlockTerminator(line)) {
2803
+ break;
2804
+ }
2805
+ }
2806
+ const snippet = selected.join('\n').trim();
2807
+ if (!snippet) {
2808
+ return undefined;
2809
+ }
2810
+ return snippet.length <= options.maxChars
2811
+ ? snippet
2812
+ : snippet.slice(0, options.maxChars);
2813
+ }
2814
+ function findTestStart(lines, fromIndex) {
2815
+ for (let i = fromIndex; i >= 0; i--) {
2816
+ // Walk upward from runner-provided line metadata until we hit a JS/TS
2817
+ // test/it call, including common modifiers used by Vitest/Playwright.
2818
+ if (/\b(?:test|it)(?:\.(?:only|skip|fixme|slow))?\s*\(/.test(lines[i])) {
2819
+ return i;
2820
+ }
2821
+ }
2822
+ return undefined;
2823
+ }
2824
+ function isJsTestBlockTerminator(line) {
2825
+ let i = line.length - 1;
2826
+ while (i >= 0 && /\s/.test(line[i])) {
2827
+ i--;
2828
+ }
2829
+ if (i >= 0 && line[i] === ';') {
2830
+ i--;
2831
+ }
2832
+ while (i >= 0 && /\s/.test(line[i])) {
2833
+ i--;
2834
+ }
2835
+ if (i < 1 || line[i] !== ')') {
2836
+ return false;
2837
+ }
2838
+ i--;
2839
+ while (i >= 0 && /\s/.test(line[i])) {
2840
+ i--;
2841
+ }
2842
+ return i >= 0 && line[i] === '}';
2843
+ }
2844
+ function isInsideSourceRoot(filePath, sourceRoot) {
2845
+ const relative = node_path_1.default.relative(sourceRoot, filePath);
2846
+ return relative.length > 0 && !relative.startsWith('..') && !node_path_1.default.isAbsolute(relative);
2847
+ }
2848
+ function normalizePositiveInt(value, fallback) {
2849
+ return typeof value === 'number' && Number.isInteger(value) && value > 0
2850
+ ? value
2851
+ : fallback;
2852
+ }
2853
+ //# sourceMappingURL=source-snippets.js.map
2854
+
2855
+ /***/ }),
2856
+
2857
+ /***/ 2293:
2858
+ /***/ ((__unused_webpack_module, exports) => {
2859
+
2860
+ "use strict";
2861
+
2862
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
2863
+ exports.createTestLocationCollector = createTestLocationCollector;
2864
+ /**
2865
+ * Generic name-based location mapper for CTRF reports.
2866
+ *
2867
+ * Different reporters can collect test locations in their own format
2868
+ * (Playwright runtime metadata, parsed JUnit XML, etc.) and then feed
2869
+ * this collector to apply file/line metadata in a consistent FIFO way.
2870
+ */
2871
+ function createTestLocationCollector() {
2872
+ const locationsByTestName = new Map();
2873
+ return {
2874
+ add(testName, location) {
2875
+ if (!testName || !isValidLocation(location)) {
2876
+ return;
2877
+ }
2878
+ const queue = locationsByTestName.get(testName) ?? [];
2879
+ queue.push(location);
2880
+ locationsByTestName.set(testName, queue);
2881
+ },
2882
+ applyToReport(report) {
2883
+ const queues = new Map([...locationsByTestName.entries()].map(([name, locations]) => [name, [...locations]]));
2884
+ for (const test of report.results.tests) {
2885
+ const queue = queues.get(test.name);
2886
+ const location = queue?.shift();
2887
+ if (!location) {
2888
+ continue;
2889
+ }
2890
+ test.filePath ?? (test.filePath = location.filePath);
2891
+ test.line ?? (test.line = location.line);
2892
+ }
2893
+ },
2894
+ };
2895
+ }
2896
+ function isValidLocation(location) {
2897
+ return Boolean(location.filePath) && Number.isInteger(location.line) && location.line > 0;
2898
+ }
2899
+ //# sourceMappingURL=test-locations.js.map
2900
+
2901
+ /***/ }),
2902
+
2903
+ /***/ 8969:
2345
2904
  /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
2346
2905
 
2347
2906
  "use strict";
@@ -2351,10 +2910,12 @@ exports.ensureReportId = ensureReportId;
2351
2910
  exports.uploadTestRun = uploadTestRun;
2352
2911
  exports.mapAttachmentsToTestResults = mapAttachmentsToTestResults;
2353
2912
  exports.uploadArtifacts = uploadArtifacts;
2354
- const ci_detection_1 = __nccwpck_require__(406);
2355
- const DEFAULT_API_URL = 'https://test-manager-backend.fly.dev';
2913
+ const ci_detection_1 = __nccwpck_require__(2406);
2914
+ const source_snippets_1 = __nccwpck_require__(9304);
2915
+ const DEFAULT_API_URL = "https://api.testream.app";
2356
2916
  function ensureReportId(report) {
2357
- if (typeof report.reportId === 'string' && report.reportId.trim().length > 0) {
2917
+ if (typeof report.reportId === "string" &&
2918
+ report.reportId.trim().length > 0) {
2358
2919
  return report.reportId;
2359
2920
  }
2360
2921
  const reportId = crypto.randomUUID();
@@ -2373,7 +2934,7 @@ function resolveApiUrl(explicitApiUrl) {
2373
2934
  return DEFAULT_API_URL;
2374
2935
  }
2375
2936
  function getEnvApiUrl() {
2376
- if (typeof process === 'undefined' || !process?.env) {
2937
+ if (typeof process === "undefined" || !process?.env) {
2377
2938
  return undefined;
2378
2939
  }
2379
2940
  return normalizeApiUrl(process.env.TESTREAM_API_URL);
@@ -2386,20 +2947,25 @@ function normalizeApiUrl(value) {
2386
2947
  if (!trimmed) {
2387
2948
  return undefined;
2388
2949
  }
2389
- return trimmed.replace(/\/+$/, '');
2950
+ // Use while loop instead of regex for better performance and clarity
2951
+ let result = trimmed;
2952
+ while (result.endsWith("/")) {
2953
+ result = result.slice(0, -1);
2954
+ }
2955
+ return result;
2390
2956
  }
2391
2957
  function isReportAlreadyExistsConflict(error) {
2392
- return error.errorCode === 'report_already_exists';
2958
+ return error.errorCode === "report_already_exists";
2393
2959
  }
2394
2960
  function formatUploadError(error) {
2395
- const detail = error.detail || error.title || error.rawBody || 'Unknown error';
2396
- const codeLabel = error.errorCode ? `, code=${error.errorCode}` : '';
2961
+ const detail = error.detail || error.title || error.rawBody || "Unknown error";
2962
+ const codeLabel = error.errorCode ? `, code=${error.errorCode}` : "";
2397
2963
  return `Upload failed (HTTP ${error.statusCode}${codeLabel}): ${detail}`;
2398
2964
  }
2399
2965
  async function parseHttpError(response) {
2400
2966
  const rawBody = await response.text();
2401
- const contentType = response.headers.get('content-type') || '';
2402
- if (contentType.toLowerCase().includes('json') && rawBody.trim().length > 0) {
2967
+ const contentType = response.headers.get("content-type") || "";
2968
+ if (contentType.toLowerCase().includes("json") && rawBody.trim().length > 0) {
2403
2969
  try {
2404
2970
  const parsed = JSON.parse(rawBody);
2405
2971
  return {
@@ -2442,6 +3008,7 @@ async function uploadTestRun(options) {
2442
3008
  const apiUrl = resolveApiUrl(options.apiUrl);
2443
3009
  const reportId = ensureReportId(report);
2444
3010
  const uploadContext = resolveUploadContext(options);
3011
+ await (0, source_snippets_1.enrichReportWithSourceSnippets)(report);
2445
3012
  // Build type-safe IngestRequest payload
2446
3013
  const ingestPayload = {
2447
3014
  report,
@@ -2449,14 +3016,14 @@ async function uploadTestRun(options) {
2449
3016
  ...uploadContext,
2450
3017
  };
2451
3018
  // Professional logging
2452
- console.log('Uploading test results...');
3019
+ console.log("Uploading test results...");
2453
3020
  let response;
2454
3021
  try {
2455
3022
  response = await fetch(`${apiUrl}/api/v1/ingest`, {
2456
- method: 'POST',
3023
+ method: "POST",
2457
3024
  headers: {
2458
- 'X-API-KEY': apiKey,
2459
- 'Content-Type': 'application/json',
3025
+ "X-API-KEY": apiKey,
3026
+ "Content-Type": "application/json",
2460
3027
  },
2461
3028
  body: JSON.stringify(ingestPayload),
2462
3029
  });
@@ -2474,7 +3041,7 @@ async function uploadTestRun(options) {
2474
3041
  if (!response.ok) {
2475
3042
  const parsedError = await parseHttpError(response);
2476
3043
  if (response.status === 409 && isReportAlreadyExistsConflict(parsedError)) {
2477
- console.warn('Report already exists (workflow may have been re-run)');
3044
+ console.warn("Report already exists (workflow may have been re-run)");
2478
3045
  return {
2479
3046
  success: true,
2480
3047
  reportId,
@@ -2582,8 +3149,8 @@ async function uploadArtifacts(options) {
2582
3149
  async function uploadSingleArtifact(options) {
2583
3150
  const { testResultId, attachment, reportId, apiKey, apiUrl } = options;
2584
3151
  // Dynamically import fs for Node.js environments
2585
- const fs = await Promise.resolve(/* import() */).then(__nccwpck_require__.t.bind(__nccwpck_require__, 943, 23));
2586
- const path = await Promise.resolve(/* import() */).then(__nccwpck_require__.t.bind(__nccwpck_require__, 928, 23));
3152
+ const fs = await Promise.resolve(/* import() */).then(__nccwpck_require__.t.bind(__nccwpck_require__, 1455, 23));
3153
+ const path = await Promise.resolve(/* import() */).then(__nccwpck_require__.t.bind(__nccwpck_require__, 6760, 23));
2587
3154
  const filePath = path.resolve(attachment.path);
2588
3155
  // Check if file exists
2589
3156
  try {
@@ -2597,7 +3164,7 @@ async function uploadSingleArtifact(options) {
2597
3164
  let fileBuffer;
2598
3165
  let sizeBytes;
2599
3166
  const fileName = path.basename(filePath);
2600
- const contentType = attachment.contentType || 'application/octet-stream';
3167
+ const contentType = attachment.contentType || "application/octet-stream";
2601
3168
  try {
2602
3169
  fileBuffer = await fs.readFile(filePath);
2603
3170
  sizeBytes = fileBuffer.byteLength;
@@ -2637,7 +3204,7 @@ async function uploadSingleArtifact(options) {
2637
3204
  }
2638
3205
  class LegacyUploadRequiredError extends Error {
2639
3206
  constructor() {
2640
- super('Legacy upload endpoint required');
3207
+ super("Legacy upload endpoint required");
2641
3208
  }
2642
3209
  }
2643
3210
  async function uploadWithPresignedUrl(options) {
@@ -2650,10 +3217,10 @@ async function uploadWithPresignedUrl(options) {
2650
3217
  sizeBytes,
2651
3218
  };
2652
3219
  const initResponse = await fetch(`${apiUrl}/api/v1/artifacts/${reportId}/upload-url`, {
2653
- method: 'POST',
3220
+ method: "POST",
2654
3221
  headers: {
2655
- 'X-API-KEY': apiKey,
2656
- 'Content-Type': 'application/json',
3222
+ "X-API-KEY": apiKey,
3223
+ "Content-Type": "application/json",
2657
3224
  },
2658
3225
  body: JSON.stringify(initPayload),
2659
3226
  });
@@ -2665,12 +3232,14 @@ async function uploadWithPresignedUrl(options) {
2665
3232
  throw new Error(`Failed to create direct upload URL (HTTP ${initResponse.status}): ${errorText}`);
2666
3233
  }
2667
3234
  const uploadInitResult = (await initResponse.json());
2668
- const uploadHeaders = { ...(uploadInitResult.requiredHeaders ?? {}) };
2669
- if (!hasHeaderIgnoreCase(uploadHeaders, 'Content-Type')) {
2670
- uploadHeaders['Content-Type'] = contentType;
3235
+ const uploadHeaders = {
3236
+ ...(uploadInitResult.requiredHeaders),
3237
+ };
3238
+ if (!hasHeaderIgnoreCase(uploadHeaders, "Content-Type")) {
3239
+ uploadHeaders["Content-Type"] = contentType;
2671
3240
  }
2672
3241
  const directUploadResponse = await fetch(uploadInitResult.uploadUrl, {
2673
- method: 'PUT',
3242
+ method: "PUT",
2674
3243
  headers: uploadHeaders,
2675
3244
  body: fileBuffer,
2676
3245
  });
@@ -2687,10 +3256,10 @@ async function uploadWithPresignedUrl(options) {
2687
3256
  storageKey: uploadInitResult.storageKey,
2688
3257
  };
2689
3258
  const completeResponse = await fetch(`${apiUrl}/api/v1/artifacts/${reportId}/complete`, {
2690
- method: 'POST',
3259
+ method: "POST",
2691
3260
  headers: {
2692
- 'X-API-KEY': apiKey,
2693
- 'Content-Type': 'application/json',
3261
+ "X-API-KEY": apiKey,
3262
+ "Content-Type": "application/json",
2694
3263
  },
2695
3264
  body: JSON.stringify(completePayload),
2696
3265
  });
@@ -2701,16 +3270,16 @@ async function uploadWithPresignedUrl(options) {
2701
3270
  return true;
2702
3271
  }
2703
3272
  async function uploadWithLegacyEndpoint(options) {
2704
- const { testResultId, attachmentName, reportId, apiKey, apiUrl, fileName, contentType, fileBuffer } = options;
3273
+ const { testResultId, attachmentName, reportId, apiKey, apiUrl, fileName, contentType, fileBuffer, } = options;
2705
3274
  const blob = new Blob([new Uint8Array(fileBuffer)], { type: contentType });
2706
3275
  const formData = new FormData();
2707
- formData.append('testResultId', testResultId);
2708
- formData.append('ctrfAttachmentName', attachmentName);
2709
- formData.append('file', blob, fileName);
3276
+ formData.append("testResultId", testResultId);
3277
+ formData.append("ctrfAttachmentName", attachmentName);
3278
+ formData.append("file", blob, fileName);
2710
3279
  const response = await fetch(`${apiUrl}/api/v1/artifacts/${reportId}`, {
2711
- method: 'POST',
3280
+ method: "POST",
2712
3281
  headers: {
2713
- 'X-API-KEY': apiKey,
3282
+ "X-API-KEY": apiKey,
2714
3283
  },
2715
3284
  body: formData,
2716
3285
  });
@@ -2731,7 +3300,7 @@ function hasHeaderIgnoreCase(headers, headerName) {
2731
3300
 
2732
3301
  /***/ }),
2733
3302
 
2734
- /***/ 328:
3303
+ /***/ 4328:
2735
3304
  /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
2736
3305
 
2737
3306
  "use strict";
@@ -2771,14 +3340,14 @@ var __importStar = (this && this.__importStar) || (function () {
2771
3340
  })();
2772
3341
  Object.defineProperty(exports, "__esModule", ({ value: true }));
2773
3342
  const glob_1 = __nccwpck_require__(447);
2774
- const path = __importStar(__nccwpck_require__(928));
2775
- const fs = __importStar(__nccwpck_require__(943));
3343
+ const path = __importStar(__nccwpck_require__(6928));
3344
+ const fs = __importStar(__nccwpck_require__(1943));
2776
3345
  const os = __importStar(__nccwpck_require__(857));
2777
- const child_process_1 = __nccwpck_require__(317);
2778
- const trx_parser_1 = __nccwpck_require__(914);
2779
- const uploader_1 = __nccwpck_require__(10);
3346
+ const child_process_1 = __nccwpck_require__(5317);
3347
+ const trx_parser_1 = __nccwpck_require__(8914);
3348
+ const uploader_1 = __nccwpck_require__(8010);
2780
3349
  function printUsage() {
2781
- console.log(`
3350
+ console.log(String.raw `
2782
3351
  @testream/dotnet-reporter - Run .NET tests and upload results to Testream
2783
3352
 
2784
3353
  Usage:
@@ -2823,7 +3392,7 @@ Examples:
2823
3392
  npx @testream/dotnet-reporter -k your-api-key --project ./MyTests
2824
3393
 
2825
3394
  # With environment metadata
2826
- npx @testream/dotnet-reporter -k your-api-key \\
3395
+ npx @testream/dotnet-reporter -k your-api-key \
2827
3396
  --test-environment staging --app-name MyApp --app-version 1.0.0
2828
3397
 
2829
3398
  # Pass additional arguments to dotnet test
@@ -2960,15 +3529,15 @@ async function runDotnetTest(projectPath, additionalArgs = []) {
2960
3529
  const logger = console;
2961
3530
  // Create temp directory for TRX output
2962
3531
  const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'dotnet-reporter-'));
2963
- const trxFileName = `results-${Date.now()}.trx`;
2964
3532
  // Build dotnet test command
2965
3533
  const args = ['test'];
2966
3534
  if (projectPath) {
2967
3535
  args.push(projectPath);
2968
3536
  }
2969
- // Add TRX logger
2970
- args.push('--logger', `trx;LogFileName=${trxFileName}`);
2971
- args.push('--results-directory', tempDir);
3537
+ // Add TRX logger without a fixed filename so each test project gets a unique
3538
+ // TRX file. Specifying LogFileName causes all projects in a solution to write
3539
+ // to the same file, with later projects overwriting earlier ones.
3540
+ args.push('--logger', 'trx', '--results-directory', tempDir);
2972
3541
  // Add any additional user-provided args
2973
3542
  args.push(...additionalArgs);
2974
3543
  logger.info('Running dotnet test...');
@@ -3094,7 +3663,308 @@ main();
3094
3663
 
3095
3664
  /***/ }),
3096
3665
 
3097
- /***/ 914:
3666
+ /***/ 148:
3667
+ /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
3668
+
3669
+ "use strict";
3670
+
3671
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3672
+ return (mod && mod.__esModule) ? mod : { "default": mod };
3673
+ };
3674
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
3675
+ exports.createDotnetSourceSnippetResolver = createDotnetSourceSnippetResolver;
3676
+ exports.extractDotnetSourceSnippet = extractDotnetSourceSnippet;
3677
+ exports.resolveDotnetSourceSnippet = resolveDotnetSourceSnippet;
3678
+ const promises_1 = __nccwpck_require__(1455);
3679
+ const node_path_1 = __importDefault(__nccwpck_require__(6760));
3680
+ const DEFAULT_MAX_CHARS = 2000;
3681
+ const DEFAULT_MAX_LINES = 40;
3682
+ function createDotnetSourceSnippetResolver() {
3683
+ const cache = {
3684
+ candidateSourceFiles: new Map(),
3685
+ fileContentByPath: new Map(),
3686
+ };
3687
+ return {
3688
+ resolve: (options) => resolveDotnetSourceSnippet(options, cache),
3689
+ };
3690
+ }
3691
+ async function extractDotnetSourceSnippet(filePath, methodName, lineNumber) {
3692
+ const result = await resolveDotnetSourceSnippet({ filePath, methodName, lineNumber });
3693
+ return result?.snippet;
3694
+ }
3695
+ async function resolveDotnetSourceSnippet(options, cache) {
3696
+ if (!options.filePath || !options.methodName) {
3697
+ return undefined;
3698
+ }
3699
+ const direct = await tryExtractFromSourceFile(options.filePath, options.methodName, options.lineNumber, cache);
3700
+ if (direct) {
3701
+ return direct;
3702
+ }
3703
+ const candidates = await getCandidateSourceFiles(options.filePath, options.className, cache);
3704
+ for (const candidate of candidates) {
3705
+ const resolved = await tryExtractFromSourceFile(candidate, options.methodName, options.lineNumber, cache);
3706
+ if (resolved) {
3707
+ return resolved;
3708
+ }
3709
+ }
3710
+ return undefined;
3711
+ }
3712
+ async function tryExtractFromSourceFile(filePath, methodName, lineNumber, cache) {
3713
+ if (node_path_1.default.extname(filePath).toLowerCase() !== '.cs') {
3714
+ return undefined;
3715
+ }
3716
+ const resolvedPath = node_path_1.default.resolve(filePath);
3717
+ const content = await getFileContent(resolvedPath, cache);
3718
+ if (!content) {
3719
+ return undefined;
3720
+ }
3721
+ for (const candidateMethodName of getMethodNameCandidates(methodName)) {
3722
+ const extracted = extractCSharpMethodBlock(content, candidateMethodName, lineNumber);
3723
+ if (extracted) {
3724
+ return { filePath: resolvedPath, ...extracted };
3725
+ }
3726
+ }
3727
+ return undefined;
3728
+ }
3729
+ function getFileContent(filePath, cache) {
3730
+ if (!cache) {
3731
+ return (0, promises_1.readFile)(filePath, 'utf-8').catch(() => undefined);
3732
+ }
3733
+ let cached = cache.fileContentByPath.get(filePath);
3734
+ if (!cached) {
3735
+ cached = (0, promises_1.readFile)(filePath, 'utf-8').catch(() => undefined);
3736
+ cache.fileContentByPath.set(filePath, cached);
3737
+ }
3738
+ return cached;
3739
+ }
3740
+ function extractCSharpMethodBlock(content, methodName, lineNumber) {
3741
+ const lines = content.split(/\r?\n/);
3742
+ const definitionIndex = findMethodDefinitionNearLine(lines, methodName, lineNumber) ??
3743
+ findMethodDefinition(lines, methodName);
3744
+ if (definitionIndex == null) {
3745
+ return undefined;
3746
+ }
3747
+ const start = includeCSharpAttributes(lines, definitionIndex);
3748
+ const selected = [];
3749
+ let braceBalance = 0;
3750
+ let sawOpeningBrace = false;
3751
+ let isExpressionBodied = false;
3752
+ for (let i = start; i < lines.length && selected.length < DEFAULT_MAX_LINES; i++) {
3753
+ const line = lines[i];
3754
+ selected.push(line);
3755
+ if (!sawOpeningBrace && line.includes('=>')) {
3756
+ isExpressionBodied = true;
3757
+ }
3758
+ for (const char of line) {
3759
+ if (char === '{') {
3760
+ braceBalance++;
3761
+ sawOpeningBrace = true;
3762
+ }
3763
+ else if (char === '}') {
3764
+ braceBalance--;
3765
+ }
3766
+ }
3767
+ if (isExpressionBodied && line.includes(';')) {
3768
+ break;
3769
+ }
3770
+ if (sawOpeningBrace && braceBalance <= 0) {
3771
+ break;
3772
+ }
3773
+ }
3774
+ const snippet = selected.join('\n').trim();
3775
+ if (!snippet) {
3776
+ return undefined;
3777
+ }
3778
+ return {
3779
+ line: start + 1,
3780
+ snippet: snippet.length <= DEFAULT_MAX_CHARS ? snippet : snippet.slice(0, DEFAULT_MAX_CHARS),
3781
+ };
3782
+ }
3783
+ function findMethodDefinitionNearLine(lines, methodName, lineNumber) {
3784
+ if (!lineNumber) {
3785
+ return undefined;
3786
+ }
3787
+ const startIndex = Math.max(0, Math.min(lines.length - 1, lineNumber - 1));
3788
+ for (let i = startIndex; i >= 0; i--) {
3789
+ if (containsMethodSignatureName(lines[i], methodName)) {
3790
+ return i;
3791
+ }
3792
+ }
3793
+ return undefined;
3794
+ }
3795
+ function findMethodDefinition(lines, methodName) {
3796
+ for (let i = 0; i < lines.length; i++) {
3797
+ if (containsMethodSignatureName(lines[i], methodName)) {
3798
+ return i;
3799
+ }
3800
+ }
3801
+ return undefined;
3802
+ }
3803
+ function containsMethodSignatureName(line, methodName) {
3804
+ const nameIndex = line.indexOf(methodName);
3805
+ if (nameIndex < 0) {
3806
+ return false;
3807
+ }
3808
+ const before = nameIndex === 0 ? '' : line[nameIndex - 1];
3809
+ if (before && isIdentifierChar(before)) {
3810
+ return false;
3811
+ }
3812
+ let i = nameIndex + methodName.length;
3813
+ while (i < line.length && /\s/.test(line[i])) {
3814
+ i++;
3815
+ }
3816
+ return line[i] === '(';
3817
+ }
3818
+ function includeCSharpAttributes(lines, definitionIndex) {
3819
+ let start = definitionIndex;
3820
+ while (start > 0) {
3821
+ const previous = lines[start - 1].trim();
3822
+ if (!previous.startsWith('[') || !previous.endsWith(']')) {
3823
+ break;
3824
+ }
3825
+ start--;
3826
+ }
3827
+ return start;
3828
+ }
3829
+ function getMethodNameCandidates(methodName) {
3830
+ const trimmed = methodName.trim();
3831
+ const candidates = [trimmed];
3832
+ const invocationIndex = trimmed.indexOf('(');
3833
+ // NUnit can put TestCase argument values in TestMethod/@name, e.g.
3834
+ // Password_MinimumLength_Validation("pass",False). Source matching needs
3835
+ // the underlying C# method identifier.
3836
+ if (invocationIndex > 0) {
3837
+ const sourceMethodName = trimmed.slice(0, invocationIndex).trim();
3838
+ if (sourceMethodName && sourceMethodName !== trimmed) {
3839
+ candidates.push(sourceMethodName);
3840
+ }
3841
+ }
3842
+ return candidates;
3843
+ }
3844
+ async function findCandidateSourceFiles(storagePath, className) {
3845
+ const sourceRoot = getProjectSourceRootFromStorage(storagePath);
3846
+ if (!sourceRoot) {
3847
+ return [];
3848
+ }
3849
+ const resolvedSourceRoot = await resolveExistingDirectoryCaseInsensitive(sourceRoot);
3850
+ if (!resolvedSourceRoot) {
3851
+ return [];
3852
+ }
3853
+ const files = await listCSharpFiles(resolvedSourceRoot);
3854
+ const classFileName = getClassFileName(className);
3855
+ if (!classFileName) {
3856
+ return files;
3857
+ }
3858
+ // TRX commonly stores passed tests against the compiled DLL. Prefer the class
3859
+ // filename when available, then fall back to every source file for cases where
3860
+ // a project keeps multiple test classes in one file.
3861
+ return [
3862
+ ...files.filter((file) => node_path_1.default.basename(file).toLowerCase() === classFileName),
3863
+ ...files.filter((file) => node_path_1.default.basename(file).toLowerCase() !== classFileName),
3864
+ ];
3865
+ }
3866
+ function getCandidateSourceFiles(storagePath, className, cache) {
3867
+ if (!cache) {
3868
+ return findCandidateSourceFiles(storagePath, className);
3869
+ }
3870
+ const key = `${node_path_1.default.resolve(storagePath)}\0${className ?? ''}`;
3871
+ let cached = cache.candidateSourceFiles.get(key);
3872
+ if (!cached) {
3873
+ cached = findCandidateSourceFiles(storagePath, className);
3874
+ cache.candidateSourceFiles.set(key, cached);
3875
+ }
3876
+ return cached;
3877
+ }
3878
+ function getProjectSourceRootFromStorage(storagePath) {
3879
+ const resolved = node_path_1.default.resolve(storagePath);
3880
+ const parts = resolved.split(node_path_1.default.sep);
3881
+ // /Project/bin/Debug/net8.0/Project.dll is the normal TRX storage path for
3882
+ // passed tests, so the source root is the directory before bin/.
3883
+ const binIndex = parts.findIndex((part) => part.toLowerCase() === 'bin');
3884
+ if (binIndex <= 0) {
3885
+ return undefined;
3886
+ }
3887
+ return parts.slice(0, binIndex).join(node_path_1.default.sep) || node_path_1.default.sep;
3888
+ }
3889
+ async function resolveExistingDirectoryCaseInsensitive(dirPath) {
3890
+ try {
3891
+ await (0, promises_1.readdir)(dirPath, { withFileTypes: true });
3892
+ return dirPath;
3893
+ }
3894
+ catch {
3895
+ // TRX storage paths can lowercase project output paths on Linux
3896
+ // (`mstesttests/bin/...`) while the checked-out source directory is
3897
+ // case-sensitive (`MSTestTests`). Walk each segment case-insensitively so
3898
+ // passed tests can still resolve their project source root.
3899
+ }
3900
+ const resolved = node_path_1.default.resolve(dirPath);
3901
+ const parsed = node_path_1.default.parse(resolved);
3902
+ const relativeParts = node_path_1.default.relative(parsed.root, resolved).split(node_path_1.default.sep).filter(Boolean);
3903
+ let current = parsed.root;
3904
+ for (const part of relativeParts) {
3905
+ let entries;
3906
+ try {
3907
+ entries = await (0, promises_1.readdir)(current, { withFileTypes: true });
3908
+ }
3909
+ catch {
3910
+ return undefined;
3911
+ }
3912
+ const match = entries.find((entry) => entry.name === part) ??
3913
+ entries.find((entry) => entry.name.toLowerCase() === part.toLowerCase());
3914
+ if (!match) {
3915
+ return undefined;
3916
+ }
3917
+ current = node_path_1.default.join(current, match.name);
3918
+ }
3919
+ try {
3920
+ await (0, promises_1.readdir)(current, { withFileTypes: true });
3921
+ return current;
3922
+ }
3923
+ catch {
3924
+ return undefined;
3925
+ }
3926
+ }
3927
+ async function listCSharpFiles(root) {
3928
+ const files = [];
3929
+ async function visit(dir) {
3930
+ let entries;
3931
+ try {
3932
+ entries = await (0, promises_1.readdir)(dir, { withFileTypes: true });
3933
+ }
3934
+ catch {
3935
+ return;
3936
+ }
3937
+ for (const entry of entries) {
3938
+ const entryPath = node_path_1.default.join(dir, entry.name);
3939
+ if (entry.isDirectory()) {
3940
+ const lowerName = entry.name.toLowerCase();
3941
+ if (lowerName === 'bin' || lowerName === 'obj') {
3942
+ continue;
3943
+ }
3944
+ await visit(entryPath);
3945
+ continue;
3946
+ }
3947
+ if (entry.isFile() && node_path_1.default.extname(entry.name).toLowerCase() === '.cs') {
3948
+ files.push(entryPath);
3949
+ }
3950
+ }
3951
+ }
3952
+ await visit(root);
3953
+ return files;
3954
+ }
3955
+ function getClassFileName(className) {
3956
+ const shortName = className?.split(/[.+]/).filter(Boolean).pop();
3957
+ return shortName ? `${shortName.toLowerCase()}.cs` : undefined;
3958
+ }
3959
+ function isIdentifierChar(char) {
3960
+ // Prevent matching a method name inside another common C# identifier.
3961
+ return /[A-Za-z0-9_]/.test(char);
3962
+ }
3963
+
3964
+
3965
+ /***/ }),
3966
+
3967
+ /***/ 8914:
3098
3968
  /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
3099
3969
 
3100
3970
  "use strict";
@@ -3135,16 +4005,14 @@ var __importStar = (this && this.__importStar) || (function () {
3135
4005
  Object.defineProperty(exports, "__esModule", ({ value: true }));
3136
4006
  exports.parseTrxFile = parseTrxFile;
3137
4007
  exports.parseTrxFiles = parseTrxFiles;
3138
- const fs = __importStar(__nccwpck_require__(943));
3139
- const fast_xml_parser_1 = __nccwpck_require__(537);
4008
+ const fs = __importStar(__nccwpck_require__(1455));
4009
+ const fast_xml_parser_1 = __nccwpck_require__(1537);
4010
+ const node_crypto_1 = __nccwpck_require__(7598);
4011
+ const source_snippets_1 = __nccwpck_require__(148);
3140
4012
  const TOOL_NAME = 'dotnet';
3141
- // Simple UUID v4 generator (avoid extra dependency)
4013
+ // Use crypto.randomUUID() for secure UUID generation (available in Node.js 15.7.0+)
3142
4014
  function generateUUID() {
3143
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
3144
- const r = (Math.random() * 16) | 0;
3145
- const v = c === 'x' ? r : (r & 0x3) | 0x8;
3146
- return v.toString(16);
3147
- });
4015
+ return (0, node_crypto_1.randomUUID)();
3148
4016
  }
3149
4017
  /**
3150
4018
  * Parse TRX duration string (HH:MM:SS.mmmmmmm) to milliseconds
@@ -3152,13 +4020,22 @@ function generateUUID() {
3152
4020
  function parseDuration(duration) {
3153
4021
  if (!duration)
3154
4022
  return 0;
3155
- const match = duration.match(/^(\d+):(\d+):(\d+)\.?(\d+)?$/);
3156
- if (!match)
4023
+ // Use split() instead of regex to avoid ReDoS vulnerability
4024
+ const parts = duration.split(':');
4025
+ if (parts.length !== 3)
3157
4026
  return 0;
3158
- const hours = parseInt(match[1], 10);
3159
- const minutes = parseInt(match[2], 10);
3160
- const seconds = parseInt(match[3], 10);
3161
- const fraction = match[4] ? parseFloat(`0.${match[4]}`) * 1000 : 0;
4027
+ const hours = parseInt(parts[0], 10);
4028
+ if (Number.isNaN(hours))
4029
+ return 0;
4030
+ const minutes = parseInt(parts[1], 10);
4031
+ if (Number.isNaN(minutes))
4032
+ return 0;
4033
+ // Handle seconds and fractional part (may contain decimal point)
4034
+ const secondsParts = parts[2].split('.');
4035
+ const seconds = Number.parseInt(secondsParts[0], 10);
4036
+ if (Number.isNaN(seconds))
4037
+ return 0;
4038
+ const fraction = secondsParts[1] ? parseFloat(`0.${secondsParts[1]}`) * 1000 : 0;
3162
4039
  return hours * 3600000 + minutes * 60000 + seconds * 1000 + Math.round(fraction);
3163
4040
  }
3164
4041
  /**
@@ -3168,7 +4045,7 @@ function parseTimestamp(dateStr) {
3168
4045
  if (!dateStr)
3169
4046
  return Date.now();
3170
4047
  const date = new Date(dateStr);
3171
- return isNaN(date.getTime()) ? Date.now() : date.getTime();
4048
+ return Number.isNaN(date.getTime()) ? Date.now() : date.getTime();
3172
4049
  }
3173
4050
  /**
3174
4051
  * Map TRX outcome to CTRF status
@@ -3196,9 +4073,9 @@ function extractLineNumber(stackTrace) {
3196
4073
  if (!stackTrace)
3197
4074
  return undefined;
3198
4075
  // Match patterns like ":line 79" or ".cs:79"
3199
- const match = stackTrace.match(/:line (\d+)|\.cs:(\d+)/i);
4076
+ const match = new RegExp(/:line (\d+)|\.cs:(\d+)/i).exec(stackTrace);
3200
4077
  if (match) {
3201
- return parseInt(match[1] || match[2], 10);
4078
+ return Number.parseInt(match[1] || match[2], 10);
3202
4079
  }
3203
4080
  return undefined;
3204
4081
  }
@@ -3208,8 +4085,8 @@ function extractLineNumber(stackTrace) {
3208
4085
  function extractFilePath(stackTrace) {
3209
4086
  if (!stackTrace)
3210
4087
  return undefined;
3211
- // Match file paths ending in .cs
3212
- const match = stackTrace.match(/([A-Za-z]:\\[^\s:]+\.cs|\/[^\s:]+\.cs)/);
4088
+ // Match file paths ending in .cs with bounded length to prevent ReDoS
4089
+ const match = new RegExp(/([A-Za-z]:\\[^\s:]{1,256}\.cs|\/[^\s:]{1,256}\.cs)/).exec(stackTrace);
3213
4090
  return match ? match[1] : undefined;
3214
4091
  }
3215
4092
  /**
@@ -3243,6 +4120,7 @@ async function parseTrxFile(trxPath) {
3243
4120
  // Parse test results
3244
4121
  const results = testRun.Results?.UnitTestResult || [];
3245
4122
  const tests = [];
4123
+ const sourceSnippetResolver = (0, source_snippets_1.createDotnetSourceSnippetResolver)();
3246
4124
  let passed = 0;
3247
4125
  let failed = 0;
3248
4126
  let skipped = 0;
@@ -3280,6 +4158,15 @@ async function parseTrxFile(trxPath) {
3280
4158
  const stackTrace = result.Output?.ErrorInfo?.StackTrace;
3281
4159
  const stdout = result.Output?.StdOut;
3282
4160
  const stderr = result.Output?.StdErr;
4161
+ const stackTraceFilePath = extractFilePath(stackTrace);
4162
+ const storagePath = testDef?.['@_storage'];
4163
+ const line = extractLineNumber(stackTrace);
4164
+ const sourceSnippet = await sourceSnippetResolver.resolve({
4165
+ filePath: stackTraceFilePath || storagePath,
4166
+ className,
4167
+ methodName: testDef?.TestMethod?.['@_name'],
4168
+ lineNumber: line,
4169
+ });
3283
4170
  const test = {
3284
4171
  name: result['@_testName'],
3285
4172
  status,
@@ -3296,8 +4183,9 @@ async function parseTrxFile(trxPath) {
3296
4183
  stderr: stderr ? [stderr] : [],
3297
4184
  message: errorMessage,
3298
4185
  trace: stackTrace,
3299
- line: extractLineNumber(stackTrace),
3300
- filePath: extractFilePath(stackTrace) || testDef?.['@_storage'],
4186
+ line: line ?? sourceSnippet?.line,
4187
+ filePath: sourceSnippet?.filePath ?? stackTraceFilePath ?? storagePath,
4188
+ snippet: sourceSnippet?.snippet,
3301
4189
  };
3302
4190
  tests.push(test);
3303
4191
  }
@@ -3401,7 +4289,7 @@ async function parseTrxFiles(trxPaths) {
3401
4289
 
3402
4290
  /***/ }),
3403
4291
 
3404
- /***/ 10:
4292
+ /***/ 8010:
3405
4293
  /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
3406
4294
 
3407
4295
  "use strict";
@@ -3409,7 +4297,7 @@ async function parseTrxFiles(trxPaths) {
3409
4297
  Object.defineProperty(exports, "__esModule", ({ value: true }));
3410
4298
  exports.detectGitContext = void 0;
3411
4299
  exports.uploadToApi = uploadToApi;
3412
- const shared_types_1 = __nccwpck_require__(322);
4300
+ const shared_types_1 = __nccwpck_require__(7322);
3413
4301
  /**
3414
4302
  * Upload CTRF report to Testream API
3415
4303
  */
@@ -3436,7 +4324,7 @@ exports.detectGitContext = shared_types_1.detectCIContext;
3436
4324
 
3437
4325
  /***/ }),
3438
4326
 
3439
- /***/ 317:
4327
+ /***/ 5317:
3440
4328
  /***/ ((module) => {
3441
4329
 
3442
4330
  "use strict";
@@ -3444,7 +4332,7 @@ module.exports = require("child_process");
3444
4332
 
3445
4333
  /***/ }),
3446
4334
 
3447
- /***/ 896:
4335
+ /***/ 9896:
3448
4336
  /***/ ((module) => {
3449
4337
 
3450
4338
  "use strict";
@@ -3452,7 +4340,7 @@ module.exports = require("fs");
3452
4340
 
3453
4341
  /***/ }),
3454
4342
 
3455
- /***/ 943:
4343
+ /***/ 1943:
3456
4344
  /***/ ((module) => {
3457
4345
 
3458
4346
  "use strict";
@@ -3460,7 +4348,15 @@ module.exports = require("fs/promises");
3460
4348
 
3461
4349
  /***/ }),
3462
4350
 
3463
- /***/ 474:
4351
+ /***/ 7598:
4352
+ /***/ ((module) => {
4353
+
4354
+ "use strict";
4355
+ module.exports = require("node:crypto");
4356
+
4357
+ /***/ }),
4358
+
4359
+ /***/ 8474:
3464
4360
  /***/ ((module) => {
3465
4361
 
3466
4362
  "use strict";
@@ -3468,7 +4364,7 @@ module.exports = require("node:events");
3468
4364
 
3469
4365
  /***/ }),
3470
4366
 
3471
- /***/ 24:
4367
+ /***/ 3024:
3472
4368
  /***/ ((module) => {
3473
4369
 
3474
4370
  "use strict";
@@ -3476,7 +4372,7 @@ module.exports = require("node:fs");
3476
4372
 
3477
4373
  /***/ }),
3478
4374
 
3479
- /***/ 455:
4375
+ /***/ 1455:
3480
4376
  /***/ ((module) => {
3481
4377
 
3482
4378
  "use strict";
@@ -3484,7 +4380,7 @@ module.exports = require("node:fs/promises");
3484
4380
 
3485
4381
  /***/ }),
3486
4382
 
3487
- /***/ 760:
4383
+ /***/ 6760:
3488
4384
  /***/ ((module) => {
3489
4385
 
3490
4386
  "use strict";
@@ -3492,7 +4388,7 @@ module.exports = require("node:path");
3492
4388
 
3493
4389
  /***/ }),
3494
4390
 
3495
- /***/ 75:
4391
+ /***/ 7075:
3496
4392
  /***/ ((module) => {
3497
4393
 
3498
4394
  "use strict";
@@ -3500,7 +4396,7 @@ module.exports = require("node:stream");
3500
4396
 
3501
4397
  /***/ }),
3502
4398
 
3503
- /***/ 193:
4399
+ /***/ 6193:
3504
4400
  /***/ ((module) => {
3505
4401
 
3506
4402
  "use strict";
@@ -3508,7 +4404,7 @@ module.exports = require("node:string_decoder");
3508
4404
 
3509
4405
  /***/ }),
3510
4406
 
3511
- /***/ 136:
4407
+ /***/ 3136:
3512
4408
  /***/ ((module) => {
3513
4409
 
3514
4410
  "use strict";
@@ -3524,7 +4420,7 @@ module.exports = require("os");
3524
4420
 
3525
4421
  /***/ }),
3526
4422
 
3527
- /***/ 928:
4423
+ /***/ 6928:
3528
4424
  /***/ ((module) => {
3529
4425
 
3530
4426
  "use strict";
@@ -3532,7 +4428,7 @@ module.exports = require("path");
3532
4428
 
3533
4429
  /***/ }),
3534
4430
 
3535
- /***/ 80:
4431
+ /***/ 7080:
3536
4432
  /***/ ((__unused_webpack_module, exports) => {
3537
4433
 
3538
4434
  "use strict";
@@ -3598,14 +4494,14 @@ exports.range = range;
3598
4494
 
3599
4495
  /***/ }),
3600
4496
 
3601
- /***/ 339:
4497
+ /***/ 2339:
3602
4498
  /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
3603
4499
 
3604
4500
  "use strict";
3605
4501
 
3606
4502
  Object.defineProperty(exports, "__esModule", ({ value: true }));
3607
4503
  exports.expand = expand;
3608
- const balanced_match_1 = __nccwpck_require__(80);
4504
+ const balanced_match_1 = __nccwpck_require__(7080);
3609
4505
  const escSlash = '\0SLASH' + Math.random() + '\0';
3610
4506
  const escOpen = '\0OPEN' + Math.random() + '\0';
3611
4507
  const escClose = '\0CLOSE' + Math.random() + '\0';
@@ -3801,18 +4697,18 @@ function expand_(str, isTop) {
3801
4697
 
3802
4698
  /***/ }),
3803
4699
 
3804
- /***/ 809:
4700
+ /***/ 8809:
3805
4701
  /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
3806
4702
 
3807
4703
  "use strict";
3808
4704
 
3809
4705
  Object.defineProperty(exports, "__esModule", ({ value: true }));
3810
4706
  exports.Glob = void 0;
3811
- const minimatch_1 = __nccwpck_require__(647);
3812
- const node_url_1 = __nccwpck_require__(136);
3813
- const path_scurry_1 = __nccwpck_require__(125);
3814
- const pattern_js_1 = __nccwpck_require__(841);
3815
- const walker_js_1 = __nccwpck_require__(89);
4707
+ const minimatch_1 = __nccwpck_require__(6647);
4708
+ const node_url_1 = __nccwpck_require__(3136);
4709
+ const path_scurry_1 = __nccwpck_require__(5125);
4710
+ const pattern_js_1 = __nccwpck_require__(2841);
4711
+ const walker_js_1 = __nccwpck_require__(6089);
3816
4712
  // if no process global, just call it linux.
3817
4713
  // so we default to case-sensitive, / separators
3818
4714
  const defaultPlatform = (typeof process === 'object' &&
@@ -4055,14 +4951,14 @@ exports.Glob = Glob;
4055
4951
 
4056
4952
  /***/ }),
4057
4953
 
4058
- /***/ 233:
4954
+ /***/ 6233:
4059
4955
  /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
4060
4956
 
4061
4957
  "use strict";
4062
4958
 
4063
4959
  Object.defineProperty(exports, "__esModule", ({ value: true }));
4064
4960
  exports.hasMagic = void 0;
4065
- const minimatch_1 = __nccwpck_require__(647);
4961
+ const minimatch_1 = __nccwpck_require__(6647);
4066
4962
  /**
4067
4963
  * Return true if the patterns provided contain any magic glob characters,
4068
4964
  * given the options provided.
@@ -4089,7 +4985,7 @@ exports.hasMagic = hasMagic;
4089
4985
 
4090
4986
  /***/ }),
4091
4987
 
4092
- /***/ 449:
4988
+ /***/ 6449:
4093
4989
  /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
4094
4990
 
4095
4991
  "use strict";
@@ -4100,8 +4996,8 @@ exports.hasMagic = hasMagic;
4100
4996
  // Ignores are always parsed in dot:true mode
4101
4997
  Object.defineProperty(exports, "__esModule", ({ value: true }));
4102
4998
  exports.Ignore = void 0;
4103
- const minimatch_1 = __nccwpck_require__(647);
4104
- const pattern_js_1 = __nccwpck_require__(841);
4999
+ const minimatch_1 = __nccwpck_require__(6647);
5000
+ const pattern_js_1 = __nccwpck_require__(2841);
4105
5001
  const defaultPlatform = (typeof process === 'object' &&
4106
5002
  process &&
4107
5003
  typeof process.platform === 'string') ?
@@ -4227,17 +5123,17 @@ exports.globStream = globStream;
4227
5123
  exports.globSync = globSync;
4228
5124
  exports.globIterateSync = globIterateSync;
4229
5125
  exports.globIterate = globIterate;
4230
- const minimatch_1 = __nccwpck_require__(647);
4231
- const glob_js_1 = __nccwpck_require__(809);
4232
- const has_magic_js_1 = __nccwpck_require__(233);
4233
- var minimatch_2 = __nccwpck_require__(647);
5126
+ const minimatch_1 = __nccwpck_require__(6647);
5127
+ const glob_js_1 = __nccwpck_require__(8809);
5128
+ const has_magic_js_1 = __nccwpck_require__(6233);
5129
+ var minimatch_2 = __nccwpck_require__(6647);
4234
5130
  Object.defineProperty(exports, "escape", ({ enumerable: true, get: function () { return minimatch_2.escape; } }));
4235
5131
  Object.defineProperty(exports, "unescape", ({ enumerable: true, get: function () { return minimatch_2.unescape; } }));
4236
- var glob_js_2 = __nccwpck_require__(809);
5132
+ var glob_js_2 = __nccwpck_require__(8809);
4237
5133
  Object.defineProperty(exports, "Glob", ({ enumerable: true, get: function () { return glob_js_2.Glob; } }));
4238
- var has_magic_js_2 = __nccwpck_require__(233);
5134
+ var has_magic_js_2 = __nccwpck_require__(6233);
4239
5135
  Object.defineProperty(exports, "hasMagic", ({ enumerable: true, get: function () { return has_magic_js_2.hasMagic; } }));
4240
- var ignore_js_1 = __nccwpck_require__(449);
5136
+ var ignore_js_1 = __nccwpck_require__(6449);
4241
5137
  Object.defineProperty(exports, "Ignore", ({ enumerable: true, get: function () { return ignore_js_1.Ignore; } }));
4242
5138
  function globStreamSync(pattern, options = {}) {
4243
5139
  return new glob_js_1.Glob(pattern, options).streamSync();
@@ -4290,7 +5186,7 @@ exports.glob.glob = exports.glob;
4290
5186
 
4291
5187
  /***/ }),
4292
5188
 
4293
- /***/ 841:
5189
+ /***/ 2841:
4294
5190
  /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
4295
5191
 
4296
5192
  "use strict";
@@ -4298,7 +5194,7 @@ exports.glob.glob = exports.glob;
4298
5194
  // this is just a very light wrapper around 2 arrays with an offset index
4299
5195
  Object.defineProperty(exports, "__esModule", ({ value: true }));
4300
5196
  exports.Pattern = void 0;
4301
- const minimatch_1 = __nccwpck_require__(647);
5197
+ const minimatch_1 = __nccwpck_require__(6647);
4302
5198
  const isPatternList = (pl) => pl.length >= 1;
4303
5199
  const isGlobList = (gl) => gl.length >= 1;
4304
5200
  /**
@@ -4516,7 +5412,7 @@ exports.Pattern = Pattern;
4516
5412
 
4517
5413
  /***/ }),
4518
5414
 
4519
- /***/ 999:
5415
+ /***/ 7999:
4520
5416
  /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
4521
5417
 
4522
5418
  "use strict";
@@ -4524,7 +5420,7 @@ exports.Pattern = Pattern;
4524
5420
  // synchronous utility for filtering entries and calculating subwalks
4525
5421
  Object.defineProperty(exports, "__esModule", ({ value: true }));
4526
5422
  exports.Processor = exports.SubWalks = exports.MatchRecord = exports.HasWalkedCache = void 0;
4527
- const minimatch_1 = __nccwpck_require__(647);
5423
+ const minimatch_1 = __nccwpck_require__(6647);
4528
5424
  /**
4529
5425
  * A cache of which patterns have been processed for a given Path
4530
5426
  */
@@ -4824,7 +5720,7 @@ exports.Processor = Processor;
4824
5720
 
4825
5721
  /***/ }),
4826
5722
 
4827
- /***/ 89:
5723
+ /***/ 6089:
4828
5724
  /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
4829
5725
 
4830
5726
  "use strict";
@@ -4837,9 +5733,9 @@ exports.GlobStream = exports.GlobWalker = exports.GlobUtil = void 0;
4837
5733
  *
4838
5734
  * @module
4839
5735
  */
4840
- const minipass_1 = __nccwpck_require__(31);
4841
- const ignore_js_1 = __nccwpck_require__(449);
4842
- const processor_js_1 = __nccwpck_require__(999);
5736
+ const minipass_1 = __nccwpck_require__(1031);
5737
+ const ignore_js_1 = __nccwpck_require__(6449);
5738
+ const processor_js_1 = __nccwpck_require__(7999);
4843
5739
  const makeIgnore = (ignore, opts) => typeof ignore === 'string' ? new ignore_js_1.Ignore([ignore], opts)
4844
5740
  : Array.isArray(ignore) ? new ignore_js_1.Ignore(ignore, opts)
4845
5741
  : ignore;
@@ -5218,7 +6114,7 @@ exports.GlobStream = GlobStream;
5218
6114
 
5219
6115
  /***/ }),
5220
6116
 
5221
- /***/ 481:
6117
+ /***/ 3481:
5222
6118
  /***/ ((__unused_webpack_module, exports) => {
5223
6119
 
5224
6120
  "use strict";
@@ -6831,7 +7727,7 @@ exports.assertValidPattern = assertValidPattern;
6831
7727
 
6832
7728
  /***/ }),
6833
7729
 
6834
- /***/ 743:
7730
+ /***/ 8743:
6835
7731
  /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
6836
7732
 
6837
7733
  "use strict";
@@ -6839,8 +7735,8 @@ exports.assertValidPattern = assertValidPattern;
6839
7735
  // parse a single path portion
6840
7736
  Object.defineProperty(exports, "__esModule", ({ value: true }));
6841
7737
  exports.AST = void 0;
6842
- const brace_expressions_js_1 = __nccwpck_require__(694);
6843
- const unescape_js_1 = __nccwpck_require__(967);
7738
+ const brace_expressions_js_1 = __nccwpck_require__(6694);
7739
+ const unescape_js_1 = __nccwpck_require__(7967);
6844
7740
  const types = new Set(['!', '?', '+', '*', '@']);
6845
7741
  const isExtglobType = (c) => types.has(c);
6846
7742
  // Patterns that get prepended to bind to the start of either the
@@ -7429,7 +8325,7 @@ exports.AST = AST;
7429
8325
 
7430
8326
  /***/ }),
7431
8327
 
7432
- /***/ 694:
8328
+ /***/ 6694:
7433
8329
  /***/ ((__unused_webpack_module, exports) => {
7434
8330
 
7435
8331
  "use strict";
@@ -7588,7 +8484,7 @@ exports.parseClass = parseClass;
7588
8484
 
7589
8485
  /***/ }),
7590
8486
 
7591
- /***/ 516:
8487
+ /***/ 7516:
7592
8488
  /***/ ((__unused_webpack_module, exports) => {
7593
8489
 
7594
8490
  "use strict";
@@ -7625,18 +8521,18 @@ exports.escape = escape;
7625
8521
 
7626
8522
  /***/ }),
7627
8523
 
7628
- /***/ 647:
8524
+ /***/ 6647:
7629
8525
  /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
7630
8526
 
7631
8527
  "use strict";
7632
8528
 
7633
8529
  Object.defineProperty(exports, "__esModule", ({ value: true }));
7634
8530
  exports.unescape = exports.escape = exports.AST = exports.Minimatch = exports.match = exports.makeRe = exports.braceExpand = exports.defaults = exports.filter = exports.GLOBSTAR = exports.sep = exports.minimatch = void 0;
7635
- const brace_expansion_1 = __nccwpck_require__(339);
8531
+ const brace_expansion_1 = __nccwpck_require__(2339);
7636
8532
  const assert_valid_pattern_js_1 = __nccwpck_require__(557);
7637
- const ast_js_1 = __nccwpck_require__(743);
7638
- const escape_js_1 = __nccwpck_require__(516);
7639
- const unescape_js_1 = __nccwpck_require__(967);
8533
+ const ast_js_1 = __nccwpck_require__(8743);
8534
+ const escape_js_1 = __nccwpck_require__(7516);
8535
+ const unescape_js_1 = __nccwpck_require__(7967);
7640
8536
  const minimatch = (p, pattern, options = {}) => {
7641
8537
  (0, assert_valid_pattern_js_1.assertValidPattern)(pattern);
7642
8538
  // shortcut: comments match nothing.
@@ -8646,11 +9542,11 @@ class Minimatch {
8646
9542
  }
8647
9543
  exports.Minimatch = Minimatch;
8648
9544
  /* c8 ignore start */
8649
- var ast_js_2 = __nccwpck_require__(743);
9545
+ var ast_js_2 = __nccwpck_require__(8743);
8650
9546
  Object.defineProperty(exports, "AST", ({ enumerable: true, get: function () { return ast_js_2.AST; } }));
8651
- var escape_js_2 = __nccwpck_require__(516);
9547
+ var escape_js_2 = __nccwpck_require__(7516);
8652
9548
  Object.defineProperty(exports, "escape", ({ enumerable: true, get: function () { return escape_js_2.escape; } }));
8653
- var unescape_js_2 = __nccwpck_require__(967);
9549
+ var unescape_js_2 = __nccwpck_require__(7967);
8654
9550
  Object.defineProperty(exports, "unescape", ({ enumerable: true, get: function () { return unescape_js_2.unescape; } }));
8655
9551
  /* c8 ignore stop */
8656
9552
  exports.minimatch.AST = ast_js_1.AST;
@@ -8661,7 +9557,7 @@ exports.minimatch.unescape = unescape_js_1.unescape;
8661
9557
 
8662
9558
  /***/ }),
8663
9559
 
8664
- /***/ 967:
9560
+ /***/ 7967:
8665
9561
  /***/ ((__unused_webpack_module, exports) => {
8666
9562
 
8667
9563
  "use strict";
@@ -8706,7 +9602,7 @@ exports.unescape = unescape;
8706
9602
 
8707
9603
  /***/ }),
8708
9604
 
8709
- /***/ 31:
9605
+ /***/ 1031:
8710
9606
  /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
8711
9607
 
8712
9608
  "use strict";
@@ -8722,9 +9618,9 @@ const proc = typeof process === 'object' && process
8722
9618
  stdout: null,
8723
9619
  stderr: null,
8724
9620
  };
8725
- const node_events_1 = __nccwpck_require__(474);
8726
- const node_stream_1 = __importDefault(__nccwpck_require__(75));
8727
- const node_string_decoder_1 = __nccwpck_require__(193);
9621
+ const node_events_1 = __nccwpck_require__(8474);
9622
+ const node_stream_1 = __importDefault(__nccwpck_require__(7075));
9623
+ const node_string_decoder_1 = __nccwpck_require__(6193);
8728
9624
  /**
8729
9625
  * Return true if the argument is a Minipass stream, Node stream, or something
8730
9626
  * else that Minipass can interact with.
@@ -9741,7 +10637,7 @@ exports.Minipass = Minipass;
9741
10637
 
9742
10638
  /***/ }),
9743
10639
 
9744
- /***/ 125:
10640
+ /***/ 5125:
9745
10641
  /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
9746
10642
 
9747
10643
  "use strict";
@@ -9771,16 +10667,16 @@ var __importStar = (this && this.__importStar) || function (mod) {
9771
10667
  };
9772
10668
  Object.defineProperty(exports, "__esModule", ({ value: true }));
9773
10669
  exports.PathScurry = exports.Path = exports.PathScurryDarwin = exports.PathScurryPosix = exports.PathScurryWin32 = exports.PathScurryBase = exports.PathPosix = exports.PathWin32 = exports.PathBase = exports.ChildrenCache = exports.ResolveCache = void 0;
9774
- const lru_cache_1 = __nccwpck_require__(481);
9775
- const node_path_1 = __nccwpck_require__(760);
9776
- const node_url_1 = __nccwpck_require__(136);
9777
- const fs_1 = __nccwpck_require__(896);
9778
- const actualFS = __importStar(__nccwpck_require__(24));
10670
+ const lru_cache_1 = __nccwpck_require__(3481);
10671
+ const node_path_1 = __nccwpck_require__(6760);
10672
+ const node_url_1 = __nccwpck_require__(3136);
10673
+ const fs_1 = __nccwpck_require__(9896);
10674
+ const actualFS = __importStar(__nccwpck_require__(3024));
9779
10675
  const realpathSync = fs_1.realpathSync.native;
9780
10676
  // TODO: test perf of fs/promises realpath vs realpathCB,
9781
10677
  // since the promises one uses realpath.native
9782
- const promises_1 = __nccwpck_require__(455);
9783
- const minipass_1 = __nccwpck_require__(31);
10678
+ const promises_1 = __nccwpck_require__(1455);
10679
+ const minipass_1 = __nccwpck_require__(1031);
9784
10680
  const defaultFS = {
9785
10681
  lstatSync: fs_1.lstatSync,
9786
10682
  readdir: fs_1.readdir,
@@ -11866,7 +12762,7 @@ exports.PathScurry = process.platform === 'win32' ? PathScurryWin32
11866
12762
  /******/ // startup
11867
12763
  /******/ // Load entry module and return exports
11868
12764
  /******/ // This entry module is referenced by other modules so it can't be inlined
11869
- /******/ var __webpack_exports__ = __nccwpck_require__(328);
12765
+ /******/ var __webpack_exports__ = __nccwpck_require__(4328);
11870
12766
  /******/ module.exports = __webpack_exports__;
11871
12767
  /******/
11872
12768
  /******/ })()