@gesslar/toolkit 3.22.1 → 3.22.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/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "gesslar",
6
6
  "url": "https://gesslar.dev"
7
7
  },
8
- "version": "3.22.1",
8
+ "version": "3.22.2",
9
9
  "license": "Unlicense",
10
10
  "homepage": "https://github.com/gesslar/toolkit#readme",
11
11
  "repository": {
@@ -93,16 +93,17 @@ export default class DirectoryObject extends FS {
93
93
  * Constructs a DirectoryObject instance.
94
94
  *
95
95
  * @param {string?} [supplied="."] - The directory path (defaults to current directory)
96
+ * @param {DirectoryObject?} [parent] - Optional parent directory (ignored by DirectoryObject, used by subclasses)
96
97
  */
97
98
  constructor(supplied) {
99
+ super()
100
+
98
101
  const fixedDir = supplied || "."
99
102
 
100
103
  Valid.type(fixedDir, "String")
101
104
 
102
- super()
103
-
104
105
  const normalizedDir = FS.fixSlashes(fixedDir)
105
- const resolved = path.resolve(normalizedDir)
106
+ const resolved = FS.resolvePath(DirectoryObject.cwd, normalizedDir)
106
107
  const {dir, name, root} = FS.pathParts(resolved)
107
108
  const url = new URL(FS.pathToUrl(resolved))
108
109
  const trail = resolved.split(path.sep)
@@ -131,7 +132,7 @@ export default class DirectoryObject extends FS {
131
132
  * console.log(projectRoot.path) // process.cwd()
132
133
  */
133
134
  static fromCwd() {
134
- return new this(process.cwd())
135
+ return new this(FS.cwd)
135
136
  }
136
137
 
137
138
  /**
@@ -560,6 +561,26 @@ export default class DirectoryObject extends FS {
560
561
  return normalized
561
562
  }
562
563
 
564
+ /**
565
+ * Gets the parent directory object for a given virtual path.
566
+ * Returns the cap if the path is at the cap root.
567
+ *
568
+ * @private
569
+ * @param {string} virtualPath - The virtual path
570
+ * @returns {VDirectoryObject} The parent directory object
571
+ */
572
+ #getParentDirectoryForPath(virtualPath) {
573
+ const {dir} = FS.pathParts(virtualPath)
574
+
575
+ // If at cap root, return cap
576
+ if(dir === this.cap.path || dir === this.sep) {
577
+ return this.cap
578
+ }
579
+
580
+ // Create parent directory object (recursive - it will get its own parent)
581
+ return new this.constructor(dir, this.cap)
582
+ }
583
+
563
584
  /**
564
585
  * Validates that a resolved virtual path stays within the cap boundary.
565
586
  *
@@ -578,7 +599,12 @@ export default class DirectoryObject extends FS {
578
599
  relativeFromCap
579
600
  )
580
601
 
581
- if(!FS.pathContains(this.cap.real.path, resolvedRealPath)) {
602
+ // Check if resolved path is within cap (handles case where path equals cap root)
603
+ const capRealPath = this.cap.real.path
604
+ const isWithinCap = resolvedRealPath === capRealPath
605
+ || FS.pathContains(capRealPath, resolvedRealPath)
606
+
607
+ if(!isWithinCap) {
582
608
  throw Sass.new(`${normalized} would be out of bounds (cap: ${this.cap.path}).`)
583
609
  }
584
610
 
@@ -609,35 +635,28 @@ export default class DirectoryObject extends FS {
609
635
  getDirectory(dir) {
610
636
  Valid.type(dir, "String", {allowEmpty: false})
611
637
 
612
- // Handle VDirectoryObject with absolute virtual paths (starting with "/")
613
- if(this.isVirtual && dir.startsWith(this.sep)) {
614
- const normalized = this.#resolveAndValidateFromCap(dir)
638
+ // Validate boundaries before passing raw input to constructor
639
+ if(this.isVirtual) {
640
+ // VDO: validate cap boundary, then pass raw input to constructor
641
+ if(dir.startsWith(this.sep)) {
642
+ // Absolute path: validate from cap root
643
+ this.#resolveAndValidateFromCap(dir)
644
+ } else {
645
+ // Relative path: resolve and validate stays within cap
646
+ const newPath = FS.resolvePath(this.path, dir)
647
+ this.#validateCapBoundary(newPath)
648
+ }
615
649
 
616
- // Pass cap as parent so it resolves from cap root, not current directory
617
- return new this.constructor(normalized, this.cap)
650
+ // Pass raw input; constructor handles resolution and parent determination
651
+ return new this.constructor(dir, this)
618
652
  }
619
653
 
620
- // Regular resolution
654
+ // Regular DO: validate local-only constraint
621
655
  const newPath = FS.resolvePath(this.path, dir)
656
+ Valid.assert(this.#isLocal(newPath), `${newPath} would be out of bounds.`)
622
657
 
623
- // Validate bounds
624
- if(!this.isVirtual) {
625
- // Regular DO: enforce local-only constraint
626
- Valid.assert(this.#isLocal(newPath), `${newPath} would be out of bounds.`)
627
-
628
- return new this.constructor(newPath, this)
629
- }
630
-
631
- // VDO relative paths: only allow nested if explicitly prefixed with ./
632
- // This maintains security while allowing explicit relative navigation
633
- if(dir.includes(this.sep) && !dir.startsWith(`.${this.sep}`)) {
634
- throw Sass.new(`${dir} would be out of bounds. Use "./${dir}" for nested paths or chain getDirectory() calls.`)
635
- }
636
-
637
- // VDO relative paths: validate cap boundary and pass resolved path
638
- const normalized = this.#validateCapBoundary(newPath)
639
-
640
- return new this.constructor(normalized, this)
658
+ // Pass raw input; constructor will resolve it to cwd
659
+ return new this.constructor(newPath)
641
660
  }
642
661
 
643
662
  /**
@@ -672,33 +691,24 @@ export default class DirectoryObject extends FS {
672
691
  getFile(file) {
673
692
  Valid.type(file, "String", {allowEmpty: false})
674
693
 
675
- // Handle VDirectoryObject with absolute virtual paths (starting with "/")
676
- if(this.isVirtual && file.startsWith(this.sep)) {
677
- const normalized = this.#resolveAndValidateFromCap(file)
678
-
679
- return new VFileObject(normalized, this)
680
- }
681
-
682
- // Regular resolution
683
- const resolvedPath = FS.resolvePath(this.path, file)
684
-
685
- // Validate bounds
694
+ // Validate boundaries - check what the resolved path would be
686
695
  if(!this.isVirtual) {
687
- // Regular DO: enforce local-only constraint
696
+ // Regular DO: validate local-only constraint
697
+ const resolvedPath = FS.resolvePath(this.path, file)
688
698
  Valid.assert(this.#isLocal(resolvedPath), `${resolvedPath} would be out of bounds.`)
689
-
690
- return new FileObject(file, this)
691
- }
692
-
693
- // VDO relative paths: only allow nested if explicitly prefixed with ./
694
- // This maintains security while allowing explicit relative navigation
695
- if(file.includes(this.sep) && !file.startsWith(`.${this.sep}`)) {
696
- throw Sass.new(`${file} would be out of bounds. Use "./${file}" for nested paths or chain getFile() calls.`)
699
+ } else {
700
+ // VDO: validate cap boundary
701
+ if(file.startsWith(this.sep)) {
702
+ this.#resolveAndValidateFromCap(file)
703
+ } else {
704
+ const resolvedPath = FS.resolvePath(this.path, file)
705
+ this.#validateCapBoundary(resolvedPath)
706
+ }
697
707
  }
698
708
 
699
- // VDO relative paths: validate cap boundary and pass resolved path
700
- const normalized = this.#validateCapBoundary(resolvedPath)
701
-
702
- return new VFileObject(normalized, this)
709
+ // Pass raw input to constructor - it handles resolution and parent determination
710
+ return this.isVirtual
711
+ ? new VFileObject(file, this)
712
+ : new FileObject(file, this)
703
713
  }
704
714
  }
@@ -206,8 +206,8 @@ export default class FileSystem {
206
206
  if(path.isAbsolute(to))
207
207
  return path.resolve(to)
208
208
 
209
- // Strategy 2: If 'to' contains relative navigation
210
- if(to.startsWith(this.fixSlashes("../")))
209
+ // Strategy 2: If 'to' contains relative navigation (../ or ..)
210
+ if(to.startsWith(this.fixSlashes("../")) || to === "..")
211
211
  return path.resolve(from, to)
212
212
 
213
213
  // Strategy 3: Try overlap-based merging, which will default to a basic
@@ -375,4 +375,13 @@ export default class FileSystem {
375
375
 
376
376
  return this.resolvePath(cap, target)
377
377
  }
378
+
379
+ /**
380
+ * Returns the current working directory as a string.
381
+ *
382
+ * @returns {string} The current working directory
383
+ */
384
+ static get cwd() {
385
+ return process.cwd()
386
+ }
378
387
  }
@@ -60,6 +60,7 @@ export default class DirectoryObject extends FS {
60
60
  * Constructs a DirectoryObject instance.
61
61
  *
62
62
  * @param {string?} [supplied="."] - The directory path (defaults to current directory)
63
+ * @param {DirectoryObject?} [parent] - Optional parent directory (ignored by DirectoryObject, used by subclasses)
63
64
  */
64
65
  constructor(supplied?: string | null);
65
66
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"DirectoryObject.d.ts","sourceRoot":"","sources":["../../../src/node/lib/DirectoryObject.js"],"names":[],"mappings":"AAiBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH;IA2DE;;;;;;;;;OASG;IACH,kBALa,eAAe,CAO3B;IA3CD;;;;OAIG;IACH,uBAFW,MAAM,OAAC,EA0BjB;IA2BD;;;;OAIG;IACH,cAFa,OAAO,CAAC,OAAO,CAAC,CAI5B;IAED;;;;OAIG;IACH,gBAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,YAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,WAFa,GAAG,CAIf;IAED;;;;OAIG;IACH,YAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,cAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,iBAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,WAFa,MAAM,CAIlB;IAED;;;;;;;OAOG;IACH,aALa,KAAK,CAAC,MAAM,CAAC,CAOzB;IAED;;;;;;;;;;;;OAYG;IACH,cARa,eAAe,GAAC,IAAI,CAsBhC;IAED;;;;OAIG;IACH,mBAFa,OAAO,CAInB;IAmBD;;;;;;;;;;;;;;;;;;OAkBG;IACH,WAZW,MAAM,GACJ,OAAO,CAAC;QAAC,KAAK,EAAE,KAAK,CAAC,UAAU,GAAC,WAAW,CAAC,CAAC;QAAC,WAAW,EAAE,KAAK,CAAC,eAAe,GAAC,gBAAgB,CAAC,CAAA;KAAC,CAAC,CA0CjH;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACH,WAZW,MAAM,GACJ,OAAO,CAAC;QAAC,KAAK,EAAE,KAAK,CAAC,UAAU,GAAC,WAAW,CAAC,CAAC;QAAC,WAAW,EAAE,KAAK,CAAC,eAAe,GAAC,gBAAgB,CAAC,CAAA;KAAC,CAAC,CAgDjH;IAED;;;;;;;;;;;;OAYG;IACH,uBARW,MAAM,GACJ,OAAO,CAAC,IAAI,CAAC,CAuBzB;IAyBD;;;;;;;;;;;;;;;OAeG;IACH,cAZa,eAAe,CAc3B;IAED;;;;;;;;;;;;;;OAcG;IACH,UARa,OAAO,CAAC,IAAI,CAAC,CAkBzB;IAED;;;;;OAKG;IACH,kBAHW,MAAM,GACJ,OAAO,CAAC,OAAO,CAAC,CAQ5B;IAED;;;;;OAKG;IACH,sBAHW,MAAM,GACJ,OAAO,CAAC,OAAO,CAAC,CAO5B;IAgED;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,kBAdW,MAAM,GACJ,eAAe,CA6C3B;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,cAfW,MAAM,GACJ,UAAU,GAAC,WAAW,CA6ClC;;CACF;eAnrBc,iBAAiB;uBADT,iBAAiB;wBAIhB,kBAAkB"}
1
+ {"version":3,"file":"DirectoryObject.d.ts","sourceRoot":"","sources":["../../../src/node/lib/DirectoryObject.js"],"names":[],"mappings":"AAiBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH;IA4DE;;;;;;;;;OASG;IACH,kBALa,eAAe,CAO3B;IA5CD;;;;;OAKG;IACH,uBAHW,MAAM,OAAC,EA2BjB;IA2BD;;;;OAIG;IACH,cAFa,OAAO,CAAC,OAAO,CAAC,CAI5B;IAED;;;;OAIG;IACH,gBAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,YAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,WAFa,GAAG,CAIf;IAED;;;;OAIG;IACH,YAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,cAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,iBAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,WAFa,MAAM,CAIlB;IAED;;;;;;;OAOG;IACH,aALa,KAAK,CAAC,MAAM,CAAC,CAOzB;IAED;;;;;;;;;;;;OAYG;IACH,cARa,eAAe,GAAC,IAAI,CAsBhC;IAED;;;;OAIG;IACH,mBAFa,OAAO,CAInB;IAmBD;;;;;;;;;;;;;;;;;;OAkBG;IACH,WAZW,MAAM,GACJ,OAAO,CAAC;QAAC,KAAK,EAAE,KAAK,CAAC,UAAU,GAAC,WAAW,CAAC,CAAC;QAAC,WAAW,EAAE,KAAK,CAAC,eAAe,GAAC,gBAAgB,CAAC,CAAA;KAAC,CAAC,CA0CjH;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACH,WAZW,MAAM,GACJ,OAAO,CAAC;QAAC,KAAK,EAAE,KAAK,CAAC,UAAU,GAAC,WAAW,CAAC,CAAC;QAAC,WAAW,EAAE,KAAK,CAAC,eAAe,GAAC,gBAAgB,CAAC,CAAA;KAAC,CAAC,CAgDjH;IAED;;;;;;;;;;;;OAYG;IACH,uBARW,MAAM,GACJ,OAAO,CAAC,IAAI,CAAC,CAuBzB;IAyBD;;;;;;;;;;;;;;;OAeG;IACH,cAZa,eAAe,CAc3B;IAED;;;;;;;;;;;;;;OAcG;IACH,UARa,OAAO,CAAC,IAAI,CAAC,CAkBzB;IAED;;;;;OAKG;IACH,kBAHW,MAAM,GACJ,OAAO,CAAC,OAAO,CAAC,CAQ5B;IAED;;;;;OAKG;IACH,sBAHW,MAAM,GACJ,OAAO,CAAC,OAAO,CAAC,CAO5B;IAyFD;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,kBAdW,MAAM,GACJ,eAAe,CAsC3B;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,cAfW,MAAM,GACJ,UAAU,GAAC,WAAW,CAoClC;;CACF;eA7rBc,iBAAiB;uBADT,iBAAiB;wBAIhB,kBAAkB"}
@@ -168,6 +168,12 @@ export default class FileSystem {
168
168
  * FS.virtualToRealPath(regular) // "/home/user/file.txt"
169
169
  */
170
170
  static virtualToRealPath(fileOrDirectoryObject: FileObject | DirectoryObject): string;
171
+ /**
172
+ * Returns the current working directory as a string.
173
+ *
174
+ * @returns {string} The current working directory
175
+ */
176
+ static get cwd(): string;
171
177
  /**
172
178
  * Compute the relative path from another file or directory to this instance.
173
179
  *
@@ -1 +1 @@
1
- {"version":3,"file":"FileSystem.d.ts","sourceRoot":"","sources":["../../../src/node/lib/FileSystem.js"],"names":[],"mappings":"AA0BA;;GAEG;AACH;IACE,kCAAwB;IACxB,uCAAkC;IAClC,mBAAsB;IAsBtB;;;;;;OAMG;IACH,4BAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;;;;OAMG;IACH,2BAHW,MAAM,GACJ,MAAM,CAQlB;IAED;;;;;;OAMG;IACH,2BAHW,MAAM,GACJ,MAAM,CAQlB;IAED;;;;;;;;;;OAUG;IACH,gCAJW,UAAU,GAAC,eAAe,MAC1B,UAAU,GAAC,eAAe,GACxB,MAAM,CAYlB;IAED;;;;;;;;;;OAUG;IACH,oCAJW,MAAM,MACN,MAAM,GACJ,MAAM,CAQlB;IAED;;;;;;;;;OASG;IACH,oCALW,MAAM,SACN,MAAM,QACN,MAAM,GACJ,MAAM,CA0BlB;IAED;;;;;;;;OAQG;IACH,6BAJW,MAAM,UACN,MAAM,GACJ,MAAM,CAmClB;IAED;;;;;;;;;;;;OAYG;IACH,+BATW,MAAM,aACN,MAAM,GACJ,OAAO,CAcnB;IAED;;;;;;;;;;;;;;OAcG;IACH,4BATW,MAAM,MACN,MAAM,QACN,MAAM,GACJ,MAAM,GAAC,IAAI,CAwBvB;IAED;;;;;;;;;;;;;;;OAeG;IACH,+BAXW,MAAM,MACN,MAAM,QACN,MAAM,GACJ,MAAM,GAAC,IAAI,CA+BvB;IAED;;;;;OAKG;IAEH;;;;;;;OAOG;IACH,2BAJW,MAAM;;;;cATH,MAAM;;;;aACN,MAAM;;;;aACN,MAAM;MAenB;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,gDAZW,UAAU,GAAC,eAAe,GACxB,MAAM,CAiClB;IAtVD;;;;;;;;;OASG;IACH,kCAJW,UAAU,GAAC,eAAe,GACxB,MAAM,CAWlB;CAqUF;yBAxWa,OAAO,iBAAiB,EAAE,OAAO;8BACjC,OAAO,sBAAsB,EAAE,OAAO"}
1
+ {"version":3,"file":"FileSystem.d.ts","sourceRoot":"","sources":["../../../src/node/lib/FileSystem.js"],"names":[],"mappings":"AA0BA;;GAEG;AACH;IACE,kCAAwB;IACxB,uCAAkC;IAClC,mBAAsB;IAsBtB;;;;;;OAMG;IACH,4BAHW,MAAM,GACJ,MAAM,CAIlB;IAED;;;;;;OAMG;IACH,2BAHW,MAAM,GACJ,MAAM,CAQlB;IAED;;;;;;OAMG;IACH,2BAHW,MAAM,GACJ,MAAM,CAQlB;IAED;;;;;;;;;;OAUG;IACH,gCAJW,UAAU,GAAC,eAAe,MAC1B,UAAU,GAAC,eAAe,GACxB,MAAM,CAYlB;IAED;;;;;;;;;;OAUG;IACH,oCAJW,MAAM,MACN,MAAM,GACJ,MAAM,CAQlB;IAED;;;;;;;;;OASG;IACH,oCALW,MAAM,SACN,MAAM,QACN,MAAM,GACJ,MAAM,CA0BlB;IAED;;;;;;;;OAQG;IACH,6BAJW,MAAM,UACN,MAAM,GACJ,MAAM,CAmClB;IAED;;;;;;;;;;;;OAYG;IACH,+BATW,MAAM,aACN,MAAM,GACJ,OAAO,CAcnB;IAED;;;;;;;;;;;;;;OAcG;IACH,4BATW,MAAM,MACN,MAAM,QACN,MAAM,GACJ,MAAM,GAAC,IAAI,CAwBvB;IAED;;;;;;;;;;;;;;;OAeG;IACH,+BAXW,MAAM,MACN,MAAM,QACN,MAAM,GACJ,MAAM,GAAC,IAAI,CA+BvB;IAED;;;;;OAKG;IAEH;;;;;;;OAOG;IACH,2BAJW,MAAM;;;;cATH,MAAM;;;;aACN,MAAM;;;;aACN,MAAM;MAenB;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,gDAZW,UAAU,GAAC,eAAe,GACxB,MAAM,CAiClB;IAED;;;;OAIG;IACH,kBAFa,MAAM,CAIlB;IA/VD;;;;;;;;;OASG;IACH,kCAJW,UAAU,GAAC,eAAe,GACxB,MAAM,CAWlB;CA8UF;yBAjXa,OAAO,iBAAiB,EAAE,OAAO;8BACjC,OAAO,sBAAsB,EAAE,OAAO"}