isomorphic-git 1.38.3 → 1.38.5

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 CHANGED
@@ -1511,6 +1511,18 @@ function compareRefNames(a, b) {
1511
1511
  * This code for `path.join` is directly copied from @zenfs/core/path for bundle size improvements.
1512
1512
  * SPDX-License-Identifier: LGPL-3.0-or-later
1513
1513
  * Copyright (c) James Prevett and other ZenFS contributors.
1514
+ *
1515
+ * Windows support added:
1516
+ * - Backslashes are normalised to forward slashes before processing.
1517
+ * - Drive-letter prefixes (e.g. "C:") are detected and preserved through
1518
+ * normalisation, so absolute Windows paths are handled correctly.
1519
+ * - An absolute argument passed to join() resets the accumulated path,
1520
+ * matching Node behaviour and handling worktree gitdir paths properly.
1521
+ *
1522
+ * Limitation: UNC paths (e.g. \\server\share) are not supported. The leading
1523
+ * backslashes are normalised to forward slashes and then collapsed by
1524
+ * normalizeString, losing the UNC root. Git on Windows works with
1525
+ * drive-letter paths, so this is not expected to be a practical issue.
1514
1526
  */
1515
1527
 
1516
1528
  function normalizeString(path, aar) {
@@ -1574,29 +1586,67 @@ function normalizeString(path, aar) {
1574
1586
  return res
1575
1587
  }
1576
1588
 
1589
+ // Returns the Windows drive prefix ("C:") if present, otherwise null.
1590
+ function getWindowsDrivePrefix(path) {
1591
+ if (path.length >= 2 && /^[a-zA-Z]:/.test(path)) {
1592
+ return path.slice(0, 2) // e.g. "C:"
1593
+ }
1594
+ return null
1595
+ }
1596
+
1577
1597
  function normalize(path) {
1578
1598
  if (!path.length) return '.'
1579
1599
 
1580
- const isAbsolute = path[0] === '/';
1600
+ // Normalise backslashes to forward slashes before any other processing.
1601
+ path = path.replace(/\\/g, '/');
1602
+
1603
+ const drivePrefix = getWindowsDrivePrefix(path);
1604
+ // isAbsolute: Unix root ('/foo') OR Windows drive+slash ('C:/foo').
1605
+ const isAbsolute =
1606
+ path[0] === '/' || (drivePrefix !== null && path[2] === '/');
1581
1607
  const trailingSeparator = path.at(-1) === '/';
1582
1608
 
1583
- path = normalizeString(path, !isAbsolute);
1609
+ // Strip the drive prefix before feeding into normalizeString so that the
1610
+ // core algorithm only ever sees a plain POSIX-style string.
1611
+ const pathBody = drivePrefix ? path.slice(2) : path;
1612
+
1613
+ let normalized = normalizeString(pathBody, !isAbsolute);
1584
1614
 
1585
- if (!path.length) {
1586
- if (isAbsolute) return '/'
1587
- return trailingSeparator ? './' : '.'
1615
+ if (!normalized.length) {
1616
+ const root = drivePrefix
1617
+ ? isAbsolute
1618
+ ? drivePrefix + '/'
1619
+ : drivePrefix
1620
+ : isAbsolute
1621
+ ? '/'
1622
+ : '.';
1623
+ return trailingSeparator && !isAbsolute ? root + '/' : root
1588
1624
  }
1589
- if (trailingSeparator) path += '/';
1625
+ if (trailingSeparator) normalized += '/';
1590
1626
 
1591
- return isAbsolute ? `/${path}` : path
1627
+ if (drivePrefix) {
1628
+ return isAbsolute
1629
+ ? `${drivePrefix}/${normalized}`
1630
+ : `${drivePrefix}${normalized}`
1631
+ }
1632
+ return isAbsolute ? `/${normalized}` : normalized
1592
1633
  }
1593
1634
 
1594
1635
  function join(...args) {
1595
1636
  if (args.length === 0) return '.'
1596
1637
  let joined;
1597
1638
  for (let i = 0; i < args.length; ++i) {
1598
- const arg = args[i];
1599
- if (arg.length > 0) {
1639
+ // Normalise separators before processing.
1640
+ const arg = args[i].replace(/\\/g, '/');
1641
+ if (arg.length === 0) continue
1642
+
1643
+ // A Windows drive-letter path (e.g. "C:/worktrees/foo") cannot be
1644
+ // meaningfully appended to any base, so it resets the accumulator.
1645
+ // Unix absolute paths (leading '/') are NOT reset here — that would be
1646
+ // path.resolve() semantics; path.join('foo', '/bar') must yield 'foo/bar'.
1647
+ if (/^[a-zA-Z]:\//.test(arg)) {
1648
+ joined = arg;
1649
+ } else {
1600
1650
  if (joined === undefined) joined = arg;
1601
1651
  else joined += '/' + arg;
1602
1652
  }
@@ -9331,6 +9381,16 @@ async function hasObject({
9331
9381
  return result
9332
9382
  }
9333
9383
 
9384
+ function addCredentialUsername({ config, onAuth }) {
9385
+ if (!onAuth) return onAuth
9386
+
9387
+ return async (url, auth) => {
9388
+ const username =
9389
+ auth.username || (await config.get(`credential.${url}.username`));
9390
+ return onAuth(url, username ? { ...auth, username } : auth)
9391
+ }
9392
+ }
9393
+
9334
9394
  // TODO: make a function that just returns obCount. then emptyPackfile = () => sizePack(pack) === 0
9335
9395
  function emptyPackfile(pack) {
9336
9396
  const pheader = '5041434b';
@@ -9350,8 +9410,8 @@ function filterCapabilities(server, client) {
9350
9410
 
9351
9411
  const pkg = {
9352
9412
  name: 'isomorphic-git',
9353
- version: '1.38.3',
9354
- agent: 'git/isomorphic-git@1.38.3',
9413
+ version: '1.38.5',
9414
+ agent: 'git/isomorphic-git@1.38.5',
9355
9415
  };
9356
9416
 
9357
9417
  class FIFO {
@@ -9765,9 +9825,9 @@ async function _fetch({
9765
9825
  const GitRemoteHTTP = GitRemoteManager.getRemoteHelperFor({ url });
9766
9826
  const remoteHTTP = await GitRemoteHTTP.discover({
9767
9827
  http,
9768
- onAuth,
9828
+ onAuth: addCredentialUsername({ config, onAuth }),
9769
9829
  onAuthSuccess,
9770
- onAuthFailure,
9830
+ onAuthFailure: addCredentialUsername({ config, onAuth: onAuthFailure }),
9771
9831
  corsProxy,
9772
9832
  service: 'git-upload-pack',
9773
9833
  url,
@@ -13886,9 +13946,9 @@ async function _push({
13886
13946
  const GitRemoteHTTP = GitRemoteManager.getRemoteHelperFor({ url });
13887
13947
  const httpRemote = await GitRemoteHTTP.discover({
13888
13948
  http,
13889
- onAuth,
13949
+ onAuth: addCredentialUsername({ config, onAuth }),
13890
13950
  onAuthSuccess,
13891
- onAuthFailure,
13951
+ onAuthFailure: addCredentialUsername({ config, onAuth: onAuthFailure }),
13892
13952
  corsProxy,
13893
13953
  service: 'git-receive-pack',
13894
13954
  url,
package/index.js CHANGED
@@ -1504,6 +1504,18 @@ function compareRefNames(a, b) {
1504
1504
  * This code for `path.join` is directly copied from @zenfs/core/path for bundle size improvements.
1505
1505
  * SPDX-License-Identifier: LGPL-3.0-or-later
1506
1506
  * Copyright (c) James Prevett and other ZenFS contributors.
1507
+ *
1508
+ * Windows support added:
1509
+ * - Backslashes are normalised to forward slashes before processing.
1510
+ * - Drive-letter prefixes (e.g. "C:") are detected and preserved through
1511
+ * normalisation, so absolute Windows paths are handled correctly.
1512
+ * - An absolute argument passed to join() resets the accumulated path,
1513
+ * matching Node behaviour and handling worktree gitdir paths properly.
1514
+ *
1515
+ * Limitation: UNC paths (e.g. \\server\share) are not supported. The leading
1516
+ * backslashes are normalised to forward slashes and then collapsed by
1517
+ * normalizeString, losing the UNC root. Git on Windows works with
1518
+ * drive-letter paths, so this is not expected to be a practical issue.
1507
1519
  */
1508
1520
 
1509
1521
  function normalizeString(path, aar) {
@@ -1567,29 +1579,67 @@ function normalizeString(path, aar) {
1567
1579
  return res
1568
1580
  }
1569
1581
 
1582
+ // Returns the Windows drive prefix ("C:") if present, otherwise null.
1583
+ function getWindowsDrivePrefix(path) {
1584
+ if (path.length >= 2 && /^[a-zA-Z]:/.test(path)) {
1585
+ return path.slice(0, 2) // e.g. "C:"
1586
+ }
1587
+ return null
1588
+ }
1589
+
1570
1590
  function normalize(path) {
1571
1591
  if (!path.length) return '.'
1572
1592
 
1573
- const isAbsolute = path[0] === '/';
1593
+ // Normalise backslashes to forward slashes before any other processing.
1594
+ path = path.replace(/\\/g, '/');
1595
+
1596
+ const drivePrefix = getWindowsDrivePrefix(path);
1597
+ // isAbsolute: Unix root ('/foo') OR Windows drive+slash ('C:/foo').
1598
+ const isAbsolute =
1599
+ path[0] === '/' || (drivePrefix !== null && path[2] === '/');
1574
1600
  const trailingSeparator = path.at(-1) === '/';
1575
1601
 
1576
- path = normalizeString(path, !isAbsolute);
1602
+ // Strip the drive prefix before feeding into normalizeString so that the
1603
+ // core algorithm only ever sees a plain POSIX-style string.
1604
+ const pathBody = drivePrefix ? path.slice(2) : path;
1605
+
1606
+ let normalized = normalizeString(pathBody, !isAbsolute);
1577
1607
 
1578
- if (!path.length) {
1579
- if (isAbsolute) return '/'
1580
- return trailingSeparator ? './' : '.'
1608
+ if (!normalized.length) {
1609
+ const root = drivePrefix
1610
+ ? isAbsolute
1611
+ ? drivePrefix + '/'
1612
+ : drivePrefix
1613
+ : isAbsolute
1614
+ ? '/'
1615
+ : '.';
1616
+ return trailingSeparator && !isAbsolute ? root + '/' : root
1581
1617
  }
1582
- if (trailingSeparator) path += '/';
1618
+ if (trailingSeparator) normalized += '/';
1583
1619
 
1584
- return isAbsolute ? `/${path}` : path
1620
+ if (drivePrefix) {
1621
+ return isAbsolute
1622
+ ? `${drivePrefix}/${normalized}`
1623
+ : `${drivePrefix}${normalized}`
1624
+ }
1625
+ return isAbsolute ? `/${normalized}` : normalized
1585
1626
  }
1586
1627
 
1587
1628
  function join(...args) {
1588
1629
  if (args.length === 0) return '.'
1589
1630
  let joined;
1590
1631
  for (let i = 0; i < args.length; ++i) {
1591
- const arg = args[i];
1592
- if (arg.length > 0) {
1632
+ // Normalise separators before processing.
1633
+ const arg = args[i].replace(/\\/g, '/');
1634
+ if (arg.length === 0) continue
1635
+
1636
+ // A Windows drive-letter path (e.g. "C:/worktrees/foo") cannot be
1637
+ // meaningfully appended to any base, so it resets the accumulator.
1638
+ // Unix absolute paths (leading '/') are NOT reset here — that would be
1639
+ // path.resolve() semantics; path.join('foo', '/bar') must yield 'foo/bar'.
1640
+ if (/^[a-zA-Z]:\//.test(arg)) {
1641
+ joined = arg;
1642
+ } else {
1593
1643
  if (joined === undefined) joined = arg;
1594
1644
  else joined += '/' + arg;
1595
1645
  }
@@ -9318,6 +9368,16 @@ async function hasObject({
9318
9368
  return result
9319
9369
  }
9320
9370
 
9371
+ function addCredentialUsername({ config, onAuth }) {
9372
+ if (!onAuth) return onAuth
9373
+
9374
+ return async (url, auth) => {
9375
+ const username =
9376
+ auth.username || (await config.get(`credential.${url}.username`));
9377
+ return onAuth(url, username ? { ...auth, username } : auth)
9378
+ }
9379
+ }
9380
+
9321
9381
  // TODO: make a function that just returns obCount. then emptyPackfile = () => sizePack(pack) === 0
9322
9382
  function emptyPackfile(pack) {
9323
9383
  const pheader = '5041434b';
@@ -9337,8 +9397,8 @@ function filterCapabilities(server, client) {
9337
9397
 
9338
9398
  const pkg = {
9339
9399
  name: 'isomorphic-git',
9340
- version: '1.38.3',
9341
- agent: 'git/isomorphic-git@1.38.3',
9400
+ version: '1.38.5',
9401
+ agent: 'git/isomorphic-git@1.38.5',
9342
9402
  };
9343
9403
 
9344
9404
  class FIFO {
@@ -9752,9 +9812,9 @@ async function _fetch({
9752
9812
  const GitRemoteHTTP = GitRemoteManager.getRemoteHelperFor({ url });
9753
9813
  const remoteHTTP = await GitRemoteHTTP.discover({
9754
9814
  http,
9755
- onAuth,
9815
+ onAuth: addCredentialUsername({ config, onAuth }),
9756
9816
  onAuthSuccess,
9757
- onAuthFailure,
9817
+ onAuthFailure: addCredentialUsername({ config, onAuth: onAuthFailure }),
9758
9818
  corsProxy,
9759
9819
  service: 'git-upload-pack',
9760
9820
  url,
@@ -13873,9 +13933,9 @@ async function _push({
13873
13933
  const GitRemoteHTTP = GitRemoteManager.getRemoteHelperFor({ url });
13874
13934
  const httpRemote = await GitRemoteHTTP.discover({
13875
13935
  http,
13876
- onAuth,
13936
+ onAuth: addCredentialUsername({ config, onAuth }),
13877
13937
  onAuthSuccess,
13878
- onAuthFailure,
13938
+ onAuthFailure: addCredentialUsername({ config, onAuth: onAuthFailure }),
13879
13939
  corsProxy,
13880
13940
  service: 'git-receive-pack',
13881
13941
  url,