@gesslar/toolkit 3.12.3 → 3.14.0
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/README.md +5 -4
- package/package.json +2 -2
- package/src/{index.js → node/index.js} +11 -10
- package/src/{lib → node/lib}/DirectoryObject.js +47 -88
- package/src/{lib → node/lib}/FileObject.js +78 -179
- package/src/{lib/FS.js → node/lib/FileSystem.js} +7 -7
- package/src/{lib → node/lib}/Glog.js +2 -2
- package/src/{lib → node/lib}/Logger.js +1 -1
- package/src/{lib → node/lib}/Sass.js +1 -1
- package/src/{lib → node/lib}/Tantrum.js +1 -1
- package/src/{lib → node/lib}/TempDirectoryObject.js +9 -9
- package/src/{lib → node/lib}/Util.js +1 -1
- package/src/node/lib/VDirectoryObject.js +198 -0
- package/src/node/lib/VFileObject.js +61 -0
- package/src/{lib → node/lib}/Valid.js +11 -5
- package/src/lib/CappedDirectoryObject.js +0 -276
- package/src/types/browser/index.d.ts +0 -13
- package/src/types/browser/index.d.ts.map +0 -1
- package/src/types/browser/lib/Collection.d.ts +0 -248
- package/src/types/browser/lib/Collection.d.ts.map +0 -1
- package/src/types/browser/lib/Data.d.ts +0 -250
- package/src/types/browser/lib/Data.d.ts.map +0 -1
- package/src/types/browser/lib/Disposer.d.ts +0 -33
- package/src/types/browser/lib/Disposer.d.ts.map +0 -1
- package/src/types/browser/lib/HTML.d.ts +0 -40
- package/src/types/browser/lib/HTML.d.ts.map +0 -1
- package/src/types/browser/lib/Notify.d.ts +0 -60
- package/src/types/browser/lib/Notify.d.ts.map +0 -1
- package/src/types/browser/lib/Promised.d.ts +0 -119
- package/src/types/browser/lib/Promised.d.ts.map +0 -1
- package/src/types/browser/lib/Sass.d.ts +0 -63
- package/src/types/browser/lib/Sass.d.ts.map +0 -1
- package/src/types/browser/lib/Tantrum.d.ts +0 -52
- package/src/types/browser/lib/Tantrum.d.ts.map +0 -1
- package/src/types/browser/lib/Time.d.ts +0 -42
- package/src/types/browser/lib/Time.d.ts.map +0 -1
- package/src/types/browser/lib/TypeSpec.d.ts +0 -90
- package/src/types/browser/lib/TypeSpec.d.ts.map +0 -1
- package/src/types/browser/lib/Util.d.ts +0 -62
- package/src/types/browser/lib/Util.d.ts.map +0 -1
- package/src/types/browser/lib/Valid.d.ts +0 -33
- package/src/types/browser/lib/Valid.d.ts.map +0 -1
- package/src/types/browser/lib/vendor/dompurify.esm.d.ts +0 -29
- package/src/types/browser/lib/vendor/dompurify.esm.d.ts.map +0 -1
- package/src/types/index.d.ts +0 -20
- package/src/types/index.d.ts.map +0 -1
- package/src/types/lib/Cache.d.ts +0 -27
- package/src/types/lib/Cache.d.ts.map +0 -1
- package/src/types/lib/CappedDirectoryObject.d.ts +0 -144
- package/src/types/lib/CappedDirectoryObject.d.ts.map +0 -1
- package/src/types/lib/DirectoryObject.d.ts +0 -288
- package/src/types/lib/DirectoryObject.d.ts.map +0 -1
- package/src/types/lib/FS.d.ts +0 -188
- package/src/types/lib/FS.d.ts.map +0 -1
- package/src/types/lib/FileObject.d.ts +0 -245
- package/src/types/lib/FileObject.d.ts.map +0 -1
- package/src/types/lib/Glog.d.ts +0 -228
- package/src/types/lib/Glog.d.ts.map +0 -1
- package/src/types/lib/Logger.d.ts +0 -46
- package/src/types/lib/Logger.d.ts.map +0 -1
- package/src/types/lib/Notify.d.ts +0 -54
- package/src/types/lib/Notify.d.ts.map +0 -1
- package/src/types/lib/Sass.d.ts +0 -9
- package/src/types/lib/Sass.d.ts.map +0 -1
- package/src/types/lib/Tantrum.d.ts +0 -9
- package/src/types/lib/Tantrum.d.ts.map +0 -1
- package/src/types/lib/TempDirectoryObject.d.ts +0 -42
- package/src/types/lib/TempDirectoryObject.d.ts.map +0 -1
- package/src/types/lib/Term.d.ts +0 -127
- package/src/types/lib/Term.d.ts.map +0 -1
- package/src/types/lib/Util.d.ts +0 -100
- package/src/types/lib/Util.d.ts.map +0 -1
- package/src/types/lib/Valid.d.ts +0 -33
- package/src/types/lib/Valid.d.ts.map +0 -1
- /package/src/{lib → node/lib}/Cache.js +0 -0
- /package/src/{lib → node/lib}/Notify.js +0 -0
- /package/src/{lib → node/lib}/Term.js +0 -0
|
@@ -7,13 +7,12 @@
|
|
|
7
7
|
import JSON5 from "json5"
|
|
8
8
|
import fs from "node:fs/promises"
|
|
9
9
|
import path from "node:path"
|
|
10
|
-
import util from "node:util"
|
|
11
10
|
import YAML from "yaml"
|
|
12
11
|
import {URL} from "node:url"
|
|
13
12
|
|
|
14
|
-
import Data from "
|
|
13
|
+
import Data from "../../browser/lib/Data.js"
|
|
15
14
|
import DirectoryObject from "./DirectoryObject.js"
|
|
16
|
-
import FS from "./
|
|
15
|
+
import FS from "./FileSystem.js"
|
|
17
16
|
import Sass from "./Sass.js"
|
|
18
17
|
import Valid from "./Valid.js"
|
|
19
18
|
|
|
@@ -28,7 +27,6 @@ import Valid from "./Valid.js"
|
|
|
28
27
|
* @property {string} module - The file name without extension
|
|
29
28
|
* @property {string} extension - The file extension
|
|
30
29
|
* @property {boolean} isFile - Always true for files
|
|
31
|
-
* @property {boolean} isDirectory - Always false for files
|
|
32
30
|
* @property {DirectoryObject} parent - The parent directory object
|
|
33
31
|
* @property {Promise<boolean>} exists - Whether the file exists (async)
|
|
34
32
|
*/
|
|
@@ -57,7 +55,6 @@ export default class FileObject extends FS {
|
|
|
57
55
|
* @property {string|null} module - The file name without extension
|
|
58
56
|
* @property {string|null} extension - The file extension
|
|
59
57
|
* @property {boolean} isFile - Always true
|
|
60
|
-
* @property {boolean} isDirectory - Always false
|
|
61
58
|
* @property {DirectoryObject|null} parent - The parent directory object
|
|
62
59
|
*/
|
|
63
60
|
#meta = Object.seal({
|
|
@@ -68,7 +65,6 @@ export default class FileObject extends FS {
|
|
|
68
65
|
module: null,
|
|
69
66
|
extension: null,
|
|
70
67
|
isFile: true,
|
|
71
|
-
isDirectory: false,
|
|
72
68
|
parent: null,
|
|
73
69
|
parentPath: null,
|
|
74
70
|
})
|
|
@@ -76,55 +72,65 @@ export default class FileObject extends FS {
|
|
|
76
72
|
/**
|
|
77
73
|
* Constructs a FileObject instance.
|
|
78
74
|
*
|
|
79
|
-
* @param {string}
|
|
75
|
+
* @param {string} submitted - The file path
|
|
80
76
|
* @param {DirectoryObject|string|null} [parent] - The parent directory (object or string)
|
|
81
77
|
*/
|
|
82
|
-
constructor(
|
|
78
|
+
constructor(submitted, parent=null) {
|
|
83
79
|
super()
|
|
84
80
|
|
|
85
|
-
Valid.type(
|
|
81
|
+
Valid.type(submitted, "String", {allowEmpty: false})
|
|
86
82
|
Valid.type(parent, "Null|String|DirectoryObject", {allowEmpty: false})
|
|
87
83
|
|
|
88
|
-
const
|
|
89
|
-
const
|
|
84
|
+
const normalizedFile = FS.fixSlashes(submitted)
|
|
85
|
+
const absOrRel = path.isAbsolute(normalizedFile) && parent
|
|
86
|
+
? FS.absoluteToRelative(normalizedFile, true)
|
|
87
|
+
: normalizedFile
|
|
88
|
+
const {dir, base, ext, name} = FS.pathParts(absOrRel)
|
|
89
|
+
|
|
90
|
+
const [parentObject, fullPath] = (() => {
|
|
91
|
+
if(Data.isType(parent, "String")) {
|
|
92
|
+
const joined = FS.resolvePath(parent, absOrRel)
|
|
93
|
+
const {dir} = FS.pathParts(joined)
|
|
94
|
+
|
|
95
|
+
return [
|
|
96
|
+
new DirectoryObject(dir),
|
|
97
|
+
joined,
|
|
98
|
+
]
|
|
99
|
+
}
|
|
90
100
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
101
|
+
if(Data.isType(parent, "DirectoryObject")) {
|
|
102
|
+
const joined = FS.resolvePath(parent.path, absOrRel)
|
|
103
|
+
const {dir} = FS.pathParts(joined)
|
|
94
104
|
|
|
95
|
-
|
|
96
|
-
|
|
105
|
+
return [
|
|
106
|
+
parent.path === dir
|
|
107
|
+
? parent
|
|
108
|
+
: new DirectoryObject(dir),
|
|
109
|
+
joined,
|
|
110
|
+
]
|
|
111
|
+
}
|
|
97
112
|
|
|
98
|
-
|
|
99
|
-
|
|
113
|
+
const directory = new DirectoryObject(dir)
|
|
114
|
+
const joined = FS.resolvePath(directory.path, absOrRel)
|
|
100
115
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
116
|
+
return [
|
|
117
|
+
directory,
|
|
118
|
+
joined,
|
|
119
|
+
]
|
|
120
|
+
})()
|
|
106
121
|
|
|
107
|
-
|
|
108
|
-
const
|
|
109
|
-
const resolved = FS.resolvePath(parentPath ?? ".", resolvedFilename)
|
|
110
|
-
const {dir: actualParent} = FS.pathParts(resolved)
|
|
122
|
+
const parentPath = parentObject.path
|
|
123
|
+
const resolved = FS.resolvePath(parentPath, fullPath)
|
|
111
124
|
const url = new URL(FS.pathToUrl(resolved))
|
|
112
125
|
|
|
113
|
-
this.#meta.supplied =
|
|
126
|
+
this.#meta.supplied = submitted
|
|
114
127
|
this.#meta.path = resolved
|
|
115
128
|
this.#meta.url = url
|
|
116
129
|
this.#meta.name = base
|
|
117
130
|
this.#meta.extension = ext
|
|
118
|
-
this.#meta.module =
|
|
119
|
-
this.#meta.parentPath =
|
|
120
|
-
|
|
121
|
-
const useCappedParent =
|
|
122
|
-
parentObject.isCapped ||
|
|
123
|
-
FS.fixSlashes(actualParent) === FS.fixSlashes(parentObject.path)
|
|
124
|
-
|
|
125
|
-
this.#meta.parent = useCappedParent
|
|
126
|
-
? parentObject
|
|
127
|
-
: new DirectoryObject(actualParent)
|
|
131
|
+
this.#meta.module = name
|
|
132
|
+
this.#meta.parentPath = parentPath
|
|
133
|
+
this.#meta.parent = parentObject
|
|
128
134
|
|
|
129
135
|
Object.freeze(this.#meta)
|
|
130
136
|
}
|
|
@@ -132,39 +138,12 @@ export default class FileObject extends FS {
|
|
|
132
138
|
/**
|
|
133
139
|
* Returns a string representation of the FileObject.
|
|
134
140
|
*
|
|
135
|
-
* @returns {string}
|
|
141
|
+
* @returns {string} String representation of the FileObject
|
|
136
142
|
*/
|
|
137
143
|
toString() {
|
|
138
|
-
return
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Returns a JSON representation of the FileObject.
|
|
143
|
-
*
|
|
144
|
-
* @returns {object} JSON representation of the FileObject
|
|
145
|
-
*/
|
|
146
|
-
toJSON() {
|
|
147
|
-
return {
|
|
148
|
-
supplied: this.supplied,
|
|
149
|
-
path: this.path,
|
|
150
|
-
url: this.url.toString(),
|
|
151
|
-
name: this.name,
|
|
152
|
-
module: this.module,
|
|
153
|
-
extension: this.extension,
|
|
154
|
-
isFile: this.isFile,
|
|
155
|
-
isDirectory: this.isDirectory,
|
|
156
|
-
parentPath: this.parentPath,
|
|
157
|
-
parent: this.parent ? this.parent.path : null
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Custom inspect method for Node.js console.
|
|
163
|
-
*
|
|
164
|
-
* @returns {object} JSON representation of this object.
|
|
165
|
-
*/
|
|
166
|
-
[util.inspect.custom]() {
|
|
167
|
-
return this.toJSON()
|
|
144
|
+
return this.isVirtual
|
|
145
|
+
?`[${this.constructor.name}: ${this.path} → ${this.real.path}]`
|
|
146
|
+
:`[${this.constructor.name}: ${this.path}]`
|
|
168
147
|
}
|
|
169
148
|
|
|
170
149
|
/**
|
|
@@ -186,44 +165,20 @@ export default class FileObject extends FS {
|
|
|
186
165
|
}
|
|
187
166
|
|
|
188
167
|
/**
|
|
189
|
-
* Returns the file path.
|
|
190
|
-
* virtual path relative to the cap. Otherwise returns the real filesystem
|
|
191
|
-
* path.
|
|
192
|
-
*
|
|
193
|
-
* Use `.real.path` to always get the actual filesystem path.
|
|
168
|
+
* Returns the file path.
|
|
194
169
|
*
|
|
195
|
-
* @returns {string} The file path
|
|
170
|
+
* @returns {string} The file path
|
|
196
171
|
*/
|
|
197
172
|
get path() {
|
|
198
|
-
|
|
199
|
-
const parent = this.#meta.parent
|
|
200
|
-
|
|
201
|
-
// If parent is capped, return virtual path
|
|
202
|
-
if(parent?.isCapped) {
|
|
203
|
-
const cap = parent.cap.real.path
|
|
204
|
-
const capResolved = path.resolve(cap)
|
|
205
|
-
const relativeRealPath = FS.absoluteToRelative(realPath)
|
|
206
|
-
const absolute = FS.resolvePath(capResolved, relativeRealPath)
|
|
207
|
-
|
|
208
|
-
// Return with leading slash to indicate it's cap-relative
|
|
209
|
-
return FS.absoluteToRelative(absolute)
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// Otherwise return real path
|
|
213
|
-
return realPath
|
|
173
|
+
return this.#meta.path
|
|
214
174
|
}
|
|
215
175
|
|
|
216
176
|
/**
|
|
217
|
-
* Returns the URL of the current file.
|
|
218
|
-
* returns a virtual URL relative to the cap. Otherwise returns the real URL.
|
|
177
|
+
* Returns the URL of the current file.
|
|
219
178
|
*
|
|
220
|
-
* @returns {URL} The file URL
|
|
179
|
+
* @returns {URL} The file URL
|
|
221
180
|
*/
|
|
222
181
|
get url() {
|
|
223
|
-
// If parent is capped, return virtual URL
|
|
224
|
-
if(this.parent?.isCapped)
|
|
225
|
-
return new URL(FS.pathToUrl(this.path))
|
|
226
|
-
|
|
227
182
|
return this.#meta.url
|
|
228
183
|
}
|
|
229
184
|
|
|
@@ -262,15 +217,6 @@ export default class FileObject extends FS {
|
|
|
262
217
|
return this.#meta.isFile
|
|
263
218
|
}
|
|
264
219
|
|
|
265
|
-
/**
|
|
266
|
-
* We're not masquerading as a directory! Nope.
|
|
267
|
-
*
|
|
268
|
-
* @returns {boolean} Always false
|
|
269
|
-
*/
|
|
270
|
-
get isDirectory() {
|
|
271
|
-
return this.#meta.isDirectory
|
|
272
|
-
}
|
|
273
|
-
|
|
274
220
|
/**
|
|
275
221
|
* Returns the directory containing this file. This does not necessarily
|
|
276
222
|
* mean that the directory exists. It could be theoretical, you will need
|
|
@@ -294,26 +240,6 @@ export default class FileObject extends FS {
|
|
|
294
240
|
return this.#meta.parentPath
|
|
295
241
|
}
|
|
296
242
|
|
|
297
|
-
/**
|
|
298
|
-
* Returns a plain FileObject representing the actual filesystem location.
|
|
299
|
-
* This provides an "escape hatch" when working with capped directories,
|
|
300
|
-
* allowing direct filesystem access when needed.
|
|
301
|
-
*
|
|
302
|
-
* @returns {FileObject} Uncapped file object at the real filesystem path
|
|
303
|
-
* @example
|
|
304
|
-
* const temp = new TempDirectoryObject("myapp")
|
|
305
|
-
* const file = temp.getFile("/config/app.json")
|
|
306
|
-
*
|
|
307
|
-
* // file.path shows virtual path
|
|
308
|
-
* console.log(file.path) // "/config/app.json"
|
|
309
|
-
* // file.real.path shows actual filesystem path
|
|
310
|
-
* console.log(file.real.path) // "/tmp/myapp-ABC123/config/app.json"
|
|
311
|
-
* file.real.parent.parent // Can traverse outside the cap
|
|
312
|
-
*/
|
|
313
|
-
get real() {
|
|
314
|
-
return new FileObject(this.path)
|
|
315
|
-
}
|
|
316
|
-
|
|
317
243
|
/**
|
|
318
244
|
* Check if a file can be read. Returns true if the file can be read, false
|
|
319
245
|
*
|
|
@@ -321,7 +247,7 @@ export default class FileObject extends FS {
|
|
|
321
247
|
*/
|
|
322
248
|
async canRead() {
|
|
323
249
|
try {
|
|
324
|
-
await fs.access(this
|
|
250
|
+
await fs.access(this.real?.path ?? this.path, fs.constants.R_OK)
|
|
325
251
|
|
|
326
252
|
return true
|
|
327
253
|
} catch {
|
|
@@ -336,7 +262,7 @@ export default class FileObject extends FS {
|
|
|
336
262
|
*/
|
|
337
263
|
async canWrite() {
|
|
338
264
|
try {
|
|
339
|
-
await fs.access(this
|
|
265
|
+
await fs.access(this.real?.path ?? this.path, fs.constants.W_OK)
|
|
340
266
|
|
|
341
267
|
return true
|
|
342
268
|
} catch {
|
|
@@ -351,7 +277,7 @@ export default class FileObject extends FS {
|
|
|
351
277
|
*/
|
|
352
278
|
async #fileExists() {
|
|
353
279
|
try {
|
|
354
|
-
await fs.access(this
|
|
280
|
+
await fs.access(this.real?.path ?? this.path, fs.constants.F_OK)
|
|
355
281
|
|
|
356
282
|
return true
|
|
357
283
|
} catch {
|
|
@@ -366,7 +292,7 @@ export default class FileObject extends FS {
|
|
|
366
292
|
*/
|
|
367
293
|
async size() {
|
|
368
294
|
try {
|
|
369
|
-
const stat = await fs.stat(this
|
|
295
|
+
const stat = await fs.stat(this.real?.path ?? this.path)
|
|
370
296
|
|
|
371
297
|
return stat.size
|
|
372
298
|
} catch {
|
|
@@ -382,7 +308,7 @@ export default class FileObject extends FS {
|
|
|
382
308
|
*/
|
|
383
309
|
async modified() {
|
|
384
310
|
try {
|
|
385
|
-
const stat = await fs.stat(this
|
|
311
|
+
const stat = await fs.stat(this.real?.path ?? this.path)
|
|
386
312
|
|
|
387
313
|
return stat.mtime
|
|
388
314
|
} catch {
|
|
@@ -397,15 +323,12 @@ export default class FileObject extends FS {
|
|
|
397
323
|
* @returns {Promise<string>} The file contents
|
|
398
324
|
*/
|
|
399
325
|
async read(encoding="utf8") {
|
|
400
|
-
const
|
|
401
|
-
|
|
402
|
-
if(!url)
|
|
403
|
-
throw Sass.new("No URL in file map")
|
|
326
|
+
const filePath = this.real?.path ?? this.path
|
|
404
327
|
|
|
405
328
|
if(!(await this.exists))
|
|
406
|
-
throw Sass.new(`No such file '${
|
|
329
|
+
throw Sass.new(`No such file '${filePath}'`)
|
|
407
330
|
|
|
408
|
-
return await fs.readFile(
|
|
331
|
+
return await fs.readFile(filePath, encoding)
|
|
409
332
|
}
|
|
410
333
|
|
|
411
334
|
/**
|
|
@@ -421,15 +344,12 @@ export default class FileObject extends FS {
|
|
|
421
344
|
* // Use the buffer (e.g., send in HTTP response, process image, etc.)
|
|
422
345
|
*/
|
|
423
346
|
async readBinary() {
|
|
424
|
-
const
|
|
425
|
-
|
|
426
|
-
if(!url)
|
|
427
|
-
throw Sass.new("No URL in file map")
|
|
347
|
+
const filePath = this.real?.path ?? this.path
|
|
428
348
|
|
|
429
349
|
if(!(await this.exists))
|
|
430
|
-
throw Sass.new(`No such file '${
|
|
350
|
+
throw Sass.new(`No such file '${filePath}'`)
|
|
431
351
|
|
|
432
|
-
return await fs.readFile(
|
|
352
|
+
return await fs.readFile(filePath)
|
|
433
353
|
}
|
|
434
354
|
|
|
435
355
|
/**
|
|
@@ -445,29 +365,15 @@ export default class FileObject extends FS {
|
|
|
445
365
|
* await file.write(JSON.stringify({key: 'value'}))
|
|
446
366
|
*/
|
|
447
367
|
async write(content, encoding="utf8") {
|
|
448
|
-
const
|
|
449
|
-
if(!realPath)
|
|
450
|
-
throw Sass.new("No actual disk location detected.")
|
|
368
|
+
const filePath = this.real?.path ?? this.path
|
|
451
369
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
if(process.platform === "win32") {
|
|
455
|
-
try {
|
|
456
|
-
const parentPath = path.dirname(realPath)
|
|
457
|
-
const normalizedParent = await fs.realpath(parentPath)
|
|
458
|
-
pathToWrite = path.join(normalizedParent, path.basename(realPath))
|
|
459
|
-
} catch {
|
|
460
|
-
// If normalization fails, use original path
|
|
461
|
-
}
|
|
462
|
-
}
|
|
370
|
+
if(!filePath)
|
|
371
|
+
throw Sass.new("No actual disk location detected.")
|
|
463
372
|
|
|
464
373
|
try {
|
|
465
|
-
await fs.writeFile(
|
|
374
|
+
await fs.writeFile(filePath, content, encoding)
|
|
466
375
|
} catch(error) {
|
|
467
|
-
|
|
468
|
-
throw Sass.new(`Invalid directory: ${path.dirname(pathToWrite)}`)
|
|
469
|
-
|
|
470
|
-
throw Sass.from(error, "Failed to write file")
|
|
376
|
+
throw Sass.new("Failed to write file.", error)
|
|
471
377
|
}
|
|
472
378
|
}
|
|
473
379
|
|
|
@@ -488,11 +394,10 @@ export default class FileObject extends FS {
|
|
|
488
394
|
* await file.writeBinary(buffer)
|
|
489
395
|
*/
|
|
490
396
|
async writeBinary(data) {
|
|
491
|
-
|
|
492
|
-
throw Sass.new("No URL in file")
|
|
397
|
+
const filePath = this.real?.path ?? this.path
|
|
493
398
|
|
|
494
399
|
const exists = await this.parent.exists
|
|
495
|
-
Valid.assert(exists, `Invalid directory
|
|
400
|
+
Valid.assert(exists, `Invalid directory writing ${filePath}`)
|
|
496
401
|
|
|
497
402
|
Valid.assert(Data.isBinary(data), "Data must be binary (ArrayBuffer, TypedArray, Blob, or Buffer)")
|
|
498
403
|
|
|
@@ -501,7 +406,7 @@ export default class FileObject extends FS {
|
|
|
501
406
|
|
|
502
407
|
// According to the internet, if it's already binary, I don't need
|
|
503
408
|
// an encoding. 🤷
|
|
504
|
-
return await fs.writeFile(
|
|
409
|
+
return await fs.writeFile(filePath, bufferData)
|
|
505
410
|
}
|
|
506
411
|
|
|
507
412
|
/**
|
|
@@ -552,15 +457,12 @@ export default class FileObject extends FS {
|
|
|
552
457
|
* @returns {Promise<object>} The file contents as a module.
|
|
553
458
|
*/
|
|
554
459
|
async import() {
|
|
555
|
-
const
|
|
556
|
-
|
|
557
|
-
if(!url)
|
|
558
|
-
throw Sass.new("No URL in file map")
|
|
460
|
+
const filePath = this.real?.path ?? this.path
|
|
559
461
|
|
|
560
462
|
if(!(await this.exists))
|
|
561
|
-
throw Sass.new(`No such file '${
|
|
463
|
+
throw Sass.new(`No such file '${filePath}'`)
|
|
562
464
|
|
|
563
|
-
return await import(
|
|
465
|
+
return await import(filePath)
|
|
564
466
|
}
|
|
565
467
|
|
|
566
468
|
/**
|
|
@@ -574,14 +476,11 @@ export default class FileObject extends FS {
|
|
|
574
476
|
* await file.delete()
|
|
575
477
|
*/
|
|
576
478
|
async delete() {
|
|
577
|
-
const
|
|
578
|
-
|
|
579
|
-
if(!url)
|
|
580
|
-
throw Sass.new("This object does not represent a valid resource.")
|
|
479
|
+
const filePath = this.real?.path ?? this.path
|
|
581
480
|
|
|
582
481
|
if(!(await this.exists))
|
|
583
|
-
throw Sass.new(`No such resource '${
|
|
482
|
+
throw Sass.new(`No such resource '${filePath}'`)
|
|
584
483
|
|
|
585
|
-
return await fs.unlink(
|
|
484
|
+
return await fs.unlink(filePath)
|
|
586
485
|
}
|
|
587
486
|
}
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
import path from "node:path"
|
|
12
12
|
import url from "node:url"
|
|
13
13
|
|
|
14
|
-
import Collection from "
|
|
15
|
-
import Data from "
|
|
14
|
+
import Collection from "../../browser/lib/Collection.js"
|
|
15
|
+
import Data from "../../browser/lib/Data.js"
|
|
16
16
|
import Valid from "./Valid.js"
|
|
17
17
|
|
|
18
18
|
/** @typedef {import("./FileObject.js").default} FileObject */
|
|
@@ -27,7 +27,7 @@ const fdType = Object.freeze(
|
|
|
27
27
|
/**
|
|
28
28
|
* File system utility class for path operations and file discovery.
|
|
29
29
|
*/
|
|
30
|
-
export default class
|
|
30
|
+
export default class FileSystem {
|
|
31
31
|
static fdTypes = fdTypes
|
|
32
32
|
static upperFdTypes = upperFdTypes
|
|
33
33
|
static fdType = fdType
|
|
@@ -49,7 +49,7 @@ export default class FS {
|
|
|
49
49
|
1
|
|
50
50
|
)
|
|
51
51
|
|
|
52
|
-
return
|
|
52
|
+
return FileSystem.relativeOrAbsolutePath(fileOrDirectoryObject, this)
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
/**
|
|
@@ -193,7 +193,7 @@ export default class FS {
|
|
|
193
193
|
|
|
194
194
|
// Strategy 3: Try overlap-based merging, which will default to a basic
|
|
195
195
|
// join if no overlap
|
|
196
|
-
return
|
|
196
|
+
return FileSystem.mergeOverlappingPaths(from, to)
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
/**
|
|
@@ -339,14 +339,14 @@ export default class FS {
|
|
|
339
339
|
let target, cap
|
|
340
340
|
|
|
341
341
|
if(fileOrDirectoryObject.isFile) {
|
|
342
|
-
if(!fileOrDirectoryObject.parent.
|
|
342
|
+
if(!fileOrDirectoryObject.parent.isVirtual) {
|
|
343
343
|
return fileOrDirectoryObject.path
|
|
344
344
|
} else {
|
|
345
345
|
target = fileOrDirectoryObject.path
|
|
346
346
|
cap = fileOrDirectoryObject.parent.cap.real.path
|
|
347
347
|
}
|
|
348
348
|
} else {
|
|
349
|
-
if(!fileOrDirectoryObject.
|
|
349
|
+
if(!fileOrDirectoryObject.isVirtual) {
|
|
350
350
|
return fileOrDirectoryObject.path
|
|
351
351
|
} else {
|
|
352
352
|
target = fileOrDirectoryObject.path
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
|
|
14
14
|
import c from "@gesslar/colours"
|
|
15
15
|
|
|
16
|
-
import Data from "
|
|
16
|
+
import Data from "../../browser/lib/Data.js"
|
|
17
17
|
import Term from "./Term.js"
|
|
18
|
-
import Util from "
|
|
18
|
+
import Util from "../../browser/lib/Util.js"
|
|
19
19
|
// ErrorStackParser will be dynamically imported when needed
|
|
20
20
|
|
|
21
21
|
// Enhanced color system using @gesslar/colours
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
import ErrorStackParser from "error-stack-parser"
|
|
27
27
|
import console from "node:console"
|
|
28
28
|
import {Environment} from "./Core.js"
|
|
29
|
-
import {FileObject, Util} from "
|
|
29
|
+
import {FileObject, Util} from "../../../types/node/index.js"
|
|
30
30
|
|
|
31
31
|
export const loggerColours = {
|
|
32
32
|
debug: [
|
|
@@ -8,24 +8,24 @@ import fs, {mkdirSync, mkdtempSync} from "node:fs"
|
|
|
8
8
|
import os from "node:os"
|
|
9
9
|
import path from "node:path"
|
|
10
10
|
|
|
11
|
-
import Data from "
|
|
12
|
-
import
|
|
11
|
+
import Data from "../../browser/lib/Data.js"
|
|
12
|
+
import VDirectoryObject from "./VDirectoryObject.js"
|
|
13
13
|
import DirectoryObject from "./DirectoryObject.js"
|
|
14
|
-
import
|
|
14
|
+
import FileSystem from "./FileSystem.js"
|
|
15
15
|
import Sass from "./Sass.js"
|
|
16
16
|
import Valid from "./Valid.js"
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* TempDirectoryObject extends
|
|
19
|
+
* TempDirectoryObject extends VDirectoryObject with the cap set to
|
|
20
20
|
* the OS's temporary directory. Temporary directories are created
|
|
21
21
|
* synchronously during construction and exist immediately.
|
|
22
22
|
*
|
|
23
23
|
* All path operations are validated to ensure they remain within the temp
|
|
24
24
|
* directory hierarchy for security.
|
|
25
25
|
*
|
|
26
|
-
* @augments
|
|
26
|
+
* @augments VDirectoryObject
|
|
27
27
|
*/
|
|
28
|
-
export default class TempDirectoryObject extends
|
|
28
|
+
export default class TempDirectoryObject extends VDirectoryObject {
|
|
29
29
|
#tmpReal
|
|
30
30
|
#tmpCap
|
|
31
31
|
|
|
@@ -62,7 +62,7 @@ export default class TempDirectoryObject extends CappedDirectoryObject {
|
|
|
62
62
|
const parentRealPath = source?.real.path ?? os.tmpdir()
|
|
63
63
|
|
|
64
64
|
if(source && path.isAbsolute(directory)) {
|
|
65
|
-
const {root} =
|
|
65
|
+
const {root} = FileSystem.pathParts(directory)
|
|
66
66
|
|
|
67
67
|
directory = Data.chopLeft(directory, root)
|
|
68
68
|
}
|
|
@@ -72,12 +72,12 @@ export default class TempDirectoryObject extends CappedDirectoryObject {
|
|
|
72
72
|
if(source) {
|
|
73
73
|
toSuper = `/${directory}`
|
|
74
74
|
realTempDirectoryPath =
|
|
75
|
-
|
|
75
|
+
FileSystem.mergeOverlappingPaths(parentRealPath, directory)
|
|
76
76
|
if(!fs.existsSync(realTempDirectoryPath))
|
|
77
77
|
mkdirSync(realTempDirectoryPath)
|
|
78
78
|
} else {
|
|
79
79
|
realTempDirectoryPath =
|
|
80
|
-
mkdtempSync(
|
|
80
|
+
mkdtempSync(FileSystem.mergeOverlappingPaths(os.tmpdir(), directory))
|
|
81
81
|
toSuper = path.resolve(path.sep)
|
|
82
82
|
}
|
|
83
83
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {createHash} from "node:crypto"
|
|
2
2
|
import {EventEmitter} from "node:events"
|
|
3
|
-
import {Util as BrowserUtil} from "
|
|
3
|
+
import {Util as BrowserUtil} from "../../browser/index.js"
|
|
4
4
|
import Sass from "./Sass.js"
|
|
5
5
|
import process from "node:process"
|
|
6
6
|
import JSON5 from "json5"
|