@interactive-inc/docs-client 1.0.20 → 1.1.1
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/build/doc-file-system-DEmPPJPE.d.ts +205 -0
- package/build/doc-file-system.interface-C5vpYrOL.d.ts +135 -0
- package/build/file-system-json.d.ts +224 -0
- package/build/file-system-json.js +765 -0
- package/build/file-system-mock.d.ts +112 -0
- package/build/file-system-mock.js +513 -0
- package/build/file-system-node.d.ts +16 -0
- package/build/file-system-node.js +544 -0
- package/build/file-system-octokit.d.ts +166 -0
- package/build/file-system-octokit.js +715 -0
- package/build/file-system.d.ts +119 -0
- package/build/file-system.js +523 -0
- package/build/index.d.ts +1236 -2121
- package/build/index.js +3390 -5329
- package/build/models.js +4 -75
- package/package.json +7 -2
- package/tmp/docs-studio/files/a.md +9 -0
- package/tmp/docs-studio/pages/delete-document.md +7 -0
- package/tmp/docs-studio/pages/document-editor.md +9 -0
- package/tmp/docs-studio/pages/edit-document-content.md +7 -0
- package/tmp/docs-studio/pages/index.md +14 -0
|
@@ -0,0 +1,765 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
// lib/modules/file-system/doc-file-system-json.ts
|
|
4
|
+
|
|
5
|
+
// lib/modules/path-system/doc-path-system.ts
|
|
6
|
+
var DocPathSystem = class {
|
|
7
|
+
separator = "/";
|
|
8
|
+
/**
|
|
9
|
+
* Join paths
|
|
10
|
+
*/
|
|
11
|
+
join(...paths) {
|
|
12
|
+
const parts = [];
|
|
13
|
+
for (const path of paths) {
|
|
14
|
+
if (path === "") continue;
|
|
15
|
+
const segments = path.split(this.separator).filter(Boolean);
|
|
16
|
+
parts.push(...segments);
|
|
17
|
+
}
|
|
18
|
+
if (parts.length === 0) {
|
|
19
|
+
return ".";
|
|
20
|
+
}
|
|
21
|
+
const isAbsolute = paths[0]?.startsWith(this.separator);
|
|
22
|
+
const joined = parts.join(this.separator);
|
|
23
|
+
return isAbsolute ? `${this.separator}${joined}` : joined;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Get filename with extension
|
|
27
|
+
*/
|
|
28
|
+
basename(path, ext) {
|
|
29
|
+
const segments = path.split(this.separator);
|
|
30
|
+
const filename = segments[segments.length - 1] || "";
|
|
31
|
+
if (ext && filename.endsWith(ext)) {
|
|
32
|
+
return filename.slice(0, -ext.length);
|
|
33
|
+
}
|
|
34
|
+
return filename;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get directory name
|
|
38
|
+
*/
|
|
39
|
+
dirname(path) {
|
|
40
|
+
const segments = path.split(this.separator);
|
|
41
|
+
if (segments.length <= 1) {
|
|
42
|
+
return ".";
|
|
43
|
+
}
|
|
44
|
+
segments.pop();
|
|
45
|
+
const dir = segments.join(this.separator);
|
|
46
|
+
return dir || ".";
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get extension
|
|
50
|
+
*/
|
|
51
|
+
extname(path) {
|
|
52
|
+
const basename = this.basename(path);
|
|
53
|
+
const lastDot = basename.lastIndexOf(".");
|
|
54
|
+
if (lastDot <= 0) {
|
|
55
|
+
return "";
|
|
56
|
+
}
|
|
57
|
+
return basename.slice(lastDot);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Calculate relative path
|
|
61
|
+
*/
|
|
62
|
+
relative(from, to) {
|
|
63
|
+
const fromSegments = from.split(this.separator).filter(Boolean);
|
|
64
|
+
const toSegments = to.split(this.separator).filter(Boolean);
|
|
65
|
+
let commonLength = 0;
|
|
66
|
+
for (let i = 0; i < Math.min(fromSegments.length, toSegments.length); i++) {
|
|
67
|
+
if (fromSegments[i] === toSegments[i]) {
|
|
68
|
+
commonLength++;
|
|
69
|
+
} else {
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const upCount = fromSegments.length - commonLength;
|
|
74
|
+
const upSegments = Array(upCount).fill("..");
|
|
75
|
+
const downSegments = toSegments.slice(commonLength);
|
|
76
|
+
const segments = [...upSegments, ...downSegments];
|
|
77
|
+
return segments.length > 0 ? segments.join(this.separator) : ".";
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Convert to absolute path
|
|
81
|
+
*/
|
|
82
|
+
resolve(...paths) {
|
|
83
|
+
let resolved = "";
|
|
84
|
+
for (const path of paths) {
|
|
85
|
+
if (path.startsWith(this.separator)) {
|
|
86
|
+
resolved = path;
|
|
87
|
+
} else if (path !== "") {
|
|
88
|
+
resolved = resolved ? this.join(resolved, path) : path;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return resolved || ".";
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Normalize path
|
|
95
|
+
*/
|
|
96
|
+
normalize(path) {
|
|
97
|
+
const isAbsolute = path.startsWith(this.separator);
|
|
98
|
+
const segments = path.split(this.separator).filter(Boolean);
|
|
99
|
+
const normalized = [];
|
|
100
|
+
for (const segment of segments) {
|
|
101
|
+
if (segment === "..") {
|
|
102
|
+
if (normalized.length > 0 && normalized[normalized.length - 1] !== "..") {
|
|
103
|
+
normalized.pop();
|
|
104
|
+
} else if (!isAbsolute) {
|
|
105
|
+
normalized.push("..");
|
|
106
|
+
}
|
|
107
|
+
} else if (segment !== ".") {
|
|
108
|
+
normalized.push(segment);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (normalized.length === 0) {
|
|
112
|
+
return isAbsolute ? this.separator : ".";
|
|
113
|
+
}
|
|
114
|
+
const result = normalized.join(this.separator);
|
|
115
|
+
return isAbsolute ? `${this.separator}${result}` : result;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Check if path is absolute
|
|
119
|
+
*/
|
|
120
|
+
isAbsolute(path) {
|
|
121
|
+
return path.startsWith(this.separator);
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// lib/modules/file-system/doc-file-system.ts
|
|
126
|
+
var DocFileSystem = class {
|
|
127
|
+
reader;
|
|
128
|
+
writer;
|
|
129
|
+
basePath;
|
|
130
|
+
pathSystem;
|
|
131
|
+
constructor(props) {
|
|
132
|
+
this.basePath = props.basePath;
|
|
133
|
+
this.pathSystem = props.pathSystem ?? new DocPathSystem();
|
|
134
|
+
this.reader = props.reader;
|
|
135
|
+
this.writer = props.writer;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Read file content at the specified path
|
|
139
|
+
*/
|
|
140
|
+
async readFile(relativePath) {
|
|
141
|
+
return this.reader.readFile(relativePath);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Write content to file at the specified path (creates directory if needed)
|
|
145
|
+
*/
|
|
146
|
+
async writeFile(relativePath, content) {
|
|
147
|
+
return this.writer.writeFile(relativePath, content);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Delete file at the specified path
|
|
151
|
+
*/
|
|
152
|
+
async deleteFile(relativePath) {
|
|
153
|
+
return this.writer.deleteFile(relativePath);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Get file name from path
|
|
157
|
+
*/
|
|
158
|
+
readFileName(relativePath) {
|
|
159
|
+
return this.reader.readFileName(relativePath);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Get file extension from path
|
|
163
|
+
*/
|
|
164
|
+
readFileExtension(relativePath) {
|
|
165
|
+
return this.reader.readFileExtension(relativePath);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Get directory path where the file exists
|
|
169
|
+
*/
|
|
170
|
+
readFileDirectory(relativePath) {
|
|
171
|
+
return this.reader.readFileDirectory(relativePath);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Get list of entries in directory
|
|
175
|
+
*/
|
|
176
|
+
async readDirectoryFileNames(relativePath = "") {
|
|
177
|
+
return this.reader.readDirectoryFileNames(relativePath);
|
|
178
|
+
}
|
|
179
|
+
async readDirectoryFilePaths(relativePath) {
|
|
180
|
+
return this.reader.readDirectoryFilePaths(relativePath);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Check if path is a directory
|
|
184
|
+
*/
|
|
185
|
+
async isDirectory(relativePath) {
|
|
186
|
+
return this.reader.isDirectory(relativePath);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Check if path is a file
|
|
190
|
+
*/
|
|
191
|
+
async isFile(relativePath) {
|
|
192
|
+
return this.reader.isFile(relativePath);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Check if file or directory exists
|
|
196
|
+
*/
|
|
197
|
+
async exists(relativePath) {
|
|
198
|
+
return this.reader.exists(relativePath);
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Check if directory exists
|
|
202
|
+
*/
|
|
203
|
+
async directoryExists(relativePath) {
|
|
204
|
+
return this.reader.directoryExists(relativePath);
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Check if file exists
|
|
208
|
+
*/
|
|
209
|
+
async fileExists(relativePath) {
|
|
210
|
+
return this.reader.fileExists(relativePath);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Get base path
|
|
214
|
+
*/
|
|
215
|
+
getBasePath() {
|
|
216
|
+
return this.reader.getBasePath();
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Convert relative path to absolute path
|
|
220
|
+
*/
|
|
221
|
+
resolve(relativePath) {
|
|
222
|
+
return this.reader.resolve(relativePath);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Create directory
|
|
226
|
+
*/
|
|
227
|
+
async createEmptyDirectory(relativePath) {
|
|
228
|
+
return this.writer.createEmptyDirectory(relativePath);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Get file size in bytes
|
|
232
|
+
*/
|
|
233
|
+
async getFileSize(relativePath) {
|
|
234
|
+
return this.reader.getFileSize(relativePath);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Create directory if it doesn't exist
|
|
238
|
+
*/
|
|
239
|
+
async createDirectory(relativePath) {
|
|
240
|
+
return this.writer.createDirectory(relativePath);
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Copy file
|
|
244
|
+
*/
|
|
245
|
+
async copyFile(sourcePath, destinationPath) {
|
|
246
|
+
return this.writer.copyFile(sourcePath, destinationPath);
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Move file
|
|
250
|
+
*/
|
|
251
|
+
async moveFile(sourcePath, destinationPath) {
|
|
252
|
+
return this.writer.moveFile(sourcePath, destinationPath);
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Get file last modified time
|
|
256
|
+
*/
|
|
257
|
+
async getFileUpdatedTime(relativePath) {
|
|
258
|
+
return this.reader.getFileUpdatedTime(relativePath);
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Get file creation time
|
|
262
|
+
*/
|
|
263
|
+
async getFileCreatedTime(relativePath) {
|
|
264
|
+
return this.reader.getFileCreatedTime(relativePath);
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
var zJsonDocumentData = z.record(z.string(), z.string());
|
|
268
|
+
function parseJsonDocumentData(data) {
|
|
269
|
+
try {
|
|
270
|
+
return zJsonDocumentData.parse(data);
|
|
271
|
+
} catch (error) {
|
|
272
|
+
return error instanceof Error ? error : new Error("Failed to parse JSON document data");
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
var DocFileSystemJsonRead = class {
|
|
276
|
+
data;
|
|
277
|
+
basePath;
|
|
278
|
+
pathSystem;
|
|
279
|
+
constructor(props) {
|
|
280
|
+
const parsed = parseJsonDocumentData(props.data);
|
|
281
|
+
if (parsed instanceof Error) {
|
|
282
|
+
throw parsed;
|
|
283
|
+
}
|
|
284
|
+
this.data = parsed;
|
|
285
|
+
this.basePath = props.basePath ?? "docs";
|
|
286
|
+
this.pathSystem = props.pathSystem ?? new DocPathSystem();
|
|
287
|
+
Object.freeze(this);
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Read file content from JSON data
|
|
291
|
+
*/
|
|
292
|
+
async readFile(relativePath) {
|
|
293
|
+
try {
|
|
294
|
+
const normalizedPath = this.normalizePath(relativePath);
|
|
295
|
+
const content = this.data[normalizedPath];
|
|
296
|
+
return content ?? null;
|
|
297
|
+
} catch (error) {
|
|
298
|
+
return error instanceof Error ? error : new Error(`Failed to read file at ${relativePath}`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Get file name from path
|
|
303
|
+
*/
|
|
304
|
+
readFileName(relativePath) {
|
|
305
|
+
return this.pathSystem.basename(relativePath);
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Get file extension from path
|
|
309
|
+
*/
|
|
310
|
+
readFileExtension(relativePath) {
|
|
311
|
+
return this.pathSystem.extname(relativePath);
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Get directory path where the file exists
|
|
315
|
+
*/
|
|
316
|
+
readFileDirectory(relativePath) {
|
|
317
|
+
return this.pathSystem.dirname(relativePath);
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Get list of file names in directory
|
|
321
|
+
*/
|
|
322
|
+
async readDirectoryFileNames(relativePath = "") {
|
|
323
|
+
try {
|
|
324
|
+
const normalizedDir = this.normalizePath(relativePath);
|
|
325
|
+
const fileNames = /* @__PURE__ */ new Set();
|
|
326
|
+
for (const filePath of Object.keys(this.data)) {
|
|
327
|
+
if (this.isFileInDirectory(filePath, normalizedDir)) {
|
|
328
|
+
const relativePart = this.getRelativePartFromDirectory(
|
|
329
|
+
filePath,
|
|
330
|
+
normalizedDir
|
|
331
|
+
);
|
|
332
|
+
const segments = relativePart.split("/").filter(Boolean);
|
|
333
|
+
if (segments.length > 0) {
|
|
334
|
+
fileNames.add(segments[0]);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
return Array.from(fileNames).sort();
|
|
339
|
+
} catch (error) {
|
|
340
|
+
return error instanceof Error ? error : new Error(`Failed to read directory at ${relativePath}`);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Get list of file paths in directory
|
|
345
|
+
*/
|
|
346
|
+
async readDirectoryFilePaths(relativePath) {
|
|
347
|
+
try {
|
|
348
|
+
const fileNames = await this.readDirectoryFileNames(relativePath);
|
|
349
|
+
if (fileNames instanceof Error) {
|
|
350
|
+
return fileNames;
|
|
351
|
+
}
|
|
352
|
+
return fileNames.map(
|
|
353
|
+
(fileName) => this.pathSystem.join(relativePath, fileName)
|
|
354
|
+
);
|
|
355
|
+
} catch (error) {
|
|
356
|
+
return error instanceof Error ? error : new Error(`Failed to read directory file paths at ${relativePath}`);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Check if path is a directory
|
|
361
|
+
*/
|
|
362
|
+
async isDirectory(relativePath) {
|
|
363
|
+
try {
|
|
364
|
+
const normalizedPath = this.normalizePath(relativePath);
|
|
365
|
+
for (const filePath of Object.keys(this.data)) {
|
|
366
|
+
if (filePath.startsWith(`${normalizedPath}/`)) {
|
|
367
|
+
return true;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return false;
|
|
371
|
+
} catch {
|
|
372
|
+
return false;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Check if path is a file
|
|
377
|
+
*/
|
|
378
|
+
async isFile(relativePath) {
|
|
379
|
+
try {
|
|
380
|
+
const normalizedPath = this.normalizePath(relativePath);
|
|
381
|
+
return normalizedPath in this.data;
|
|
382
|
+
} catch {
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Check if file or directory exists
|
|
388
|
+
*/
|
|
389
|
+
async exists(relativePath) {
|
|
390
|
+
const isFile = await this.isFile(relativePath);
|
|
391
|
+
if (isFile) return true;
|
|
392
|
+
const isDir = await this.isDirectory(relativePath);
|
|
393
|
+
return isDir;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Check if directory exists
|
|
397
|
+
*/
|
|
398
|
+
async directoryExists(relativePath) {
|
|
399
|
+
return this.isDirectory(relativePath);
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Check if file exists
|
|
403
|
+
*/
|
|
404
|
+
async fileExists(relativePath) {
|
|
405
|
+
return this.isFile(relativePath);
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Get base path
|
|
409
|
+
*/
|
|
410
|
+
getBasePath() {
|
|
411
|
+
return this.basePath;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Convert relative path to absolute path
|
|
415
|
+
*/
|
|
416
|
+
resolve(relativePath) {
|
|
417
|
+
return this.pathSystem.join(this.basePath, relativePath);
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Get file size in bytes
|
|
421
|
+
*/
|
|
422
|
+
async getFileSize(relativePath) {
|
|
423
|
+
try {
|
|
424
|
+
const content = await this.readFile(relativePath);
|
|
425
|
+
if (content instanceof Error) {
|
|
426
|
+
return content;
|
|
427
|
+
}
|
|
428
|
+
if (content === null) {
|
|
429
|
+
return new Error(`File not found: ${relativePath}`);
|
|
430
|
+
}
|
|
431
|
+
return Buffer.byteLength(content, "utf8");
|
|
432
|
+
} catch (error) {
|
|
433
|
+
return error instanceof Error ? error : new Error(`Failed to get file size at ${relativePath}`);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Get file last modified time (not available for JSON data)
|
|
438
|
+
*/
|
|
439
|
+
async getFileUpdatedTime(_relativePath) {
|
|
440
|
+
return new Error("File modified time not available for JSON data");
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Get file creation time (not available for JSON data)
|
|
444
|
+
*/
|
|
445
|
+
async getFileCreatedTime(_relativePath) {
|
|
446
|
+
return new Error("File creation time not available for JSON data");
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Get all file paths in the JSON data
|
|
450
|
+
*/
|
|
451
|
+
getAllFilePaths() {
|
|
452
|
+
return Object.keys(this.data);
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Get the raw JSON data
|
|
456
|
+
*/
|
|
457
|
+
getRawData() {
|
|
458
|
+
return { ...this.data };
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Normalize path by removing leading/trailing slashes
|
|
462
|
+
*/
|
|
463
|
+
normalizePath(path) {
|
|
464
|
+
return path.replace(/^\/+|\/+$/g, "");
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Check if a file path is within a directory
|
|
468
|
+
*/
|
|
469
|
+
isFileInDirectory(filePath, dirPath) {
|
|
470
|
+
if (dirPath === "") {
|
|
471
|
+
return true;
|
|
472
|
+
}
|
|
473
|
+
return filePath.startsWith(`${dirPath}/`) || filePath === dirPath;
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Get the relative part of a file path from a directory
|
|
477
|
+
*/
|
|
478
|
+
getRelativePartFromDirectory(filePath, dirPath) {
|
|
479
|
+
if (dirPath === "") {
|
|
480
|
+
return filePath;
|
|
481
|
+
}
|
|
482
|
+
if (filePath.startsWith(`${dirPath}/`)) {
|
|
483
|
+
return filePath.slice(dirPath.length + 1);
|
|
484
|
+
}
|
|
485
|
+
return "";
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
var zJsonDocumentData2 = z.record(z.string(), z.string());
|
|
489
|
+
function parseJsonDocumentData2(data) {
|
|
490
|
+
try {
|
|
491
|
+
return zJsonDocumentData2.parse(data);
|
|
492
|
+
} catch (error) {
|
|
493
|
+
return error instanceof Error ? error : new Error("Failed to parse JSON document data");
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
var DocFileSystemJsonWrite = class {
|
|
497
|
+
data;
|
|
498
|
+
basePath;
|
|
499
|
+
pathSystem;
|
|
500
|
+
reader;
|
|
501
|
+
onDataChange;
|
|
502
|
+
constructor(props = {}) {
|
|
503
|
+
if (props.data !== void 0) {
|
|
504
|
+
const parsed = parseJsonDocumentData2(props.data);
|
|
505
|
+
if (parsed instanceof Error) {
|
|
506
|
+
throw parsed;
|
|
507
|
+
}
|
|
508
|
+
this.data = parsed;
|
|
509
|
+
} else {
|
|
510
|
+
this.data = {};
|
|
511
|
+
}
|
|
512
|
+
this.basePath = props.basePath ?? "docs";
|
|
513
|
+
this.pathSystem = props.pathSystem ?? new DocPathSystem();
|
|
514
|
+
this.reader = props.reader;
|
|
515
|
+
this.onDataChange = props.onDataChange;
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Write content to JSON data
|
|
519
|
+
*/
|
|
520
|
+
async writeFile(relativePath, content) {
|
|
521
|
+
try {
|
|
522
|
+
const normalizedPath = this.normalizePath(relativePath);
|
|
523
|
+
this.data[normalizedPath] = content;
|
|
524
|
+
this.notifyDataChange();
|
|
525
|
+
return null;
|
|
526
|
+
} catch (error) {
|
|
527
|
+
return error instanceof Error ? error : new Error(`Failed to write file at ${relativePath}`);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* Delete file from JSON data
|
|
532
|
+
*/
|
|
533
|
+
async deleteFile(relativePath) {
|
|
534
|
+
try {
|
|
535
|
+
const normalizedPath = this.normalizePath(relativePath);
|
|
536
|
+
if (!(normalizedPath in this.data)) {
|
|
537
|
+
return new Error(`File not found: ${relativePath}`);
|
|
538
|
+
}
|
|
539
|
+
delete this.data[normalizedPath];
|
|
540
|
+
this.notifyDataChange();
|
|
541
|
+
return null;
|
|
542
|
+
} catch (error) {
|
|
543
|
+
return error instanceof Error ? error : new Error(`Failed to delete file at ${relativePath}`);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* Create directory (creates a placeholder entry)
|
|
548
|
+
*/
|
|
549
|
+
async createEmptyDirectory(relativePath) {
|
|
550
|
+
try {
|
|
551
|
+
const normalizedPath = this.normalizePath(relativePath);
|
|
552
|
+
const gitkeepPath = this.pathSystem.join(normalizedPath, ".gitkeep");
|
|
553
|
+
const normalizedGitkeepPath = this.normalizePath(gitkeepPath);
|
|
554
|
+
this.data[normalizedGitkeepPath] = "";
|
|
555
|
+
this.notifyDataChange();
|
|
556
|
+
return null;
|
|
557
|
+
} catch (error) {
|
|
558
|
+
return error instanceof Error ? error : new Error(`Failed to create directory at ${relativePath}`);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Create directory if it doesn't exist
|
|
563
|
+
*/
|
|
564
|
+
async createDirectory(relativePath) {
|
|
565
|
+
try {
|
|
566
|
+
if (this.reader) {
|
|
567
|
+
const exists = await this.reader.exists(relativePath);
|
|
568
|
+
if (exists) {
|
|
569
|
+
return null;
|
|
570
|
+
}
|
|
571
|
+
} else {
|
|
572
|
+
if (await this.directoryExistsInData(relativePath)) {
|
|
573
|
+
return null;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
return await this.createEmptyDirectory(relativePath);
|
|
577
|
+
} catch (error) {
|
|
578
|
+
return error instanceof Error ? error : new Error(`Failed to ensure directory exists at ${relativePath}`);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Copy file within JSON data
|
|
583
|
+
*/
|
|
584
|
+
async copyFile(sourcePath, destinationPath) {
|
|
585
|
+
try {
|
|
586
|
+
const normalizedSourcePath = this.normalizePath(sourcePath);
|
|
587
|
+
const normalizedDestPath = this.normalizePath(destinationPath);
|
|
588
|
+
if (this.reader) {
|
|
589
|
+
const content = await this.reader.readFile(sourcePath);
|
|
590
|
+
if (content instanceof Error) {
|
|
591
|
+
return content;
|
|
592
|
+
}
|
|
593
|
+
if (content === null) {
|
|
594
|
+
return new Error(`Source file not found: ${sourcePath}`);
|
|
595
|
+
}
|
|
596
|
+
this.data[normalizedDestPath] = content;
|
|
597
|
+
} else {
|
|
598
|
+
if (!(normalizedSourcePath in this.data)) {
|
|
599
|
+
return new Error(`Source file not found: ${sourcePath}`);
|
|
600
|
+
}
|
|
601
|
+
this.data[normalizedDestPath] = this.data[normalizedSourcePath];
|
|
602
|
+
}
|
|
603
|
+
this.notifyDataChange();
|
|
604
|
+
return null;
|
|
605
|
+
} catch (error) {
|
|
606
|
+
return error instanceof Error ? error : new Error(
|
|
607
|
+
`Failed to copy file from ${sourcePath} to ${destinationPath}`
|
|
608
|
+
);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* Move file within JSON data
|
|
613
|
+
*/
|
|
614
|
+
async moveFile(sourcePath, destinationPath) {
|
|
615
|
+
try {
|
|
616
|
+
const copyResult = await this.copyFile(sourcePath, destinationPath);
|
|
617
|
+
if (copyResult !== null) {
|
|
618
|
+
return copyResult;
|
|
619
|
+
}
|
|
620
|
+
return await this.deleteFile(sourcePath);
|
|
621
|
+
} catch (error) {
|
|
622
|
+
return error instanceof Error ? error : new Error(
|
|
623
|
+
`Failed to move file from ${sourcePath} to ${destinationPath}`
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Get the current JSON data
|
|
629
|
+
*/
|
|
630
|
+
getData() {
|
|
631
|
+
return { ...this.data };
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Update the entire JSON data
|
|
635
|
+
*/
|
|
636
|
+
setData(data) {
|
|
637
|
+
try {
|
|
638
|
+
const parsed = parseJsonDocumentData2(data);
|
|
639
|
+
if (parsed instanceof Error) {
|
|
640
|
+
return parsed;
|
|
641
|
+
}
|
|
642
|
+
this.data = parsed;
|
|
643
|
+
this.notifyDataChange();
|
|
644
|
+
return null;
|
|
645
|
+
} catch (error) {
|
|
646
|
+
return error instanceof Error ? error : new Error("Failed to set JSON data");
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* Clear all data
|
|
651
|
+
*/
|
|
652
|
+
clear() {
|
|
653
|
+
this.data = {};
|
|
654
|
+
this.notifyDataChange();
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* Get all file paths in the JSON data
|
|
658
|
+
*/
|
|
659
|
+
getAllFilePaths() {
|
|
660
|
+
return Object.keys(this.data);
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Normalize path by removing leading/trailing slashes
|
|
664
|
+
*/
|
|
665
|
+
normalizePath(path) {
|
|
666
|
+
return path.replace(/^\/+|\/+$/g, "");
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* Check if directory exists in data
|
|
670
|
+
*/
|
|
671
|
+
async directoryExistsInData(relativePath) {
|
|
672
|
+
const normalizedPath = this.normalizePath(relativePath);
|
|
673
|
+
for (const filePath of Object.keys(this.data)) {
|
|
674
|
+
if (filePath.startsWith(`${normalizedPath}/`)) {
|
|
675
|
+
return true;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
return false;
|
|
679
|
+
}
|
|
680
|
+
/**
|
|
681
|
+
* Notify data change callback
|
|
682
|
+
*/
|
|
683
|
+
notifyDataChange() {
|
|
684
|
+
if (this.onDataChange) {
|
|
685
|
+
this.onDataChange({ ...this.data });
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
};
|
|
689
|
+
|
|
690
|
+
// lib/modules/file-system/doc-file-system-json.ts
|
|
691
|
+
z.record(z.string(), z.string());
|
|
692
|
+
var DocFileSystemJson = class _DocFileSystemJson extends DocFileSystem {
|
|
693
|
+
jsonReader;
|
|
694
|
+
jsonWriter;
|
|
695
|
+
constructor(props = {}) {
|
|
696
|
+
const reader = new DocFileSystemJsonRead({
|
|
697
|
+
data: props.data,
|
|
698
|
+
basePath: props.basePath,
|
|
699
|
+
pathSystem: props.pathSystem
|
|
700
|
+
});
|
|
701
|
+
const writer = new DocFileSystemJsonWrite({
|
|
702
|
+
data: props.data,
|
|
703
|
+
basePath: props.basePath,
|
|
704
|
+
pathSystem: props.pathSystem,
|
|
705
|
+
reader,
|
|
706
|
+
onDataChange: props.onDataChange
|
|
707
|
+
});
|
|
708
|
+
super({
|
|
709
|
+
basePath: props.basePath ?? "docs",
|
|
710
|
+
pathSystem: props.pathSystem,
|
|
711
|
+
reader,
|
|
712
|
+
writer
|
|
713
|
+
});
|
|
714
|
+
this.jsonReader = reader;
|
|
715
|
+
this.jsonWriter = writer;
|
|
716
|
+
Object.freeze(this);
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* Get the current JSON data
|
|
720
|
+
*/
|
|
721
|
+
getData() {
|
|
722
|
+
return this.jsonWriter.getData();
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Update the entire JSON data
|
|
726
|
+
*/
|
|
727
|
+
setData(data) {
|
|
728
|
+
return this.jsonWriter.setData(data);
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* Clear all data
|
|
732
|
+
*/
|
|
733
|
+
clear() {
|
|
734
|
+
this.jsonWriter.clear();
|
|
735
|
+
}
|
|
736
|
+
/**
|
|
737
|
+
* Get all file paths in the JSON data
|
|
738
|
+
*/
|
|
739
|
+
getAllFilePaths() {
|
|
740
|
+
return this.jsonReader.getAllFilePaths();
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* Get the raw JSON data (read-only copy)
|
|
744
|
+
*/
|
|
745
|
+
getRawData() {
|
|
746
|
+
return this.jsonReader.getRawData();
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* Create from docs-to-json format
|
|
750
|
+
*/
|
|
751
|
+
static fromDocsToJson(data, options = {}) {
|
|
752
|
+
return new _DocFileSystemJson({
|
|
753
|
+
...options,
|
|
754
|
+
data
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Export to docs-to-json format
|
|
759
|
+
*/
|
|
760
|
+
toDocsToJson() {
|
|
761
|
+
return this.getData();
|
|
762
|
+
}
|
|
763
|
+
};
|
|
764
|
+
|
|
765
|
+
export { DocFileSystemJson, DocFileSystemJsonRead, DocFileSystemJsonWrite };
|