@zenera/sandbox 1.1.57 → 1.1.58
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.d.ts +5 -5
- package/dist/fs.js +18 -3
- package/dist/in-memory-fs.d.ts +2 -1
- package/dist/in-memory-fs.js +8 -3
- package/dist/testing.js +12 -2
- package/package.json +1 -1
package/dist/fs.d.ts
CHANGED
|
@@ -13,12 +13,12 @@ export interface FsDriver {
|
|
|
13
13
|
/** how this driver's paths are spelled: the host's for `localFs`, posix otherwise */
|
|
14
14
|
readonly path: PlatformPath;
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
16
|
+
* Where a path really is: absolute, with every symlink in the part that
|
|
17
|
+
* exists resolved, and the part that does not exist yet appended as
|
|
18
|
+
* written — what a create needs, and what containment is decided on. A
|
|
19
|
+
* path through a file is `ENOTDIR`, as `realpath` says.
|
|
20
20
|
*/
|
|
21
|
-
|
|
21
|
+
resolve(path: string): Promise<string>;
|
|
22
22
|
stat(path: string): Promise<FsStat>;
|
|
23
23
|
readdir(path: string): Promise<FsEntry[]>;
|
|
24
24
|
readFile(path: string): Promise<Buffer>;
|
package/dist/fs.js
CHANGED
|
@@ -1,10 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { cp, mkdir, open, readFile, readdir, rename, rm, stat, writeFile } from 'node:fs/promises';
|
|
1
|
+
import { cp, mkdir, open, readFile, readdir, realpath, rename, rm, stat, writeFile, } from 'node:fs/promises';
|
|
3
2
|
import path, {} from 'node:path';
|
|
4
3
|
/** This machine's disk, through `node:fs`. */
|
|
5
4
|
export const localFs = {
|
|
6
5
|
path,
|
|
7
|
-
|
|
6
|
+
async resolve(p) {
|
|
7
|
+
const missing = [];
|
|
8
|
+
let at = path.resolve(p);
|
|
9
|
+
for (;;) {
|
|
10
|
+
try {
|
|
11
|
+
return path.join(await realpath(at), ...missing.reverse());
|
|
12
|
+
}
|
|
13
|
+
catch (err) {
|
|
14
|
+
const up = path.dirname(at);
|
|
15
|
+
if (err.code !== 'ENOENT' || up === at) {
|
|
16
|
+
throw err;
|
|
17
|
+
}
|
|
18
|
+
missing.push(path.basename(at));
|
|
19
|
+
at = up;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
},
|
|
8
23
|
stat: (p) => stat(p),
|
|
9
24
|
readdir: (p) => readdir(p, { withFileTypes: true }),
|
|
10
25
|
readFile: (p) => readFile(p),
|
package/dist/in-memory-fs.d.ts
CHANGED
|
@@ -6,7 +6,8 @@ export declare class InMemoryFs implements FsDriver {
|
|
|
6
6
|
constructor(files?: Record<string, string | Uint8Array>);
|
|
7
7
|
/** An empty directory, with its parents. */
|
|
8
8
|
dir(at: string): this;
|
|
9
|
-
|
|
9
|
+
/** No symlinks here, so only a path through a file needs saying anything about. */
|
|
10
|
+
resolve(at: string): Promise<string>;
|
|
10
11
|
stat(at: string): Promise<FsStat>;
|
|
11
12
|
readdir(at: string): Promise<FsEntry[]>;
|
|
12
13
|
readFile(at: string): Promise<Buffer>;
|
package/dist/in-memory-fs.js
CHANGED
|
@@ -15,10 +15,15 @@ export class InMemoryFs {
|
|
|
15
15
|
this.#mkdirs(this.#abs(at));
|
|
16
16
|
return this;
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
/** No symlinks here, so only a path through a file needs saying anything about. */
|
|
19
|
+
async resolve(at) {
|
|
19
20
|
const abs = this.#abs(at);
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
let probe = abs;
|
|
22
|
+
while (!this.#nodes.has(probe)) {
|
|
23
|
+
probe = posix.dirname(probe);
|
|
24
|
+
}
|
|
25
|
+
if (probe !== abs && this.#nodes.get(probe)?.kind === 'file') {
|
|
26
|
+
throw fsError('ENOTDIR', 'realpath', at);
|
|
22
27
|
}
|
|
23
28
|
return abs;
|
|
24
29
|
}
|
package/dist/testing.js
CHANGED
|
@@ -52,8 +52,18 @@ export function describeFsDriver(name, make) {
|
|
|
52
52
|
code: 'ENOENT',
|
|
53
53
|
path: expect.stringContaining('ghost.txt'),
|
|
54
54
|
});
|
|
55
|
-
expect(
|
|
56
|
-
|
|
55
|
+
expect(await fs.resolve(at('.'))).toBe(await fs.resolve(at()));
|
|
56
|
+
}));
|
|
57
|
+
it('resolves where a path really is, the part that does not exist yet included', withFs(async ({ fs }, at) => {
|
|
58
|
+
const root = await fs.resolve(at());
|
|
59
|
+
await fs.mkdirp(at('real', 'dir'));
|
|
60
|
+
expect(await fs.resolve(at('real', 'dir'))).toBe(fs.path.join(root, 'real', 'dir'));
|
|
61
|
+
expect(await fs.resolve(at('real', 'ghost', 'deeper.txt'))).toBe(fs.path.join(root, 'real', 'ghost', 'deeper.txt'));
|
|
62
|
+
expect(await fs.resolve(at('real', 'dir', '..', 'x'))).toBe(fs.path.join(root, 'real', 'x'));
|
|
63
|
+
await fs.writeFile(at('file.txt'), 'x');
|
|
64
|
+
await expect(fs.resolve(at('file.txt', 'under'))).rejects.toMatchObject({
|
|
65
|
+
code: 'ENOTDIR',
|
|
66
|
+
});
|
|
57
67
|
}));
|
|
58
68
|
});
|
|
59
69
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenera/sandbox",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.58",
|
|
4
4
|
"description": "Where an agent's commands run and the files they see: the Sandbox contract, a podman implementation, filesystem drivers and a contract test suite for other implementations.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sandbox",
|