@mak-98/posix-fs-dirvi-app 0.11.0-beta.2 → 0.11.0-beta.4
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/domain/posix-tree.d.ts +19 -198
- package/dist/domain/posix-tree.d.ts.map +1 -1
- package/dist/domain/posix-tree.js +191 -150
- package/dist/infrastructure/create-file-view-api.d.ts.map +1 -1
- package/dist/infrastructure/get-dir-entries.d.ts +4 -4
- package/dist/infrastructure/get-dir-entries.d.ts.map +1 -1
- package/dist/infrastructure/get-dir-entries.js +8 -7
- package/dist/infrastructure/get-unix-abs-path.d.ts.map +1 -1
- package/dist/infrastructure/load-node-posix-app-api.d.ts +1 -9
- package/dist/infrastructure/load-node-posix-app-api.d.ts.map +1 -1
- package/dist/infrastructure/load-node-posix-app-api.js +64 -103
- package/dist/posix-fs-dirvi-app.d.ts +4 -2
- package/dist/posix-fs-dirvi-app.d.ts.map +1 -1
- package/dist/posix-fs-dirvi-app.js +39 -6
- package/package.json +3 -3
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
2
|
+
import type { TreeNode, TreeNodeApi } from 'dirvi-lib';
|
|
3
3
|
import { UnixPath } from './unix-path.js';
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* A JavaScript-string representation of a non-special POSIX filename.
|
|
6
|
+
*
|
|
7
|
+
* Validates invariants needed for a tree entry ID, not full POSIX compatibility.
|
|
8
|
+
*/
|
|
9
|
+
export declare const posixFilenameSchema: z.ZodString;
|
|
10
|
+
/**
|
|
11
|
+
* `Id` type used for posix-fs-dirvi-app.
|
|
12
|
+
*/
|
|
13
|
+
export type PosixId = z.output<typeof posixFilenameSchema>;
|
|
6
14
|
/**
|
|
7
15
|
* POSIX-specific meaning attached to a tree node.
|
|
8
16
|
*/
|
|
9
|
-
export type
|
|
17
|
+
export type PosixValue = Readonly<{
|
|
10
18
|
kind: 'file';
|
|
11
19
|
}> | Readonly<{
|
|
12
20
|
kind: 'symlink';
|
|
@@ -14,51 +22,13 @@ export type PosixEntry = Readonly<{
|
|
|
14
22
|
}> | Readonly<{
|
|
15
23
|
kind: 'directory';
|
|
16
24
|
}>;
|
|
17
|
-
export
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
createLeaf(id: string, value: PosixEntry): TreeNode<string, PosixEntry>;
|
|
25
|
-
createUnloadedBranch(id: string, value: PosixEntry): TreeNode<string, PosixEntry>;
|
|
26
|
-
createLoadedBranch(id: string, value: PosixEntry, children: Iterable<TreeNode<string, PosixEntry>>): TreeNode<string, PosixEntry> | undefined;
|
|
27
|
-
id(node: TreeNode<string, PosixEntry>): string;
|
|
28
|
-
value(node: TreeNode<string, PosixEntry>): PosixEntry;
|
|
29
|
-
kind(node: TreeNode<string, PosixEntry>): import("dirvi-lib").TreeNodeKind;
|
|
30
|
-
match<Result>(node: TreeNode<string, PosixEntry>, handlers: Readonly<{
|
|
31
|
-
leaf: (node: Readonly<{
|
|
32
|
-
id: string;
|
|
33
|
-
value: PosixEntry;
|
|
34
|
-
}>) => Result;
|
|
35
|
-
unloadedBranch: (node: Readonly<{
|
|
36
|
-
id: string;
|
|
37
|
-
value: PosixEntry;
|
|
38
|
-
}>) => Result;
|
|
39
|
-
loadedBranch: (node: Readonly<{
|
|
40
|
-
id: string;
|
|
41
|
-
value: PosixEntry;
|
|
42
|
-
children: Iterable<TreeNode<string, PosixEntry>>;
|
|
43
|
-
}>) => Result;
|
|
44
|
-
}>): Result;
|
|
45
|
-
getLoadedChildren(node: TreeNode<string, PosixEntry>): Iterable<TreeNode<string, PosixEntry>> | undefined;
|
|
46
|
-
findChildById(node: TreeNode<string, PosixEntry>, id: string): TreeNode<string, PosixEntry> | undefined;
|
|
47
|
-
withValue(node: TreeNode<string, PosixEntry>, value: PosixEntry): TreeNode<string, PosixEntry>;
|
|
48
|
-
toLeaf(node: TreeNode<string, PosixEntry>): TreeNode<string, PosixEntry>;
|
|
49
|
-
toUnloadedBranch(node: TreeNode<string, PosixEntry>): TreeNode<string, PosixEntry>;
|
|
50
|
-
withLoadedChildren(node: TreeNode<string, PosixEntry>, children: Iterable<TreeNode<string, PosixEntry>>): TreeNode<string, PosixEntry> | undefined;
|
|
51
|
-
findAtPath(root: TreeNode<string, PosixEntry>, path: readonly string[]): TreeNode<string, PosixEntry> | undefined;
|
|
52
|
-
selectAtPath<Result>(root: TreeNode<string, PosixEntry>, path: readonly string[], selector: (node: TreeNode<string, PosixEntry>) => Result): Result | undefined;
|
|
53
|
-
updateAtPath(root: TreeNode<string, PosixEntry>, path: readonly string[], update: (node: TreeNode<string, PosixEntry>) => TreeNode<string, PosixEntry> | undefined): TreeNode<string, PosixEntry> | undefined;
|
|
54
|
-
toModel(node: TreeNode<string, PosixEntry>): TreeNodeModel<string, PosixEntry>;
|
|
55
|
-
fromModel(model: TreeNodeModel<string, PosixEntry>): TreeNode<string, PosixEntry> | undefined;
|
|
56
|
-
}>;
|
|
57
|
-
export declare const PosixTreeNode: {
|
|
58
|
-
readonly file: (name: PosixName) => PosixTreeNode;
|
|
59
|
-
readonly symlink: (name: PosixName, target: UnixPath) => PosixTreeNode;
|
|
60
|
-
readonly unloadedDirectory: (name: PosixName) => PosixTreeNode;
|
|
61
|
-
readonly loadedDirectory: (name: PosixName, children: Iterable<PosixTreeNode>) => PosixTreeNode | undefined;
|
|
25
|
+
export type PosixTreeNode = TreeNode<PosixId, PosixValue>;
|
|
26
|
+
export declare const posixValueSchema: z.ZodType<PosixValue>;
|
|
27
|
+
export declare function createConstructors(posixTreeNodeApi: TreeNodeApi<PosixId, PosixValue>): {
|
|
28
|
+
readonly file: (name: PosixId) => PosixTreeNode;
|
|
29
|
+
readonly symlink: (name: PosixId, target: UnixPath) => PosixTreeNode;
|
|
30
|
+
readonly unloadedDirectory: (name: PosixId) => PosixTreeNode;
|
|
31
|
+
readonly loadedDirectory: (name: PosixId, children: Iterable<PosixTreeNode>) => PosixTreeNode | undefined;
|
|
62
32
|
/**
|
|
63
33
|
* Runtime domain invariant check.
|
|
64
34
|
*
|
|
@@ -81,153 +51,4 @@ export declare const PosixTreeNode: {
|
|
|
81
51
|
*/
|
|
82
52
|
readonly toUnloadedDirectory: (node: PosixTreeNode) => PosixTreeNode | undefined;
|
|
83
53
|
};
|
|
84
|
-
/**
|
|
85
|
-
* This is a DTO / persistence shape, not the runtime domain type.
|
|
86
|
-
*
|
|
87
|
-
* It intentionally exposes `id`, `value`, and `children`, because serialized
|
|
88
|
-
* data must have a concrete public format.
|
|
89
|
-
*/
|
|
90
|
-
export type PosixTreeNodeModel = TreeNodeModel<PosixName, PosixEntry>;
|
|
91
|
-
/**
|
|
92
|
-
* Validates both the generic tree model shape and the POSIX-specific
|
|
93
|
-
* file/symlink/directory invariants.
|
|
94
|
-
*
|
|
95
|
-
* Files and symlinks must be leaf models.
|
|
96
|
-
* Directories must be unloaded or loaded branch models.
|
|
97
|
-
*/
|
|
98
|
-
export declare const PosixTreeNodeModelSchema: z.ZodType<PosixTreeNodeModel>;
|
|
99
|
-
/**
|
|
100
|
-
* Decodes validated external data into the opaque domain type.
|
|
101
|
-
*
|
|
102
|
-
* `fromModel` additionally checks sibling-name uniqueness. That validation is
|
|
103
|
-
* separate from Zod's object-shape validation.
|
|
104
|
-
*/
|
|
105
|
-
export declare function decodePosixTreeNode(input: unknown): PosixTreeNode | undefined;
|
|
106
|
-
export declare function encodePosixTreeNode(node: PosixTreeNode): PosixTreeNodeModel;
|
|
107
|
-
/**
|
|
108
|
-
* Fold definitions for one POSIX directory tree.
|
|
109
|
-
*/
|
|
110
|
-
export type PosixFolds = Folds<PosixName>;
|
|
111
|
-
export declare const PosixFoldsApi: Readonly<{
|
|
112
|
-
create(rootId: string, initialPrimaryInfo: Readonly<{
|
|
113
|
-
name: string;
|
|
114
|
-
description: string | null;
|
|
115
|
-
}>): Folds<string>;
|
|
116
|
-
getIndexByName(folds: Folds<string>, name: string): import("dirvi-lib").FoldIndex | undefined;
|
|
117
|
-
getInfoAtIndex(folds: Folds<string>, index: import("dirvi-lib").FoldIndex): Readonly<{
|
|
118
|
-
name: string;
|
|
119
|
-
description: string | null;
|
|
120
|
-
}> | undefined;
|
|
121
|
-
isActiveAtIndex(folds: Folds<string>, index: import("dirvi-lib").FoldIndex): boolean | undefined;
|
|
122
|
-
hasAtIndex(folds: Folds<string>, index: import("dirvi-lib").FoldIndex): boolean;
|
|
123
|
-
indexes(folds: Folds<string>): Iterable<import("dirvi-lib").FoldIndex>;
|
|
124
|
-
setAtIndex(folds: Folds<string>, index: import("dirvi-lib").FoldIndex, foldData: Readonly<{
|
|
125
|
-
name: string;
|
|
126
|
-
description: string | null;
|
|
127
|
-
active: boolean;
|
|
128
|
-
tree: Readonly<{
|
|
129
|
-
id: string;
|
|
130
|
-
hiddenEntryIds: readonly string[];
|
|
131
|
-
children: readonly Readonly</*elided*/ any>[];
|
|
132
|
-
}>;
|
|
133
|
-
}>): Folds<string> | undefined;
|
|
134
|
-
setAdditionalFoldAtIndex(folds: Folds<string>, index: import("dirvi-lib").FoldIndex, rootId: string, info: Readonly<{
|
|
135
|
-
name: string;
|
|
136
|
-
description: string | null;
|
|
137
|
-
}>): Folds<string> | undefined;
|
|
138
|
-
removeAdditionalFoldAtIndex(folds: Folds<string>, index: import("dirvi-lib").FoldIndex): Folds<string> | undefined;
|
|
139
|
-
updateInfoAtIndex(folds: Folds<string>, index: import("dirvi-lib").FoldIndex, update: Readonly<{
|
|
140
|
-
name?: string;
|
|
141
|
-
description?: string | null;
|
|
142
|
-
}>): Folds<string> | undefined;
|
|
143
|
-
activateAtIndex(folds: Folds<string>, index: import("dirvi-lib").FoldIndex): Folds<string> | undefined;
|
|
144
|
-
deactivateAtIndex(folds: Folds<string>, index: import("dirvi-lib").FoldIndex): Folds<string> | undefined;
|
|
145
|
-
toggleActiveAtIndex(folds: Folds<string>, index: import("dirvi-lib").FoldIndex): Folds<string> | undefined;
|
|
146
|
-
isEntryHiddenInFoldAtPath(folds: Folds<string>, index: import("dirvi-lib").FoldIndex, path: readonly string[], entryId: string): boolean;
|
|
147
|
-
isEntryHiddenAtPath(folds: Folds<string>, path: readonly string[], entryId: string): boolean;
|
|
148
|
-
hiddenEntryIdsAtPath(folds: Folds<string>, index: import("dirvi-lib").FoldIndex, path: readonly string[]): Iterable<string> | undefined;
|
|
149
|
-
hideEntryAtPath(folds: Folds<string>, index: import("dirvi-lib").FoldIndex, path: readonly string[], entryId: string): Folds<string> | undefined;
|
|
150
|
-
showEntryAtPath(folds: Folds<string>, index: import("dirvi-lib").FoldIndex, path: readonly string[], entryId: string): Folds<string> | undefined;
|
|
151
|
-
showAllHiddenEntriesAtPath(folds: Folds<string>, index: import("dirvi-lib").FoldIndex, path: readonly string[]): Folds<string> | undefined;
|
|
152
|
-
toModel(folds: Folds<string>): Readonly<{
|
|
153
|
-
slots: readonly [Readonly<{
|
|
154
|
-
name: string;
|
|
155
|
-
description: string | null;
|
|
156
|
-
active: boolean;
|
|
157
|
-
tree: Readonly<{
|
|
158
|
-
id: string;
|
|
159
|
-
hiddenEntryIds: readonly string[];
|
|
160
|
-
children: readonly Readonly</*elided*/ any>[];
|
|
161
|
-
}>;
|
|
162
|
-
}>, ...(Readonly<{
|
|
163
|
-
name: string;
|
|
164
|
-
description: string | null;
|
|
165
|
-
active: boolean;
|
|
166
|
-
tree: Readonly<{
|
|
167
|
-
id: string;
|
|
168
|
-
hiddenEntryIds: readonly string[];
|
|
169
|
-
children: readonly Readonly</*elided*/ any>[];
|
|
170
|
-
}>;
|
|
171
|
-
}> | null)[]];
|
|
172
|
-
}>;
|
|
173
|
-
fromModel(model: Readonly<{
|
|
174
|
-
slots: readonly [Readonly<{
|
|
175
|
-
name: string;
|
|
176
|
-
description: string | null;
|
|
177
|
-
active: boolean;
|
|
178
|
-
tree: Readonly<{
|
|
179
|
-
id: string;
|
|
180
|
-
hiddenEntryIds: readonly string[];
|
|
181
|
-
children: readonly Readonly</*elided*/ any>[];
|
|
182
|
-
}>;
|
|
183
|
-
}>, ...(Readonly<{
|
|
184
|
-
name: string;
|
|
185
|
-
description: string | null;
|
|
186
|
-
active: boolean;
|
|
187
|
-
tree: Readonly<{
|
|
188
|
-
id: string;
|
|
189
|
-
hiddenEntryIds: readonly string[];
|
|
190
|
-
children: readonly Readonly</*elided*/ any>[];
|
|
191
|
-
}>;
|
|
192
|
-
}> | null)[]];
|
|
193
|
-
}>): Folds<string> | undefined;
|
|
194
|
-
}>;
|
|
195
|
-
export type PosixFoldsModel = FoldsModel<PosixName>;
|
|
196
|
-
export declare const PosixFoldsModelSchema: z.ZodType<PosixFoldsModel>;
|
|
197
|
-
export declare const PosixCursorSchema: z.ZodType<PosixCursor>;
|
|
198
|
-
export type PosixCursor = Cursor<PosixName>;
|
|
199
|
-
export declare const PosixCursorApi: import("dirvi-lib").CursorApi<string>;
|
|
200
|
-
/**
|
|
201
|
-
* NavNode should now be parameterized by node value, not the recursive
|
|
202
|
-
* application node shape.
|
|
203
|
-
*/
|
|
204
|
-
export type PosixNavNode = NavNode<PosixName>;
|
|
205
|
-
export declare const PosixNavApi: import("dirvi-lib").NavNodeApi<string, PosixEntry>;
|
|
206
|
-
/**
|
|
207
|
-
* State should now be parameterized by application value, not a recursive
|
|
208
|
-
* structural node type.
|
|
209
|
-
*/
|
|
210
|
-
export type PosixState = State<PosixName, PosixEntry>;
|
|
211
|
-
export declare const PosixStateApi: Readonly<{
|
|
212
|
-
getNodeAtCursor(state: Readonly<{
|
|
213
|
-
root: TreeNode<string, PosixEntry>;
|
|
214
|
-
folds: Folds<string>;
|
|
215
|
-
cursor: Cursor<string>;
|
|
216
|
-
}>): TreeNode<string, PosixEntry> | undefined;
|
|
217
|
-
resync(oldState: Readonly<{
|
|
218
|
-
root: TreeNode<string, PosixEntry>;
|
|
219
|
-
folds: Folds<string>;
|
|
220
|
-
cursor: Cursor<string>;
|
|
221
|
-
}>, loadBranches: (path: readonly string[]) => Promise<readonly TreeNode<string, PosixEntry>[]>): Promise<Readonly<{
|
|
222
|
-
root: TreeNode<string, PosixEntry>;
|
|
223
|
-
folds: Folds<string>;
|
|
224
|
-
cursor: Cursor<string>;
|
|
225
|
-
}>>;
|
|
226
|
-
}>;
|
|
227
|
-
export type PosixStateModel = StateModel<PosixName, PosixEntry>;
|
|
228
|
-
/**
|
|
229
|
-
* The state schema should operate on a serializable tree *model*, then decode
|
|
230
|
-
* it to opaque nodes. Do not try to make Zod construct TreeNode directly.
|
|
231
|
-
*/
|
|
232
|
-
export declare const PosixStateModelSchema: z.ZodType<PosixStateModel>;
|
|
233
54
|
//# sourceMappingURL=posix-tree.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"posix-tree.d.ts","sourceRoot":"","sources":["../../src/domain/posix-tree.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"posix-tree.d.ts","sourceRoot":"","sources":["../../src/domain/posix-tree.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAEV,QAAQ,EACR,WAAW,EACZ,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,QAAQ,EAAkB,MAAM,gBAAgB,CAAC;AAY1D;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,aAU1B,CAAC;AAEP;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAY3D;;GAEG;AACH,MAAM,MAAM,UAAU,GAClB,QAAQ,CAAC;IACP,IAAI,EAAE,MAAM,CAAC;CACd,CAAC,GACF,QAAQ,CAAC;IACP,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,QAAQ,CAAC;CAClB,CAAC,GACF,QAAQ,CAAC;IACP,IAAI,EAAE,WAAW,CAAC;CACnB,CAAC,CAAC;AAEP,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AAuB1D,eAAO,MAAM,gBAAgB,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAGlD,CAAC;AAMF,wBAAgB,kBAAkB,CAChC,gBAAgB,EAAE,WAAW,CAAC,OAAO,EAAE,UAAU,CAAC;0BAGrC,OAAO,KAAG,aAAa;6BAMpB,OAAO,UAAU,QAAQ,KAAG,aAAa;uCAO/B,OAAO,KAAG,aAAa;qCAOvC,OAAO,YACH,QAAQ,CAAC,aAAa,CAAC,KAChC,aAAa,GAAG,SAAS;IAQ5B;;;;;OAKG;6BACW,aAAa,KAAG,OAAO;IAcrC;;;;;;OAMG;wCAEK,aAAa,YACT,QAAQ,CAAC,aAAa,CAAC,KAChC,aAAa,GAAG,SAAS;IAQ5B;;;;OAIG;yCACuB,aAAa,KAAG,aAAa,GAAG,SAAS;EAQtE"}
|
|
@@ -1,18 +1,25 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { serializableKeySchema, createNavNodeApi, createStateApi, createTreeNodeApi, createFoldsApi, createFoldsModelSchema, createCursorSchema, createCursorApi, createStateModelSchema, } from 'dirvi-lib';
|
|
3
2
|
import { UnixPathSchema } from './unix-path.js';
|
|
4
3
|
// -----------------------------------------------------------------------------
|
|
5
|
-
//
|
|
4
|
+
// PosixId: Id extends SerializableKey
|
|
6
5
|
// -----------------------------------------------------------------------------
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
/**
|
|
7
|
+
* A JavaScript-string representation of a non-special POSIX filename.
|
|
8
|
+
*
|
|
9
|
+
* Validates invariants needed for a tree entry ID, not full POSIX compatibility.
|
|
10
|
+
*/
|
|
11
|
+
export const posixFilenameSchema = z.string()
|
|
9
12
|
.min(1, 'Entry name cannot be empty.')
|
|
13
|
+
.refine((value) => !value.includes('\0'), {
|
|
14
|
+
message: 'Entry name must not contain a NUL character.',
|
|
15
|
+
})
|
|
10
16
|
.refine((value) => !value.includes('/'), {
|
|
11
17
|
message: "Entry name must not contain '/'.",
|
|
12
18
|
})
|
|
13
19
|
.refine((value) => value !== '.' && value !== '..', {
|
|
14
|
-
message: "Entry name
|
|
15
|
-
})
|
|
20
|
+
message: "Entry name must not be '.' or '..'.",
|
|
21
|
+
});
|
|
22
|
+
// Schema ----------------------------------------------------------------------
|
|
16
23
|
const PosixFileEntrySchema = z
|
|
17
24
|
.object({
|
|
18
25
|
kind: z.literal('file'),
|
|
@@ -29,153 +36,187 @@ const PosixDirectoryEntrySchema = z
|
|
|
29
36
|
kind: z.literal('directory'),
|
|
30
37
|
})
|
|
31
38
|
.strict();
|
|
32
|
-
export const
|
|
33
|
-
export const PosixTreeNodeApi = createTreeNodeApi();
|
|
39
|
+
export const posixValueSchema = z.discriminatedUnion('kind', [PosixFileEntrySchema, PosixSymlinkEntrySchema, PosixDirectoryEntrySchema]);
|
|
34
40
|
// -----------------------------------------------------------------------------
|
|
35
41
|
// POSIX domain constructors
|
|
36
42
|
// -----------------------------------------------------------------------------
|
|
37
|
-
export
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
* Validates both the generic tree model shape and the POSIX-specific
|
|
101
|
-
* file/symlink/directory invariants.
|
|
102
|
-
*
|
|
103
|
-
* Files and symlinks must be leaf models.
|
|
104
|
-
* Directories must be unloaded or loaded branch models.
|
|
105
|
-
*/
|
|
106
|
-
export const PosixTreeNodeModelSchema = z.lazy(() => z.union([
|
|
107
|
-
// Leaf: file
|
|
108
|
-
z
|
|
109
|
-
.object({
|
|
110
|
-
id: PosixNameSchema,
|
|
111
|
-
value: PosixFileEntrySchema,
|
|
112
|
-
})
|
|
113
|
-
.strict(),
|
|
114
|
-
// Leaf: symlink
|
|
115
|
-
z
|
|
116
|
-
.object({
|
|
117
|
-
id: PosixNameSchema,
|
|
118
|
-
value: PosixSymlinkEntrySchema,
|
|
119
|
-
})
|
|
120
|
-
.strict(),
|
|
121
|
-
// Unloaded branch: directory
|
|
122
|
-
z
|
|
123
|
-
.object({
|
|
124
|
-
id: PosixNameSchema,
|
|
125
|
-
value: PosixDirectoryEntrySchema,
|
|
126
|
-
children: z.null(),
|
|
127
|
-
})
|
|
128
|
-
.strict(),
|
|
129
|
-
// Loaded branch: directory
|
|
130
|
-
z
|
|
131
|
-
.object({
|
|
132
|
-
id: PosixNameSchema,
|
|
133
|
-
value: PosixDirectoryEntrySchema,
|
|
134
|
-
children: z.array(PosixTreeNodeModelSchema),
|
|
135
|
-
})
|
|
136
|
-
.strict(),
|
|
137
|
-
]));
|
|
138
|
-
/**
|
|
139
|
-
* Decodes validated external data into the opaque domain type.
|
|
140
|
-
*
|
|
141
|
-
* `fromModel` additionally checks sibling-name uniqueness. That validation is
|
|
142
|
-
* separate from Zod's object-shape validation.
|
|
143
|
-
*/
|
|
144
|
-
export function decodePosixTreeNode(input) {
|
|
145
|
-
const model = PosixTreeNodeModelSchema.safeParse(input);
|
|
146
|
-
if (!model.success) {
|
|
147
|
-
return undefined;
|
|
148
|
-
}
|
|
149
|
-
const node = PosixTreeNodeApi.fromModel(model.data);
|
|
150
|
-
if (node === undefined) {
|
|
151
|
-
return undefined;
|
|
152
|
-
}
|
|
153
|
-
return PosixTreeNode.isValid(node) ? node : undefined;
|
|
43
|
+
export function createConstructors(posixTreeNodeApi) {
|
|
44
|
+
return {
|
|
45
|
+
file(name) {
|
|
46
|
+
return posixTreeNodeApi.createLeaf(name, {
|
|
47
|
+
kind: 'file',
|
|
48
|
+
});
|
|
49
|
+
},
|
|
50
|
+
symlink(name, target) {
|
|
51
|
+
return posixTreeNodeApi.createLeaf(name, {
|
|
52
|
+
kind: 'symlink',
|
|
53
|
+
target,
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
unloadedDirectory(name) {
|
|
57
|
+
return posixTreeNodeApi.createUnloadedBranch(name, {
|
|
58
|
+
kind: 'directory',
|
|
59
|
+
});
|
|
60
|
+
},
|
|
61
|
+
loadedDirectory(name, children) {
|
|
62
|
+
return posixTreeNodeApi.createLoadedBranch(name, { kind: 'directory' }, children);
|
|
63
|
+
},
|
|
64
|
+
/**
|
|
65
|
+
* Runtime domain invariant check.
|
|
66
|
+
*
|
|
67
|
+
* A file and symlink must be leaves. A directory must be a branch, whether
|
|
68
|
+
* loaded or unloaded.
|
|
69
|
+
*/
|
|
70
|
+
isValid(node) {
|
|
71
|
+
const entry = posixTreeNodeApi.value(node);
|
|
72
|
+
const treeKind = posixTreeNodeApi.kind(node);
|
|
73
|
+
switch (entry.kind) {
|
|
74
|
+
case 'file':
|
|
75
|
+
case 'symlink':
|
|
76
|
+
return treeKind === 'leaf';
|
|
77
|
+
case 'directory':
|
|
78
|
+
return treeKind === 'unloaded-branch' || treeKind === 'loaded-branch';
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
/**
|
|
82
|
+
* Adds or replaces the loaded children of a directory.
|
|
83
|
+
*
|
|
84
|
+
* Returns `undefined` when:
|
|
85
|
+
* - the supplied node is not a directory; or
|
|
86
|
+
* - siblings have duplicate names.
|
|
87
|
+
*/
|
|
88
|
+
withLoadedChildren(node, children) {
|
|
89
|
+
if (posixTreeNodeApi.value(node).kind !== 'directory') {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
return posixTreeNodeApi.withLoadedChildren(node, children);
|
|
93
|
+
},
|
|
94
|
+
/**
|
|
95
|
+
* Converts a directory to an unloaded directory.
|
|
96
|
+
*
|
|
97
|
+
* Files and symlinks cannot be converted to branches through this POSIX API.
|
|
98
|
+
*/
|
|
99
|
+
toUnloadedDirectory(node) {
|
|
100
|
+
if (posixTreeNodeApi.value(node).kind !== 'directory') {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
return posixTreeNodeApi.toUnloadedBranch(node);
|
|
104
|
+
},
|
|
105
|
+
};
|
|
154
106
|
}
|
|
155
|
-
|
|
156
|
-
return PosixTreeNodeApi.toModel(node);
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Folds internally store sparse trees whose values are direct child IDs hidden
|
|
160
|
-
* at that tree position. This implementation detail remains private to the
|
|
161
|
-
* POSIX domain module.
|
|
162
|
-
*/
|
|
163
|
-
const PosixFoldTreeNodeApi = createTreeNodeApi();
|
|
164
|
-
export const PosixFoldsApi = createFoldsApi(PosixFoldTreeNodeApi);
|
|
165
|
-
export const PosixFoldsModelSchema = createFoldsModelSchema(PosixNameSchema);
|
|
107
|
+
;
|
|
166
108
|
// -----------------------------------------------------------------------------
|
|
167
|
-
//
|
|
109
|
+
// Serializable POSIX model
|
|
168
110
|
// -----------------------------------------------------------------------------
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
111
|
+
// /**
|
|
112
|
+
// * This is a DTO / persistence shape, not the runtime domain type.
|
|
113
|
+
// *
|
|
114
|
+
// * It intentionally exposes `id`, `value`, and `children`, because serialized
|
|
115
|
+
// * data must have a concrete public format.
|
|
116
|
+
// */
|
|
117
|
+
// export type PosixTreeNodeModel = TreeNodeModel<PosixId, PosixValue>;
|
|
118
|
+
//
|
|
119
|
+
// /**
|
|
120
|
+
// * Validates both the generic tree model shape and the POSIX-specific
|
|
121
|
+
// * file/symlink/directory invariants.
|
|
122
|
+
// *
|
|
123
|
+
// * Files and symlinks must be leaf models.
|
|
124
|
+
// * Directories must be unloaded or loaded branch models.
|
|
125
|
+
// */
|
|
126
|
+
// export const PosixTreeNodeModelSchema: z.ZodType<PosixTreeNodeModel> = z.lazy(
|
|
127
|
+
// () =>
|
|
128
|
+
// z.union([
|
|
129
|
+
// // Leaf: file
|
|
130
|
+
// z
|
|
131
|
+
// .object({
|
|
132
|
+
// id: posixFilenameSchema,
|
|
133
|
+
// value: PosixFileEntrySchema,
|
|
134
|
+
// })
|
|
135
|
+
// .strict(),
|
|
136
|
+
//
|
|
137
|
+
// // Leaf: symlink
|
|
138
|
+
// z
|
|
139
|
+
// .object({
|
|
140
|
+
// id: posixFilenameSchema,
|
|
141
|
+
// value: PosixSymlinkEntrySchema,
|
|
142
|
+
// })
|
|
143
|
+
// .strict(),
|
|
144
|
+
//
|
|
145
|
+
// // Unloaded branch: directory
|
|
146
|
+
// z
|
|
147
|
+
// .object({
|
|
148
|
+
// id: posixFilenameSchema,
|
|
149
|
+
// value: PosixDirectoryEntrySchema,
|
|
150
|
+
// children: z.null(),
|
|
151
|
+
// })
|
|
152
|
+
// .strict(),
|
|
153
|
+
//
|
|
154
|
+
// // Loaded branch: directory
|
|
155
|
+
// z
|
|
156
|
+
// .object({
|
|
157
|
+
// id: posixFilenameSchema,
|
|
158
|
+
// value: PosixDirectoryEntrySchema,
|
|
159
|
+
// children: z.array(PosixTreeNodeModelSchema),
|
|
160
|
+
// })
|
|
161
|
+
// .strict(),
|
|
162
|
+
// ]),
|
|
163
|
+
// );
|
|
164
|
+
// /**
|
|
165
|
+
// * Decodes validated external data into the opaque domain type.
|
|
166
|
+
// *
|
|
167
|
+
// * `fromModel` additionally checks sibling-name uniqueness. That validation is
|
|
168
|
+
// * separate from Zod's object-shape validation.
|
|
169
|
+
// */
|
|
170
|
+
// export function decodePosixTreeNode(input: unknown): PosixTreeNode | undefined {
|
|
171
|
+
// const model = PosixTreeNodeModelSchema.safeParse(input);
|
|
172
|
+
//
|
|
173
|
+
// if (!model.success) {
|
|
174
|
+
// return undefined;
|
|
175
|
+
// }
|
|
176
|
+
//
|
|
177
|
+
// const node = PosixTreeNodeApi.fromModel(model.data);
|
|
178
|
+
//
|
|
179
|
+
// if (node === undefined) {
|
|
180
|
+
// return undefined;
|
|
181
|
+
// }
|
|
182
|
+
//
|
|
183
|
+
// return PosixTreeNode.isValid(node) ? node : undefined;
|
|
184
|
+
// }
|
|
185
|
+
//
|
|
186
|
+
// export function encodePosixTreeNode(node: PosixTreeNode): PosixTreeNodeModel {
|
|
187
|
+
// return PosixTreeNodeApi.toModel(node);
|
|
188
|
+
// }
|
|
189
|
+
// // -----------------------------------------------------------------------------
|
|
190
|
+
// // PosixFolds
|
|
191
|
+
// // -----------------------------------------------------------------------------
|
|
192
|
+
//
|
|
193
|
+
// export type PosixFoldsModel = FoldsModel<PosixId>;
|
|
194
|
+
//
|
|
195
|
+
// export const PosixFoldsModelSchema: z.ZodType<PosixFoldsModel> =
|
|
196
|
+
// createFoldsModelSchema(posixFilenameSchema);
|
|
197
|
+
//
|
|
198
|
+
// // -----------------------------------------------------------------------------
|
|
199
|
+
// // PosixCursor
|
|
200
|
+
// // -----------------------------------------------------------------------------
|
|
201
|
+
//
|
|
202
|
+
// export const PosixCursorSchema: z.ZodType<PosixCursor> =
|
|
203
|
+
// createCursorSchema(posixFilenameSchema);
|
|
204
|
+
//
|
|
205
|
+
// export type PosixCursor = Cursor<PosixId>;
|
|
206
|
+
//
|
|
207
|
+
// // -----------------------------------------------------------------------------
|
|
208
|
+
// // PosixState
|
|
209
|
+
// // -----------------------------------------------------------------------------
|
|
210
|
+
//
|
|
211
|
+
// export type PosixStateModel = StateModel<PosixId, PosixValue>;
|
|
212
|
+
//
|
|
213
|
+
// /**
|
|
214
|
+
// * The state schema should operate on a serializable tree *model*, then decode
|
|
215
|
+
// * it to opaque nodes. Do not try to make Zod construct TreeNode directly.
|
|
216
|
+
// */
|
|
217
|
+
// export const PosixStateModelSchema: z.ZodType<PosixStateModel> =
|
|
218
|
+
// createStateModelSchema(
|
|
219
|
+
// posixTreeNodeModelSchema,
|
|
220
|
+
// PosixFoldsModelSchema,
|
|
221
|
+
// PosixCursorSchema,
|
|
222
|
+
// );
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-file-view-api.d.ts","sourceRoot":"","sources":["../../src/infrastructure/create-file-view-api.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"create-file-view-api.d.ts","sourceRoot":"","sources":["../../src/infrastructure/create-file-view-api.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EACV,eAAe,EACf,KAAK,EACL,UAAU,EACV,OAAO,EAER,MAAM,WAAW,CAAC;AAInB;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,CACpB,EAAE,SAAS,eAAe,EAC1B,KAAK,EACL,WAAW,SAAS,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,IACvC,QAAQ,CAAC;IACX,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/B,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,KAAK,WAAW,CAAC;IAOjD,MAAM,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,SAAS,CAAC;CAC9D,CAAC,CAAC;AA2BH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAC/B,EAAE,SAAS,eAAe,EAC1B,KAAK,EACL,WAAW,SAAS,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,EACzC,GAAG,EACH,EACA,SAAS,EACT,SAAS,EACT,UAAU,GACX,EAAE;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,CAAC;IAChC,UAAU,EAAE,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;CAChD,GAAG,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,GAAG,CAAC,CAkKjC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { TreeNode } from 'dirvi-lib';
|
|
2
|
-
import {
|
|
3
|
-
import { UnixAbsolutePath } from '../domain/unix-path.js';
|
|
4
|
-
export declare function getDirEntries(address: UnixAbsolutePath): Promise<TreeNode<
|
|
1
|
+
import type { TreeNode, TreeNodeApi } from 'dirvi-lib';
|
|
2
|
+
import { type PosixValue, type PosixId } from '../domain/posix-tree.js';
|
|
3
|
+
import { type UnixAbsolutePath } from '../domain/unix-path.js';
|
|
4
|
+
export declare function getDirEntries(treeNodeApi: TreeNodeApi<PosixId, PosixValue>, address: UnixAbsolutePath): Promise<TreeNode<PosixId, PosixValue>[]>;
|
|
5
5
|
//# sourceMappingURL=get-dir-entries.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-dir-entries.d.ts","sourceRoot":"","sources":["../../src/infrastructure/get-dir-entries.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"get-dir-entries.d.ts","sourceRoot":"","sources":["../../src/infrastructure/get-dir-entries.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAEvD,OAAO,EACL,KAAK,UAAU,EACf,KAAK,OAAO,EAIb,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,KAAK,gBAAgB,EAAkB,MAAM,wBAAwB,CAAC;AAE/E,wBAAsB,aAAa,CACjC,WAAW,EAAE,WAAW,CAAC,OAAO,EAAE,UAAU,CAAC,EAC7C,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,CAAC,CA+B1C"}
|
|
@@ -1,22 +1,23 @@
|
|
|
1
|
-
import { PosixNameSchema, PosixTreeNode, } from '../domain/posix-tree.js';
|
|
2
|
-
import { UnixPathSchema } from '../domain/unix-path.js';
|
|
3
1
|
import { readdir, readlink } from 'node:fs/promises';
|
|
4
2
|
import { join } from 'node:path';
|
|
5
|
-
|
|
3
|
+
import { posixFilenameSchema, createConstructors, } from '../domain/posix-tree.js';
|
|
4
|
+
import { UnixPathSchema } from '../domain/unix-path.js';
|
|
5
|
+
export async function getDirEntries(treeNodeApi, address) {
|
|
6
6
|
const directoryEntries = await readdir(address, {
|
|
7
7
|
withFileTypes: true,
|
|
8
8
|
});
|
|
9
|
+
const constructors = createConstructors(treeNodeApi);
|
|
9
10
|
return Promise.all(directoryEntries.map(async (directoryEntry) => {
|
|
10
|
-
const id =
|
|
11
|
+
const id = posixFilenameSchema.parse(directoryEntry.name);
|
|
11
12
|
if (directoryEntry.isSymbolicLink()) {
|
|
12
13
|
const target = UnixPathSchema.parse(await readlink(join(address, directoryEntry.name)));
|
|
13
|
-
return
|
|
14
|
+
return constructors.symlink(id, target);
|
|
14
15
|
}
|
|
15
16
|
if (directoryEntry.isDirectory()) {
|
|
16
|
-
return
|
|
17
|
+
return constructors.unloadedDirectory(id);
|
|
17
18
|
}
|
|
18
19
|
if (directoryEntry.isFile()) {
|
|
19
|
-
return
|
|
20
|
+
return constructors.file(id);
|
|
20
21
|
}
|
|
21
22
|
throw new Error(`Unsupported filesystem entry "${join(address, directoryEntry.name)}"`);
|
|
22
23
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-unix-abs-path.d.ts","sourceRoot":"","sources":["../../src/infrastructure/get-unix-abs-path.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"get-unix-abs-path.d.ts","sourceRoot":"","sources":["../../src/infrastructure/get-unix-abs-path.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,gBAAgB,EAEjB,MAAM,wBAAwB,CAAC;AAEhC,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,CAgBlE"}
|
|
@@ -1,10 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
import { UnixAbsolutePath } from '../domain/unix-path.js';
|
|
3
|
-
import type { AppApi } from 'dirvi-apis';
|
|
4
|
-
/**
|
|
5
|
-
* Creates the AppApi for the POSIX app.
|
|
6
|
-
*
|
|
7
|
-
* @param directory - optional directory path for loading the app not at the cwd.
|
|
8
|
-
*/
|
|
9
|
-
export declare function loadNodePosixAppApi(directory?: string): AppApi<PosixName, PosixEntry, UnixAbsolutePath>;
|
|
1
|
+
export declare function createFsResyncSubscription(directory: string): (listener: () => void) => () => void;
|
|
10
2
|
//# sourceMappingURL=load-node-posix-app-api.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load-node-posix-app-api.d.ts","sourceRoot":"","sources":["../../src/infrastructure/load-node-posix-app-api.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"load-node-posix-app-api.d.ts","sourceRoot":"","sources":["../../src/infrastructure/load-node-posix-app-api.ts"],"names":[],"mappings":"AAwEA,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,MAAM,GAChB,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CA6EtC"}
|
|
@@ -1,112 +1,73 @@
|
|
|
1
|
-
import { basename, join } from 'node:path';
|
|
2
1
|
import { watch } from 'node:fs';
|
|
3
|
-
import { getUnixAbsPath } from './get-unix-abs-path.js';
|
|
4
|
-
import { getDirEntries } from './get-dir-entries.js';
|
|
5
|
-
import envPaths from 'env-paths';
|
|
6
|
-
import { createFileViewApi } from './create-file-view-api.js';
|
|
7
|
-
import { createHash } from 'node:crypto';
|
|
8
|
-
import { PosixCursorApi, PosixFoldsApi, PosixNameSchema, PosixNavApi, PosixStateModelSchema, PosixTreeNode, PosixTreeNodeApi, } from '../domain/posix-tree.js';
|
|
9
|
-
import { createAppStateApis } from 'dirvi-lib';
|
|
10
2
|
// ---*--- App Data ---*---
|
|
11
3
|
// Paths for app data:
|
|
12
|
-
const environmentPaths = envPaths('dirvi');
|
|
13
|
-
const posixAppDataDirectory = join(environmentPaths.data, 'apps', 'posix');
|
|
14
|
-
const posixAppViewsDirectory = join(posixAppDataDirectory, 'views');
|
|
15
|
-
//
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
function loadBranches(path) {
|
|
76
|
-
const address = join(unixAbsPath, ...path);
|
|
77
|
-
return getDirEntries(address);
|
|
78
|
-
}
|
|
79
|
-
return {
|
|
80
|
-
appId: 'posix',
|
|
81
|
-
name: unixAbsPath,
|
|
82
|
-
rootId,
|
|
83
|
-
loadBranches,
|
|
84
|
-
createRoot: async () => {
|
|
85
|
-
// Start with root branches already loaded
|
|
86
|
-
const rootBranches = await loadBranches([]);
|
|
87
|
-
const root = PosixTreeNode.loadedDirectory(rootId, rootBranches);
|
|
88
|
-
if (root === undefined) {
|
|
89
|
-
throw new Error('Cannot create POSIX root: duplicate directory entry names');
|
|
90
|
-
}
|
|
91
|
-
return root;
|
|
92
|
-
},
|
|
93
|
-
subscribeToResync: createFsResyncSubscription(join(unixAbsPath)),
|
|
94
|
-
// The key for the Posix app instance is just the directory working in:
|
|
95
|
-
viewKey: unixAbsPath,
|
|
96
|
-
viewApi: createFileViewApi({
|
|
97
|
-
directory: posixAppViewsDirectory,
|
|
98
|
-
encodeKey,
|
|
99
|
-
stateCodec: posixStateCodec,
|
|
100
|
-
}),
|
|
101
|
-
foldsApi: PosixFoldsApi,
|
|
102
|
-
navNodeApi: PosixNavApi,
|
|
103
|
-
...apis,
|
|
104
|
-
};
|
|
105
|
-
}
|
|
4
|
+
// const environmentPaths = envPaths('dirvi');
|
|
5
|
+
// const posixAppDataDirectory = join(environmentPaths.data, 'apps', 'posix');
|
|
6
|
+
// const posixAppViewsDirectory = join(posixAppDataDirectory, 'views');
|
|
7
|
+
//
|
|
8
|
+
// // Helpers for saving app data:
|
|
9
|
+
// function encodeKey(key: UnixAbsolutePath): string {
|
|
10
|
+
// return createHash('sha256').update(key).digest('hex');
|
|
11
|
+
// }
|
|
12
|
+
//
|
|
13
|
+
// /**
|
|
14
|
+
// * Persists public POSIX state models while keeping TreeNode and Folds runtime
|
|
15
|
+
// * representations opaque.
|
|
16
|
+
// */
|
|
17
|
+
// const posixStateCodec: StateCodec<PosixId, PosixValue, PosixStateModel> = {
|
|
18
|
+
// schema: PosixStateModelSchema,
|
|
19
|
+
// encode: encodePosixState,
|
|
20
|
+
// decode: decodePosixState,
|
|
21
|
+
// };
|
|
22
|
+
//
|
|
23
|
+
// /**
|
|
24
|
+
// * Converts opaque POSIX runtime state into its serializable persistence model.
|
|
25
|
+
// */
|
|
26
|
+
// function encodePosixState(state: PosixState): PosixStateModel {
|
|
27
|
+
// return {
|
|
28
|
+
// root: PosixTreeNodeApi.toModel(state.root),
|
|
29
|
+
// folds: PosixFoldsApi.toModel(state.folds),
|
|
30
|
+
// cursor: PosixCursorApi.getPath(state.cursor),
|
|
31
|
+
// };
|
|
32
|
+
// }
|
|
33
|
+
//
|
|
34
|
+
// /**
|
|
35
|
+
// * Restores opaque POSIX runtime state from a schema-validated model.
|
|
36
|
+
// *
|
|
37
|
+
// * `TreeNodeApi.fromModel` performs the structural sibling-ID uniqueness check
|
|
38
|
+
// * which cannot be fully expressed by the JSON/Zod model schema.
|
|
39
|
+
// */
|
|
40
|
+
// function decodePosixState(model: PosixStateModel): PosixState | undefined {
|
|
41
|
+
// const root = PosixTreeNodeApi.fromModel(model.root);
|
|
42
|
+
//
|
|
43
|
+
// /*
|
|
44
|
+
// * State requires an open root branch. The POSIX domain additionally requires
|
|
45
|
+
// * files and symlinks to be leaves, and directories to be branches.
|
|
46
|
+
// */
|
|
47
|
+
// if (
|
|
48
|
+
// root === undefined ||
|
|
49
|
+
// !PosixTreeNode.isValid(root) ||
|
|
50
|
+
// PosixTreeNodeApi.kind(root) !== 'loaded-branch'
|
|
51
|
+
// ) {
|
|
52
|
+
// return undefined;
|
|
53
|
+
// }
|
|
54
|
+
//
|
|
55
|
+
// const folds = PosixFoldsApi.fromModel(model.folds);
|
|
56
|
+
//
|
|
57
|
+
// if (folds === undefined) {
|
|
58
|
+
// return undefined;
|
|
59
|
+
// }
|
|
60
|
+
//
|
|
61
|
+
// return {
|
|
62
|
+
// root,
|
|
63
|
+
// folds,
|
|
64
|
+
// cursor: PosixCursorApi.getPath(model.cursor),
|
|
65
|
+
// };
|
|
66
|
+
// }
|
|
106
67
|
// `recursive: true` is supported by macOS and Windows, but
|
|
107
68
|
// recursive watching is not supported on all Node/POSIX
|
|
108
69
|
// platforms: Linux unsupported.
|
|
109
|
-
function createFsResyncSubscription(directory) {
|
|
70
|
+
export function createFsResyncSubscription(directory) {
|
|
110
71
|
const listeners = new Set();
|
|
111
72
|
let watcher;
|
|
112
73
|
let notificationTimer;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import type { AppPlugin } from 'dirvi-apis
|
|
1
|
+
import type { AppPlugin } from 'dirvi-apis';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Creates applicator of AppDefinition.
|
|
4
|
+
*
|
|
5
|
+
* Input for this app is the absolute path to the directory to open on.
|
|
4
6
|
*/
|
|
5
7
|
export declare const posixAppPlugin: AppPlugin;
|
|
6
8
|
//# sourceMappingURL=posix-fs-dirvi-app.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"posix-fs-dirvi-app.d.ts","sourceRoot":"","sources":["../src/posix-fs-dirvi-app.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"posix-fs-dirvi-app.d.ts","sourceRoot":"","sources":["../src/posix-fs-dirvi-app.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAa5C;;;;GAIG;AACH,eAAO,MAAM,cAAc,EAAE,SAwD5B,CAAC"}
|
|
@@ -1,12 +1,45 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { basename, join } from 'node:path';
|
|
2
|
+
import { posixFilenameSchema, posixValueSchema, createConstructors, } from './domain/posix-tree.js';
|
|
3
|
+
import { createFsResyncSubscription } from './infrastructure/load-node-posix-app-api.js';
|
|
4
|
+
import { getUnixAbsPath } from './infrastructure/get-unix-abs-path.js';
|
|
5
|
+
import { getDirEntries } from './infrastructure/get-dir-entries.js';
|
|
2
6
|
/**
|
|
3
|
-
*
|
|
7
|
+
* Creates applicator of AppDefinition.
|
|
8
|
+
*
|
|
9
|
+
* Input for this app is the absolute path to the directory to open on.
|
|
4
10
|
*/
|
|
5
11
|
export const posixAppPlugin = {
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
12
|
+
createAppDefinitionApplicator: (input) => {
|
|
13
|
+
const unixAbsPath = getUnixAbsPath(input ?? process.cwd());
|
|
14
|
+
const rootId = posixFilenameSchema.parse(basename(unixAbsPath));
|
|
15
|
+
function loadDirectoryEntries(treeNodeApi, path) {
|
|
16
|
+
const address = join(unixAbsPath, ...path);
|
|
17
|
+
return getDirEntries(treeNodeApi, address);
|
|
18
|
+
}
|
|
19
|
+
const appDefinition = {
|
|
20
|
+
displayName: `POSIX: ${input}`,
|
|
21
|
+
rootId,
|
|
22
|
+
idSchema: posixFilenameSchema,
|
|
23
|
+
valueSchema: posixValueSchema,
|
|
24
|
+
createRoot: async (treeNodeApi) => {
|
|
25
|
+
// Start with root branches already loaded
|
|
26
|
+
const rootBranches = await loadDirectoryEntries(treeNodeApi, []);
|
|
27
|
+
const root = createConstructors(treeNodeApi).loadedDirectory(rootId, rootBranches);
|
|
28
|
+
if (root === undefined) {
|
|
29
|
+
throw new Error('Cannot create POSIX root: duplicate directory entry names');
|
|
30
|
+
}
|
|
31
|
+
return root;
|
|
32
|
+
},
|
|
33
|
+
loadChildren: (treeNodeApi, path) => loadDirectoryEntries(treeNodeApi, path),
|
|
34
|
+
subscribeToResync: createFsResyncSubscription(join(unixAbsPath)),
|
|
35
|
+
createNavNodeApiOptions: {
|
|
36
|
+
compareSiblings: (left, right) => {
|
|
37
|
+
return left.id.localeCompare(right.id);
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
return (appDefinitionConsumer) => {
|
|
42
|
+
return appDefinitionConsumer(appDefinition);
|
|
10
43
|
};
|
|
11
44
|
},
|
|
12
45
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mak-98/posix-fs-dirvi-app",
|
|
3
|
-
"version": "0.11.0-beta.
|
|
3
|
+
"version": "0.11.0-beta.4",
|
|
4
4
|
"description": "POSIX filesystem app for dirvi.",
|
|
5
5
|
"license": "GPL-3.0-or-later",
|
|
6
6
|
"type": "module",
|
|
@@ -19,12 +19,12 @@
|
|
|
19
19
|
"node": ">=22"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"dirvi-apis": "0.11.0-beta.
|
|
23
|
-
"dirvi-lib": "0.11.0-beta.1",
|
|
22
|
+
"dirvi-apis": "0.11.0-beta.4",
|
|
24
23
|
"zod": "^4.4.3",
|
|
25
24
|
"env-paths": "^4.0.0"
|
|
26
25
|
},
|
|
27
26
|
"devDependencies": {
|
|
27
|
+
"dirvi-lib": "0.11.0-beta.4",
|
|
28
28
|
"@types/node": "^22.0.0",
|
|
29
29
|
"typescript": "^5.0.0"
|
|
30
30
|
},
|