@gesslar/toolkit 3.6.3 → 3.8.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 +27 -14
- package/package.json +6 -5
- package/src/index.js +0 -3
- package/src/lib/CappedDirectoryObject.js +45 -14
- package/src/lib/DirectoryObject.js +30 -1
- package/src/lib/TempDirectoryObject.js +13 -4
- package/src/types/index.d.ts +0 -3
- package/src/types/lib/CappedDirectoryObject.d.ts +22 -0
- package/src/types/lib/CappedDirectoryObject.d.ts.map +1 -1
- package/src/types/lib/DirectoryObject.d.ts +18 -0
- package/src/types/lib/DirectoryObject.d.ts.map +1 -1
- package/src/types/lib/TempDirectoryObject.d.ts.map +1 -1
- package/src/lib/Contract.js +0 -256
- package/src/lib/Schemer.js +0 -89
- package/src/lib/Terms.js +0 -73
- package/src/types/lib/Contract.d.ts +0 -71
- package/src/types/lib/Contract.d.ts.map +0 -1
- package/src/types/lib/Schemer.d.ts +0 -23
- package/src/types/lib/Schemer.d.ts.map +0 -1
- package/src/types/lib/Terms.d.ts +0 -23
- package/src/types/lib/Terms.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/gesslar/toolkit/actions/workflows/Quality.yaml)
|
|
4
4
|
|
|
5
|
-
A collection of utilities for Node.js and browser environments, including file
|
|
5
|
+
A collection of utilities for Node.js and browser environments, including file
|
|
6
|
+
and directory abstractions, terminal utilities, validation helpers, and data
|
|
7
|
+
manipulation functions.
|
|
6
8
|
|
|
7
9
|
## Included Classes
|
|
8
10
|
|
|
9
11
|
### Browser
|
|
10
12
|
|
|
11
|
-
These classes exist and function within the browser, or browser-like
|
|
12
|
-
a Tauri app.
|
|
13
|
+
These classes exist and function within the browser, or browser-like
|
|
14
|
+
environment, such as a Tauri app.
|
|
13
15
|
|
|
14
16
|
| Name | Description |
|
|
15
17
|
| ---- | ----------- |
|
|
@@ -34,18 +36,15 @@ Includes all browser functionality plus Node.js-specific modules for file I/O, l
|
|
|
34
36
|
| ---- | ----------- |
|
|
35
37
|
| Cache | Cache management for file I/O operations |
|
|
36
38
|
| CappedDirectoryObject | Directory operations constrained to a specific tree |
|
|
37
|
-
| Contract | Contract management and validation |
|
|
38
39
|
| DirectoryObject | Directory metadata and operations including path resolution, existence checks, and traversal |
|
|
39
40
|
| FileObject | File system wrapper for file operations |
|
|
40
41
|
| FS | Base class for file system operations with static utilities |
|
|
41
42
|
| Glog | Logging framework |
|
|
42
43
|
| Notify | Event system wrapper for Node.js events |
|
|
43
44
|
| Sass | Custom Error class with enhanced features |
|
|
44
|
-
| Schemer | JSON schema validation and management |
|
|
45
45
|
| Tantrum | AggregateError implementation |
|
|
46
46
|
| TempDirectoryObject | Temporary directory management with automatic cleanup |
|
|
47
47
|
| Term | Terminal formatting and output utilities |
|
|
48
|
-
| Terms | Terms for use with Contract |
|
|
49
48
|
| Util | General utility functions (Node-enhanced version) |
|
|
50
49
|
| Valid | Validation and assertion methods |
|
|
51
50
|
|
|
@@ -57,13 +56,15 @@ npm i @gesslar/toolkit
|
|
|
57
56
|
|
|
58
57
|
## Usage
|
|
59
58
|
|
|
60
|
-
Toolkit is environment aware and automatically detects whether it is being used
|
|
59
|
+
Toolkit is environment aware and automatically detects whether it is being used
|
|
60
|
+
in a web browser or in Node.js. You can optionally specify the `node` or
|
|
61
|
+
`browser` variant explicitly.
|
|
61
62
|
|
|
62
63
|
### Browser-like
|
|
63
64
|
|
|
64
|
-
TypeScript editors do not pick up types from jsDelivr. If you want inline types
|
|
65
|
-
installing from npm, use the esm.sh `?dts` URL or install the package
|
|
66
|
-
development and use the CDN at runtime.
|
|
65
|
+
TypeScript editors do not pick up types from jsDelivr. If you want inline types
|
|
66
|
+
without installing from npm, use the esm.sh `?dts` URL or install the package
|
|
67
|
+
locally for development and use the CDN at runtime.
|
|
67
68
|
|
|
68
69
|
#### jsDelivr (runtime only)
|
|
69
70
|
|
|
@@ -96,12 +97,24 @@ import {Data, FileObject} from "@gesslar/toolkit/node"
|
|
|
96
97
|
import { Data, Collection, Util } from '@gesslar/toolkit/browser'
|
|
97
98
|
```
|
|
98
99
|
|
|
99
|
-
The browser version includes: Collection, Data, Disposer, HTML, Notify, Sass,
|
|
100
|
+
The browser version includes: Collection, Data, Disposer, HTML, Notify, Sass,
|
|
101
|
+
Tantrum, Type (TypeSpec), Util, and Valid. Node-only modules (Cache,
|
|
102
|
+
CappedDirectoryObject, DirectoryObject, FileObject, FS, Glog,
|
|
103
|
+
TempDirectoryObject, Term) are not available in the browser version.
|
|
100
104
|
|
|
101
105
|
## Post Partum
|
|
102
106
|
|
|
103
|
-
If you made it this far, please understand that I have absolutely zero scruples
|
|
104
|
-
|
|
105
|
-
|
|
107
|
+
If you made it this far, please understand that I have absolutely zero scruples
|
|
108
|
+
when it comes to breaking changes. Primarily, the audience for this library is
|
|
109
|
+
myself. Consequently, anything that relies on the contents of this library will
|
|
110
|
+
dutifully crash and I'll have to refactor those things then. It's like playing
|
|
111
|
+
nicky nicky nine doors. But with myself. And there's a lazy bomb waiting for
|
|
112
|
+
me. That I planted. For me. And the bomb just explodes poop.
|
|
113
|
+
|
|
114
|
+
You're of course welcome to use my library! It's pretty robust. Uhhh, but maybe
|
|
115
|
+
lock in the version until you see if something is gonna poop all over you. I
|
|
116
|
+
make robots make my PR notifications and generally they're very good at firing
|
|
117
|
+
off klaxons about my fetish for breaking changes, so you should be all right
|
|
118
|
+
if you're paying attention. 🤷🏻
|
|
106
119
|
|
|
107
120
|
Sincerely, Senator Yabba of the Dabba (Doo)
|
package/package.json
CHANGED
|
@@ -3,10 +3,9 @@
|
|
|
3
3
|
"description": "A collection of utilities for Node.js and browser environments.",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "gesslar",
|
|
6
|
-
"email": "bmw@gesslar.dev",
|
|
7
6
|
"url": "https://gesslar.dev"
|
|
8
7
|
},
|
|
9
|
-
"version": "3.
|
|
8
|
+
"version": "3.8.0",
|
|
10
9
|
"license": "Unlicense",
|
|
11
10
|
"homepage": "https://github.com/gesslar/toolkit#readme",
|
|
12
11
|
"repository": {
|
|
@@ -48,20 +47,20 @@
|
|
|
48
47
|
"src/",
|
|
49
48
|
"UNLICENSE.txt"
|
|
50
49
|
],
|
|
51
|
-
"sideEffects": false,
|
|
52
50
|
"engines": {
|
|
53
51
|
"node": ">=22"
|
|
54
52
|
},
|
|
55
53
|
"dependencies": {
|
|
56
|
-
"@gesslar/colours": "^0.
|
|
54
|
+
"@gesslar/colours": "^0.7.1",
|
|
57
55
|
"ajv": "^8.17.1",
|
|
58
56
|
"globby": "^16.1.0",
|
|
59
57
|
"json5": "^2.2.3",
|
|
60
58
|
"yaml": "^2.8.2"
|
|
61
59
|
},
|
|
62
60
|
"devDependencies": {
|
|
63
|
-
"@gesslar/uglier": "^0.
|
|
61
|
+
"@gesslar/uglier": "^0.5.1",
|
|
64
62
|
"eslint": "^9.39.2",
|
|
63
|
+
"happy-dom": "^20.0.11",
|
|
65
64
|
"typescript": "^5.9.3"
|
|
66
65
|
},
|
|
67
66
|
"scripts": {
|
|
@@ -71,6 +70,8 @@
|
|
|
71
70
|
"submit": "pnpm publish --access public --//registry.npmjs.org/:_authToken=\"${NPM_ACCESS_TOKEN}\"",
|
|
72
71
|
"update": "pnpm up --latest --recursive",
|
|
73
72
|
"test": "node --test tests/**/*.test.js",
|
|
73
|
+
"test:node": "node --test tests/node/*.test.js",
|
|
74
|
+
"test:browser": "node --test tests/browser/*.test.js",
|
|
74
75
|
"pr": "gt submit -p --ai",
|
|
75
76
|
"patch": "pnpm version patch",
|
|
76
77
|
"minor": "pnpm version minor",
|
package/src/index.js
CHANGED
|
@@ -16,13 +16,10 @@ export {default as Util} from "./lib/Util.js"
|
|
|
16
16
|
// Node-specific exports
|
|
17
17
|
export {default as Cache} from "./lib/Cache.js"
|
|
18
18
|
export {default as CappedDirectoryObject} from "./lib/CappedDirectoryObject.js"
|
|
19
|
-
export {default as Contract} from "./lib/Contract.js"
|
|
20
19
|
export {default as DirectoryObject} from "./lib/DirectoryObject.js"
|
|
21
20
|
export {default as TempDirectoryObject} from "./lib/TempDirectoryObject.js"
|
|
22
21
|
export {default as FileObject} from "./lib/FileObject.js"
|
|
23
22
|
export {default as FS} from "./lib/FS.js"
|
|
24
23
|
export {default as Glog} from "./lib/Glog.js"
|
|
25
24
|
export {default as Notify} from "./lib/Notify.js"
|
|
26
|
-
export {default as Schemer} from "./lib/Schemer.js"
|
|
27
25
|
export {default as Term} from "./lib/Term.js"
|
|
28
|
-
export {default as Terms} from "./lib/Terms.js"
|
|
@@ -132,6 +132,16 @@ export default class CappedDirectoryObject extends DirectoryObject {
|
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Re-caps this directory to itself, making it the new root of the capped tree.
|
|
137
|
+
* This is a protected method intended for use by subclasses like TempDirectoryObject.
|
|
138
|
+
*
|
|
139
|
+
* @protected
|
|
140
|
+
*/
|
|
141
|
+
_recapToSelf() {
|
|
142
|
+
this.#cap = this.#realPath
|
|
143
|
+
}
|
|
144
|
+
|
|
135
145
|
/**
|
|
136
146
|
* Returns the cap path for this directory.
|
|
137
147
|
*
|
|
@@ -221,14 +231,14 @@ export default class CappedDirectoryObject extends DirectoryObject {
|
|
|
221
231
|
* Returns the parent directory of this capped directory.
|
|
222
232
|
* Returns null only if this directory is at the cap (the "root" of the capped tree).
|
|
223
233
|
*
|
|
224
|
-
* Note: The returned parent is a
|
|
225
|
-
*
|
|
234
|
+
* Note: The returned parent is a CappedDirectoryObject with the same cap.
|
|
235
|
+
* This maintains the capping behavior throughout the directory hierarchy.
|
|
226
236
|
*
|
|
227
|
-
* @returns {
|
|
237
|
+
* @returns {CappedDirectoryObject|null} Parent directory or null if at cap root
|
|
228
238
|
* @example
|
|
229
239
|
* const capped = new TempDirectoryObject("myapp")
|
|
230
240
|
* const subdir = capped.getDirectory("data")
|
|
231
|
-
* console.log(subdir.parent.path) // Returns parent
|
|
241
|
+
* console.log(subdir.parent.path) // Returns parent CappedDirectoryObject
|
|
232
242
|
* console.log(capped.parent) // null (at cap root)
|
|
233
243
|
*/
|
|
234
244
|
get parent() {
|
|
@@ -239,13 +249,17 @@ export default class CappedDirectoryObject extends DirectoryObject {
|
|
|
239
249
|
return null
|
|
240
250
|
}
|
|
241
251
|
|
|
242
|
-
//
|
|
252
|
+
// Compute parent's real path
|
|
243
253
|
const parentPath = path.dirname(this.#realPath)
|
|
244
254
|
const isRoot = parentPath === this.#realPath
|
|
245
255
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
256
|
+
if(isRoot) {
|
|
257
|
+
return null
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Compute relative path from current to parent (just "..")
|
|
261
|
+
// Then use getDirectory to create the parent, which preserves the class type
|
|
262
|
+
return this.getDirectory("..")
|
|
249
263
|
}
|
|
250
264
|
|
|
251
265
|
/**
|
|
@@ -264,9 +278,24 @@ export default class CappedDirectoryObject extends DirectoryObject {
|
|
|
264
278
|
*/
|
|
265
279
|
toJSON() {
|
|
266
280
|
const capResolved = path.resolve(this.#cap)
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
281
|
+
let parentPath
|
|
282
|
+
|
|
283
|
+
if(this.#realPath === capResolved) {
|
|
284
|
+
// At cap root, no parent
|
|
285
|
+
parentPath = null
|
|
286
|
+
} else {
|
|
287
|
+
// Compute parent's virtual path
|
|
288
|
+
const parentReal = path.dirname(this.#realPath)
|
|
289
|
+
const relative = path.relative(capResolved, parentReal)
|
|
290
|
+
|
|
291
|
+
// If parent is cap root or empty, return "/"
|
|
292
|
+
if(!relative || relative === ".") {
|
|
293
|
+
parentPath = "/"
|
|
294
|
+
} else {
|
|
295
|
+
// Return parent's virtual path with leading slash
|
|
296
|
+
parentPath = "/" + relative.split(path.sep).join("/")
|
|
297
|
+
}
|
|
298
|
+
}
|
|
270
299
|
|
|
271
300
|
return {
|
|
272
301
|
supplied: this.supplied,
|
|
@@ -278,6 +307,7 @@ export default class CappedDirectoryObject extends DirectoryObject {
|
|
|
278
307
|
isFile: this.isFile,
|
|
279
308
|
isDirectory: this.isDirectory,
|
|
280
309
|
parent: parentPath,
|
|
310
|
+
root: this.root.path,
|
|
281
311
|
real: this.real.toJSON()
|
|
282
312
|
}
|
|
283
313
|
}
|
|
@@ -436,10 +466,11 @@ export default class CappedDirectoryObject extends DirectoryObject {
|
|
|
436
466
|
// Start at cap root
|
|
437
467
|
let current = this.#createCappedAtRoot()
|
|
438
468
|
|
|
439
|
-
// Traverse each segment,
|
|
440
|
-
// (not subclass instances, to avoid constructor signature issues)
|
|
469
|
+
// Traverse each segment, using constructor to preserve class type
|
|
441
470
|
for(const segment of segments) {
|
|
442
|
-
|
|
471
|
+
// Use simple name constructor to preserve subclass type
|
|
472
|
+
// Works for both CappedDirectoryObject and TempDirectoryObject
|
|
473
|
+
current = new this.constructor(segment, current, this.temporary)
|
|
443
474
|
}
|
|
444
475
|
|
|
445
476
|
return current
|
|
@@ -157,7 +157,8 @@ export default class DirectoryObject extends FS {
|
|
|
157
157
|
extension: this.extension,
|
|
158
158
|
isFile: this.isFile,
|
|
159
159
|
isDirectory: this.isDirectory,
|
|
160
|
-
parent: this.parent ? this.parent.path : null
|
|
160
|
+
parent: this.parent ? this.parent.path : null,
|
|
161
|
+
root: this.root.path
|
|
161
162
|
}
|
|
162
163
|
}
|
|
163
164
|
|
|
@@ -294,6 +295,34 @@ export default class DirectoryObject extends FS {
|
|
|
294
295
|
return this.#parent
|
|
295
296
|
}
|
|
296
297
|
|
|
298
|
+
/**
|
|
299
|
+
* Returns the root directory of the filesystem.
|
|
300
|
+
*
|
|
301
|
+
* For DirectoryObject, this walks up to the filesystem root.
|
|
302
|
+
* For CappedDirectoryObject, this returns the cap root.
|
|
303
|
+
*
|
|
304
|
+
* @returns {DirectoryObject} The root directory
|
|
305
|
+
* @example
|
|
306
|
+
* const dir = new DirectoryObject("/usr/local/bin")
|
|
307
|
+
* console.log(dir.root.path) // "/"
|
|
308
|
+
*
|
|
309
|
+
* @example
|
|
310
|
+
* const capped = new CappedDirectoryObject("/projects/myapp")
|
|
311
|
+
* const sub = capped.getDirectory("src/lib")
|
|
312
|
+
* console.log(sub.root.path) // "/" (virtual, cap root)
|
|
313
|
+
* console.log(sub.root.real.path) // "/projects/myapp"
|
|
314
|
+
*/
|
|
315
|
+
get root() {
|
|
316
|
+
// Walk up until we find a directory with no parent
|
|
317
|
+
let current = this
|
|
318
|
+
|
|
319
|
+
while(current.parent !== null) {
|
|
320
|
+
current = current.parent
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return current
|
|
324
|
+
}
|
|
325
|
+
|
|
297
326
|
/**
|
|
298
327
|
* Recursively removes a temporary directory and all its contents.
|
|
299
328
|
*
|
|
@@ -99,11 +99,13 @@ export default class TempDirectoryObject extends CappedDirectoryObject {
|
|
|
99
99
|
)
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
// SECURITY: Ensure parent's cap is tmpdir (prevent escape to other caps)
|
|
103
|
-
const tmpdir = os.tmpdir()
|
|
104
|
-
|
|
102
|
+
// SECURITY: Ensure parent's cap is within tmpdir (prevent escape to other caps)
|
|
103
|
+
const tmpdir = path.resolve(os.tmpdir())
|
|
104
|
+
const parentCap = path.resolve(parent.cap)
|
|
105
|
+
|
|
106
|
+
if(!parentCap.startsWith(tmpdir)) {
|
|
105
107
|
throw Sass.new(
|
|
106
|
-
`Parent must be capped to OS temp directory (${tmpdir}), ` +
|
|
108
|
+
`Parent must be capped to OS temp directory (${tmpdir}) or a subdirectory thereof, ` +
|
|
107
109
|
`got cap: ${parent.cap}`
|
|
108
110
|
)
|
|
109
111
|
}
|
|
@@ -119,6 +121,13 @@ export default class TempDirectoryObject extends CappedDirectoryObject {
|
|
|
119
121
|
|
|
120
122
|
// Temp-specific behavior: create directory immediately
|
|
121
123
|
this.#createDirectory()
|
|
124
|
+
|
|
125
|
+
// Re-cap to the temp directory itself for consistent behavior with CappedDirectoryObject
|
|
126
|
+
// This makes temp.cap === temp.real.path and temp.parent === null
|
|
127
|
+
if(!parent) {
|
|
128
|
+
// Only re-cap if this is a root temp directory (no TempDirectoryObject parent)
|
|
129
|
+
this._recapToSelf()
|
|
130
|
+
}
|
|
122
131
|
}
|
|
123
132
|
|
|
124
133
|
/**
|
package/src/types/index.d.ts
CHANGED
|
@@ -9,15 +9,12 @@ export { default as Tantrum } from "./lib/Tantrum.js";
|
|
|
9
9
|
export { default as Util } from "./lib/Util.js";
|
|
10
10
|
export { default as Cache } from "./lib/Cache.js";
|
|
11
11
|
export { default as CappedDirectoryObject } from "./lib/CappedDirectoryObject.js";
|
|
12
|
-
export { default as Contract } from "./lib/Contract.js";
|
|
13
12
|
export { default as DirectoryObject } from "./lib/DirectoryObject.js";
|
|
14
13
|
export { default as TempDirectoryObject } from "./lib/TempDirectoryObject.js";
|
|
15
14
|
export { default as FileObject } from "./lib/FileObject.js";
|
|
16
15
|
export { default as FS } from "./lib/FS.js";
|
|
17
16
|
export { default as Glog } from "./lib/Glog.js";
|
|
18
17
|
export { default as Notify } from "./lib/Notify.js";
|
|
19
|
-
export { default as Schemer } from "./lib/Schemer.js";
|
|
20
18
|
export { default as Term } from "./lib/Term.js";
|
|
21
|
-
export { default as Terms } from "./lib/Terms.js";
|
|
22
19
|
export { default as Disposer, Disposer as DisposerClass } from "./browser/lib/Disposer.js";
|
|
23
20
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -37,6 +37,13 @@ export default class CappedDirectoryObject extends DirectoryObject {
|
|
|
37
37
|
* // path: /home/user/.cache/etc/config, cap: /home/user/.cache
|
|
38
38
|
*/
|
|
39
39
|
constructor(dirPath: string, parent?: CappedDirectoryObject | null, temporary?: boolean);
|
|
40
|
+
/**
|
|
41
|
+
* Re-caps this directory to itself, making it the new root of the capped tree.
|
|
42
|
+
* This is a protected method intended for use by subclasses like TempDirectoryObject.
|
|
43
|
+
*
|
|
44
|
+
* @protected
|
|
45
|
+
*/
|
|
46
|
+
protected _recapToSelf(): void;
|
|
40
47
|
/**
|
|
41
48
|
* Returns the cap path for this directory.
|
|
42
49
|
*
|
|
@@ -75,6 +82,21 @@ export default class CappedDirectoryObject extends DirectoryObject {
|
|
|
75
82
|
* subdir.real.parent // Can traverse outside the cap
|
|
76
83
|
*/
|
|
77
84
|
get real(): DirectoryObject;
|
|
85
|
+
/**
|
|
86
|
+
* Returns the parent directory of this capped directory.
|
|
87
|
+
* Returns null only if this directory is at the cap (the "root" of the capped tree).
|
|
88
|
+
*
|
|
89
|
+
* Note: The returned parent is a CappedDirectoryObject with the same cap.
|
|
90
|
+
* This maintains the capping behavior throughout the directory hierarchy.
|
|
91
|
+
*
|
|
92
|
+
* @returns {CappedDirectoryObject|null} Parent directory or null if at cap root
|
|
93
|
+
* @example
|
|
94
|
+
* const capped = new TempDirectoryObject("myapp")
|
|
95
|
+
* const subdir = capped.getDirectory("data")
|
|
96
|
+
* console.log(subdir.parent.path) // Returns parent CappedDirectoryObject
|
|
97
|
+
* console.log(capped.parent) // null (at cap root)
|
|
98
|
+
*/
|
|
99
|
+
get parent(): CappedDirectoryObject | null;
|
|
78
100
|
/**
|
|
79
101
|
* Returns the URL with virtual path (cap-relative).
|
|
80
102
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CappedDirectoryObject.d.ts","sourceRoot":"","sources":["../../lib/CappedDirectoryObject.js"],"names":[],"mappings":"AAkBA;;;;;;;;GAQG;AACH;IAGE;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,qBArBW,MAAM,WACN,qBAAqB,OAAC,cACtB,OAAO,EA0EjB;IAqBD;;;;OAIG;IACH,WAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,cAFa,OAAO,CAInB;IAED;;;;;OAKG;IACH,0BAFa,MAAM,CAIlB;IAqCD;;;;;;;;;;;;;;;;;OAiBG;IACH,YAba,eAAe,CAe3B;
|
|
1
|
+
{"version":3,"file":"CappedDirectoryObject.d.ts","sourceRoot":"","sources":["../../lib/CappedDirectoryObject.js"],"names":[],"mappings":"AAkBA;;;;;;;;GAQG;AACH;IAGE;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,qBArBW,MAAM,WACN,qBAAqB,OAAC,cACtB,OAAO,EA0EjB;IAqBD;;;;;OAKG;IACH,+BAEC;IAED;;;;OAIG;IACH,WAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,cAFa,OAAO,CAInB;IAED;;;;;OAKG;IACH,0BAFa,MAAM,CAIlB;IAqCD;;;;;;;;;;;;;;;;;OAiBG;IACH,YAba,eAAe,CAe3B;IAED;;;;;;;;;;;;;OAaG;IACH,cAPa,qBAAqB,GAAC,IAAI,CA0BtC;IAED;;;;OAIG;IACH,WAFa,GAAG,CAIf;IAqFD;;;;OAIG;IACH,cAFa,SAAS,CAAC,eAAe,CAAC,CAItC;IAED;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,sBAjBW,MAAM,GACJ,qBAAqB,CAiEjC;IAsID;;;;;OAKG;IACH,WAHW,MAAM,GACJ,OAAO,CAAC;QAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;QAAC,WAAW,QAAO;KAAC,CAAC,CAgBnE;;CA8DF;4BAloB2B,sBAAsB;uBAC3B,iBAAiB"}
|
|
@@ -139,6 +139,24 @@ export default class DirectoryObject extends FS {
|
|
|
139
139
|
* console.log(root.parent) // null
|
|
140
140
|
*/
|
|
141
141
|
get parent(): DirectoryObject | null;
|
|
142
|
+
/**
|
|
143
|
+
* Returns the root directory of the filesystem.
|
|
144
|
+
*
|
|
145
|
+
* For DirectoryObject, this walks up to the filesystem root.
|
|
146
|
+
* For CappedDirectoryObject, this returns the cap root.
|
|
147
|
+
*
|
|
148
|
+
* @returns {DirectoryObject} The root directory
|
|
149
|
+
* @example
|
|
150
|
+
* const dir = new DirectoryObject("/usr/local/bin")
|
|
151
|
+
* console.log(dir.root.path) // "/"
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* const capped = new CappedDirectoryObject("/projects/myapp")
|
|
155
|
+
* const sub = capped.getDirectory("src/lib")
|
|
156
|
+
* console.log(sub.root.path) // "/" (virtual, cap root)
|
|
157
|
+
* console.log(sub.root.real.path) // "/projects/myapp"
|
|
158
|
+
*/
|
|
159
|
+
get root(): DirectoryObject;
|
|
142
160
|
/**
|
|
143
161
|
* Recursively removes a temporary directory and all its contents.
|
|
144
162
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DirectoryObject.d.ts","sourceRoot":"","sources":["../../lib/DirectoryObject.js"],"names":[],"mappings":"AAgBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH;
|
|
1
|
+
{"version":3,"file":"DirectoryObject.d.ts","sourceRoot":"","sources":["../../lib/DirectoryObject.js"],"names":[],"mappings":"AAgBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH;uBAsGe,MAAM;IAnEnB;;;;;OAKG;IACH,yCAFW,OAAO,EA6BjB;IAWD;;;;OAIG;IACH,UAFa,MAAM,CAelB;IAWD;;;;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;;;;OAIG;IACH,iBAFa,OAAO,CAInB;IAED;;;;;;;;;;;;OAYG;IACH,cARa,eAAe,GAAC,IAAI,CAwBhC;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,YAXa,eAAe,CAoB3B;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,UATa,OAAO,CAAC,IAAI,CAAC,CA0BzB;IAED;;;;OAIG;IACH,cAFa,OAAO,CAInB;IAED;;;;OAIG;IACH,mBAFa,OAAO,CAInB;IAiBD;;;;;;;;;;;;;;;OAeG;IACH,WAZW,MAAM,GACJ,OAAO,CAAC;QAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;QAAC,WAAW,EAAE,KAAK,CAAC,eAAe,CAAC,CAAA;KAAC,CAAC,CAoCpF;IAED;;;;;;;;;;;;OAYG;IACH,uBARW,MAAM,GACJ,OAAO,CAAC,IAAI,CAAC,CAqBzB;IA8BD;;;;;;;;;;;;;;;OAeG;IACH,cAZa,MAAM,CAclB;IAED;;;;;;;;;;;;;;OAcG;IACH,UARa,OAAO,CAAC,IAAI,CAAC,CAkBzB;IAED;;;;;OAKG;IACH,kBAHW,MAAM,GACJ,OAAO,CAAC,OAAO,CAAC,CAM5B;IAED;;;;;OAKG;IACH,sBAHW,MAAM,GACJ,OAAO,CAAC,OAAO,CAAC,CAO5B;IAED;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,sBAdW,MAAM,GACJ,eAAe,CAoB3B;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACH,kBAbW,MAAM,GACJ,UAAU,CAkBtB;;CACF;eAnmBc,SAAS;uBACD,iBAAiB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TempDirectoryObject.d.ts","sourceRoot":"","sources":["../../lib/TempDirectoryObject.js"],"names":[],"mappings":"AAcA;;;;;;;;;GASG;AACH;IAEE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCG;IACH,mBAxBW,MAAM,OAAC,WACP,mBAAmB,OAAC,
|
|
1
|
+
{"version":3,"file":"TempDirectoryObject.d.ts","sourceRoot":"","sources":["../../lib/TempDirectoryObject.js"],"names":[],"mappings":"AAcA;;;;;;;;;GASG;AACH;IAEE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCG;IACH,mBAxBW,MAAM,OAAC,WACP,mBAAmB,OAAC,EA6F9B;IAsBD;;;;;;;;;;;;;;OAcG;IACH,sBAVW,MAAM,GACJ,mBAAmB,CAY/B;IAED;;;;;;;;;;;;;;OAcG;IACH,kBAVW,MAAM,GACJ,UAAU,CAYtB;;CAUF;kCA9LiC,4BAA4B"}
|
package/src/lib/Contract.js
DELETED
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
import Sass from "./Sass.js"
|
|
2
|
-
import Schemer from "./Schemer.js"
|
|
3
|
-
import Data from "../browser/lib/Data.js"
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Contract represents a successful negotiation between Terms.
|
|
7
|
-
* It handles validation and compatibility checking between what
|
|
8
|
-
* one action provides and what another accepts.
|
|
9
|
-
*/
|
|
10
|
-
export default class Contract {
|
|
11
|
-
#providerTerms = null
|
|
12
|
-
#consumerTerms = null
|
|
13
|
-
#validator = null
|
|
14
|
-
#debug = null
|
|
15
|
-
#isNegotiated = false
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Creates a contract by negotiating between provider and consumer terms
|
|
19
|
-
*
|
|
20
|
-
* @param {import("./Terms.js").Terms} providerTerms - What the provider offers
|
|
21
|
-
* @param {import("./Terms.js").Terms} consumerTerms - What the consumer expects
|
|
22
|
-
* @param {object} options - Configuration options
|
|
23
|
-
* @param {import('../types.js').DebugFunction} [options.debug] - Debug function
|
|
24
|
-
*/
|
|
25
|
-
constructor(providerTerms, consumerTerms, {debug = null} = {}) {
|
|
26
|
-
this.#providerTerms = providerTerms
|
|
27
|
-
this.#consumerTerms = consumerTerms
|
|
28
|
-
this.#debug = debug
|
|
29
|
-
|
|
30
|
-
// Perform the negotiation
|
|
31
|
-
this.#negotiate()
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Extracts the actual schema from a terms definition
|
|
36
|
-
*
|
|
37
|
-
* @param {object} definition - Terms definition with TLD descriptor
|
|
38
|
-
* @returns {object} Extracted schema content
|
|
39
|
-
* @throws {Sass} If definition structure is invalid
|
|
40
|
-
* @private
|
|
41
|
-
*/
|
|
42
|
-
static #extractSchemaFromTerms(definition) {
|
|
43
|
-
// Must be a plain object
|
|
44
|
-
if(!Data.isPlainObject(definition)) {
|
|
45
|
-
throw Sass.new("Terms definition must be a plain object")
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Must have exactly one key (the TLD/descriptor)
|
|
49
|
-
const keys = Object.keys(definition)
|
|
50
|
-
if(keys.length !== 1) {
|
|
51
|
-
throw Sass.new("Terms definition must have exactly one top-level key (descriptor)")
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Extract the content under the TLD
|
|
55
|
-
const [key] = keys
|
|
56
|
-
|
|
57
|
-
return definition[key]
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Creates a contract from terms with schema validation
|
|
62
|
-
*
|
|
63
|
-
* @param {string} name - Contract identifier
|
|
64
|
-
* @param {object} termsDefinition - The terms definition
|
|
65
|
-
* @param {import('ajv').ValidateFunction|null} [validator] - Optional AJV schema validator function with .errors property
|
|
66
|
-
* @param {import('../types.js').DebugFunction} [debug] - Debug function
|
|
67
|
-
* @returns {Contract} New contract instance
|
|
68
|
-
*/
|
|
69
|
-
static fromTerms(name, termsDefinition, validator = null, debug = null) {
|
|
70
|
-
// Validate the terms definition if validator provided
|
|
71
|
-
if(validator) {
|
|
72
|
-
const valid = validator(termsDefinition)
|
|
73
|
-
|
|
74
|
-
if(!valid) {
|
|
75
|
-
const error = Schemer.reportValidationErrors(validator.errors)
|
|
76
|
-
throw Sass.new(`Invalid terms definition for ${name}:\n${error}`)
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Extract schema from terms definition for validation
|
|
81
|
-
const schemaDefinition = Contract.#extractSchemaFromTerms(termsDefinition)
|
|
82
|
-
const termsSchemaValidator = Schemer.getValidator(schemaDefinition)
|
|
83
|
-
|
|
84
|
-
const contract = new Contract(null, null, {debug})
|
|
85
|
-
contract.#validator = termsSchemaValidator
|
|
86
|
-
contract.#isNegotiated = true // Single-party contract is automatically negotiated
|
|
87
|
-
|
|
88
|
-
return contract
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Performs negotiation between provider and consumer terms
|
|
93
|
-
*
|
|
94
|
-
* @private
|
|
95
|
-
*/
|
|
96
|
-
#negotiate() {
|
|
97
|
-
if(!this.#providerTerms || !this.#consumerTerms) {
|
|
98
|
-
// Single-party contract scenario
|
|
99
|
-
this.#isNegotiated = true
|
|
100
|
-
|
|
101
|
-
return
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Extract content for comparison (ignore TLD metadata)
|
|
105
|
-
const providerContent = Contract.#extractSchemaFromTerms(
|
|
106
|
-
this.#providerTerms.definition
|
|
107
|
-
)
|
|
108
|
-
const consumerContent = Contract.#extractSchemaFromTerms(
|
|
109
|
-
this.#consumerTerms.definition
|
|
110
|
-
)
|
|
111
|
-
|
|
112
|
-
// Compare terms for compatibility
|
|
113
|
-
const compatibility = this.#compareTerms(providerContent, consumerContent)
|
|
114
|
-
|
|
115
|
-
if(compatibility.status === "error") {
|
|
116
|
-
throw Sass.new(
|
|
117
|
-
`Contract negotiation failed: ${compatibility.errors.map(e => e.message).join(", ")}`
|
|
118
|
-
)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
this.#isNegotiated = true
|
|
122
|
-
this.#debug?.(`Contract negotiated successfully`, 3)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Validates data against this contract
|
|
127
|
-
*
|
|
128
|
-
* @param {object} data - Data to validate
|
|
129
|
-
* @returns {boolean} True if valid
|
|
130
|
-
* @throws {Sass} If validation fails or contract not negotiated
|
|
131
|
-
*/
|
|
132
|
-
validate(data) {
|
|
133
|
-
const debug = this.#debug
|
|
134
|
-
|
|
135
|
-
if(!this.#isNegotiated)
|
|
136
|
-
throw Sass.new("Cannot validate against unnegotiated contract")
|
|
137
|
-
|
|
138
|
-
if(!this.#validator)
|
|
139
|
-
throw Sass.new("No validator available for this contract")
|
|
140
|
-
|
|
141
|
-
debug?.("Validating data %o", 4, data)
|
|
142
|
-
|
|
143
|
-
const valid = this.#validator(data)
|
|
144
|
-
|
|
145
|
-
if(!valid) {
|
|
146
|
-
const error = Schemer.reportValidationErrors(this.#validator.errors)
|
|
147
|
-
throw Sass.new(`Contract validation failed:\n${error}`)
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return true
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Compares terms for compatibility
|
|
155
|
-
*
|
|
156
|
-
* @param {object} providerTerms - Terms offered by provider
|
|
157
|
-
* @param {object} consumerTerms - Terms expected by consumer
|
|
158
|
-
* @param {Array<string>} stack - Stack trace for nested validation
|
|
159
|
-
* @returns {object} Result with status and errors
|
|
160
|
-
* @private
|
|
161
|
-
*/
|
|
162
|
-
#compareTerms(providerTerms, consumerTerms, stack = []) {
|
|
163
|
-
const debug = this.#debug
|
|
164
|
-
const breadcrumb = key => (stack.length ? `@${stack.join(".")}` : key)
|
|
165
|
-
const errors = []
|
|
166
|
-
|
|
167
|
-
if(!providerTerms || !consumerTerms) {
|
|
168
|
-
return {
|
|
169
|
-
status: "error",
|
|
170
|
-
errors: [Sass.new("Both provider and consumer terms are required")]
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
debug?.("Comparing provider keys:%o with consumer keys:%o", 3,
|
|
175
|
-
Object.keys(providerTerms), Object.keys(consumerTerms))
|
|
176
|
-
|
|
177
|
-
// Check that consumer requirements are met by provider
|
|
178
|
-
for(const [key, consumerRequirement] of Object.entries(consumerTerms)) {
|
|
179
|
-
debug?.("Checking consumer requirement: %o [required = %o]", 3,
|
|
180
|
-
key, consumerRequirement.required ?? false)
|
|
181
|
-
|
|
182
|
-
if(consumerRequirement.required && !(key in providerTerms)) {
|
|
183
|
-
debug?.("Provider missing required capability: %o", 2, key)
|
|
184
|
-
errors.push(
|
|
185
|
-
Sass.new(`Provider missing required capability: ${key} ${breadcrumb(key)}`)
|
|
186
|
-
)
|
|
187
|
-
continue
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
if(key in providerTerms) {
|
|
191
|
-
const expectedType = consumerRequirement.dataType
|
|
192
|
-
const providedType = providerTerms[key]?.dataType
|
|
193
|
-
|
|
194
|
-
if(expectedType && providedType && expectedType !== providedType) {
|
|
195
|
-
errors.push(
|
|
196
|
-
Sass.new(
|
|
197
|
-
`Type mismatch for ${key}: Consumer expects ${expectedType}, provider offers ${providedType} ${breadcrumb(key)}`
|
|
198
|
-
)
|
|
199
|
-
)
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// Recursive validation for nested requirements
|
|
203
|
-
if(consumerRequirement.contains) {
|
|
204
|
-
debug?.("Recursing into nested requirement: %o", 3, key)
|
|
205
|
-
const nestedResult = this.#compareTerms(
|
|
206
|
-
providerTerms[key]?.contains,
|
|
207
|
-
consumerRequirement.contains,
|
|
208
|
-
[...stack, key]
|
|
209
|
-
)
|
|
210
|
-
|
|
211
|
-
if(nestedResult.errors.length) {
|
|
212
|
-
errors.push(...nestedResult.errors)
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
return {status: errors.length === 0 ? "success" : "error", errors}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Check if contract negotiation was successful
|
|
223
|
-
*
|
|
224
|
-
* @returns {boolean} True if negotiated
|
|
225
|
-
*/
|
|
226
|
-
get isNegotiated() {
|
|
227
|
-
return this.#isNegotiated
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Get the provider terms (if any)
|
|
232
|
-
*
|
|
233
|
-
* @returns {import("./Terms.js").default|null} Provider terms
|
|
234
|
-
*/
|
|
235
|
-
get providerTerms() {
|
|
236
|
-
return this.#providerTerms
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Get the consumer terms (if any)
|
|
241
|
-
*
|
|
242
|
-
* @returns {import("./Terms.js").default|null} Consumer terms
|
|
243
|
-
*/
|
|
244
|
-
get consumerTerms() {
|
|
245
|
-
return this.#consumerTerms
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Get the contract validator
|
|
250
|
-
*
|
|
251
|
-
* @returns {(data: object) => boolean|null} The contract validator function
|
|
252
|
-
*/
|
|
253
|
-
get validator() {
|
|
254
|
-
return this.#validator
|
|
255
|
-
}
|
|
256
|
-
}
|
package/src/lib/Schemer.js
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import Ajv from "ajv"
|
|
2
|
-
|
|
3
|
-
import Data from "../browser/lib/Data.js"
|
|
4
|
-
import Util from "../browser/lib/Util.js"
|
|
5
|
-
import Valid from "./Valid.js"
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Schemer provides utilities for compiling and validating JSON schemas using AJV.
|
|
9
|
-
*
|
|
10
|
-
* Usage:
|
|
11
|
-
* - Use Schemer.fromFile(file, options) to create a validator from a file.
|
|
12
|
-
* - Use Schemer.from(schemaData, options) to create a validator from a schema object.
|
|
13
|
-
* - Use Schemer.getValidator(schema, options) to get a raw AJV validator function.
|
|
14
|
-
* - Use Schemer.reportValidationErrors(errors) to format AJV validation errors.
|
|
15
|
-
*/
|
|
16
|
-
export default class Schemer {
|
|
17
|
-
static async fromFile(file, options={}) {
|
|
18
|
-
Valid.type(file, "FileObject")
|
|
19
|
-
Valid.assert(Data.isPlainObject(options), "Options must be a plain object.")
|
|
20
|
-
|
|
21
|
-
const schemaData = await file.loadData()
|
|
22
|
-
|
|
23
|
-
return Schemer.getValidator(schemaData, options)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
static async from(schemaData={}, options={}) {
|
|
27
|
-
Valid.assert(Data.isPlainObject(schemaData), "Schema data must be a plain object.")
|
|
28
|
-
Valid.assert(Data.isPlainObject(options), "Options must be a plain object.")
|
|
29
|
-
|
|
30
|
-
return Schemer.getValidator(schemaData, options)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Creates a validator function from a schema object
|
|
35
|
-
*
|
|
36
|
-
* @param {object} schema - The schema to compile
|
|
37
|
-
* @param {object} [options] - AJV options
|
|
38
|
-
* @returns {(data: unknown) => boolean} The AJV validator function, which may have additional properties (e.g., `.errors`)
|
|
39
|
-
*/
|
|
40
|
-
static getValidator(schema, options = {allErrors: true, verbose: true}) {
|
|
41
|
-
const ajv = new Ajv(options)
|
|
42
|
-
|
|
43
|
-
return ajv.compile(schema)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
static reportValidationErrors(errors) {
|
|
47
|
-
if(!errors) {
|
|
48
|
-
return ""
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return errors.reduce((errorMessages, error) => {
|
|
52
|
-
let msg = `- "${error.instancePath || "(root)"}" ${error.message}`
|
|
53
|
-
|
|
54
|
-
if(error.params) {
|
|
55
|
-
const details = []
|
|
56
|
-
|
|
57
|
-
if(error.params.type)
|
|
58
|
-
details.push(` ➜ Expected type: ${error.params.type}`)
|
|
59
|
-
|
|
60
|
-
if(error.params.missingProperty)
|
|
61
|
-
details.push(` ➜ Missing required field: ${error.params.missingProperty}`)
|
|
62
|
-
|
|
63
|
-
if(error.params.allowedValues) {
|
|
64
|
-
details.push(` ➜ Allowed values: "${error.params.allowedValues.join('", "')}"`)
|
|
65
|
-
details.push(` ➜ Received value: "${error.data}"`)
|
|
66
|
-
const closestMatch =
|
|
67
|
-
Util.findClosestMatch(error.data, error.params.allowedValues)
|
|
68
|
-
|
|
69
|
-
if(closestMatch)
|
|
70
|
-
details.push(` ➜ Did you mean: "${closestMatch}"?`)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if(error.params.pattern)
|
|
74
|
-
details.push(` ➜ Expected pattern: ${error.params.pattern}`)
|
|
75
|
-
|
|
76
|
-
if(error.params.format)
|
|
77
|
-
details.push(` ➜ Expected format: ${error.params.format}`)
|
|
78
|
-
|
|
79
|
-
if(error.params.additionalProperty)
|
|
80
|
-
details.push(` ➜ Unexpected property: ${error.params.additionalProperty}`)
|
|
81
|
-
|
|
82
|
-
if(details.length)
|
|
83
|
-
msg += `\n${details.join("\n")}`
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return errorMessages ? `${errorMessages}\n${msg}` : msg
|
|
87
|
-
}, "")
|
|
88
|
-
}
|
|
89
|
-
}
|
package/src/lib/Terms.js
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import JSON5 from "json5"
|
|
2
|
-
import yaml from "yaml"
|
|
3
|
-
|
|
4
|
-
import Data from "../browser/lib/Data.js"
|
|
5
|
-
import FileObject from "./FileObject.js"
|
|
6
|
-
import Sass from "./Sass.js"
|
|
7
|
-
import Valid from "./Valid.js"
|
|
8
|
-
|
|
9
|
-
const refex = /^ref:\/\/(?<file>.*)$/
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Terms represents an interface definition - what an action promises to provide or accept.
|
|
13
|
-
* It's just the specification, not the negotiation. Contract handles the negotiation.
|
|
14
|
-
*/
|
|
15
|
-
export default class Terms {
|
|
16
|
-
#definition = null
|
|
17
|
-
|
|
18
|
-
constructor(definition) {
|
|
19
|
-
this.#definition = definition
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Parses terms data, handling file references
|
|
24
|
-
*
|
|
25
|
-
* @param {string|object} termsData - Terms data or reference
|
|
26
|
-
* @param {import("./DirectoryObject.js").DirectoryObject?} directoryObject - Directory context for file resolution
|
|
27
|
-
* @returns {object} Parsed terms data
|
|
28
|
-
*/
|
|
29
|
-
static async parse(termsData, directoryObject) {
|
|
30
|
-
if(Data.isBaseType(termsData, "String")) {
|
|
31
|
-
const match = refex.exec(termsData)
|
|
32
|
-
|
|
33
|
-
if(match?.groups?.file) {
|
|
34
|
-
Valid.type(directoryObject, "DirectoryObject")
|
|
35
|
-
|
|
36
|
-
const file = new FileObject(match.groups.file, directoryObject)
|
|
37
|
-
|
|
38
|
-
return await file.loadData()
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Try parsing as YAML/JSON
|
|
42
|
-
try {
|
|
43
|
-
const result = JSON5.parse(termsData)
|
|
44
|
-
|
|
45
|
-
return result
|
|
46
|
-
} catch {
|
|
47
|
-
try {
|
|
48
|
-
const result = yaml.parse(termsData)
|
|
49
|
-
|
|
50
|
-
return result
|
|
51
|
-
} catch {
|
|
52
|
-
throw Sass.new(`Could not parse terms data as YAML or JSON: ${termsData}`)
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if(Data.isBaseType(termsData, "Object")) {
|
|
58
|
-
return termsData
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
throw Sass.new(`Invalid terms data type: ${typeof termsData}`)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Get the terms definition
|
|
66
|
-
*
|
|
67
|
-
* @returns {object} The terms definition
|
|
68
|
-
*/
|
|
69
|
-
get definition() {
|
|
70
|
-
return this.#definition
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Contract represents a successful negotiation between Terms.
|
|
3
|
-
* It handles validation and compatibility checking between what
|
|
4
|
-
* one action provides and what another accepts.
|
|
5
|
-
*/
|
|
6
|
-
export default class Contract {
|
|
7
|
-
/**
|
|
8
|
-
* Extracts the actual schema from a terms definition
|
|
9
|
-
*
|
|
10
|
-
* @param {object} definition - Terms definition with TLD descriptor
|
|
11
|
-
* @returns {object} Extracted schema content
|
|
12
|
-
* @throws {Sass} If definition structure is invalid
|
|
13
|
-
* @private
|
|
14
|
-
*/
|
|
15
|
-
private static "__#private@#extractSchemaFromTerms";
|
|
16
|
-
/**
|
|
17
|
-
* Creates a contract from terms with schema validation
|
|
18
|
-
*
|
|
19
|
-
* @param {string} name - Contract identifier
|
|
20
|
-
* @param {object} termsDefinition - The terms definition
|
|
21
|
-
* @param {import('ajv').ValidateFunction|null} [validator] - Optional AJV schema validator function with .errors property
|
|
22
|
-
* @param {import('../types.js').DebugFunction} [debug] - Debug function
|
|
23
|
-
* @returns {Contract} New contract instance
|
|
24
|
-
*/
|
|
25
|
-
static fromTerms(name: string, termsDefinition: object, validator?: any | null, debug?: any): Contract;
|
|
26
|
-
/**
|
|
27
|
-
* Creates a contract by negotiating between provider and consumer terms
|
|
28
|
-
*
|
|
29
|
-
* @param {import("./Terms.js").Terms} providerTerms - What the provider offers
|
|
30
|
-
* @param {import("./Terms.js").Terms} consumerTerms - What the consumer expects
|
|
31
|
-
* @param {object} options - Configuration options
|
|
32
|
-
* @param {import('../types.js').DebugFunction} [options.debug] - Debug function
|
|
33
|
-
*/
|
|
34
|
-
constructor(providerTerms: import("./Terms.js").Terms, consumerTerms: import("./Terms.js").Terms, { debug }?: {
|
|
35
|
-
debug?: any;
|
|
36
|
-
});
|
|
37
|
-
/**
|
|
38
|
-
* Validates data against this contract
|
|
39
|
-
*
|
|
40
|
-
* @param {object} data - Data to validate
|
|
41
|
-
* @returns {boolean} True if valid
|
|
42
|
-
* @throws {Sass} If validation fails or contract not negotiated
|
|
43
|
-
*/
|
|
44
|
-
validate(data: object): boolean;
|
|
45
|
-
/**
|
|
46
|
-
* Check if contract negotiation was successful
|
|
47
|
-
*
|
|
48
|
-
* @returns {boolean} True if negotiated
|
|
49
|
-
*/
|
|
50
|
-
get isNegotiated(): boolean;
|
|
51
|
-
/**
|
|
52
|
-
* Get the provider terms (if any)
|
|
53
|
-
*
|
|
54
|
-
* @returns {import("./Terms.js").default|null} Provider terms
|
|
55
|
-
*/
|
|
56
|
-
get providerTerms(): import("./Terms.js").default | null;
|
|
57
|
-
/**
|
|
58
|
-
* Get the consumer terms (if any)
|
|
59
|
-
*
|
|
60
|
-
* @returns {import("./Terms.js").default|null} Consumer terms
|
|
61
|
-
*/
|
|
62
|
-
get consumerTerms(): import("./Terms.js").default | null;
|
|
63
|
-
/**
|
|
64
|
-
* Get the contract validator
|
|
65
|
-
*
|
|
66
|
-
* @returns {(data: object) => boolean|null} The contract validator function
|
|
67
|
-
*/
|
|
68
|
-
get validator(): (data: object) => boolean | null;
|
|
69
|
-
#private;
|
|
70
|
-
}
|
|
71
|
-
//# sourceMappingURL=Contract.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Contract.d.ts","sourceRoot":"","sources":["../../lib/Contract.js"],"names":[],"mappings":"AAIA;;;;GAIG;AACH;IAwBE;;;;;;;OAOG;IACH,oDAgBC;IAED;;;;;;;;OAQG;IACH,uBANW,MAAM,mBACN,MAAM,cACN,GAA8B,GAAC,IAAI,gBAEjC,QAAQ,CAsBpB;IAxED;;;;;;;OAOG;IACH,2BALW,OAAO,YAAY,EAAE,KAAK,iBAC1B,OAAO,YAAY,EAAE,KAAK,cAElC;QAAsD,KAAK,GAAnD,GAAmC;KAC7C,EAQA;IA6FD;;;;;;OAMG;IACH,eAJW,MAAM,GACJ,OAAO,CAsBnB;IAsED;;;;OAIG;IACH,oBAFa,OAAO,CAInB;IAED;;;;OAIG;IACH,qBAFa,OAAO,YAAY,EAAE,OAAO,GAAC,IAAI,CAI7C;IAED;;;;OAIG;IACH,qBAFa,OAAO,YAAY,EAAE,OAAO,GAAC,IAAI,CAI7C;IAED;;;;OAIG;IACH,iBAFa,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAAC,IAAI,CAI1C;;CACF"}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Schemer provides utilities for compiling and validating JSON schemas using AJV.
|
|
3
|
-
*
|
|
4
|
-
* Usage:
|
|
5
|
-
* - Use Schemer.fromFile(file, options) to create a validator from a file.
|
|
6
|
-
* - Use Schemer.from(schemaData, options) to create a validator from a schema object.
|
|
7
|
-
* - Use Schemer.getValidator(schema, options) to get a raw AJV validator function.
|
|
8
|
-
* - Use Schemer.reportValidationErrors(errors) to format AJV validation errors.
|
|
9
|
-
*/
|
|
10
|
-
export default class Schemer {
|
|
11
|
-
static fromFile(file: any, options?: {}): Promise<(data: unknown) => boolean>;
|
|
12
|
-
static from(schemaData?: {}, options?: {}): Promise<(data: unknown) => boolean>;
|
|
13
|
-
/**
|
|
14
|
-
* Creates a validator function from a schema object
|
|
15
|
-
*
|
|
16
|
-
* @param {object} schema - The schema to compile
|
|
17
|
-
* @param {object} [options] - AJV options
|
|
18
|
-
* @returns {(data: unknown) => boolean} The AJV validator function, which may have additional properties (e.g., `.errors`)
|
|
19
|
-
*/
|
|
20
|
-
static getValidator(schema: object, options?: object): (data: unknown) => boolean;
|
|
21
|
-
static reportValidationErrors(errors: any): any;
|
|
22
|
-
}
|
|
23
|
-
//# sourceMappingURL=Schemer.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Schemer.d.ts","sourceRoot":"","sources":["../../lib/Schemer.js"],"names":[],"mappings":"AAMA;;;;;;;;GAQG;AACH;IACE,yDAqBoB,OAAO,KAAK,OAAO,EAdtC;IAED,2DAYoB,OAAO,KAAK,OAAO,EAPtC;IAED;;;;;;OAMG;IACH,4BAJW,MAAM,YACN,MAAM,GACJ,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAMtC;IAED,gDA0CC;CACF"}
|
package/src/types/lib/Terms.d.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Terms represents an interface definition - what an action promises to provide or accept.
|
|
3
|
-
* It's just the specification, not the negotiation. Contract handles the negotiation.
|
|
4
|
-
*/
|
|
5
|
-
export default class Terms {
|
|
6
|
-
/**
|
|
7
|
-
* Parses terms data, handling file references
|
|
8
|
-
*
|
|
9
|
-
* @param {string|object} termsData - Terms data or reference
|
|
10
|
-
* @param {import("./DirectoryObject.js").DirectoryObject?} directoryObject - Directory context for file resolution
|
|
11
|
-
* @returns {object} Parsed terms data
|
|
12
|
-
*/
|
|
13
|
-
static parse(termsData: string | object, directoryObject: import("./DirectoryObject.js").DirectoryObject | null): object;
|
|
14
|
-
constructor(definition: any);
|
|
15
|
-
/**
|
|
16
|
-
* Get the terms definition
|
|
17
|
-
*
|
|
18
|
-
* @returns {object} The terms definition
|
|
19
|
-
*/
|
|
20
|
-
get definition(): object;
|
|
21
|
-
#private;
|
|
22
|
-
}
|
|
23
|
-
//# sourceMappingURL=Terms.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Terms.d.ts","sourceRoot":"","sources":["../../lib/Terms.js"],"names":[],"mappings":"AAUA;;;GAGG;AACH;IAOE;;;;;;OAMG;IACH,wBAJW,MAAM,GAAC,MAAM,mBACb,OAAO,sBAAsB,EAAE,eAAe,OAAC,GAC7C,MAAM,CAmClB;IA5CD,6BAEC;IA4CD;;;;OAIG;IACH,kBAFa,MAAM,CAIlB;;CAEF"}
|