@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.
@@ -1,12 +1,20 @@
1
1
  import { z } from 'zod';
2
- import { NavNode, SerializableKey, State, TreeNode, TreeNodeModel, Folds, FoldsModel, Cursor, StateModel } from 'dirvi-lib';
2
+ import type { TreeNode, TreeNodeApi } from 'dirvi-lib';
3
3
  import { UnixPath } from './unix-path.js';
4
- export declare const PosixNameSchema: z.ZodPipe<z.ZodType<SerializableKey, unknown, z.core.$ZodTypeInternals<SerializableKey, unknown>>, z.ZodString>;
5
- export type PosixName = z.output<typeof PosixNameSchema>;
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 PosixEntry = Readonly<{
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 declare const PosixEntrySchema: z.ZodType<PosixEntry>;
18
- /**
19
- * An opaque tree whose IDs are POSIX entry names and whose values describe
20
- * POSIX entry semantics.
21
- */
22
- export type PosixTreeNode = TreeNode<PosixName, PosixEntry>;
23
- export declare const PosixTreeNodeApi: Readonly<{
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":"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"}
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
- // PosixName
4
+ // PosixId: Id extends SerializableKey
6
5
  // -----------------------------------------------------------------------------
7
- export const PosixNameSchema = serializableKeySchema.pipe(z
8
- .string()
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 cannot be '.' or '..'.",
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 PosixEntrySchema = z.discriminatedUnion('kind', [PosixFileEntrySchema, PosixSymlinkEntrySchema, PosixDirectoryEntrySchema]);
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 const PosixTreeNode = {
38
- file(name) {
39
- return PosixTreeNodeApi.createLeaf(name, {
40
- kind: 'file',
41
- });
42
- },
43
- symlink(name, target) {
44
- return PosixTreeNodeApi.createLeaf(name, {
45
- kind: 'symlink',
46
- target,
47
- });
48
- },
49
- unloadedDirectory(name) {
50
- return PosixTreeNodeApi.createUnloadedBranch(name, {
51
- kind: 'directory',
52
- });
53
- },
54
- loadedDirectory(name, children) {
55
- return PosixTreeNodeApi.createLoadedBranch(name, { kind: 'directory' }, children);
56
- },
57
- /**
58
- * Runtime domain invariant check.
59
- *
60
- * A file and symlink must be leaves. A directory must be a branch, whether
61
- * loaded or unloaded.
62
- */
63
- isValid(node) {
64
- const entry = PosixTreeNodeApi.value(node);
65
- const treeKind = PosixTreeNodeApi.kind(node);
66
- switch (entry.kind) {
67
- case 'file':
68
- case 'symlink':
69
- return treeKind === 'leaf';
70
- case 'directory':
71
- return treeKind === 'unloaded-branch' || treeKind === 'loaded-branch';
72
- }
73
- },
74
- /**
75
- * Adds or replaces the loaded children of a directory.
76
- *
77
- * Returns `undefined` when:
78
- * - the supplied node is not a directory; or
79
- * - siblings have duplicate names.
80
- */
81
- withLoadedChildren(node, children) {
82
- if (PosixTreeNodeApi.value(node).kind !== 'directory') {
83
- return undefined;
84
- }
85
- return PosixTreeNodeApi.withLoadedChildren(node, children);
86
- },
87
- /**
88
- * Converts a directory to an unloaded directory.
89
- *
90
- * Files and symlinks cannot be converted to branches through this POSIX API.
91
- */
92
- toUnloadedDirectory(node) {
93
- if (PosixTreeNodeApi.value(node).kind !== 'directory') {
94
- return undefined;
95
- }
96
- return PosixTreeNodeApi.toUnloadedBranch(node);
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
- export function encodePosixTreeNode(node) {
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
- // PosixCursor
109
+ // Serializable POSIX model
168
110
  // -----------------------------------------------------------------------------
169
- export const PosixCursorSchema = createCursorSchema(PosixNameSchema);
170
- export const PosixCursorApi = createCursorApi();
171
- export const PosixNavApi = createNavNodeApi(PosixTreeNodeApi, PosixFoldsApi, PosixCursorApi, {
172
- compareEntries(left, right) {
173
- return left.id.localeCompare(right.id);
174
- },
175
- });
176
- export const PosixStateApi = createStateApi(PosixTreeNodeApi, PosixCursorApi);
177
- /**
178
- * The state schema should operate on a serializable tree *model*, then decode
179
- * it to opaque nodes. Do not try to make Zod construct TreeNode directly.
180
- */
181
- export const PosixStateModelSchema = createStateModelSchema(PosixTreeNodeModelSchema, PosixFoldsModelSchema, PosixCursorSchema);
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;AAGxB,OAAO,KAAK,EACV,eAAe,EACf,KAAK,EACL,UAAU,EACV,OAAO,EAER,MAAM,WAAW,CAAC;AAEnB;;;;;;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
+ {"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 { PosixEntry, PosixName } from '../domain/posix-tree.js';
3
- import { UnixAbsolutePath } from '../domain/unix-path.js';
4
- export declare function getDirEntries(address: UnixAbsolutePath): Promise<TreeNode<PosixName, PosixEntry>[]>;
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":"AAAA,OAAO,EAAE,QAAQ,EAAe,MAAM,WAAW,CAAC;AAClD,OAAO,EACL,UAAU,EACV,SAAS,EAGV,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAkB,MAAM,wBAAwB,CAAC;AAI1E,wBAAsB,aAAa,CACjC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE,CAAC,CA8B5C"}
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
- export async function getDirEntries(address) {
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 = PosixNameSchema.parse(directoryEntry.name);
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 PosixTreeNode.symlink(id, target);
14
+ return constructors.symlink(id, target);
14
15
  }
15
16
  if (directoryEntry.isDirectory()) {
16
- return PosixTreeNode.unloadedDirectory(id);
17
+ return constructors.unloadedDirectory(id);
17
18
  }
18
19
  if (directoryEntry.isFile()) {
19
- return PosixTreeNode.file(id);
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":"AACA,OAAO,EACL,gBAAgB,EAEjB,MAAM,wBAAwB,CAAC;AAEhC,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,CAgBlE"}
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
- import { PosixEntry, PosixName } from '../domain/posix-tree.js';
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":"AAQA,OAAO,EAEL,UAAU,EAEV,SAAS,EAQV,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAwEzC;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CAAC,SAAS,EAAE,UAAU,EAAE,gBAAgB,CAAC,CA2CjD"}
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
- // Helpers for saving app data:
16
- function encodeKey(key) {
17
- return createHash('sha256').update(key).digest('hex');
18
- }
19
- /**
20
- * Persists public POSIX state models while keeping TreeNode and Folds runtime
21
- * representations opaque.
22
- */
23
- const posixStateCodec = {
24
- schema: PosixStateModelSchema,
25
- encode: encodePosixState,
26
- decode: decodePosixState,
27
- };
28
- /**
29
- * Converts opaque POSIX runtime state into its serializable persistence model.
30
- */
31
- function encodePosixState(state) {
32
- return {
33
- root: PosixTreeNodeApi.toModel(state.root),
34
- folds: PosixFoldsApi.toModel(state.folds),
35
- cursor: PosixCursorApi.getPath(state.cursor),
36
- };
37
- }
38
- /**
39
- * Restores opaque POSIX runtime state from a schema-validated model.
40
- *
41
- * `TreeNodeApi.fromModel` performs the structural sibling-ID uniqueness check
42
- * which cannot be fully expressed by the JSON/Zod model schema.
43
- */
44
- function decodePosixState(model) {
45
- const root = PosixTreeNodeApi.fromModel(model.root);
46
- /*
47
- * State requires an open root branch. The POSIX domain additionally requires
48
- * files and symlinks to be leaves, and directories to be branches.
49
- */
50
- if (root === undefined ||
51
- !PosixTreeNode.isValid(root) ||
52
- PosixTreeNodeApi.kind(root) !== 'loaded-branch') {
53
- return undefined;
54
- }
55
- const folds = PosixFoldsApi.fromModel(model.folds);
56
- if (folds === undefined) {
57
- return undefined;
58
- }
59
- return {
60
- root,
61
- folds,
62
- cursor: PosixCursorApi.getPath(model.cursor),
63
- };
64
- }
65
- // --- Creating Posix App API ---
66
- /**
67
- * Creates the AppApi for the POSIX app.
68
- *
69
- * @param directory - optional directory path for loading the app not at the cwd.
70
- */
71
- export function loadNodePosixAppApi(directory) {
72
- const unixAbsPath = getUnixAbsPath(directory ?? process.cwd());
73
- const rootId = PosixNameSchema.parse(basename(unixAbsPath));
74
- const apis = createAppStateApis();
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/plugin';
1
+ import type { AppPlugin } from 'dirvi-apis';
2
2
  /**
3
- * A dirvi app that exposes a POSIX filesystem as a navigable tree.
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":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAInD;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,SAQ5B,CAAC"}
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 { loadNodePosixAppApi } from './infrastructure/load-node-posix-app-api.js';
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
- * A dirvi app that exposes a POSIX filesystem as a navigable tree.
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
- createAppApiApplicator: (input) => {
7
- const appApi = loadNodePosixAppApi(input);
8
- return (appApiConsumer) => {
9
- return appApiConsumer(appApi);
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.2",
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.1",
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
  },