@orkestrel/test 0.0.1 → 0.0.3
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 +39 -21
- package/dist/src/core/index.cjs +5 -4
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +38 -4
- package/dist/src/core/index.d.ts +38 -4
- package/dist/src/core/index.js +5 -4
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +125 -29
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +114 -13
- package/dist/src/server/index.d.ts +114 -13
- package/dist/src/server/index.js +125 -31
- package/dist/src/server/index.js.map +1 -1
- package/package.json +1 -1
package/dist/src/server/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, rmSync, statSync, symlinkSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
@@ -17,36 +17,72 @@ function resolveContained(root, target) {
|
|
|
17
17
|
return candidate;
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
20
|
+
* Reports whether two directory identities name the same allocation.
|
|
21
|
+
*
|
|
22
|
+
* @param current - The identity read from the path now.
|
|
23
|
+
* @param allocation - The identity recorded when the directory was allocated.
|
|
24
|
+
* @returns Whether the device, the index node, and the creation time all match.
|
|
25
|
+
* @remarks All three fields are compared because none of them alone identifies an allocation. A
|
|
26
|
+
* device is shared by every directory on one filesystem, an index node is reused once its directory
|
|
27
|
+
* is removed, and a creation time repeats within the host's timestamp resolution.
|
|
28
|
+
*/
|
|
29
|
+
function matchesIdentity(current, allocation) {
|
|
30
|
+
return current.device === allocation.device && current.inode === allocation.inode && current.birth === allocation.birth;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Reports whether a root-relative key matches an exclusion.
|
|
34
|
+
*
|
|
35
|
+
* @param key - The root-relative key to test.
|
|
36
|
+
* @param exclusions - The normalized root-relative exclusion keys.
|
|
37
|
+
* @returns Whether an exclusion names the key or one of its ancestors.
|
|
38
|
+
*/
|
|
39
|
+
function isExcluded(key, exclusions) {
|
|
40
|
+
return exclusions.some((rule) => rule === "" || key === rule || key.startsWith(`${rule}/`));
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Reads files from selected targets below a root directory.
|
|
21
44
|
*
|
|
22
45
|
* @param root - The root directory as a path or file URL.
|
|
23
|
-
* @param
|
|
24
|
-
* @param options - Optional file extension and
|
|
46
|
+
* @param targets - The files to read directly and directories to visit below the root.
|
|
47
|
+
* @param options - Optional file extension and path exclusions.
|
|
25
48
|
* @returns File contents keyed by sorted root-relative paths.
|
|
26
|
-
* @
|
|
49
|
+
* @throws When the root or a named target is a symbolic link, is not a supported entry, or resolves
|
|
50
|
+
* outside the root.
|
|
51
|
+
* @remarks A named file is included regardless of the extension filter. An absent extension filter
|
|
52
|
+
* includes every walked file. An exclusion matches whole root-relative key segments and covers every
|
|
53
|
+
* key below it, and it applies to a named target and a walked entry alike.
|
|
27
54
|
*/
|
|
28
|
-
function readInventory(root,
|
|
55
|
+
function readInventory(root, targets, options) {
|
|
29
56
|
const supplied = resolve(typeof root === "string" ? root : fileURLToPath(root));
|
|
30
57
|
const rootStatus = lstatSync(supplied);
|
|
31
58
|
if (rootStatus.isSymbolicLink()) throw new Error("Root is a symbolic link");
|
|
32
59
|
if (!rootStatus.isDirectory()) throw new Error("Root is not a directory");
|
|
33
60
|
const base = realpathSync.native(supplied);
|
|
34
|
-
if (
|
|
35
|
-
const
|
|
61
|
+
if (targets.length === 0) return Object.fromEntries([]);
|
|
62
|
+
const exclusions = (options?.exclude ?? []).map((rule) => {
|
|
63
|
+
const collapsed = (rule.startsWith("./") ? rule.slice(2) : rule).replace(/\/+/g, "/");
|
|
64
|
+
const untrailed = collapsed.endsWith("/") ? collapsed.slice(0, -1) : collapsed;
|
|
65
|
+
return untrailed === "." ? "" : untrailed;
|
|
66
|
+
});
|
|
36
67
|
const pending = [];
|
|
37
68
|
const queued = /* @__PURE__ */ new Set();
|
|
38
69
|
const contents = /* @__PURE__ */ new Map();
|
|
39
|
-
for (const
|
|
40
|
-
const candidate = resolveContained(base,
|
|
41
|
-
if (candidate === void 0) throw new Error(`
|
|
70
|
+
for (const target of targets) {
|
|
71
|
+
const candidate = resolveContained(base, target);
|
|
72
|
+
if (candidate === void 0) throw new Error(`Target outside root: ${target}`);
|
|
42
73
|
const status = lstatSync(candidate);
|
|
43
|
-
if (status.isSymbolicLink()) throw new Error(`
|
|
44
|
-
if (!status.isDirectory()) throw new Error(`
|
|
74
|
+
if (status.isSymbolicLink()) throw new Error(`Target is a symbolic link: ${target}`);
|
|
75
|
+
if (!status.isDirectory() && !status.isFile()) throw new Error(`Target is not a file or directory: ${target}`);
|
|
45
76
|
const physical = realpathSync.native(candidate);
|
|
46
77
|
const resolved = resolveContained(base, relative(base, physical));
|
|
47
|
-
if (resolved === void 0) throw new Error(`
|
|
78
|
+
if (resolved === void 0) throw new Error(`Target outside root: ${target}`);
|
|
48
79
|
const key = relative(base, resolved).split(sep).join("/");
|
|
49
|
-
if (
|
|
80
|
+
if (isExcluded(key, exclusions)) continue;
|
|
81
|
+
if (status.isFile()) {
|
|
82
|
+
contents.set(key, readFileSync(physical, "utf8"));
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (queued.has(physical)) continue;
|
|
50
86
|
queued.add(physical);
|
|
51
87
|
pending.push(physical);
|
|
52
88
|
}
|
|
@@ -58,7 +94,7 @@ function readInventory(root, directories, options) {
|
|
|
58
94
|
const status = lstatSync(path);
|
|
59
95
|
if (status.isSymbolicLink()) continue;
|
|
60
96
|
const key = relative(base, path).split(sep).join("/");
|
|
61
|
-
if (
|
|
97
|
+
if (isExcluded(key, exclusions)) continue;
|
|
62
98
|
if (status.isDirectory()) {
|
|
63
99
|
const physical = realpathSync.native(path);
|
|
64
100
|
if (resolveContained(base, relative(base, physical)) === void 0 || queued.has(physical)) continue;
|
|
@@ -77,17 +113,30 @@ function readInventory(root, directories, options) {
|
|
|
77
113
|
/**
|
|
78
114
|
* Allocates an owned temporary directory with contained file operations.
|
|
79
115
|
*
|
|
80
|
-
* @param options - Optional directory prefix and initial files.
|
|
116
|
+
* @param options - Optional parent directory, name prefix, and initial files.
|
|
81
117
|
* @returns The scratch directory and its file operations.
|
|
82
|
-
* @
|
|
118
|
+
* @throws When the parent is missing, a symbolic link, or not a directory; when the prefix contains
|
|
119
|
+
* `/` or `\`; or when allocation or seeding fails.
|
|
120
|
+
* @remarks The parent defaults to the host temporary directory. The prefix defaults to
|
|
121
|
+
* `orkestrel-test-`. Seed keys use root-relative paths.
|
|
83
122
|
*/
|
|
84
123
|
function createScratch(options) {
|
|
85
|
-
const
|
|
86
|
-
const
|
|
87
|
-
if (
|
|
88
|
-
|
|
89
|
-
|
|
124
|
+
const parent = resolve(options?.parent ?? tmpdir());
|
|
125
|
+
const parentStatus = lstatSync(parent, { throwIfNoEntry: false });
|
|
126
|
+
if (parentStatus === void 0) throw new Error("Scratch parent does not exist");
|
|
127
|
+
if (parentStatus.isSymbolicLink()) throw new Error("Scratch parent is a symbolic link");
|
|
128
|
+
if (!parentStatus.isDirectory()) throw new Error("Scratch parent is not a directory");
|
|
129
|
+
const prefix = options?.prefix ?? "orkestrel-test-";
|
|
130
|
+
if (prefix.includes("/") || prefix.includes("\\")) throw new Error("Scratch prefix must be a name fragment");
|
|
131
|
+
const path = mkdtempSync(`${parent}${sep}${prefix}`);
|
|
132
|
+
const allocated = statSync(path);
|
|
133
|
+
const allocation = {
|
|
134
|
+
birth: allocated.birthtimeMs,
|
|
135
|
+
device: allocated.dev,
|
|
136
|
+
inode: allocated.ino
|
|
137
|
+
};
|
|
90
138
|
const outside = "Path outside scratch directory";
|
|
139
|
+
const unremovable = "Scratch directory is not a removable target";
|
|
91
140
|
try {
|
|
92
141
|
for (const [target, text] of Object.entries(options?.files ?? {})) {
|
|
93
142
|
const candidate = resolveContained(path, target);
|
|
@@ -107,23 +156,20 @@ function createScratch(options) {
|
|
|
107
156
|
write(target, text) {
|
|
108
157
|
const candidate = resolveContained(path, target);
|
|
109
158
|
if (candidate === void 0) throw new Error(`${outside}: ${target}`);
|
|
110
|
-
|
|
111
|
-
if (rootStatus === void 0) throw new Error("Scratch directory does not exist");
|
|
112
|
-
if (rootStatus.isSymbolicLink()) throw new Error("Scratch directory is a symbolic link");
|
|
113
|
-
if (!rootStatus.isDirectory()) throw new Error("Scratch path is not a directory");
|
|
159
|
+
if (!scratch.has(".")) throw new Error("Scratch directory does not exist");
|
|
114
160
|
mkdirSync(dirname(candidate), { recursive: true });
|
|
115
161
|
writeFileSync(candidate, text);
|
|
116
162
|
},
|
|
117
163
|
read(target) {
|
|
118
164
|
const candidate = resolveContained(path, target);
|
|
119
165
|
if (candidate === void 0) throw new Error(`${outside}: ${target}`);
|
|
120
|
-
if (!scratch.
|
|
166
|
+
if (!scratch.has(target)) return void 0;
|
|
121
167
|
const status = statSync(candidate, { throwIfNoEntry: false });
|
|
122
168
|
if (status === void 0) return void 0;
|
|
123
169
|
if (status.isDirectory()) throw new Error(`Scratch path is a directory: ${target}`);
|
|
124
170
|
return readFileSync(candidate, "utf8");
|
|
125
171
|
},
|
|
126
|
-
|
|
172
|
+
has(target) {
|
|
127
173
|
const candidate = resolveContained(path, target);
|
|
128
174
|
if (candidate === void 0) throw new Error(`${outside}: ${target}`);
|
|
129
175
|
const rootStatus = lstatSync(path, { throwIfNoEntry: false });
|
|
@@ -132,9 +178,57 @@ function createScratch(options) {
|
|
|
132
178
|
if (!rootStatus.isDirectory()) throw new Error("Scratch path is not a directory");
|
|
133
179
|
return lstatSync(candidate, { throwIfNoEntry: false }) !== void 0;
|
|
134
180
|
},
|
|
181
|
+
names(target = ".") {
|
|
182
|
+
const candidate = resolveContained(path, target);
|
|
183
|
+
if (candidate === void 0) throw new Error(`${outside}: ${target}`);
|
|
184
|
+
if (!scratch.has(".")) throw new Error("Scratch directory does not exist");
|
|
185
|
+
const status = statSync(candidate, { throwIfNoEntry: false });
|
|
186
|
+
if (status === void 0) throw new Error(`Scratch path does not exist: ${target}`);
|
|
187
|
+
if (!status.isDirectory()) throw new Error(`Scratch path is not a directory: ${target}`);
|
|
188
|
+
return readdirSync(candidate).sort();
|
|
189
|
+
},
|
|
190
|
+
ensure(target) {
|
|
191
|
+
const candidate = resolveContained(path, target);
|
|
192
|
+
if (candidate === void 0) throw new Error(`${outside}: ${target}`);
|
|
193
|
+
if (!scratch.has(".")) throw new Error("Scratch directory does not exist");
|
|
194
|
+
const status = statSync(candidate, { throwIfNoEntry: false });
|
|
195
|
+
if (status !== void 0 && !status.isDirectory()) throw new Error(`Scratch path is not a directory: ${target}`);
|
|
196
|
+
if (status === void 0) mkdirSync(candidate, { recursive: true });
|
|
197
|
+
return candidate;
|
|
198
|
+
},
|
|
199
|
+
link(target, source) {
|
|
200
|
+
const candidate = resolveContained(path, target);
|
|
201
|
+
if (candidate === void 0) throw new Error(`${outside}: ${target}`);
|
|
202
|
+
if (!scratch.has(".")) throw new Error("Scratch directory does not exist");
|
|
203
|
+
mkdirSync(dirname(candidate), { recursive: true });
|
|
204
|
+
symlinkSync(source, candidate);
|
|
205
|
+
},
|
|
206
|
+
remove(target) {
|
|
207
|
+
const candidate = resolveContained(path, target);
|
|
208
|
+
if (candidate === void 0) throw new Error(`${outside}: ${target}`);
|
|
209
|
+
if (candidate === path) throw new Error(`${unremovable}: ${target}`);
|
|
210
|
+
if (!scratch.has(".")) throw new Error("Scratch directory does not exist");
|
|
211
|
+
const status = lstatSync(candidate, { throwIfNoEntry: false });
|
|
212
|
+
if (status !== void 0) {
|
|
213
|
+
if (matchesIdentity({
|
|
214
|
+
birth: status.birthtimeMs,
|
|
215
|
+
device: status.dev,
|
|
216
|
+
inode: status.ino
|
|
217
|
+
}, allocation)) throw new Error(`${unremovable}: ${target}`);
|
|
218
|
+
}
|
|
219
|
+
rmSync(candidate, {
|
|
220
|
+
force: true,
|
|
221
|
+
recursive: true
|
|
222
|
+
});
|
|
223
|
+
},
|
|
135
224
|
destroy() {
|
|
136
225
|
const status = lstatSync(path, { throwIfNoEntry: false });
|
|
137
|
-
if (status === void 0
|
|
226
|
+
if (status === void 0) return;
|
|
227
|
+
if (!matchesIdentity({
|
|
228
|
+
birth: status.birthtimeMs,
|
|
229
|
+
device: status.dev,
|
|
230
|
+
inode: status.ino
|
|
231
|
+
}, allocation)) return;
|
|
138
232
|
rmSync(path, {
|
|
139
233
|
force: true,
|
|
140
234
|
recursive: true
|
|
@@ -144,6 +238,6 @@ function createScratch(options) {
|
|
|
144
238
|
return scratch;
|
|
145
239
|
}
|
|
146
240
|
//#endregion
|
|
147
|
-
export { createScratch, readInventory, resolveContained };
|
|
241
|
+
export { createScratch, isExcluded, matchesIdentity, readInventory, resolveContained };
|
|
148
242
|
|
|
149
243
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/server/helpers.ts","../../../src/server/factories.ts"],"sourcesContent":["import type { InventoryOptions } from './types.js'\nimport { lstatSync, readdirSync, readFileSync, realpathSync } from 'node:fs'\nimport { isAbsolute, relative, resolve, sep } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\n/**\n * Resolves a target that stays below a root directory.\n *\n * @param root - The absolute root directory.\n * @param target - The relative or absolute target to resolve.\n * @returns The absolute target, or `undefined` when the target escapes the root.\n */\nexport function resolveContained(root: string, target: string): string | undefined {\n\tconst candidate = resolve(root, target)\n\tconst contained = relative(root, candidate)\n\tif (contained === '..' || contained.startsWith(`..${sep}`) || isAbsolute(contained)) {\n\t\treturn undefined\n\t}\n\treturn candidate\n}\n\n/**\n * Reads files from selected directories below a root directory.\n *\n * @param root - The root directory as a path or file URL.\n * @param directories - The directories to visit below the root.\n * @param options - Optional file extension and exact-path exclusions.\n * @returns File contents keyed by sorted root-relative paths.\n * @remarks An absent extension filter includes every file. Exclusions match full root-relative keys.\n */\nexport function readInventory(\n\troot: URL | string,\n\tdirectories: readonly string[],\n\toptions?: InventoryOptions,\n): Readonly<Record<string, string>> {\n\tconst supplied = resolve(typeof root === 'string' ? root : fileURLToPath(root))\n\tconst rootStatus = lstatSync(supplied)\n\tif (rootStatus.isSymbolicLink()) throw new Error('Root is a symbolic link')\n\tif (!rootStatus.isDirectory()) throw new Error('Root is not a directory')\n\n\tconst base = realpathSync.native(supplied)\n\tif (directories.length === 0) return Object.fromEntries([])\n\n\tconst excluded = new Set(options?.exclude)\n\tconst pending: string[] = []\n\tconst queued = new Set<string>()\n\tconst contents = new Map<string, string>()\n\n\tfor (const directory of directories) {\n\t\tconst candidate = resolveContained(base, directory)\n\t\tif (candidate === undefined) {\n\t\t\tthrow new Error(`Directory outside root: ${directory}`)\n\t\t}\n\n\t\tconst status = lstatSync(candidate)\n\t\tif (status.isSymbolicLink()) throw new Error(`Directory is a symbolic link: ${directory}`)\n\t\tif (!status.isDirectory()) throw new Error(`Not a directory: ${directory}`)\n\n\t\tconst physical = realpathSync.native(candidate)\n\t\tconst resolved = resolveContained(base, relative(base, physical))\n\t\tif (resolved === undefined) {\n\t\t\tthrow new Error(`Directory outside root: ${directory}`)\n\t\t}\n\n\t\tconst key = relative(base, resolved).split(sep).join('/')\n\t\tif (excluded.has(key) || queued.has(physical)) continue\n\t\tqueued.add(physical)\n\t\tpending.push(physical)\n\t}\n\n\twhile (pending.length > 0) {\n\t\tconst directory = pending.pop()\n\t\tif (directory === undefined) continue\n\n\t\tfor (const entry of readdirSync(directory, { withFileTypes: true })) {\n\t\t\tconst path = resolve(directory, entry.name)\n\t\t\tconst status = lstatSync(path)\n\t\t\tif (status.isSymbolicLink()) continue\n\n\t\t\tconst key = relative(base, path).split(sep).join('/')\n\t\t\tif (excluded.has(key)) continue\n\n\t\t\tif (status.isDirectory()) {\n\t\t\t\tconst physical = realpathSync.native(path)\n\t\t\t\tconst resolved = resolveContained(base, relative(base, physical))\n\t\t\t\tif (resolved === undefined || queued.has(physical)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tqueued.add(physical)\n\t\t\t\tpending.push(physical)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\t!status.isFile() ||\n\t\t\t\t(options?.extensions !== undefined &&\n\t\t\t\t\t!options.extensions.some((extension) => entry.name.endsWith(extension)))\n\t\t\t) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tcontents.set(key, readFileSync(path, 'utf8'))\n\t\t}\n\t}\n\n\treturn Object.fromEntries(\n\t\tArray.from(contents).sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0)),\n\t)\n}\n","import type { ScratchInterface, ScratchOptions } from './types.js'\nimport {\n\tlstatSync,\n\tmkdirSync,\n\tmkdtempSync,\n\treadFileSync,\n\trmSync,\n\tstatSync,\n\twriteFileSync,\n} from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { dirname, resolve } from 'node:path'\nimport { resolveContained } from './helpers.js'\n\n/**\n * Allocates an owned temporary directory with contained file operations.\n *\n * @param options - Optional directory prefix and initial files.\n * @returns The scratch directory and its file operations.\n * @remarks The prefix defaults to `orkestrel-test-`. Seed keys use root-relative paths.\n */\nexport function createScratch(options?: ScratchOptions): ScratchInterface {\n\tconst temporary = resolve(tmpdir())\n\tconst prefix = resolve(temporary, options?.prefix ?? 'orkestrel-test-')\n\tif (dirname(prefix) !== temporary)\n\t\tthrow new Error('Scratch prefix must stay within the temporary directory')\n\n\tconst path = mkdtempSync(prefix)\n\tconst allocation = statSync(path)\n\tconst outside = 'Path outside scratch directory'\n\ttry {\n\t\tfor (const [target, text] of Object.entries(options?.files ?? {})) {\n\t\t\tconst candidate = resolveContained(path, target)\n\t\t\tif (candidate === undefined) throw new Error(`${outside}: ${target}`)\n\n\t\t\tmkdirSync(dirname(candidate), { recursive: true })\n\t\t\twriteFileSync(candidate, text)\n\t\t}\n\t} catch (error) {\n\t\trmSync(path, { force: true, recursive: true })\n\t\tthrow error\n\t}\n\n\tconst scratch: ScratchInterface = {\n\t\tpath,\n\t\twrite(target, text) {\n\t\t\tconst candidate = resolveContained(path, target)\n\t\t\tif (candidate === undefined) throw new Error(`${outside}: ${target}`)\n\n\t\t\tconst rootStatus = lstatSync(path, { throwIfNoEntry: false })\n\t\t\tif (rootStatus === undefined) throw new Error('Scratch directory does not exist')\n\t\t\tif (rootStatus.isSymbolicLink()) throw new Error('Scratch directory is a symbolic link')\n\t\t\tif (!rootStatus.isDirectory()) throw new Error('Scratch path is not a directory')\n\n\t\t\tmkdirSync(dirname(candidate), { recursive: true })\n\t\t\twriteFileSync(candidate, text)\n\t\t},\n\t\tread(target) {\n\t\t\tconst candidate = resolveContained(path, target)\n\t\t\tif (candidate === undefined) throw new Error(`${outside}: ${target}`)\n\t\t\tif (!scratch.exists(target)) return undefined\n\t\t\tconst status = statSync(candidate, { throwIfNoEntry: false })\n\t\t\tif (status === undefined) return undefined\n\t\t\tif (status.isDirectory()) {\n\t\t\t\tthrow new Error(`Scratch path is a directory: ${target}`)\n\t\t\t}\n\t\t\treturn readFileSync(candidate, 'utf8')\n\t\t},\n\t\texists(target) {\n\t\t\tconst candidate = resolveContained(path, target)\n\t\t\tif (candidate === undefined) throw new Error(`${outside}: ${target}`)\n\n\t\t\tconst rootStatus = lstatSync(path, { throwIfNoEntry: false })\n\t\t\tif (rootStatus === undefined) return false\n\t\t\tif (rootStatus.isSymbolicLink()) throw new Error('Scratch directory is a symbolic link')\n\t\t\tif (!rootStatus.isDirectory()) throw new Error('Scratch path is not a directory')\n\n\t\t\treturn lstatSync(candidate, { throwIfNoEntry: false }) !== undefined\n\t\t},\n\t\tdestroy() {\n\t\t\tconst status = lstatSync(path, { throwIfNoEntry: false })\n\t\t\tif (\n\t\t\t\tstatus === undefined ||\n\t\t\t\tstatus.dev !== allocation.dev ||\n\t\t\t\tstatus.ino !== allocation.ino ||\n\t\t\t\tstatus.birthtimeMs !== allocation.birthtimeMs\n\t\t\t)\n\t\t\t\treturn\n\t\t\trmSync(path, { force: true, recursive: true })\n\t\t},\n\t}\n\treturn scratch\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/server/helpers.ts","../../../src/server/factories.ts"],"sourcesContent":["import type { InventoryOptions, ScratchIdentity } from './types.js'\nimport { lstatSync, readdirSync, readFileSync, realpathSync } from 'node:fs'\nimport { isAbsolute, relative, resolve, sep } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\n/**\n * Resolves a target that stays below a root directory.\n *\n * @param root - The absolute root directory.\n * @param target - The relative or absolute target to resolve.\n * @returns The absolute target, or `undefined` when the target escapes the root.\n */\nexport function resolveContained(root: string, target: string): string | undefined {\n\tconst candidate = resolve(root, target)\n\tconst contained = relative(root, candidate)\n\t// Cross-drive containment is unproven because POSIX `relative` never returns an absolute path;\n\t// a Windows gate would drive this branch.\n\tif (contained === '..' || contained.startsWith(`..${sep}`) || isAbsolute(contained)) {\n\t\treturn undefined\n\t}\n\treturn candidate\n}\n\n/**\n * Reports whether two directory identities name the same allocation.\n *\n * @param current - The identity read from the path now.\n * @param allocation - The identity recorded when the directory was allocated.\n * @returns Whether the device, the index node, and the creation time all match.\n * @remarks All three fields are compared because none of them alone identifies an allocation. A\n * device is shared by every directory on one filesystem, an index node is reused once its directory\n * is removed, and a creation time repeats within the host's timestamp resolution.\n */\nexport function matchesIdentity(current: ScratchIdentity, allocation: ScratchIdentity): boolean {\n\treturn (\n\t\tcurrent.device === allocation.device &&\n\t\tcurrent.inode === allocation.inode &&\n\t\tcurrent.birth === allocation.birth\n\t)\n}\n\n/**\n * Reports whether a root-relative key matches an exclusion.\n *\n * @param key - The root-relative key to test.\n * @param exclusions - The normalized root-relative exclusion keys.\n * @returns Whether an exclusion names the key or one of its ancestors.\n */\nexport function isExcluded(key: string, exclusions: readonly string[]): boolean {\n\treturn exclusions.some((rule) => rule === '' || key === rule || key.startsWith(`${rule}/`))\n}\n\n/**\n * Reads files from selected targets below a root directory.\n *\n * @param root - The root directory as a path or file URL.\n * @param targets - The files to read directly and directories to visit below the root.\n * @param options - Optional file extension and path exclusions.\n * @returns File contents keyed by sorted root-relative paths.\n * @throws When the root or a named target is a symbolic link, is not a supported entry, or resolves\n * outside the root.\n * @remarks A named file is included regardless of the extension filter. An absent extension filter\n * includes every walked file. An exclusion matches whole root-relative key segments and covers every\n * key below it, and it applies to a named target and a walked entry alike.\n */\nexport function readInventory(\n\troot: URL | string,\n\ttargets: readonly string[],\n\toptions?: InventoryOptions,\n): Readonly<Record<string, string>> {\n\tconst supplied = resolve(typeof root === 'string' ? root : fileURLToPath(root))\n\tconst rootStatus = lstatSync(supplied)\n\tif (rootStatus.isSymbolicLink()) throw new Error('Root is a symbolic link')\n\tif (!rootStatus.isDirectory()) throw new Error('Root is not a directory')\n\n\tconst base = realpathSync.native(supplied)\n\tif (targets.length === 0) return Object.fromEntries([])\n\n\tconst exclusions = (options?.exclude ?? []).map((rule) => {\n\t\tconst unprefixed = rule.startsWith('./') ? rule.slice(2) : rule\n\t\tconst collapsed = unprefixed.replace(/\\/+/g, '/')\n\t\tconst untrailed = collapsed.endsWith('/') ? collapsed.slice(0, -1) : collapsed\n\t\treturn untrailed === '.' ? '' : untrailed\n\t})\n\tconst pending: string[] = []\n\tconst queued = new Set<string>()\n\tconst contents = new Map<string, string>()\n\n\tfor (const target of targets) {\n\t\tconst candidate = resolveContained(base, target)\n\t\tif (candidate === undefined) {\n\t\t\tthrow new Error(`Target outside root: ${target}`)\n\t\t}\n\n\t\tconst status = lstatSync(candidate)\n\t\tif (status.isSymbolicLink()) throw new Error(`Target is a symbolic link: ${target}`)\n\t\tif (!status.isDirectory() && !status.isFile()) {\n\t\t\tthrow new Error(`Target is not a file or directory: ${target}`)\n\t\t}\n\n\t\tconst physical = realpathSync.native(candidate)\n\t\tconst resolved = resolveContained(base, relative(base, physical))\n\t\tif (resolved === undefined) {\n\t\t\tthrow new Error(`Target outside root: ${target}`)\n\t\t}\n\n\t\tconst key = relative(base, resolved).split(sep).join('/')\n\t\tif (isExcluded(key, exclusions)) continue\n\t\tif (status.isFile()) {\n\t\t\tcontents.set(key, readFileSync(physical, 'utf8'))\n\t\t\tcontinue\n\t\t}\n\t\tif (queued.has(physical)) continue\n\t\tqueued.add(physical)\n\t\tpending.push(physical)\n\t}\n\n\twhile (pending.length > 0) {\n\t\tconst directory = pending.pop()\n\t\tif (directory === undefined) continue\n\n\t\tfor (const entry of readdirSync(directory, { withFileTypes: true })) {\n\t\t\tconst path = resolve(directory, entry.name)\n\t\t\tconst status = lstatSync(path)\n\t\t\tif (status.isSymbolicLink()) continue\n\n\t\t\tconst key = relative(base, path).split(sep).join('/')\n\t\t\tif (isExcluded(key, exclusions)) continue\n\n\t\t\tif (status.isDirectory()) {\n\t\t\t\tconst physical = realpathSync.native(path)\n\t\t\t\tconst resolved = resolveContained(base, relative(base, physical))\n\t\t\t\t// Walk containment is unproven because POSIX CI skips links before `realpath`;\n\t\t\t\t// a host that resolves a walked directory outside `base` would drive this branch.\n\t\t\t\tif (resolved === undefined || queued.has(physical)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tqueued.add(physical)\n\t\t\t\tpending.push(physical)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\t!status.isFile() ||\n\t\t\t\t(options?.extensions !== undefined &&\n\t\t\t\t\t!options.extensions.some((extension) => entry.name.endsWith(extension)))\n\t\t\t) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tcontents.set(key, readFileSync(path, 'utf8'))\n\t\t}\n\t}\n\n\treturn Object.fromEntries(\n\t\tArray.from(contents).sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0)),\n\t)\n}\n","import type { ScratchIdentity, ScratchInterface, ScratchOptions } from './types.js'\nimport {\n\tlstatSync,\n\tmkdirSync,\n\tmkdtempSync,\n\treadFileSync,\n\treaddirSync,\n\trmSync,\n\tstatSync,\n\tsymlinkSync,\n\twriteFileSync,\n} from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { dirname, resolve, sep } from 'node:path'\nimport { matchesIdentity, resolveContained } from './helpers.js'\n\n/**\n * Allocates an owned temporary directory with contained file operations.\n *\n * @param options - Optional parent directory, name prefix, and initial files.\n * @returns The scratch directory and its file operations.\n * @throws When the parent is missing, a symbolic link, or not a directory; when the prefix contains\n * `/` or `\\`; or when allocation or seeding fails.\n * @remarks The parent defaults to the host temporary directory. The prefix defaults to\n * `orkestrel-test-`. Seed keys use root-relative paths.\n */\nexport function createScratch(options?: ScratchOptions): ScratchInterface {\n\tconst parent = resolve(options?.parent ?? tmpdir())\n\tconst parentStatus = lstatSync(parent, { throwIfNoEntry: false })\n\tif (parentStatus === undefined) throw new Error('Scratch parent does not exist')\n\tif (parentStatus.isSymbolicLink()) throw new Error('Scratch parent is a symbolic link')\n\tif (!parentStatus.isDirectory()) throw new Error('Scratch parent is not a directory')\n\n\tconst prefix = options?.prefix ?? 'orkestrel-test-'\n\tif (prefix.includes('/') || prefix.includes('\\\\')) {\n\t\tthrow new Error('Scratch prefix must be a name fragment')\n\t}\n\n\tconst path = mkdtempSync(`${parent}${sep}${prefix}`)\n\tconst allocated = statSync(path)\n\tconst allocation: ScratchIdentity = {\n\t\tbirth: allocated.birthtimeMs,\n\t\tdevice: allocated.dev,\n\t\tinode: allocated.ino,\n\t}\n\tconst outside = 'Path outside scratch directory'\n\tconst unremovable = 'Scratch directory is not a removable target'\n\ttry {\n\t\tfor (const [target, text] of Object.entries(options?.files ?? {})) {\n\t\t\tconst candidate = resolveContained(path, target)\n\t\t\tif (candidate === undefined) throw new Error(`${outside}: ${target}`)\n\n\t\t\tmkdirSync(dirname(candidate), { recursive: true })\n\t\t\twriteFileSync(candidate, text)\n\t\t}\n\t} catch (error) {\n\t\trmSync(path, { force: true, recursive: true })\n\t\tthrow error\n\t}\n\n\tconst scratch: ScratchInterface = {\n\t\tpath,\n\t\twrite(target, text) {\n\t\t\tconst candidate = resolveContained(path, target)\n\t\t\tif (candidate === undefined) throw new Error(`${outside}: ${target}`)\n\n\t\t\tif (!scratch.has('.')) throw new Error('Scratch directory does not exist')\n\n\t\t\tmkdirSync(dirname(candidate), { recursive: true })\n\t\t\twriteFileSync(candidate, text)\n\t\t},\n\t\tread(target) {\n\t\t\tconst candidate = resolveContained(path, target)\n\t\t\tif (candidate === undefined) throw new Error(`${outside}: ${target}`)\n\t\t\tif (!scratch.has(target)) return undefined\n\t\t\tconst status = statSync(candidate, { throwIfNoEntry: false })\n\t\t\tif (status === undefined) return undefined\n\t\t\tif (status.isDirectory()) {\n\t\t\t\tthrow new Error(`Scratch path is a directory: ${target}`)\n\t\t\t}\n\t\t\treturn readFileSync(candidate, 'utf8')\n\t\t},\n\t\thas(target) {\n\t\t\tconst candidate = resolveContained(path, target)\n\t\t\tif (candidate === undefined) throw new Error(`${outside}: ${target}`)\n\n\t\t\tconst rootStatus = lstatSync(path, { throwIfNoEntry: false })\n\t\t\tif (rootStatus === undefined) return false\n\t\t\tif (rootStatus.isSymbolicLink()) throw new Error('Scratch directory is a symbolic link')\n\t\t\tif (!rootStatus.isDirectory()) throw new Error('Scratch path is not a directory')\n\n\t\t\treturn lstatSync(candidate, { throwIfNoEntry: false }) !== undefined\n\t\t},\n\t\tnames(target = '.') {\n\t\t\tconst candidate = resolveContained(path, target)\n\t\t\tif (candidate === undefined) throw new Error(`${outside}: ${target}`)\n\t\t\tif (!scratch.has('.')) throw new Error('Scratch directory does not exist')\n\n\t\t\tconst status = statSync(candidate, { throwIfNoEntry: false })\n\t\t\tif (status === undefined) throw new Error(`Scratch path does not exist: ${target}`)\n\t\t\tif (!status.isDirectory()) throw new Error(`Scratch path is not a directory: ${target}`)\n\t\t\treturn readdirSync(candidate).sort()\n\t\t},\n\t\tensure(target) {\n\t\t\tconst candidate = resolveContained(path, target)\n\t\t\tif (candidate === undefined) throw new Error(`${outside}: ${target}`)\n\t\t\tif (!scratch.has('.')) throw new Error('Scratch directory does not exist')\n\n\t\t\tconst status = statSync(candidate, { throwIfNoEntry: false })\n\t\t\tif (status !== undefined && !status.isDirectory()) {\n\t\t\t\tthrow new Error(`Scratch path is not a directory: ${target}`)\n\t\t\t}\n\t\t\tif (status === undefined) mkdirSync(candidate, { recursive: true })\n\t\t\treturn candidate\n\t\t},\n\t\tlink(target, source) {\n\t\t\tconst candidate = resolveContained(path, target)\n\t\t\tif (candidate === undefined) throw new Error(`${outside}: ${target}`)\n\t\t\tif (!scratch.has('.')) throw new Error('Scratch directory does not exist')\n\n\t\t\tmkdirSync(dirname(candidate), { recursive: true })\n\t\t\tsymlinkSync(source, candidate)\n\t\t},\n\t\tremove(target) {\n\t\t\tconst candidate = resolveContained(path, target)\n\t\t\tif (candidate === undefined) throw new Error(`${outside}: ${target}`)\n\t\t\tif (candidate === path) throw new Error(`${unremovable}: ${target}`)\n\t\t\tif (!scratch.has('.')) throw new Error('Scratch directory does not exist')\n\n\t\t\tconst status = lstatSync(candidate, { throwIfNoEntry: false })\n\t\t\tif (status !== undefined) {\n\t\t\t\tconst identity: ScratchIdentity = {\n\t\t\t\t\tbirth: status.birthtimeMs,\n\t\t\t\t\tdevice: status.dev,\n\t\t\t\t\tinode: status.ino,\n\t\t\t\t}\n\t\t\t\tif (matchesIdentity(identity, allocation)) {\n\t\t\t\t\tthrow new Error(`${unremovable}: ${target}`)\n\t\t\t\t}\n\t\t\t}\n\t\t\trmSync(candidate, { force: true, recursive: true })\n\t\t},\n\t\tdestroy() {\n\t\t\tconst status = lstatSync(path, { throwIfNoEntry: false })\n\t\t\tif (status === undefined) return\n\t\t\tconst identity: ScratchIdentity = {\n\t\t\t\tbirth: status.birthtimeMs,\n\t\t\t\tdevice: status.dev,\n\t\t\t\tinode: status.ino,\n\t\t\t}\n\t\t\tif (!matchesIdentity(identity, allocation)) return\n\t\t\trmSync(path, { force: true, recursive: true })\n\t\t},\n\t}\n\treturn scratch\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orkestrel/test",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "The test helpers the Orkestrel fleet repeats — a call recorder, a real delay, JSON and async collectors, and an owned scratch directory with a source-file walker. Zero runtime dependencies. Part of the @orkestrel line.",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"homepage": "https://github.com/orkestrel/test#readme",
|