@expo/metro-file-map 56.0.2 → 56.0.3

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.
Files changed (2) hide show
  1. package/build/lib/TreeFS.js +214 -185
  2. package/package.json +2 -2
@@ -18,11 +18,14 @@ const normalizePathSeparatorsToPosix_1 = __importDefault(require("./normalizePat
18
18
  const normalizePathSeparatorsToSystem_1 = __importDefault(require("./normalizePathSeparatorsToSystem"));
19
19
  const fallback_1 = require("../crawlers/node/fallback");
20
20
  function isDirectory(node) {
21
- return node instanceof Map;
21
+ return node != null && typeof node.get === 'function';
22
22
  }
23
23
  function isRegularFile(node) {
24
24
  return node != null && node[constants_1.default.SYMLINK] === 0;
25
25
  }
26
+ // POSIX SYMLOOP_MAX. Bounded counter instead of a per-walk `Set` of
27
+ // visited targets — cycles are rare; bailing after N follows is enough.
28
+ const SYMLOOP_MAX = 40;
26
29
  /**
27
30
  * OVERVIEW:
28
31
  *
@@ -81,6 +84,32 @@ class TreeFS {
81
84
  #rootPattern;
82
85
  #roots;
83
86
  #rootNode = new Map();
87
+ #followScratch = {
88
+ parentNode: new Map(),
89
+ ancestorOfRootIdx: undefined,
90
+ targetNormalPath: '',
91
+ fromIdx: 0,
92
+ unseenPathFromIdx: 0,
93
+ followedSymlinks: 0,
94
+ };
95
+ // Hier isn't recursive; pool entries are mutated in place per call.
96
+ #hierAncestorsBuf = [];
97
+ #hierAncestorsPool = [];
98
+ #pushHierAncestor = (node, normalPath, segmentName, ancestorOfRootIdx) => {
99
+ const i = this.#hierAncestorsBuf.length;
100
+ let entry = this.#hierAncestorsPool[i];
101
+ if (entry === undefined) {
102
+ entry = { ancestorOfRootIdx, node, normalPath, segmentName };
103
+ this.#hierAncestorsPool[i] = entry;
104
+ }
105
+ else {
106
+ entry.ancestorOfRootIdx = ancestorOfRootIdx;
107
+ entry.node = node;
108
+ entry.normalPath = normalPath;
109
+ entry.segmentName = segmentName;
110
+ }
111
+ this.#hierAncestorsBuf.push(entry);
112
+ };
84
113
  constructor(opts) {
85
114
  const { rootDir, files, processFile, fallbackFilesystem, roots, serverRoot } = opts;
86
115
  this.#rootDir = rootDir;
@@ -468,15 +497,151 @@ class TreeFS {
468
497
  * `opts.X` branches. Thin convenience wrappers below (`#lookup`,
469
498
  * `#lookupNoFollow`, `#lookupFromNode`, `#walkAndStream`) cover the
470
499
  * common call shapes.
500
+ *
501
+ * Symlink-follow logic is shared via `#followSymlink`.
502
+ */
503
+ /**
504
+ * For `..`-prefixed symlink targets: match remainder's leading segments
505
+ * against root parts (`/A/B/C/D` + remainder `B/C/foo.js` collapses two
506
+ * `..`s away). TreeFS has no downward back-links, so we climb up once
507
+ * from `#rootNode` to build a stack, then index into it.
471
508
  */
472
- #walkLookup(startNode, startPathIdx, startAncestorOfRootIdx, requestedNormalPath, onSegment, collectLinkPaths) {
473
- // We'll update the target if we hit a symlink.
509
+ #collapseAgainstRootParts(ancestorOfRootIdx, parentNode, remainder, onSegment) {
510
+ const ancestors = [this.#rootNode];
511
+ {
512
+ let n = this.#rootNode;
513
+ for (let k = 1; k <= ancestorOfRootIdx; k++) {
514
+ n = n.get('..') ?? new Map();
515
+ if (!isDirectory(n))
516
+ break;
517
+ ancestors.push(n);
518
+ }
519
+ }
520
+ const rootParts = this.#pathUtils.getParts();
521
+ let cursorIdx = 0;
522
+ // Trimmed by `'/..'` per step; `'..'.slice(0, -3) === ''` covers K=1→0.
523
+ let collapsedPath;
524
+ while (ancestorOfRootIdx > 0 &&
525
+ cursorIdx < remainder.length &&
526
+ ancestors.length > ancestorOfRootIdx - 1) {
527
+ const nextSep = remainder.indexOf(path_1.default.sep, cursorIdx);
528
+ const segEnd = nextSep === -1 ? remainder.length : nextSep;
529
+ const segName = remainder.slice(cursorIdx, segEnd);
530
+ const expectedPart = rootParts[rootParts.length - ancestorOfRootIdx];
531
+ if (segName !== expectedPart) {
532
+ break;
533
+ }
534
+ ancestorOfRootIdx--;
535
+ parentNode = ancestors[ancestorOfRootIdx];
536
+ cursorIdx = nextSep === -1 ? remainder.length : nextSep + 1;
537
+ if (onSegment != null) {
538
+ if (collapsedPath === undefined) {
539
+ collapsedPath = '';
540
+ for (let k = 0; k < ancestorOfRootIdx; k++) {
541
+ collapsedPath = k === 0 ? '..' : collapsedPath + path_1.default.sep + '..';
542
+ }
543
+ }
544
+ else {
545
+ collapsedPath = collapsedPath.slice(0, -3);
546
+ }
547
+ onSegment(parentNode, collapsedPath, segName, ancestorOfRootIdx);
548
+ }
549
+ }
550
+ return { ancestorOfRootIdx, parentNode, cursorIdx };
551
+ }
552
+ /**
553
+ * Resolve an interior symlink. Returns a `WalkResult` to return
554
+ * immediately, or `undefined` after writing continue-state to
555
+ * `#followScratch` for the caller to read.
556
+ */
557
+ #followSymlink(symlinkNode, currentPath, segmentName, remainingTargetPath, followedSymlinks, onSegment, collectLinkPaths) {
558
+ const normalSymlinkTarget = this.#resolveSymlinkTargetToNormalPath(symlinkNode, currentPath);
559
+ if (normalSymlinkTarget == null) {
560
+ return {
561
+ canonicalMissingPath: currentPath,
562
+ exists: false,
563
+ missingSegmentName: segmentName,
564
+ };
565
+ }
566
+ else if (++followedSymlinks >= SYMLOOP_MAX) {
567
+ return {
568
+ canonicalMissingPath: normalSymlinkTarget,
569
+ exists: false,
570
+ missingSegmentName: segmentName,
571
+ };
572
+ }
573
+ else if (collectLinkPaths != null) {
574
+ collectLinkPaths.add(this.#pathUtils.normalToAbsolute(currentPath));
575
+ }
576
+ // `onSegment: undefined` so target's interior dirs aren't emitted;
577
+ // only the destination is emitted (manually, below).
578
+ const subResult = this.#walkLookup(this.#rootNode, 0, 0, normalSymlinkTarget, undefined, collectLinkPaths, followedSymlinks);
579
+ if (!subResult.exists || remainingTargetPath === '') {
580
+ return subResult;
581
+ }
582
+ else if (!isDirectory(subResult.node)) {
583
+ return {
584
+ exists: false,
585
+ canonicalMissingPath: subResult.canonicalPath,
586
+ missingSegmentName: segmentName,
587
+ };
588
+ }
589
+ let parentNode = subResult.node;
590
+ let ancestorOfRootIdx = subResult.ancestorOfRootIdx;
591
+ if (onSegment != null) {
592
+ const subBaseStart = subResult.canonicalPath.lastIndexOf(path_1.default.sep) + 1;
593
+ const subBaseName = subResult.canonicalPath.slice(subBaseStart);
594
+ onSegment(parentNode, subResult.canonicalPath, subBaseName, ancestorOfRootIdx);
595
+ }
596
+ let cursorIdx = 0;
597
+ if (ancestorOfRootIdx != null && ancestorOfRootIdx > 0) {
598
+ const collapsed = this.#collapseAgainstRootParts(ancestorOfRootIdx, parentNode, remainingTargetPath, onSegment);
599
+ ancestorOfRootIdx = collapsed.ancestorOfRootIdx;
600
+ parentNode = collapsed.parentNode;
601
+ cursorIdx = collapsed.cursorIdx;
602
+ }
603
+ // Canonical-to-parentNode: `..`-string above root, empty at root, or
604
+ // sub-walk's canonical path inside the tree.
605
+ const realRemainder = remainingTargetPath.slice(cursorIdx);
606
+ let canonicalToParent;
607
+ if (ancestorOfRootIdx != null && ancestorOfRootIdx > 0) {
608
+ canonicalToParent = '..';
609
+ for (let k = 1; k < ancestorOfRootIdx; k++) {
610
+ canonicalToParent += path_1.default.sep + '..';
611
+ }
612
+ }
613
+ else if (ancestorOfRootIdx === 0) {
614
+ canonicalToParent = '';
615
+ }
616
+ else {
617
+ canonicalToParent = subResult.canonicalPath;
618
+ }
619
+ const scratch = this.#followScratch;
620
+ scratch.parentNode = parentNode;
621
+ scratch.ancestorOfRootIdx = ancestorOfRootIdx;
622
+ scratch.followedSymlinks = followedSymlinks;
623
+ if (canonicalToParent === '') {
624
+ scratch.targetNormalPath = realRemainder;
625
+ scratch.fromIdx = 0;
626
+ scratch.unseenPathFromIdx = 0;
627
+ }
628
+ else if (realRemainder === '') {
629
+ scratch.targetNormalPath = canonicalToParent;
630
+ scratch.fromIdx = canonicalToParent.length;
631
+ scratch.unseenPathFromIdx = canonicalToParent.length;
632
+ }
633
+ else {
634
+ scratch.targetNormalPath = canonicalToParent + path_1.default.sep + realRemainder;
635
+ scratch.fromIdx = canonicalToParent.length + 1;
636
+ scratch.unseenPathFromIdx = canonicalToParent.length + 1;
637
+ }
638
+ return undefined;
639
+ }
640
+ #walkLookup(startNode, startPathIdx, startAncestorOfRootIdx, requestedNormalPath, onSegment, collectLinkPaths, initialFollows) {
641
+ // Cycle counter as a local — faster than an instance-field read in
642
+ // the per-segment loop. Recursive sub-walk inherits via `initialFollows`.
474
643
  let targetNormalPath = requestedNormalPath;
475
- // Lazy-initialised set of seen target paths, to detect symlink cycles.
476
- let seen;
477
- // Set when a symlink is followed, to allow fallback population outside
478
- // the boundary for paths reachable transitively through symlinks.
479
- let followedSymlink = false;
644
+ let followedSymlinks = initialFollows;
480
645
  let fromIdx = startPathIdx;
481
646
  let parentNode = startNode;
482
647
  let ancestorOfRootIdx = startAncestorOfRootIdx;
@@ -508,7 +673,7 @@ class TreeFS {
508
673
  ? fromIdx - segmentName.length - 1
509
674
  : fromIdx - segmentName.length - 2;
510
675
  const parentCanonicalPath = parentEnd > 0 ? targetNormalPath.slice(0, parentEnd) : '';
511
- segmentNode = this.#populateFromFilesystem(parentNode, segmentName, parentCanonicalPath, followedSymlink);
676
+ segmentNode = this.#populateFromFilesystem(parentNode, segmentName, parentCanonicalPath, followedSymlinks > 0);
512
677
  if (segmentNode != null) {
513
678
  ancestorOfRootIdx = undefined;
514
679
  }
@@ -567,87 +732,17 @@ class TreeFS {
567
732
  missingSegmentName: segmentName,
568
733
  };
569
734
  }
570
- // Symlink in a directory path
571
- const normalSymlinkTarget = this.#resolveSymlinkTargetToNormalPath(segmentNode, currentPath);
572
- if (normalSymlinkTarget == null) {
573
- return {
574
- canonicalMissingPath: currentPath,
575
- exists: false,
576
- missingSegmentName: segmentName,
577
- };
578
- }
579
- if (collectLinkPaths != null) {
580
- collectLinkPaths.add(this.#pathUtils.normalToAbsolute(currentPath));
581
- }
582
- const remainingTargetPath = isLastSegment ? '' : targetNormalPath.slice(fromIdx);
583
- // Append any subsequent path segments to the symlink target, and reset
584
- // with our new target.
585
- const joinedResult = this.#pathUtils.joinNormalToRelative(normalSymlinkTarget, remainingTargetPath);
586
- targetNormalPath = joinedResult.normalPath;
587
- // Two special cases (covered by unit tests):
588
- //
589
- // If the symlink target is the root, the root should be counted as an
590
- // ancestor. We'd otherwise miss it because new ancestors are only
591
- // streamed when entering a directory.
592
- //
593
- // If the symlink target is an ancestor of the root *and* joining it
594
- // with the remaining path results in collapsing segments, e.g:
595
- // '../..' + 'parentofroot/root/foo.js' = 'foo.js', then we must yield
596
- // parentofroot and root as ancestors.
597
- if (onSegment != null &&
598
- !isLastSegment &&
599
- // No-op optimisation to bail out the common case of nothing to do.
600
- ((ancestorOfRootIdx =
601
- this.#pathUtils.getAncestorOfRootIdx(normalSymlinkTarget) ?? undefined) === 0 ||
602
- joinedResult.collapsedSegments > 0)) {
603
- let node = this.#rootNode;
604
- let collapsedPath = '';
605
- const reverseAncestors = [];
606
- for (let i = 0; i <= joinedResult.collapsedSegments && isDirectory(node); i++) {
607
- if (
608
- // Add the root only if the target is the root or we have
609
- // collapsed segments.
610
- i > 0 ||
611
- ancestorOfRootIdx === 0 ||
612
- joinedResult.collapsedSegments > 0) {
613
- reverseAncestors.push({
614
- ancestorOfRootIdx: i,
615
- node,
616
- normalPath: collapsedPath,
617
- segmentName: this.#pathUtils.getBasenameOfNthAncestor(i),
618
- });
619
- }
620
- node = node.get('..') ?? new Map();
621
- collapsedPath = collapsedPath === '' ? '..' : collapsedPath + path_1.default.sep + '..';
622
- }
623
- // Emit in shallowest-first order, matching today's
624
- // collectAncestors.push(...reverseAncestors.reverse()).
625
- for (let i = reverseAncestors.length - 1; i >= 0; i--) {
626
- const a = reverseAncestors[i];
627
- onSegment(a.node, a.normalPath, a.segmentName, a.ancestorOfRootIdx);
628
- }
629
- }
630
- // For the purpose of streaming ancestors: Ignore the traversal to the
631
- // symlink target, and start yielding ancestors only from the target
632
- // itself (i.e. the basename of the normal target path) onwards.
633
- unseenPathFromIdx = normalSymlinkTarget.lastIndexOf(path_1.default.sep) + 1;
634
- if (seen == null) {
635
- // Optimisation: set this lazily only when we've encountered a symlink
636
- seen = new Set([requestedNormalPath]);
735
+ const followResult = this.#followSymlink(segmentNode, currentPath, segmentName, isLastSegment ? '' : targetNormalPath.slice(fromIdx), followedSymlinks, onSegment, collectLinkPaths);
736
+ if (followResult !== undefined) {
737
+ return followResult;
637
738
  }
638
- if (seen.has(targetNormalPath)) {
639
- // TODO: Warn `Symlink cycle detected: ${[...seen, node].join(' -> ')}`
640
- return {
641
- canonicalMissingPath: targetNormalPath,
642
- exists: false,
643
- missingSegmentName: segmentName,
644
- };
645
- }
646
- seen.add(targetNormalPath);
647
- followedSymlink = true;
648
- fromIdx = 0;
649
- parentNode = this.#rootNode;
650
- ancestorOfRootIdx = 0;
739
+ const scratch = this.#followScratch;
740
+ parentNode = scratch.parentNode;
741
+ ancestorOfRootIdx = scratch.ancestorOfRootIdx;
742
+ targetNormalPath = scratch.targetNormalPath;
743
+ fromIdx = scratch.fromIdx;
744
+ unseenPathFromIdx = scratch.unseenPathFromIdx;
745
+ followedSymlinks = scratch.followedSymlinks;
651
746
  }
652
747
  }
653
748
  (0, invariant_1.default)(parentNode === this.#rootNode, 'Unexpectedly escaped traversal');
@@ -668,8 +763,7 @@ class TreeFS {
668
763
  */
669
764
  #walkLookupNoFollow(startNode, startPathIdx, startAncestorOfRootIdx, requestedNormalPath, onSegment, skipFallback) {
670
765
  let targetNormalPath = requestedNormalPath;
671
- let seen;
672
- let followedSymlink = false;
766
+ let followedSymlinks = 0;
673
767
  let fromIdx = startPathIdx;
674
768
  let parentNode = startNode;
675
769
  let ancestorOfRootIdx = startAncestorOfRootIdx;
@@ -699,7 +793,7 @@ class TreeFS {
699
793
  ? fromIdx - segmentName.length - 1
700
794
  : fromIdx - segmentName.length - 2;
701
795
  const parentCanonicalPath = parentEnd > 0 ? targetNormalPath.slice(0, parentEnd) : '';
702
- segmentNode = this.#populateFromFilesystem(parentNode, segmentName, parentCanonicalPath, followedSymlink);
796
+ segmentNode = this.#populateFromFilesystem(parentNode, segmentName, parentCanonicalPath, followedSymlinks > 0);
703
797
  if (segmentNode != null) {
704
798
  ancestorOfRootIdx = undefined;
705
799
  }
@@ -750,59 +844,17 @@ class TreeFS {
750
844
  missingSegmentName: segmentName,
751
845
  };
752
846
  }
753
- // Symlink in an interior position still follow it (only the leaf
754
- // is exempt from following under followLeaf=false).
755
- const normalSymlinkTarget = this.#resolveSymlinkTargetToNormalPath(segmentNode, currentPath);
756
- if (normalSymlinkTarget == null) {
757
- return {
758
- canonicalMissingPath: currentPath,
759
- exists: false,
760
- missingSegmentName: segmentName,
761
- };
762
- }
763
- const remainingTargetPath = targetNormalPath.slice(fromIdx);
764
- const joinedResult = this.#pathUtils.joinNormalToRelative(normalSymlinkTarget, remainingTargetPath);
765
- targetNormalPath = joinedResult.normalPath;
766
- if (onSegment != null &&
767
- ((ancestorOfRootIdx =
768
- this.#pathUtils.getAncestorOfRootIdx(normalSymlinkTarget) ?? undefined) === 0 ||
769
- joinedResult.collapsedSegments > 0)) {
770
- let node = this.#rootNode;
771
- let collapsedPath = '';
772
- const reverseAncestors = [];
773
- for (let i = 0; i <= joinedResult.collapsedSegments && isDirectory(node); i++) {
774
- if (i > 0 || ancestorOfRootIdx === 0 || joinedResult.collapsedSegments > 0) {
775
- reverseAncestors.push({
776
- ancestorOfRootIdx: i,
777
- node,
778
- normalPath: collapsedPath,
779
- segmentName: this.#pathUtils.getBasenameOfNthAncestor(i),
780
- });
781
- }
782
- node = node.get('..') ?? new Map();
783
- collapsedPath = collapsedPath === '' ? '..' : collapsedPath + path_1.default.sep + '..';
784
- }
785
- for (let i = reverseAncestors.length - 1; i >= 0; i--) {
786
- const a = reverseAncestors[i];
787
- onSegment(a.node, a.normalPath, a.segmentName, a.ancestorOfRootIdx);
788
- }
847
+ const followResult = this.#followSymlink(segmentNode, currentPath, segmentName, targetNormalPath.slice(fromIdx), followedSymlinks, onSegment, undefined);
848
+ if (followResult !== undefined) {
849
+ return followResult;
789
850
  }
790
- unseenPathFromIdx = normalSymlinkTarget.lastIndexOf(path_1.default.sep) + 1;
791
- if (seen == null) {
792
- seen = new Set([requestedNormalPath]);
793
- }
794
- if (seen.has(targetNormalPath)) {
795
- return {
796
- canonicalMissingPath: targetNormalPath,
797
- exists: false,
798
- missingSegmentName: segmentName,
799
- };
800
- }
801
- seen.add(targetNormalPath);
802
- followedSymlink = true;
803
- fromIdx = 0;
804
- parentNode = this.#rootNode;
805
- ancestorOfRootIdx = 0;
851
+ const scratch = this.#followScratch;
852
+ parentNode = scratch.parentNode;
853
+ ancestorOfRootIdx = scratch.ancestorOfRootIdx;
854
+ targetNormalPath = scratch.targetNormalPath;
855
+ fromIdx = scratch.fromIdx;
856
+ unseenPathFromIdx = scratch.unseenPathFromIdx;
857
+ followedSymlinks = scratch.followedSymlinks;
806
858
  }
807
859
  }
808
860
  (0, invariant_1.default)(parentNode === this.#rootNode, 'Unexpectedly escaped traversal');
@@ -823,7 +875,7 @@ class TreeFS {
823
875
  */
824
876
  #walkAndMakeDirectories(startNode, startPathIdx, startAncestorOfRootIdx, requestedNormalPath, followLeaf, onSegment) {
825
877
  let targetNormalPath = requestedNormalPath;
826
- let seen;
878
+ let followedSymlinks = 0;
827
879
  let fromIdx = startPathIdx;
828
880
  let parentNode = startNode;
829
881
  let ancestorOfRootIdx = startAncestorOfRootIdx;
@@ -888,33 +940,17 @@ class TreeFS {
888
940
  missingSegmentName: segmentName,
889
941
  };
890
942
  }
891
- // Interior symlink: follow it.
892
- const normalSymlinkTarget = this.#resolveSymlinkTargetToNormalPath(segmentNode, currentPath);
893
- if (normalSymlinkTarget == null) {
894
- return {
895
- canonicalMissingPath: currentPath,
896
- exists: false,
897
- missingSegmentName: segmentName,
898
- };
899
- }
900
- const remainingTargetPath = isLastSegment ? '' : targetNormalPath.slice(fromIdx);
901
- const joinedResult = this.#pathUtils.joinNormalToRelative(normalSymlinkTarget, remainingTargetPath);
902
- targetNormalPath = joinedResult.normalPath;
903
- unseenPathFromIdx = normalSymlinkTarget.lastIndexOf(path_1.default.sep) + 1;
904
- if (seen == null) {
905
- seen = new Set([requestedNormalPath]);
943
+ const followResult = this.#followSymlink(segmentNode, currentPath, segmentName, isLastSegment ? '' : targetNormalPath.slice(fromIdx), followedSymlinks, undefined, undefined);
944
+ if (followResult !== undefined) {
945
+ return followResult;
906
946
  }
907
- if (seen.has(targetNormalPath)) {
908
- return {
909
- canonicalMissingPath: targetNormalPath,
910
- exists: false,
911
- missingSegmentName: segmentName,
912
- };
913
- }
914
- seen.add(targetNormalPath);
915
- fromIdx = 0;
916
- parentNode = this.#rootNode;
917
- ancestorOfRootIdx = 0;
947
+ const scratch = this.#followScratch;
948
+ parentNode = scratch.parentNode;
949
+ ancestorOfRootIdx = scratch.ancestorOfRootIdx;
950
+ targetNormalPath = scratch.targetNormalPath;
951
+ fromIdx = scratch.fromIdx;
952
+ unseenPathFromIdx = scratch.unseenPathFromIdx;
953
+ followedSymlinks = scratch.followedSymlinks;
918
954
  }
919
955
  }
920
956
  (0, invariant_1.default)(parentNode === this.#rootNode, 'Unexpectedly escaped traversal');
@@ -926,18 +962,18 @@ class TreeFS {
926
962
  parentNode: undefined,
927
963
  };
928
964
  }
929
- // Convenience wrappers for the common walker call shapes.
965
+ // Convenience wrappers. Top-level entries pass `0` for `initialFollows`.
930
966
  #lookup(normalPath, collectLinkPaths) {
931
- return this.#walkLookup(this.#rootNode, 0, 0, normalPath, undefined, collectLinkPaths);
967
+ return this.#walkLookup(this.#rootNode, 0, 0, normalPath, undefined, collectLinkPaths, 0);
932
968
  }
933
969
  #lookupNoFollow(normalPath) {
934
970
  return this.#walkLookupNoFollow(this.#rootNode, 0, 0, normalPath, undefined, false);
935
971
  }
936
972
  #lookupFromNode(startNode, startPathIdx, startAncestorOfRootIdx, target, collectLinkPaths) {
937
- return this.#walkLookup(startNode, startPathIdx, startAncestorOfRootIdx, target, undefined, collectLinkPaths);
973
+ return this.#walkLookup(startNode, startPathIdx, startAncestorOfRootIdx, target, undefined, collectLinkPaths, 0);
938
974
  }
939
975
  #walkAndStream(normalPath, onSegment, collectLinkPaths) {
940
- return this.#walkLookup(this.#rootNode, 0, 0, normalPath, onSegment, collectLinkPaths);
976
+ return this.#walkLookup(this.#rootNode, 0, 0, normalPath, onSegment, collectLinkPaths, 0);
941
977
  }
942
978
  /**
943
979
  * Given a start path (which need not exist), a subpath and type, and
@@ -963,18 +999,11 @@ class TreeFS {
963
999
  * (subpath: node_modules/pkg, type: d) in Node.js resolution.
964
1000
  */
965
1001
  hierarchicalLookup(mixedStartPath, subpath, opts) {
966
- const ancestorsOfInput = [];
1002
+ const ancestorsOfInput = this.#hierAncestorsBuf;
1003
+ ancestorsOfInput.length = 0;
967
1004
  const normalPath = this.#normalizePath(mixedStartPath);
968
1005
  const invalidatedBy = opts.invalidatedBy ?? undefined;
969
- const onSegment = (node, normalPathOfDir, segmentName, ancestorOfRootIdx) => {
970
- ancestorsOfInput.push({
971
- ancestorOfRootIdx,
972
- node,
973
- normalPath: normalPathOfDir,
974
- segmentName,
975
- });
976
- };
977
- const closestLookup = this.#walkAndStream(normalPath, onSegment, invalidatedBy);
1006
+ const closestLookup = this.#walkAndStream(normalPath, this.#pushHierAncestor, invalidatedBy);
978
1007
  if (closestLookup.exists && isDirectory(closestLookup.node)) {
979
1008
  const maybeAbsolutePathMatch = this.#checkCandidateHasSubpath(closestLookup.canonicalPath, subpath, opts.subpathType, invalidatedBy, {
980
1009
  ancestorOfRootIdx: closestLookup.ancestorOfRootIdx,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expo/metro-file-map",
3
- "version": "56.0.2",
3
+ "version": "56.0.3",
4
4
  "description": "A metro-file-map fork for Expo used with the Metro bundler",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -42,7 +42,7 @@
42
42
  "publishConfig": {
43
43
  "access": "public"
44
44
  },
45
- "gitHead": "51c27fce31a5b3a877a4b05d832dabf4a99db5e1",
45
+ "gitHead": "f26be3dd9396bf7c399a1d607865d0fabdbc0d64",
46
46
  "scripts": {
47
47
  "build": "expo-module tsc",
48
48
  "clean": "expo-module clean",