isomorphic-git 1.38.4 → 1.38.6
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/index.cjs +144 -22
- package/index.js +144 -22
- package/index.umd.min.js +1 -1
- package/index.umd.min.js.map +1 -1
- package/managers/index.cjs +112 -20
- package/managers/index.d.cts +1 -1
- package/managers/index.d.ts +1 -1
- package/managers/index.js +112 -20
- package/managers/index.umd.min.js +1 -1
- package/managers/index.umd.min.js.LICENSE.txt +12 -0
- package/managers/index.umd.min.js.map +1 -1
- package/models/index.cjs +60 -10
- package/models/index.js +60 -10
- package/models/index.umd.min.js +1 -1
- package/models/index.umd.min.js.LICENSE.txt +12 -0
- package/models/index.umd.min.js.map +1 -1
- package/package.json +2 -2
package/managers/index.cjs
CHANGED
|
@@ -698,6 +698,18 @@ function dirname(path) {
|
|
|
698
698
|
* This code for `path.join` is directly copied from @zenfs/core/path for bundle size improvements.
|
|
699
699
|
* SPDX-License-Identifier: LGPL-3.0-or-later
|
|
700
700
|
* Copyright (c) James Prevett and other ZenFS contributors.
|
|
701
|
+
*
|
|
702
|
+
* Windows support added:
|
|
703
|
+
* - Backslashes are normalised to forward slashes before processing.
|
|
704
|
+
* - Drive-letter prefixes (e.g. "C:") are detected and preserved through
|
|
705
|
+
* normalisation, so absolute Windows paths are handled correctly.
|
|
706
|
+
* - An absolute argument passed to join() resets the accumulated path,
|
|
707
|
+
* matching Node behaviour and handling worktree gitdir paths properly.
|
|
708
|
+
*
|
|
709
|
+
* Limitation: UNC paths (e.g. \\server\share) are not supported. The leading
|
|
710
|
+
* backslashes are normalised to forward slashes and then collapsed by
|
|
711
|
+
* normalizeString, losing the UNC root. Git on Windows works with
|
|
712
|
+
* drive-letter paths, so this is not expected to be a practical issue.
|
|
701
713
|
*/
|
|
702
714
|
|
|
703
715
|
function normalizeString(path, aar) {
|
|
@@ -761,29 +773,67 @@ function normalizeString(path, aar) {
|
|
|
761
773
|
return res
|
|
762
774
|
}
|
|
763
775
|
|
|
776
|
+
// Returns the Windows drive prefix ("C:") if present, otherwise null.
|
|
777
|
+
function getWindowsDrivePrefix(path) {
|
|
778
|
+
if (path.length >= 2 && /^[a-zA-Z]:/.test(path)) {
|
|
779
|
+
return path.slice(0, 2) // e.g. "C:"
|
|
780
|
+
}
|
|
781
|
+
return null
|
|
782
|
+
}
|
|
783
|
+
|
|
764
784
|
function normalize(path) {
|
|
765
785
|
if (!path.length) return '.'
|
|
766
786
|
|
|
767
|
-
|
|
787
|
+
// Normalise backslashes to forward slashes before any other processing.
|
|
788
|
+
path = path.replace(/\\/g, '/');
|
|
789
|
+
|
|
790
|
+
const drivePrefix = getWindowsDrivePrefix(path);
|
|
791
|
+
// isAbsolute: Unix root ('/foo') OR Windows drive+slash ('C:/foo').
|
|
792
|
+
const isAbsolute =
|
|
793
|
+
path[0] === '/' || (drivePrefix !== null && path[2] === '/');
|
|
768
794
|
const trailingSeparator = path.at(-1) === '/';
|
|
769
795
|
|
|
770
|
-
|
|
796
|
+
// Strip the drive prefix before feeding into normalizeString so that the
|
|
797
|
+
// core algorithm only ever sees a plain POSIX-style string.
|
|
798
|
+
const pathBody = drivePrefix ? path.slice(2) : path;
|
|
799
|
+
|
|
800
|
+
let normalized = normalizeString(pathBody, !isAbsolute);
|
|
771
801
|
|
|
772
|
-
if (!
|
|
773
|
-
|
|
774
|
-
|
|
802
|
+
if (!normalized.length) {
|
|
803
|
+
const root = drivePrefix
|
|
804
|
+
? isAbsolute
|
|
805
|
+
? drivePrefix + '/'
|
|
806
|
+
: drivePrefix
|
|
807
|
+
: isAbsolute
|
|
808
|
+
? '/'
|
|
809
|
+
: '.';
|
|
810
|
+
return trailingSeparator && !isAbsolute ? root + '/' : root
|
|
775
811
|
}
|
|
776
|
-
if (trailingSeparator)
|
|
812
|
+
if (trailingSeparator) normalized += '/';
|
|
777
813
|
|
|
778
|
-
|
|
814
|
+
if (drivePrefix) {
|
|
815
|
+
return isAbsolute
|
|
816
|
+
? `${drivePrefix}/${normalized}`
|
|
817
|
+
: `${drivePrefix}${normalized}`
|
|
818
|
+
}
|
|
819
|
+
return isAbsolute ? `/${normalized}` : normalized
|
|
779
820
|
}
|
|
780
821
|
|
|
781
822
|
function join(...args) {
|
|
782
823
|
if (args.length === 0) return '.'
|
|
783
824
|
let joined;
|
|
784
825
|
for (let i = 0; i < args.length; ++i) {
|
|
785
|
-
|
|
786
|
-
|
|
826
|
+
// Normalise separators before processing.
|
|
827
|
+
const arg = args[i].replace(/\\/g, '/');
|
|
828
|
+
if (arg.length === 0) continue
|
|
829
|
+
|
|
830
|
+
// A Windows drive-letter path (e.g. "C:/worktrees/foo") cannot be
|
|
831
|
+
// meaningfully appended to any base, so it resets the accumulator.
|
|
832
|
+
// Unix absolute paths (leading '/') are NOT reset here — that would be
|
|
833
|
+
// path.resolve() semantics; path.join('foo', '/bar') must yield 'foo/bar'.
|
|
834
|
+
if (/^[a-zA-Z]:\//.test(arg)) {
|
|
835
|
+
joined = arg;
|
|
836
|
+
} else {
|
|
787
837
|
if (joined === undefined) joined = arg;
|
|
788
838
|
else joined += '/' + arg;
|
|
789
839
|
}
|
|
@@ -2024,7 +2074,13 @@ class GitRefManager {
|
|
|
2024
2074
|
* @param {number} [args.depth = undefined] - The maximum depth to resolve symbolic refs.
|
|
2025
2075
|
* @returns {Promise<string>} - The resolved object ID.
|
|
2026
2076
|
*/
|
|
2027
|
-
static async resolve({
|
|
2077
|
+
static async resolve({
|
|
2078
|
+
fs,
|
|
2079
|
+
gitdir,
|
|
2080
|
+
ref,
|
|
2081
|
+
depth = undefined,
|
|
2082
|
+
visited = new Set(),
|
|
2083
|
+
}) {
|
|
2028
2084
|
if (depth !== undefined) {
|
|
2029
2085
|
depth--;
|
|
2030
2086
|
if (depth === -1) {
|
|
@@ -2035,7 +2091,7 @@ class GitRefManager {
|
|
|
2035
2091
|
// Is it a ref pointer?
|
|
2036
2092
|
if (ref.startsWith('ref: ')) {
|
|
2037
2093
|
ref = ref.slice('ref: '.length);
|
|
2038
|
-
return GitRefManager.resolve({ fs, gitdir, ref, depth })
|
|
2094
|
+
return GitRefManager.resolve({ fs, gitdir, ref, depth, visited })
|
|
2039
2095
|
}
|
|
2040
2096
|
// Is it a complete and valid SHA?
|
|
2041
2097
|
if (ref.length === 40 && /[0-9a-f]{40}/.test(ref)) {
|
|
@@ -2054,7 +2110,21 @@ class GitRefManager {
|
|
|
2054
2110
|
packedMap.get(ref)
|
|
2055
2111
|
);
|
|
2056
2112
|
if (sha) {
|
|
2057
|
-
|
|
2113
|
+
// Guard against circular symbolic references (e.g. a -> b -> a). Without
|
|
2114
|
+
// tracking visited refs this recursion would not terminate.
|
|
2115
|
+
if (visited.has(ref)) {
|
|
2116
|
+
throw new InternalError(
|
|
2117
|
+
`Circular reference detected while resolving ref "${ref}"`
|
|
2118
|
+
)
|
|
2119
|
+
}
|
|
2120
|
+
visited.add(ref);
|
|
2121
|
+
return GitRefManager.resolve({
|
|
2122
|
+
fs,
|
|
2123
|
+
gitdir,
|
|
2124
|
+
ref: sha.trim(),
|
|
2125
|
+
depth,
|
|
2126
|
+
visited,
|
|
2127
|
+
})
|
|
2058
2128
|
}
|
|
2059
2129
|
}
|
|
2060
2130
|
// Do we give up?
|
|
@@ -3569,21 +3639,26 @@ function applyDelta(delta, source) {
|
|
|
3569
3639
|
if (firstOp.byteLength === targetSize) {
|
|
3570
3640
|
target = firstOp;
|
|
3571
3641
|
} else {
|
|
3572
|
-
//
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3642
|
+
// Build the result from the delta ops instead of pre-allocating `targetSize`.
|
|
3643
|
+
// `targetSize` comes from the delta header and may not match the actual op output,
|
|
3644
|
+
// so allocating it up front can reserve far more memory than the ops produce.
|
|
3645
|
+
// Building from the ops bounds memory to the real output size; the size check below
|
|
3646
|
+
// still validates the total before concatenating.
|
|
3647
|
+
const chunks = [firstOp];
|
|
3648
|
+
let tell = firstOp.byteLength;
|
|
3576
3649
|
|
|
3577
3650
|
while (!reader.eof()) {
|
|
3578
|
-
|
|
3651
|
+
const op = readOp(reader, source);
|
|
3652
|
+
chunks.push(op);
|
|
3653
|
+
tell += op.byteLength;
|
|
3579
3654
|
}
|
|
3580
3655
|
|
|
3581
|
-
const tell = writer.tell();
|
|
3582
3656
|
if (targetSize !== tell) {
|
|
3583
3657
|
throw new InternalError(
|
|
3584
3658
|
`applyDelta expected target buffer to be ${targetSize} bytes but the resulting buffer was ${tell} bytes`
|
|
3585
3659
|
)
|
|
3586
3660
|
}
|
|
3661
|
+
target = Buffer.concat(chunks, targetSize);
|
|
3587
3662
|
}
|
|
3588
3663
|
return target
|
|
3589
3664
|
}
|
|
@@ -4840,8 +4915,25 @@ function parseBuffer(buffer) {
|
|
|
4840
4915
|
const type = mode2type$1(mode);
|
|
4841
4916
|
const path = buffer.slice(space + 1, nullchar).toString('utf8');
|
|
4842
4917
|
|
|
4843
|
-
//
|
|
4844
|
-
|
|
4918
|
+
// Reject reserved entry names, matching git's verify_path(): path separators,
|
|
4919
|
+
// "." and ".." (which resolve outside the working directory), and ".git" (which git
|
|
4920
|
+
// disallows as a path component). Checks mirror git's is_ntfs_dotgit() and
|
|
4921
|
+
// is_hfs_dotgit(): case-insensitive, trailing dots/spaces stripped (NTFS),
|
|
4922
|
+
// NTFS 8.3 short name aliases (git~1..git~9), and HFS+ ignorable Unicode
|
|
4923
|
+
// characters stripped (zero-width joiners, directional marks, BOM, etc.).
|
|
4924
|
+
const hfsClean = path.replace(
|
|
4925
|
+
/[\u200C-\u200F\u202A-\u202E\u206A-\u206F\uFEFF]/g,
|
|
4926
|
+
''
|
|
4927
|
+
);
|
|
4928
|
+
const normalized = hfsClean.toLowerCase().replace(/[. ]+$/, '');
|
|
4929
|
+
if (
|
|
4930
|
+
path.includes('\\') ||
|
|
4931
|
+
path.includes('/') ||
|
|
4932
|
+
hfsClean === '.' ||
|
|
4933
|
+
hfsClean === '..' ||
|
|
4934
|
+
normalized === '.git' ||
|
|
4935
|
+
/^\.?git~[1-9]$/.test(normalized)
|
|
4936
|
+
) {
|
|
4845
4937
|
throw new UnsafeFilepathError(path)
|
|
4846
4938
|
}
|
|
4847
4939
|
|
package/managers/index.d.cts
CHANGED
|
@@ -568,7 +568,7 @@ export class GitRefManager {
|
|
|
568
568
|
* @param {number} [args.depth = undefined] - The maximum depth to resolve symbolic refs.
|
|
569
569
|
* @returns {Promise<string>} - The resolved object ID.
|
|
570
570
|
*/
|
|
571
|
-
static resolve({ fs, gitdir, ref, depth }: {
|
|
571
|
+
static resolve({ fs, gitdir, ref, depth, visited, }: {
|
|
572
572
|
fs: FSClient;
|
|
573
573
|
gitdir?: string | undefined;
|
|
574
574
|
ref: string;
|
package/managers/index.d.ts
CHANGED
|
@@ -567,7 +567,7 @@ export class GitRefManager {
|
|
|
567
567
|
* @param {number} [args.depth = undefined] - The maximum depth to resolve symbolic refs.
|
|
568
568
|
* @returns {Promise<string>} - The resolved object ID.
|
|
569
569
|
*/
|
|
570
|
-
static resolve({ fs, gitdir, ref, depth }: {
|
|
570
|
+
static resolve({ fs, gitdir, ref, depth, visited, }: {
|
|
571
571
|
fs: FSClient;
|
|
572
572
|
gitdir?: string | undefined;
|
|
573
573
|
ref: string;
|
package/managers/index.js
CHANGED
|
@@ -691,6 +691,18 @@ function dirname(path) {
|
|
|
691
691
|
* This code for `path.join` is directly copied from @zenfs/core/path for bundle size improvements.
|
|
692
692
|
* SPDX-License-Identifier: LGPL-3.0-or-later
|
|
693
693
|
* Copyright (c) James Prevett and other ZenFS contributors.
|
|
694
|
+
*
|
|
695
|
+
* Windows support added:
|
|
696
|
+
* - Backslashes are normalised to forward slashes before processing.
|
|
697
|
+
* - Drive-letter prefixes (e.g. "C:") are detected and preserved through
|
|
698
|
+
* normalisation, so absolute Windows paths are handled correctly.
|
|
699
|
+
* - An absolute argument passed to join() resets the accumulated path,
|
|
700
|
+
* matching Node behaviour and handling worktree gitdir paths properly.
|
|
701
|
+
*
|
|
702
|
+
* Limitation: UNC paths (e.g. \\server\share) are not supported. The leading
|
|
703
|
+
* backslashes are normalised to forward slashes and then collapsed by
|
|
704
|
+
* normalizeString, losing the UNC root. Git on Windows works with
|
|
705
|
+
* drive-letter paths, so this is not expected to be a practical issue.
|
|
694
706
|
*/
|
|
695
707
|
|
|
696
708
|
function normalizeString(path, aar) {
|
|
@@ -754,29 +766,67 @@ function normalizeString(path, aar) {
|
|
|
754
766
|
return res
|
|
755
767
|
}
|
|
756
768
|
|
|
769
|
+
// Returns the Windows drive prefix ("C:") if present, otherwise null.
|
|
770
|
+
function getWindowsDrivePrefix(path) {
|
|
771
|
+
if (path.length >= 2 && /^[a-zA-Z]:/.test(path)) {
|
|
772
|
+
return path.slice(0, 2) // e.g. "C:"
|
|
773
|
+
}
|
|
774
|
+
return null
|
|
775
|
+
}
|
|
776
|
+
|
|
757
777
|
function normalize(path) {
|
|
758
778
|
if (!path.length) return '.'
|
|
759
779
|
|
|
760
|
-
|
|
780
|
+
// Normalise backslashes to forward slashes before any other processing.
|
|
781
|
+
path = path.replace(/\\/g, '/');
|
|
782
|
+
|
|
783
|
+
const drivePrefix = getWindowsDrivePrefix(path);
|
|
784
|
+
// isAbsolute: Unix root ('/foo') OR Windows drive+slash ('C:/foo').
|
|
785
|
+
const isAbsolute =
|
|
786
|
+
path[0] === '/' || (drivePrefix !== null && path[2] === '/');
|
|
761
787
|
const trailingSeparator = path.at(-1) === '/';
|
|
762
788
|
|
|
763
|
-
|
|
789
|
+
// Strip the drive prefix before feeding into normalizeString so that the
|
|
790
|
+
// core algorithm only ever sees a plain POSIX-style string.
|
|
791
|
+
const pathBody = drivePrefix ? path.slice(2) : path;
|
|
792
|
+
|
|
793
|
+
let normalized = normalizeString(pathBody, !isAbsolute);
|
|
764
794
|
|
|
765
|
-
if (!
|
|
766
|
-
|
|
767
|
-
|
|
795
|
+
if (!normalized.length) {
|
|
796
|
+
const root = drivePrefix
|
|
797
|
+
? isAbsolute
|
|
798
|
+
? drivePrefix + '/'
|
|
799
|
+
: drivePrefix
|
|
800
|
+
: isAbsolute
|
|
801
|
+
? '/'
|
|
802
|
+
: '.';
|
|
803
|
+
return trailingSeparator && !isAbsolute ? root + '/' : root
|
|
768
804
|
}
|
|
769
|
-
if (trailingSeparator)
|
|
805
|
+
if (trailingSeparator) normalized += '/';
|
|
770
806
|
|
|
771
|
-
|
|
807
|
+
if (drivePrefix) {
|
|
808
|
+
return isAbsolute
|
|
809
|
+
? `${drivePrefix}/${normalized}`
|
|
810
|
+
: `${drivePrefix}${normalized}`
|
|
811
|
+
}
|
|
812
|
+
return isAbsolute ? `/${normalized}` : normalized
|
|
772
813
|
}
|
|
773
814
|
|
|
774
815
|
function join(...args) {
|
|
775
816
|
if (args.length === 0) return '.'
|
|
776
817
|
let joined;
|
|
777
818
|
for (let i = 0; i < args.length; ++i) {
|
|
778
|
-
|
|
779
|
-
|
|
819
|
+
// Normalise separators before processing.
|
|
820
|
+
const arg = args[i].replace(/\\/g, '/');
|
|
821
|
+
if (arg.length === 0) continue
|
|
822
|
+
|
|
823
|
+
// A Windows drive-letter path (e.g. "C:/worktrees/foo") cannot be
|
|
824
|
+
// meaningfully appended to any base, so it resets the accumulator.
|
|
825
|
+
// Unix absolute paths (leading '/') are NOT reset here — that would be
|
|
826
|
+
// path.resolve() semantics; path.join('foo', '/bar') must yield 'foo/bar'.
|
|
827
|
+
if (/^[a-zA-Z]:\//.test(arg)) {
|
|
828
|
+
joined = arg;
|
|
829
|
+
} else {
|
|
780
830
|
if (joined === undefined) joined = arg;
|
|
781
831
|
else joined += '/' + arg;
|
|
782
832
|
}
|
|
@@ -2017,7 +2067,13 @@ class GitRefManager {
|
|
|
2017
2067
|
* @param {number} [args.depth = undefined] - The maximum depth to resolve symbolic refs.
|
|
2018
2068
|
* @returns {Promise<string>} - The resolved object ID.
|
|
2019
2069
|
*/
|
|
2020
|
-
static async resolve({
|
|
2070
|
+
static async resolve({
|
|
2071
|
+
fs,
|
|
2072
|
+
gitdir,
|
|
2073
|
+
ref,
|
|
2074
|
+
depth = undefined,
|
|
2075
|
+
visited = new Set(),
|
|
2076
|
+
}) {
|
|
2021
2077
|
if (depth !== undefined) {
|
|
2022
2078
|
depth--;
|
|
2023
2079
|
if (depth === -1) {
|
|
@@ -2028,7 +2084,7 @@ class GitRefManager {
|
|
|
2028
2084
|
// Is it a ref pointer?
|
|
2029
2085
|
if (ref.startsWith('ref: ')) {
|
|
2030
2086
|
ref = ref.slice('ref: '.length);
|
|
2031
|
-
return GitRefManager.resolve({ fs, gitdir, ref, depth })
|
|
2087
|
+
return GitRefManager.resolve({ fs, gitdir, ref, depth, visited })
|
|
2032
2088
|
}
|
|
2033
2089
|
// Is it a complete and valid SHA?
|
|
2034
2090
|
if (ref.length === 40 && /[0-9a-f]{40}/.test(ref)) {
|
|
@@ -2047,7 +2103,21 @@ class GitRefManager {
|
|
|
2047
2103
|
packedMap.get(ref)
|
|
2048
2104
|
);
|
|
2049
2105
|
if (sha) {
|
|
2050
|
-
|
|
2106
|
+
// Guard against circular symbolic references (e.g. a -> b -> a). Without
|
|
2107
|
+
// tracking visited refs this recursion would not terminate.
|
|
2108
|
+
if (visited.has(ref)) {
|
|
2109
|
+
throw new InternalError(
|
|
2110
|
+
`Circular reference detected while resolving ref "${ref}"`
|
|
2111
|
+
)
|
|
2112
|
+
}
|
|
2113
|
+
visited.add(ref);
|
|
2114
|
+
return GitRefManager.resolve({
|
|
2115
|
+
fs,
|
|
2116
|
+
gitdir,
|
|
2117
|
+
ref: sha.trim(),
|
|
2118
|
+
depth,
|
|
2119
|
+
visited,
|
|
2120
|
+
})
|
|
2051
2121
|
}
|
|
2052
2122
|
}
|
|
2053
2123
|
// Do we give up?
|
|
@@ -3562,21 +3632,26 @@ function applyDelta(delta, source) {
|
|
|
3562
3632
|
if (firstOp.byteLength === targetSize) {
|
|
3563
3633
|
target = firstOp;
|
|
3564
3634
|
} else {
|
|
3565
|
-
//
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3635
|
+
// Build the result from the delta ops instead of pre-allocating `targetSize`.
|
|
3636
|
+
// `targetSize` comes from the delta header and may not match the actual op output,
|
|
3637
|
+
// so allocating it up front can reserve far more memory than the ops produce.
|
|
3638
|
+
// Building from the ops bounds memory to the real output size; the size check below
|
|
3639
|
+
// still validates the total before concatenating.
|
|
3640
|
+
const chunks = [firstOp];
|
|
3641
|
+
let tell = firstOp.byteLength;
|
|
3569
3642
|
|
|
3570
3643
|
while (!reader.eof()) {
|
|
3571
|
-
|
|
3644
|
+
const op = readOp(reader, source);
|
|
3645
|
+
chunks.push(op);
|
|
3646
|
+
tell += op.byteLength;
|
|
3572
3647
|
}
|
|
3573
3648
|
|
|
3574
|
-
const tell = writer.tell();
|
|
3575
3649
|
if (targetSize !== tell) {
|
|
3576
3650
|
throw new InternalError(
|
|
3577
3651
|
`applyDelta expected target buffer to be ${targetSize} bytes but the resulting buffer was ${tell} bytes`
|
|
3578
3652
|
)
|
|
3579
3653
|
}
|
|
3654
|
+
target = Buffer.concat(chunks, targetSize);
|
|
3580
3655
|
}
|
|
3581
3656
|
return target
|
|
3582
3657
|
}
|
|
@@ -4827,8 +4902,25 @@ function parseBuffer(buffer) {
|
|
|
4827
4902
|
const type = mode2type$1(mode);
|
|
4828
4903
|
const path = buffer.slice(space + 1, nullchar).toString('utf8');
|
|
4829
4904
|
|
|
4830
|
-
//
|
|
4831
|
-
|
|
4905
|
+
// Reject reserved entry names, matching git's verify_path(): path separators,
|
|
4906
|
+
// "." and ".." (which resolve outside the working directory), and ".git" (which git
|
|
4907
|
+
// disallows as a path component). Checks mirror git's is_ntfs_dotgit() and
|
|
4908
|
+
// is_hfs_dotgit(): case-insensitive, trailing dots/spaces stripped (NTFS),
|
|
4909
|
+
// NTFS 8.3 short name aliases (git~1..git~9), and HFS+ ignorable Unicode
|
|
4910
|
+
// characters stripped (zero-width joiners, directional marks, BOM, etc.).
|
|
4911
|
+
const hfsClean = path.replace(
|
|
4912
|
+
/[\u200C-\u200F\u202A-\u202E\u206A-\u206F\uFEFF]/g,
|
|
4913
|
+
''
|
|
4914
|
+
);
|
|
4915
|
+
const normalized = hfsClean.toLowerCase().replace(/[. ]+$/, '');
|
|
4916
|
+
if (
|
|
4917
|
+
path.includes('\\') ||
|
|
4918
|
+
path.includes('/') ||
|
|
4919
|
+
hfsClean === '.' ||
|
|
4920
|
+
hfsClean === '..' ||
|
|
4921
|
+
normalized === '.git' ||
|
|
4922
|
+
/^\.?git~[1-9]$/.test(normalized)
|
|
4923
|
+
) {
|
|
4832
4924
|
throw new UnsafeFilepathError(path)
|
|
4833
4925
|
}
|
|
4834
4926
|
|