@zuplo/editor 1.0.30627199824 → 1.0.30628139828
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/adapters/memory-fs.d.ts +44 -0
- package/dist/adapters/memory-fs.d.ts.map +1 -0
- package/dist/adapters/memory-fs.js +204 -0
- package/dist/adapters/memory-fs.js.map +1 -0
- package/dist/adapters/memory-fs.spec.d.ts +2 -0
- package/dist/adapters/memory-fs.spec.d.ts.map +1 -0
- package/dist/adapters/memory-fs.spec.js +74 -0
- package/dist/adapters/memory-fs.spec.js.map +1 -0
- package/dist/adapters/memory-preferences.d.ts +10 -0
- package/dist/adapters/memory-preferences.d.ts.map +1 -0
- package/dist/adapters/memory-preferences.js +18 -0
- package/dist/adapters/memory-preferences.js.map +1 -0
- package/dist/adapters/memory.d.ts +10 -0
- package/dist/adapters/memory.d.ts.map +1 -0
- package/dist/adapters/memory.js +10 -0
- package/dist/adapters/memory.js.map +1 -0
- package/dist/adapters/node-fs.d.ts +11 -0
- package/dist/adapters/node-fs.d.ts.map +1 -0
- package/dist/adapters/node-fs.js +133 -0
- package/dist/adapters/node-fs.js.map +1 -0
- package/dist/adapters/node-preferences.d.ts +10 -0
- package/dist/adapters/node-preferences.d.ts.map +1 -0
- package/dist/adapters/node-preferences.js +38 -0
- package/dist/adapters/node-preferences.js.map +1 -0
- package/dist/app.d.ts +67 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +116 -0
- package/dist/app.js.map +1 -0
- package/dist/client/favicon-local.ico +0 -0
- package/dist/config.d.ts +16 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +5 -5
- package/dist/config.js.map +1 -1
- package/dist/fixtures/preview-project.d.ts +6 -0
- package/dist/fixtures/preview-project.d.ts.map +1 -0
- package/dist/fixtures/preview-project.js +21 -0
- package/dist/fixtures/preview-project.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/ports.d.ts +123 -0
- package/dist/ports.d.ts.map +1 -0
- package/dist/ports.js +71 -0
- package/dist/ports.js.map +1 -0
- package/dist/routes/api.d.ts +5 -0
- package/dist/routes/api.d.ts.map +1 -1
- package/dist/routes/api.js +10 -7
- package/dist/routes/api.js.map +1 -1
- package/dist/routes/api.spec.js +4 -0
- package/dist/routes/api.spec.js.map +1 -1
- package/dist/routes/editor.d.ts +10 -0
- package/dist/routes/editor.d.ts.map +1 -1
- package/dist/routes/editor.js +17 -36
- package/dist/routes/editor.js.map +1 -1
- package/dist/routes/editor.spec.js +7 -1
- package/dist/routes/editor.spec.js.map +1 -1
- package/dist/routes/fs-race-condition.spec.js +2 -1
- package/dist/routes/fs-race-condition.spec.js.map +1 -1
- package/dist/routes/fs.d.ts +2 -1
- package/dist/routes/fs.d.ts.map +1 -1
- package/dist/routes/fs.js +144 -191
- package/dist/routes/fs.js.map +1 -1
- package/dist/routes/fs.spec.js +2 -1
- package/dist/routes/fs.spec.js.map +1 -1
- package/dist/server.d.ts +7 -3
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +86 -116
- package/dist/server.js.map +1 -1
- package/dist/utils/path.d.ts +0 -13
- package/dist/utils/path.d.ts.map +1 -1
- package/dist/utils/path.js +0 -18
- package/dist/utils/path.js.map +1 -1
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +8 -5
- package/dist/validation.js.map +1 -1
- package/package.json +18 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type ChangeNotifier, type FileSystemPort } from "../ports.js";
|
|
2
|
+
export interface MemoryFileSystemOptions {
|
|
3
|
+
/**
|
|
4
|
+
* The project to start from, as project-relative path → file content. Parent
|
|
5
|
+
* directories are implied and don't need listing.
|
|
6
|
+
*/
|
|
7
|
+
files?: Record<string, string>;
|
|
8
|
+
/**
|
|
9
|
+
* Top-level directories whose changes are reported to `onChange` listeners.
|
|
10
|
+
* Defaults to the same set chokidar watches on Node, so the preview's
|
|
11
|
+
* live-reload behaviour matches the CLI's rather than being broader.
|
|
12
|
+
*/
|
|
13
|
+
watchedDirs?: readonly string[];
|
|
14
|
+
/** Injectable clock, so tests can control mtimes. */
|
|
15
|
+
now?: () => Date;
|
|
16
|
+
/**
|
|
17
|
+
* The mtime the seeded project starts with. Defaults to now.
|
|
18
|
+
*
|
|
19
|
+
* Worth setting to a constant wherever the same seed is loaded more than
|
|
20
|
+
* once — a Worker builds one of these per isolate, and if each picked its own
|
|
21
|
+
* startup time, a client that read a file from one isolate would be told its
|
|
22
|
+
* save conflicts when it landed on another. The file it read and the file it
|
|
23
|
+
* is saving over are byte-identical; only the clock disagreed.
|
|
24
|
+
*/
|
|
25
|
+
seedMtime?: Date;
|
|
26
|
+
}
|
|
27
|
+
export interface MemoryFileSystem extends FileSystemPort, ChangeNotifier {
|
|
28
|
+
/** Discards all edits and returns to the seeded project. */
|
|
29
|
+
reset(): void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A `FileSystemPort` held entirely in memory — what the per-PR preview Worker
|
|
33
|
+
* runs against, since a Worker has no filesystem.
|
|
34
|
+
*
|
|
35
|
+
* Directories are implied by the paths of the files inside them, plus any
|
|
36
|
+
* created explicitly, which is enough for a project tree and avoids maintaining
|
|
37
|
+
* a parallel directory structure that could disagree with the files.
|
|
38
|
+
*
|
|
39
|
+
* It doubles as the `ChangeNotifier`: writes report themselves, so the SPA's
|
|
40
|
+
* live-reload path stays exercised in the preview instead of going quiet with
|
|
41
|
+
* no chokidar to drive it.
|
|
42
|
+
*/
|
|
43
|
+
export declare function createMemoryFileSystem(options?: MemoryFileSystemOptions): MemoryFileSystem;
|
|
44
|
+
//# sourceMappingURL=memory-fs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-fs.d.ts","sourceRoot":"","sources":["../../src/adapters/memory-fs.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,cAAc,EAEnB,KAAK,cAAc,EAKpB,MAAM,aAAa,CAAC;AAOrB,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE/B;;;;OAIG;IACH,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAEhC,qDAAqD;IACrD,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IAEjB;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,IAAI,CAAC;CAClB;AAED,MAAM,WAAW,gBAAiB,SAAQ,cAAc,EAAE,cAAc;IACtE,4DAA4D;IAC5D,KAAK,IAAI,IAAI,CAAC;CACf;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,GAAE,uBAA4B,GACpC,gBAAgB,CAwOlB"}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { editorConfig } from "../constants.js";
|
|
2
|
+
import { PathNotFoundError, toSafeSegments, } from "../ports.js";
|
|
3
|
+
const decoder = new TextDecoder();
|
|
4
|
+
/**
|
|
5
|
+
* A `FileSystemPort` held entirely in memory — what the per-PR preview Worker
|
|
6
|
+
* runs against, since a Worker has no filesystem.
|
|
7
|
+
*
|
|
8
|
+
* Directories are implied by the paths of the files inside them, plus any
|
|
9
|
+
* created explicitly, which is enough for a project tree and avoids maintaining
|
|
10
|
+
* a parallel directory structure that could disagree with the files.
|
|
11
|
+
*
|
|
12
|
+
* It doubles as the `ChangeNotifier`: writes report themselves, so the SPA's
|
|
13
|
+
* live-reload path stays exercised in the preview instead of going quiet with
|
|
14
|
+
* no chokidar to drive it.
|
|
15
|
+
*/
|
|
16
|
+
export function createMemoryFileSystem(options = {}) {
|
|
17
|
+
const { files: seed = {}, watchedDirs = editorConfig.watch.watchedDirs, now = () => new Date(),
|
|
18
|
+
// One timestamp for the whole seed rather than one per file, so `reset()`
|
|
19
|
+
// restores the project exactly as it was first loaded.
|
|
20
|
+
seedMtime = now(), } = options;
|
|
21
|
+
const files = new Map();
|
|
22
|
+
/** Directories that exist without (yet) containing a file. */
|
|
23
|
+
const emptyDirs = new Map();
|
|
24
|
+
const listeners = new Set();
|
|
25
|
+
/** Canonicalises a path and refuses traversal, exactly as Node's adapter does. */
|
|
26
|
+
const key = (path) => toSafeSegments(path).join("/");
|
|
27
|
+
const parentOf = (path) => path.slice(0, Math.max(0, path.lastIndexOf("/")));
|
|
28
|
+
const isWatched = (path) => watchedDirs.some((dir) => path === dir || path.startsWith(`${dir}/`));
|
|
29
|
+
/**
|
|
30
|
+
* Announces a change the way chokidar does on Node — including for the
|
|
31
|
+
* editor's own saves, which also trip the real watcher.
|
|
32
|
+
*/
|
|
33
|
+
const emit = (path) => {
|
|
34
|
+
if (!isWatched(path)) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
for (const listener of listeners) {
|
|
38
|
+
listener(path);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
/** True when anything lives under `path`, which is what makes it a directory. */
|
|
42
|
+
const hasChildren = (path) => {
|
|
43
|
+
const prefix = `${path}/`;
|
|
44
|
+
for (const filePath of files.keys()) {
|
|
45
|
+
if (filePath.startsWith(prefix)) {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
for (const dirPath of emptyDirs.keys()) {
|
|
50
|
+
if (dirPath.startsWith(prefix)) {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
};
|
|
56
|
+
const isDirectory = (path) =>
|
|
57
|
+
// The root always exists, even in an empty project.
|
|
58
|
+
path === "" || emptyDirs.has(path) || hasChildren(path);
|
|
59
|
+
/**
|
|
60
|
+
* Records `path` and its ancestors as directories.
|
|
61
|
+
*
|
|
62
|
+
* They're only remembered while empty: once a file sits inside, the file's
|
|
63
|
+
* own path is what makes the directory exist, and keeping a second record
|
|
64
|
+
* would let the two disagree.
|
|
65
|
+
*/
|
|
66
|
+
const addDirs = (path, timestamp) => {
|
|
67
|
+
for (let dir = path; dir !== ""; dir = parentOf(dir)) {
|
|
68
|
+
if (!files.has(dir)) {
|
|
69
|
+
emptyDirs.set(dir, timestamp);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
const write = (path, content, at) => {
|
|
74
|
+
const mtime = at ?? now();
|
|
75
|
+
// A file and a directory can't share a path, and the file wins — the same
|
|
76
|
+
// way writing over a directory on disk fails rather than merging.
|
|
77
|
+
emptyDirs.delete(path);
|
|
78
|
+
addDirs(parentOf(path), mtime);
|
|
79
|
+
files.set(path, { content, mtime });
|
|
80
|
+
return { type: "file", mtime };
|
|
81
|
+
};
|
|
82
|
+
const load = () => {
|
|
83
|
+
files.clear();
|
|
84
|
+
emptyDirs.clear();
|
|
85
|
+
for (const [path, content] of Object.entries(seed)) {
|
|
86
|
+
write(key(path), content, seedMtime);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
load();
|
|
90
|
+
return {
|
|
91
|
+
onChange(listener) {
|
|
92
|
+
listeners.add(listener);
|
|
93
|
+
return () => listeners.delete(listener);
|
|
94
|
+
},
|
|
95
|
+
reset() {
|
|
96
|
+
load();
|
|
97
|
+
},
|
|
98
|
+
// Every method below is `async` even though nothing here awaits: it makes a
|
|
99
|
+
// rejected promise the only way these fail, matching the Node adapter. A
|
|
100
|
+
// sync throw from `key()` on a traversal attempt would otherwise escape
|
|
101
|
+
// before the promise existed, and callers would have to guard both ways.
|
|
102
|
+
async readFileWithStat(path) {
|
|
103
|
+
const file = files.get(key(path));
|
|
104
|
+
if (!file) {
|
|
105
|
+
throw new PathNotFoundError(path);
|
|
106
|
+
}
|
|
107
|
+
// Content and mtime come from one immutable record, so they always
|
|
108
|
+
// describe the same version — the property the Node adapter needs an open
|
|
109
|
+
// file handle to get.
|
|
110
|
+
return {
|
|
111
|
+
content: typeof file.content === "string"
|
|
112
|
+
? file.content
|
|
113
|
+
: decoder.decode(file.content),
|
|
114
|
+
mtime: file.mtime,
|
|
115
|
+
};
|
|
116
|
+
},
|
|
117
|
+
async listDir(path) {
|
|
118
|
+
const dir = key(path);
|
|
119
|
+
if (!isDirectory(dir)) {
|
|
120
|
+
throw new PathNotFoundError(path);
|
|
121
|
+
}
|
|
122
|
+
const prefix = dir === "" ? "" : `${dir}/`;
|
|
123
|
+
const entries = new Map();
|
|
124
|
+
const collect = (fullPath, type) => {
|
|
125
|
+
if (!fullPath.startsWith(prefix)) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const rest = fullPath.slice(prefix.length);
|
|
129
|
+
if (rest === "") {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const slash = rest.indexOf("/");
|
|
133
|
+
// A path continuing past the first segment describes a grandchild, so
|
|
134
|
+
// the segment itself is a directory rather than the entry.
|
|
135
|
+
const name = slash === -1 ? rest : rest.slice(0, slash);
|
|
136
|
+
entries.set(name, {
|
|
137
|
+
name,
|
|
138
|
+
type: slash === -1 ? type : "directory",
|
|
139
|
+
});
|
|
140
|
+
};
|
|
141
|
+
for (const filePath of files.keys()) {
|
|
142
|
+
collect(filePath, "file");
|
|
143
|
+
}
|
|
144
|
+
for (const dirPath of emptyDirs.keys()) {
|
|
145
|
+
collect(dirPath, "directory");
|
|
146
|
+
}
|
|
147
|
+
return [...entries.values()];
|
|
148
|
+
},
|
|
149
|
+
async statPath(path) {
|
|
150
|
+
const target = key(path);
|
|
151
|
+
const file = files.get(target);
|
|
152
|
+
if (file) {
|
|
153
|
+
return { type: "file", mtime: file.mtime };
|
|
154
|
+
}
|
|
155
|
+
if (isDirectory(target)) {
|
|
156
|
+
return {
|
|
157
|
+
type: "directory",
|
|
158
|
+
mtime: emptyDirs.get(target) ?? now(),
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return undefined;
|
|
162
|
+
},
|
|
163
|
+
async writeFile(path, content) {
|
|
164
|
+
const target = key(path);
|
|
165
|
+
const stat = write(target, content);
|
|
166
|
+
emit(target);
|
|
167
|
+
return stat;
|
|
168
|
+
},
|
|
169
|
+
async remove(path) {
|
|
170
|
+
const target = key(path);
|
|
171
|
+
if (!files.delete(target)) {
|
|
172
|
+
throw new PathNotFoundError(path);
|
|
173
|
+
}
|
|
174
|
+
// The parent may have just become empty, and an empty directory still
|
|
175
|
+
// exists on disk after its last file is deleted.
|
|
176
|
+
addDirs(parentOf(target), now());
|
|
177
|
+
emit(target);
|
|
178
|
+
},
|
|
179
|
+
async rename(from, to) {
|
|
180
|
+
const fromKey = key(from);
|
|
181
|
+
const toKey = key(to);
|
|
182
|
+
const file = files.get(fromKey);
|
|
183
|
+
if (!file) {
|
|
184
|
+
throw new PathNotFoundError(from);
|
|
185
|
+
}
|
|
186
|
+
files.delete(fromKey);
|
|
187
|
+
addDirs(parentOf(fromKey), now());
|
|
188
|
+
// Carries its mtime across, as a rename on disk does — the content didn't
|
|
189
|
+
// change, so a client holding a `Last-Modified` for it stays valid.
|
|
190
|
+
emptyDirs.delete(toKey);
|
|
191
|
+
addDirs(parentOf(toKey), file.mtime);
|
|
192
|
+
files.set(toKey, file);
|
|
193
|
+
emit(fromKey);
|
|
194
|
+
emit(toKey);
|
|
195
|
+
},
|
|
196
|
+
async mkdirp(path) {
|
|
197
|
+
const target = key(path);
|
|
198
|
+
if (target !== "") {
|
|
199
|
+
addDirs(target, now());
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=memory-fs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-fs.js","sourceRoot":"","sources":["../../src/adapters/memory-fs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-fs.spec.d.ts","sourceRoot":"","sources":["../../src/adapters/memory-fs.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { describe, it } from "node:test";
|
|
3
|
+
import { createMemoryFileSystem } from "./memory-fs.js";
|
|
4
|
+
const seed = {
|
|
5
|
+
"config/routes.oas.json": '{"openapi":"3.1.0"}',
|
|
6
|
+
"docs/introduction.md": "# Hello\n",
|
|
7
|
+
};
|
|
8
|
+
describe("createMemoryFileSystem", () => {
|
|
9
|
+
describe("seedMtime", () => {
|
|
10
|
+
// Two filesystems built from one seed stand in for two Worker isolates.
|
|
11
|
+
// Each builds its own copy of the project, and a client that reads a file
|
|
12
|
+
// from one may well save it back through the other — so if they disagree
|
|
13
|
+
// on the untouched file's mtime, that save is rejected as a conflict with
|
|
14
|
+
// bytes it matches exactly. Not hypothetical: it shipped, and every save
|
|
15
|
+
// in the preview deployment failed with 412.
|
|
16
|
+
it("gives the same mtime to every instance built from one seed", async () => {
|
|
17
|
+
const seedMtime = new Date("2026-01-02T03:04:05Z");
|
|
18
|
+
const first = createMemoryFileSystem({ files: seed, seedMtime });
|
|
19
|
+
const second = createMemoryFileSystem({ files: seed, seedMtime });
|
|
20
|
+
const fromFirst = await first.readFileWithStat("config/routes.oas.json");
|
|
21
|
+
const fromSecond = await second.readFileWithStat("config/routes.oas.json");
|
|
22
|
+
assert.strictEqual(fromFirst.mtime.getTime(), fromSecond.mtime.getTime(), "instances disagreed on the seeded mtime");
|
|
23
|
+
assert.strictEqual(fromFirst.mtime.getTime(), seedMtime.getTime());
|
|
24
|
+
});
|
|
25
|
+
it("gives every seeded file the same mtime", async () => {
|
|
26
|
+
const seedMtime = new Date("2026-01-02T03:04:05Z");
|
|
27
|
+
const fs = createMemoryFileSystem({ files: seed, seedMtime });
|
|
28
|
+
const routes = await fs.readFileWithStat("config/routes.oas.json");
|
|
29
|
+
const docs = await fs.readFileWithStat("docs/introduction.md");
|
|
30
|
+
assert.strictEqual(routes.mtime.getTime(), docs.mtime.getTime());
|
|
31
|
+
});
|
|
32
|
+
it("still stamps later writes with the clock, not the seed", async () => {
|
|
33
|
+
const seedMtime = new Date("2026-01-02T03:04:05Z");
|
|
34
|
+
const writeTime = new Date("2026-06-07T08:09:10Z");
|
|
35
|
+
const fs = createMemoryFileSystem({
|
|
36
|
+
files: seed,
|
|
37
|
+
seedMtime,
|
|
38
|
+
now: () => writeTime,
|
|
39
|
+
});
|
|
40
|
+
await fs.writeFile("docs/introduction.md", "# Edited\n");
|
|
41
|
+
const edited = await fs.readFileWithStat("docs/introduction.md");
|
|
42
|
+
assert.strictEqual(edited.mtime.getTime(), writeTime.getTime());
|
|
43
|
+
});
|
|
44
|
+
it("restores the seeded mtime on reset", async () => {
|
|
45
|
+
const seedMtime = new Date("2026-01-02T03:04:05Z");
|
|
46
|
+
const fs = createMemoryFileSystem({
|
|
47
|
+
files: seed,
|
|
48
|
+
seedMtime,
|
|
49
|
+
now: () => new Date("2026-06-07T08:09:10Z"),
|
|
50
|
+
});
|
|
51
|
+
await fs.writeFile("docs/introduction.md", "# Edited\n");
|
|
52
|
+
fs.reset();
|
|
53
|
+
const restored = await fs.readFileWithStat("docs/introduction.md");
|
|
54
|
+
assert.strictEqual(restored.content, seed["docs/introduction.md"]);
|
|
55
|
+
assert.strictEqual(restored.mtime.getTime(), seedMtime.getTime());
|
|
56
|
+
});
|
|
57
|
+
it("defaults to a single timestamp when none is given", async () => {
|
|
58
|
+
const fs = createMemoryFileSystem({ files: seed });
|
|
59
|
+
const routes = await fs.readFileWithStat("config/routes.oas.json");
|
|
60
|
+
const docs = await fs.readFileWithStat("docs/introduction.md");
|
|
61
|
+
assert.strictEqual(routes.mtime.getTime(), docs.mtime.getTime());
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
describe("listDir", () => {
|
|
65
|
+
// The root listing names each top-level entry once, rather than repeating
|
|
66
|
+
// paths of the files underneath it.
|
|
67
|
+
it("returns immediate children only", async () => {
|
|
68
|
+
const fs = createMemoryFileSystem({ files: seed });
|
|
69
|
+
const entries = await fs.listDir("/");
|
|
70
|
+
assert.deepStrictEqual(entries.map((entry) => `${entry.type}:${entry.name}`).sort(), ["directory:config", "directory:docs"]);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
//# sourceMappingURL=memory-fs.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-fs.spec.js","sourceRoot":"","sources":["../../src/adapters/memory-fs.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { EditorPreferencesPort } from "../ports.js";
|
|
2
|
+
/**
|
|
3
|
+
* Keeps the user's external-editor choice in memory for the life of the process.
|
|
4
|
+
*
|
|
5
|
+
* Used by the preview Worker, which has no home directory to persist to. The
|
|
6
|
+
* preference dialog and toolbar behave correctly within a session; the choice is
|
|
7
|
+
* simply forgotten when the isolate recycles.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createMemoryEditorPreferences(): EditorPreferencesPort;
|
|
10
|
+
//# sourceMappingURL=memory-preferences.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-preferences.d.ts","sourceRoot":"","sources":["../../src/adapters/memory-preferences.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEzD;;;;;;GAMG;AACH,wBAAgB,6BAA6B,IAAI,qBAAqB,CAUrE"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keeps the user's external-editor choice in memory for the life of the process.
|
|
3
|
+
*
|
|
4
|
+
* Used by the preview Worker, which has no home directory to persist to. The
|
|
5
|
+
* preference dialog and toolbar behave correctly within a session; the choice is
|
|
6
|
+
* simply forgotten when the isolate recycles.
|
|
7
|
+
*/
|
|
8
|
+
export function createMemoryEditorPreferences() {
|
|
9
|
+
let editor = null;
|
|
10
|
+
return {
|
|
11
|
+
get: () => Promise.resolve(editor),
|
|
12
|
+
set: (value) => {
|
|
13
|
+
editor = value;
|
|
14
|
+
return Promise.resolve();
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=memory-preferences.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-preferences.js","sourceRoot":"","sources":["../../src/adapters/memory-preferences.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,UAAU,6BAA6B,GAA0B;IACrE,IAAI,MAAM,GAAkB,IAAI,CAAC;IAEjC,OAAO;QACL,GAAG,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC;QAClC,GAAG,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC;YACtB,MAAM,GAAG,KAAK,CAAC;YACf,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAAA,CAC1B;KACF,CAAC;AAAA,CACH"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The platform-free adapters, collected so a consumer that must avoid `node:*`
|
|
3
|
+
* has a single import that is guaranteed not to reach it.
|
|
4
|
+
*
|
|
5
|
+
* The preview Worker imports from here rather than from the package root, which
|
|
6
|
+
* pulls in `LocalEditorServer` and with it `@hono/node-server` and chokidar.
|
|
7
|
+
*/
|
|
8
|
+
export { createMemoryFileSystem, type MemoryFileSystem, type MemoryFileSystemOptions, } from "./memory-fs.js";
|
|
9
|
+
export { createMemoryEditorPreferences } from "./memory-preferences.js";
|
|
10
|
+
//# sourceMappingURL=memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/adapters/memory.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,GAC7B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The platform-free adapters, collected so a consumer that must avoid `node:*`
|
|
3
|
+
* has a single import that is guaranteed not to reach it.
|
|
4
|
+
*
|
|
5
|
+
* The preview Worker imports from here rather than from the package root, which
|
|
6
|
+
* pulls in `LocalEditorServer` and with it `@hono/node-server` and chokidar.
|
|
7
|
+
*/
|
|
8
|
+
export { createMemoryFileSystem, } from "./memory-fs.js";
|
|
9
|
+
export { createMemoryEditorPreferences } from "./memory-preferences.js";
|
|
10
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/adapters/memory.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,sBAAsB,GAGvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type FileSystemPort } from "../ports.js";
|
|
2
|
+
/**
|
|
3
|
+
* A `FileSystemPort` over a real directory on disk — what the Zuplo CLI runs
|
|
4
|
+
* against.
|
|
5
|
+
*
|
|
6
|
+
* All the `node:fs` specifics the routes used to carry live here: joining onto
|
|
7
|
+
* the project root, the open-file-handle dance behind `readFileWithStat`, and
|
|
8
|
+
* translating `ENOENT` into `PathNotFoundError`.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createNodeFileSystem(sourceDirectory: string): FileSystemPort;
|
|
11
|
+
//# sourceMappingURL=node-fs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-fs.d.ts","sourceRoot":"","sources":["../../src/adapters/node-fs.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,cAAc,EAKpB,MAAM,aAAa,CAAC;AAMrB;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,eAAe,EAAE,MAAM,GAAG,cAAc,CAkI5E"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { PathNotFoundError, toSafeSegments, } from "../ports.js";
|
|
4
|
+
function isNotFound(err) {
|
|
5
|
+
return err.code === "ENOENT";
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* A `FileSystemPort` over a real directory on disk — what the Zuplo CLI runs
|
|
9
|
+
* against.
|
|
10
|
+
*
|
|
11
|
+
* All the `node:fs` specifics the routes used to carry live here: joining onto
|
|
12
|
+
* the project root, the open-file-handle dance behind `readFileWithStat`, and
|
|
13
|
+
* translating `ENOENT` into `PathNotFoundError`.
|
|
14
|
+
*/
|
|
15
|
+
export function createNodeFileSystem(sourceDirectory) {
|
|
16
|
+
/**
|
|
17
|
+
* Resolves a project-relative path to an absolute one.
|
|
18
|
+
*
|
|
19
|
+
* `toSafeSegments` has already refused anything containing `..`, so joining
|
|
20
|
+
* the segments can't escape `sourceDirectory` — the segments are rebuilt from
|
|
21
|
+
* the validated list rather than from the caller's string so that guarantee
|
|
22
|
+
* can't be sidestepped by a separator the split didn't expect.
|
|
23
|
+
*/
|
|
24
|
+
const resolve = (relativePath) => path.join(sourceDirectory, ...toSafeSegments(relativePath));
|
|
25
|
+
return {
|
|
26
|
+
async readFileWithStat(relativePath) {
|
|
27
|
+
const fullPath = resolve(relativePath);
|
|
28
|
+
let handle;
|
|
29
|
+
try {
|
|
30
|
+
handle = await fs.open(fullPath, "r");
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
if (isNotFound(err)) {
|
|
34
|
+
throw new PathNotFoundError(relativePath);
|
|
35
|
+
}
|
|
36
|
+
throw err;
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
// Both reads come from the same open handle, so the mtime returned
|
|
40
|
+
// can't describe a different version of the file than the content it
|
|
41
|
+
// accompanies. See `FileSystemPort.readFileWithStat`.
|
|
42
|
+
const stats = await handle.stat();
|
|
43
|
+
const content = await handle.readFile("utf-8");
|
|
44
|
+
return { content, mtime: stats.mtime };
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
await handle.close();
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
async listDir(relativePath) {
|
|
51
|
+
const fullPath = resolve(relativePath);
|
|
52
|
+
let entries;
|
|
53
|
+
try {
|
|
54
|
+
entries = await fs.readdir(fullPath, { withFileTypes: true });
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
if (isNotFound(err)) {
|
|
58
|
+
throw new PathNotFoundError(relativePath);
|
|
59
|
+
}
|
|
60
|
+
throw err;
|
|
61
|
+
}
|
|
62
|
+
// Anything that is neither a file nor a directory (sockets, devices, a
|
|
63
|
+
// symlink to nowhere) is dropped rather than guessed at — the editor has
|
|
64
|
+
// no way to display it.
|
|
65
|
+
return entries.flatMap((entry) => {
|
|
66
|
+
if (entry.isDirectory()) {
|
|
67
|
+
return [{ name: entry.name, type: "directory" }];
|
|
68
|
+
}
|
|
69
|
+
if (entry.isFile()) {
|
|
70
|
+
return [{ name: entry.name, type: "file" }];
|
|
71
|
+
}
|
|
72
|
+
return [];
|
|
73
|
+
});
|
|
74
|
+
},
|
|
75
|
+
async statPath(relativePath) {
|
|
76
|
+
try {
|
|
77
|
+
const stats = await fs.stat(resolve(relativePath));
|
|
78
|
+
if (stats.isDirectory()) {
|
|
79
|
+
return { type: "directory", mtime: stats.mtime };
|
|
80
|
+
}
|
|
81
|
+
if (stats.isFile()) {
|
|
82
|
+
return { type: "file", mtime: stats.mtime };
|
|
83
|
+
}
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
if (isNotFound(err)) {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
throw err;
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
async writeFile(relativePath, content) {
|
|
94
|
+
const fullPath = resolve(relativePath);
|
|
95
|
+
await fs.mkdir(path.dirname(fullPath), { recursive: true });
|
|
96
|
+
await fs.writeFile(fullPath, content);
|
|
97
|
+
const stats = await fs.stat(fullPath);
|
|
98
|
+
return { type: "file", mtime: stats.mtime };
|
|
99
|
+
},
|
|
100
|
+
async rename(from, to) {
|
|
101
|
+
const fromPath = resolve(from);
|
|
102
|
+
const toPath = resolve(to);
|
|
103
|
+
// Renaming into a directory that doesn't exist yet is how the portal
|
|
104
|
+
// moves a file into a new folder, so create the destination's parents
|
|
105
|
+
// rather than failing.
|
|
106
|
+
await fs.mkdir(path.dirname(toPath), { recursive: true });
|
|
107
|
+
try {
|
|
108
|
+
await fs.rename(fromPath, toPath);
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
if (isNotFound(err)) {
|
|
112
|
+
throw new PathNotFoundError(from);
|
|
113
|
+
}
|
|
114
|
+
throw err;
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
async remove(relativePath) {
|
|
118
|
+
try {
|
|
119
|
+
await fs.unlink(resolve(relativePath));
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
if (isNotFound(err)) {
|
|
123
|
+
throw new PathNotFoundError(relativePath);
|
|
124
|
+
}
|
|
125
|
+
throw err;
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
async mkdirp(relativePath) {
|
|
129
|
+
await fs.mkdir(resolve(relativePath), { recursive: true });
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=node-fs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-fs.js","sourceRoot":"","sources":["../../src/adapters/node-fs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { EditorPreferencesPort } from "../ports.js";
|
|
2
|
+
/**
|
|
3
|
+
* Stores the user's external-editor choice in `~/.config/zuplo/editor.json`, so
|
|
4
|
+
* it survives across CLI runs.
|
|
5
|
+
*
|
|
6
|
+
* This is deliberately outside the project directory and therefore outside
|
|
7
|
+
* `FileSystemPort` — it's a per-user setting, not part of the API being edited.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createNodeEditorPreferences(): EditorPreferencesPort;
|
|
10
|
+
//# sourceMappingURL=node-preferences.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-preferences.d.ts","sourceRoot":"","sources":["../../src/adapters/node-preferences.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAYzD;;;;;;GAMG;AACH,wBAAgB,2BAA2B,IAAI,qBAAqB,CAuBnE"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
function getZuploConfigDir() {
|
|
5
|
+
const xdgConfigHome = process.env.XDG_CONFIG_HOME ?? path.join(homedir(), ".config");
|
|
6
|
+
return path.join(xdgConfigHome, "zuplo");
|
|
7
|
+
}
|
|
8
|
+
function getEditorConfigPath() {
|
|
9
|
+
return path.join(getZuploConfigDir(), "editor.json");
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Stores the user's external-editor choice in `~/.config/zuplo/editor.json`, so
|
|
13
|
+
* it survives across CLI runs.
|
|
14
|
+
*
|
|
15
|
+
* This is deliberately outside the project directory and therefore outside
|
|
16
|
+
* `FileSystemPort` — it's a per-user setting, not part of the API being edited.
|
|
17
|
+
*/
|
|
18
|
+
export function createNodeEditorPreferences() {
|
|
19
|
+
return {
|
|
20
|
+
async get() {
|
|
21
|
+
try {
|
|
22
|
+
const data = await fs.readFile(getEditorConfigPath(), "utf-8");
|
|
23
|
+
return JSON.parse(data).editor ?? null;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// No file yet, or something unparseable in it — either way the user has
|
|
27
|
+
// no usable preference, and failing the request would block the editor
|
|
28
|
+
// from loading over a cosmetic setting.
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
async set(editor) {
|
|
33
|
+
await fs.mkdir(getZuploConfigDir(), { recursive: true });
|
|
34
|
+
await fs.writeFile(getEditorConfigPath(), JSON.stringify({ editor }, null, 2), "utf-8");
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=node-preferences.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-preferences.js","sourceRoot":"","sources":["../../src/adapters/node-preferences.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,SAAS,iBAAiB,GAAW;IACnC,MAAM,aAAa,GACjB,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;IACjE,OAAO,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;AAAA,CAC1C;AAED,SAAS,mBAAmB,GAAW;IACrC,OAAO,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,aAAa,CAAC,CAAC;AAAA,CACtD;AAED;;;;;;GAMG;AACH,MAAM,UAAU,2BAA2B,GAA0B;IACnE,OAAO;QACL,KAAK,CAAC,GAAG,GAA2B;YAClC,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,mBAAmB,EAAE,EAAE,OAAO,CAAC,CAAC;gBAC/D,OAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAA6B,IAAI,IAAI,CAAC;YACjE,CAAC;YAAC,MAAM,CAAC;gBACP,0EAAwE;gBACxE,uEAAuE;gBACvE,wCAAwC;gBACxC,OAAO,IAAI,CAAC;YACd,CAAC;QAAA,CACF;QAED,KAAK,CAAC,GAAG,CAAC,MAAc,EAAiB;YACvC,MAAM,EAAE,CAAC,KAAK,CAAC,iBAAiB,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACzD,MAAM,EAAE,CAAC,SAAS,CAChB,mBAAmB,EAAE,EACrB,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EACnC,OAAO,CACR,CAAC;QAAA,CACH;KACF,CAAC;AAAA,CACH"}
|