modern-tar 0.7.1 → 0.7.2

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/fs/index.js CHANGED
@@ -1,19 +1,37 @@
1
- import { a as normalizeBody, c as LINK, l as SYMLINK, n as createTarPacker, o as DIRECTORY, r as transformHeader, s as FILE, t as createUnpacker } from "../unpacker-Bn-I_G6u.js";
1
+ import { a as normalizeBody, c as LINK, l as SYMLINK, n as createTarPacker, o as DIRECTORY, r as transformHeader, s as FILE, t as createUnpacker } from "../unpacker-EHw0ivci.js";
2
2
  import * as fs from "node:fs/promises";
3
3
  import { cpus } from "node:os";
4
4
  import * as path from "node:path";
5
5
  import { Readable, Writable } from "node:stream";
6
6
  import * as fs$1 from "node:fs";
7
7
 
8
+ //#region src/fs/cache.ts
9
+ const createCache = () => {
10
+ const m = /* @__PURE__ */ new Map();
11
+ return {
12
+ get(k) {
13
+ const v = m.get(k);
14
+ if (m.delete(k)) m.set(k, v);
15
+ return v;
16
+ },
17
+ set(k, v) {
18
+ if (m.set(k, v).size > 1e4) m.delete(m.keys().next().value);
19
+ }
20
+ };
21
+ };
22
+
23
+ //#endregion
8
24
  //#region src/fs/path.ts
9
- const unicodeCache = /* @__PURE__ */ new Map();
25
+ const unicodeCache = createCache();
10
26
  const normalizeUnicode = (s) => {
11
- let result = unicodeCache.get(s);
12
- if (result !== void 0) unicodeCache.delete(s);
13
- result = result ?? s.normalize("NFD");
14
- unicodeCache.set(s, result);
15
- if (unicodeCache.size > 1e4) unicodeCache.delete(unicodeCache.keys().next().value);
16
- return result;
27
+ for (let i = 0; i < s.length; i++) if (s.charCodeAt(i) >= 128) {
28
+ const cached = unicodeCache.get(s);
29
+ if (cached !== void 0) return cached;
30
+ const normalized = s.normalize("NFD");
31
+ unicodeCache.set(s, normalized);
32
+ return normalized;
33
+ }
34
+ return s;
17
35
  };
18
36
  function validateBounds(targetPath, destDir, errorMessage) {
19
37
  const target = normalizeUnicode(path.resolve(targetPath));
@@ -456,17 +474,18 @@ function createFileSink(path$1, { mode = 438, mtime } = {}) {
456
474
 
457
475
  //#endregion
458
476
  //#region src/fs/path-cache.ts
477
+ const ENOENT = "ENOENT";
459
478
  const createPathCache = (destDirPath, options) => {
460
- const dirPromises = /* @__PURE__ */ new Map();
461
- const pathConflicts = /* @__PURE__ */ new Map();
479
+ const dirPromises = createCache();
480
+ const pathConflicts = createCache();
462
481
  const deferredLinks = [];
463
- const realDirCache = /* @__PURE__ */ new Map();
482
+ const realDirCache = createCache();
464
483
  const initializeDestDir = async (destDirPath$1) => {
465
484
  const symbolic = normalizeUnicode(path.resolve(destDirPath$1));
466
485
  try {
467
486
  await fs.mkdir(symbolic, { recursive: true });
468
487
  } catch (err) {
469
- if (err.code === "ENOENT") {
488
+ if (err.code === ENOENT) {
470
489
  const parentDir = path.dirname(symbolic);
471
490
  if (parentDir === symbolic) throw err;
472
491
  await fs.mkdir(parentDir, { recursive: true });
@@ -479,7 +498,7 @@ const createPathCache = (destDirPath, options) => {
479
498
  real: await fs.realpath(symbolic)
480
499
  };
481
500
  } catch (err) {
482
- if (err.code === "ENOENT") return {
501
+ if (err.code === ENOENT) return {
483
502
  symbolic,
484
503
  real: symbolic
485
504
  };
@@ -519,12 +538,12 @@ const createPathCache = (destDirPath, options) => {
519
538
  const realPath = await getRealDir(dirPath, `Symlink "${dirPath}" points outside the extraction directory.`);
520
539
  if ((await fs.stat(realPath)).isDirectory()) return;
521
540
  } catch (err) {
522
- if (err.code === "ENOENT") throw new Error(`Symlink "${dirPath}" points outside the extraction directory.`);
541
+ if (err.code === ENOENT) throw new Error(`Symlink "${dirPath}" points outside the extraction directory.`);
523
542
  throw err;
524
543
  }
525
544
  throw new Error(`"${dirPath}" is not a valid directory component.`);
526
545
  } catch (err) {
527
- if (err.code === "ENOENT") {
546
+ if (err.code === ENOENT) {
528
547
  await fs.mkdir(dirPath, { mode: mode ?? options.dmode });
529
548
  return;
530
549
  }
@@ -535,6 +554,9 @@ const createPathCache = (destDirPath, options) => {
535
554
  return promise;
536
555
  };
537
556
  return {
557
+ async ready() {
558
+ await destDirPromise;
559
+ },
538
560
  async preparePath(header) {
539
561
  const { name, linkname, type, mode, mtime } = header;
540
562
  const { maxDepth = 1024, dmode } = options;
@@ -549,10 +571,7 @@ const createPathCache = (destDirPath, options) => {
549
571
  const prevOp = pathConflicts.get(normalizedName);
550
572
  if (prevOp) {
551
573
  if (prevOp === DIRECTORY && type !== DIRECTORY || prevOp !== DIRECTORY && type === DIRECTORY) throw new Error(`Path conflict ${type} over existing ${prevOp} at "${name}"`);
552
- return {
553
- outPath,
554
- type: "skip"
555
- };
574
+ return;
556
575
  }
557
576
  const parentDir = path.dirname(outPath);
558
577
  switch (type) {
@@ -560,37 +579,22 @@ const createPathCache = (destDirPath, options) => {
560
579
  pathConflicts.set(normalizedName, DIRECTORY);
561
580
  await prepareDirectory(outPath, dmode ?? mode);
562
581
  if (mtime) await fs.lutimes(outPath, mtime, mtime).catch(() => {});
563
- return {
564
- outPath,
565
- type: "dir"
566
- };
582
+ return;
567
583
  case FILE:
568
584
  pathConflicts.set(normalizedName, FILE);
569
585
  await prepareDirectory(parentDir);
570
- return {
571
- outPath,
572
- type: "file"
573
- };
586
+ return outPath;
574
587
  case SYMLINK:
575
588
  pathConflicts.set(normalizedName, SYMLINK);
576
- if (!linkname) return {
577
- outPath,
578
- type: "symlink"
579
- };
589
+ if (!linkname) return;
580
590
  await prepareDirectory(parentDir);
581
591
  validateBounds(path.resolve(parentDir, linkname), destDir.symbolic, `Symlink "${linkname}" points outside the extraction directory.`);
582
592
  await fs.symlink(linkname, outPath);
583
593
  if (mtime) await fs.lutimes(outPath, mtime, mtime).catch(() => {});
584
- return {
585
- outPath,
586
- type: "symlink"
587
- };
594
+ return;
588
595
  case LINK: {
589
596
  pathConflicts.set(normalizedName, LINK);
590
- if (!linkname) return {
591
- outPath,
592
- type: "link"
593
- };
597
+ if (!linkname) return;
594
598
  const normalizedLink = normalizeUnicode(linkname);
595
599
  if (path.isAbsolute(normalizedLink)) throw new Error(`Hardlink "${linkname}" points outside the extraction directory.`);
596
600
  const linkTarget = path.join(destDir.symbolic, normalizedLink);
@@ -605,22 +609,16 @@ const createPathCache = (destDirPath, options) => {
605
609
  outPath
606
610
  });
607
611
  }
608
- return {
609
- outPath,
610
- type: "link"
611
- };
612
+ return;
612
613
  }
613
- default: return {
614
- outPath,
615
- type: "skip"
616
- };
614
+ default: return;
617
615
  }
618
616
  },
619
617
  async applyLinks() {
620
618
  for (const { linkTarget, outPath } of deferredLinks) try {
621
619
  await fs.link(linkTarget, outPath);
622
620
  } catch (err) {
623
- if (err.code === "ENOENT") throw new Error(`Hardlink target "${linkTarget}" does not exist for link at "${outPath}".`);
621
+ if (err.code === ENOENT) throw new Error(`Hardlink target "${linkTarget}" does not exist for link at "${outPath}".`);
624
622
  throw err;
625
623
  }
626
624
  }
@@ -669,11 +667,7 @@ function unpackTar(directoryPath, options = {}) {
669
667
  }
670
668
  while (true) {
671
669
  const header = unpacker.readHeader();
672
- if (header === void 0) {
673
- cb();
674
- return;
675
- }
676
- if (header === null) {
670
+ if (header === void 0 || header === null) {
677
671
  cb();
678
672
  return;
679
673
  }
@@ -686,9 +680,9 @@ function unpackTar(directoryPath, options = {}) {
686
680
  }
687
681
  continue;
688
682
  }
689
- const prep = await opQueue.add(() => pathCache.preparePath(transformedHeader));
690
- if (prep.type === "file") {
691
- const fileStream = createFileSink(prep.outPath, {
683
+ const outPath = await opQueue.add(() => pathCache.preparePath(transformedHeader));
684
+ if (outPath) {
685
+ const fileStream = createFileSink(outPath, {
692
686
  mode: options.fmode ?? transformedHeader.mode ?? void 0,
693
687
  mtime: transformedHeader.mtime ?? void 0
694
688
  });
@@ -729,6 +723,7 @@ function unpackTar(directoryPath, options = {}) {
729
723
  try {
730
724
  unpacker.end();
731
725
  unpacker.validateEOF();
726
+ await pathCache.ready();
732
727
  await opQueue.onIdle();
733
728
  await pathCache.applyLinks();
734
729
  cb();
@@ -91,7 +91,7 @@ function readOctal(view, offset, size) {
91
91
  const charCode = view[i];
92
92
  if (charCode === 0) break;
93
93
  if (charCode === 32) continue;
94
- value = (value << 3) + (charCode - 48);
94
+ value = value * 8 + (charCode - 48);
95
95
  }
96
96
  return value;
97
97
  }
@@ -442,8 +442,9 @@ function createTarPacker(onData, onError, onFinalize) {
442
442
 
443
443
  //#endregion
444
444
  //#region src/tar/chunk-queue.ts
445
+ const INITIAL_CAPACITY = 256;
445
446
  function createChunkQueue() {
446
- let chunks = new Array(256);
447
+ let chunks = new Array(INITIAL_CAPACITY);
447
448
  let capacityMask = chunks.length - 1;
448
449
  let head = 0;
449
450
  let tail = 0;
@@ -455,6 +456,12 @@ function createChunkQueue() {
455
456
  head = head + 1 & capacityMask;
456
457
  } else chunks[head] = chunk.subarray(count);
457
458
  totalAvailable -= count;
459
+ if (totalAvailable === 0 && chunks.length > INITIAL_CAPACITY) {
460
+ chunks = new Array(INITIAL_CAPACITY);
461
+ capacityMask = INITIAL_CAPACITY - 1;
462
+ head = 0;
463
+ tail = 0;
464
+ }
458
465
  };
459
466
  function pull(bytes, callback) {
460
467
  if (callback) {
package/dist/web/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as normalizeBody, i as isBodyless, n as createTarPacker$1, r as transformHeader, t as createUnpacker } from "../unpacker-Bn-I_G6u.js";
1
+ import { a as normalizeBody, i as isBodyless, n as createTarPacker$1, r as transformHeader, t as createUnpacker } from "../unpacker-EHw0ivci.js";
2
2
 
3
3
  //#region src/web/compression.ts
4
4
  function createGzipEncoder() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "modern-tar",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
4
4
  "description": "Zero dependency streaming tar parser and writer for JavaScript.",
5
5
  "author": "Ayuhito <hello@ayuhito.com>",
6
6
  "license": "MIT",