dirvi-lib 0.4.0 → 0.5.0

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.
Files changed (119) hide show
  1. package/dist/domain/posix-node.d.ts +29 -0
  2. package/dist/domain/posix-node.d.ts.map +1 -0
  3. package/dist/domain/posix-node.js +20 -0
  4. package/dist/domain/unix-path.d.ts +1 -1
  5. package/dist/domain/unix-path.js +6 -9
  6. package/dist/index.d.ts +9 -14
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +8 -13
  9. package/dist/tree-surfer/cursor.d.ts +24 -0
  10. package/dist/tree-surfer/cursor.d.ts.map +1 -0
  11. package/dist/tree-surfer/cursor.js +65 -0
  12. package/dist/tree-surfer/fold-node/fold-node.impl.d.ts +5 -0
  13. package/dist/tree-surfer/fold-node/fold-node.impl.d.ts.map +1 -0
  14. package/dist/tree-surfer/fold-node/fold-node.impl.js +143 -0
  15. package/dist/tree-surfer/fold-node/fold-node.types.d.ts +70 -0
  16. package/dist/tree-surfer/fold-node/fold-node.types.d.ts.map +1 -0
  17. package/dist/tree-surfer/fold-node/fold-node.types.js +1 -0
  18. package/dist/tree-surfer/index.d.ts +9 -0
  19. package/dist/tree-surfer/index.d.ts.map +1 -0
  20. package/dist/tree-surfer/index.js +8 -0
  21. package/dist/tree-surfer/nav-node/nav-node.impl.d.ts +6 -0
  22. package/dist/tree-surfer/nav-node/nav-node.impl.d.ts.map +1 -0
  23. package/dist/tree-surfer/nav-node/nav-node.impl.js +191 -0
  24. package/dist/tree-surfer/nav-node/nav-node.types.d.ts +42 -0
  25. package/dist/tree-surfer/nav-node/nav-node.types.d.ts.map +1 -0
  26. package/dist/tree-surfer/nav-node/nav-node.types.js +3 -0
  27. package/dist/tree-surfer/state.d.ts +19 -0
  28. package/dist/tree-surfer/state.d.ts.map +1 -0
  29. package/dist/tree-surfer/state.js +109 -0
  30. package/dist/tree-surfer/tree-node/tree-node.arb.d.ts +31 -0
  31. package/dist/tree-surfer/tree-node/tree-node.arb.d.ts.map +1 -0
  32. package/dist/tree-surfer/tree-node/tree-node.arb.js +80 -0
  33. package/dist/tree-surfer/tree-node/tree-node.impl.d.ts +13 -0
  34. package/dist/tree-surfer/tree-node/tree-node.impl.d.ts.map +1 -0
  35. package/dist/tree-surfer/tree-node/tree-node.impl.js +87 -0
  36. package/dist/tree-surfer/tree-node/tree-node.test.d.ts +2 -0
  37. package/dist/tree-surfer/tree-node/tree-node.test.d.ts.map +1 -0
  38. package/dist/tree-surfer/tree-node/tree-node.test.js +117 -0
  39. package/dist/tree-surfer/tree-node/tree-node.types.d.ts +184 -0
  40. package/dist/tree-surfer/tree-node/tree-node.types.d.ts.map +1 -0
  41. package/dist/tree-surfer/tree-node/tree-node.types.js +12 -0
  42. package/dist/tree-surfer-ui/application/index.d.ts +3 -0
  43. package/dist/tree-surfer-ui/application/index.d.ts.map +1 -0
  44. package/dist/tree-surfer-ui/application/index.js +2 -0
  45. package/dist/tree-surfer-ui/application/intent-to-effect-no-state.test.d.ts +2 -0
  46. package/dist/tree-surfer-ui/application/intent-to-effect-no-state.test.d.ts.map +1 -0
  47. package/dist/tree-surfer-ui/application/intent-to-effect-no-state.test.js +192 -0
  48. package/dist/tree-surfer-ui/application/intent-to-effect.d.ts +6 -0
  49. package/dist/tree-surfer-ui/application/intent-to-effect.d.ts.map +1 -0
  50. package/dist/tree-surfer-ui/application/intent-to-effect.js +137 -0
  51. package/dist/tree-surfer-ui/application/user-input-to-intent.d.ts +3 -0
  52. package/dist/tree-surfer-ui/application/user-input-to-intent.d.ts.map +1 -0
  53. package/dist/tree-surfer-ui/application/user-input-to-intent.js +98 -0
  54. package/dist/tree-surfer-ui/application/user-input-to-intent.test.d.ts +2 -0
  55. package/dist/tree-surfer-ui/application/user-input-to-intent.test.d.ts.map +1 -0
  56. package/dist/tree-surfer-ui/application/user-input-to-intent.test.js +118 -0
  57. package/dist/tree-surfer-ui/domain/effect.d.ts +36 -0
  58. package/dist/tree-surfer-ui/domain/effect.d.ts.map +1 -0
  59. package/dist/tree-surfer-ui/domain/index.d.ts +5 -0
  60. package/dist/tree-surfer-ui/domain/index.d.ts.map +1 -0
  61. package/dist/tree-surfer-ui/domain/index.js +4 -0
  62. package/dist/tree-surfer-ui/domain/input-state.d.ts +8 -0
  63. package/dist/tree-surfer-ui/domain/input-state.d.ts.map +1 -0
  64. package/dist/tree-surfer-ui/domain/intent.d.ts +25 -0
  65. package/dist/tree-surfer-ui/domain/intent.d.ts.map +1 -0
  66. package/dist/tree-surfer-ui/domain/user-input.d.ts +19 -0
  67. package/dist/tree-surfer-ui/domain/user-input.d.ts.map +1 -0
  68. package/package.json +3 -2
  69. package/dist/application/intent-to-effect-no-state.test.d.ts +0 -2
  70. package/dist/application/intent-to-effect-no-state.test.d.ts.map +0 -1
  71. package/dist/application/intent-to-effect-no-state.test.js +0 -178
  72. package/dist/application/intent-to-effect.d.ts +0 -8
  73. package/dist/application/intent-to-effect.d.ts.map +0 -1
  74. package/dist/application/intent-to-effect.js +0 -142
  75. package/dist/application/intent-to-effect.test-no-state.d.ts +0 -2
  76. package/dist/application/intent-to-effect.test-no-state.d.ts.map +0 -1
  77. package/dist/application/intent-to-effect.test-no-state.js +0 -178
  78. package/dist/application/user-input-to-intent.d.ts +0 -8
  79. package/dist/application/user-input-to-intent.d.ts.map +0 -1
  80. package/dist/application/user-input-to-intent.js +0 -98
  81. package/dist/application/user-input-to-intent.test.d.ts +0 -2
  82. package/dist/application/user-input-to-intent.test.d.ts.map +0 -1
  83. package/dist/application/user-input-to-intent.test.js +0 -125
  84. package/dist/domain/cursor.d.ts +0 -19
  85. package/dist/domain/cursor.d.ts.map +0 -1
  86. package/dist/domain/cursor.js +0 -46
  87. package/dist/domain/display-row.d.ts +0 -34
  88. package/dist/domain/display-row.d.ts.map +0 -1
  89. package/dist/domain/display-row.js +0 -33
  90. package/dist/domain/effect.d.ts +0 -48
  91. package/dist/domain/effect.d.ts.map +0 -1
  92. package/dist/domain/fold-node.d.ts +0 -25
  93. package/dist/domain/fold-node.d.ts.map +0 -1
  94. package/dist/domain/fold-node.js +0 -93
  95. package/dist/domain/input-state.d.ts +0 -10
  96. package/dist/domain/input-state.d.ts.map +0 -1
  97. package/dist/domain/intent.d.ts +0 -34
  98. package/dist/domain/intent.d.ts.map +0 -1
  99. package/dist/domain/navigation-node.d.ts +0 -58
  100. package/dist/domain/navigation-node.d.ts.map +0 -1
  101. package/dist/domain/navigation-node.js +0 -210
  102. package/dist/domain/state.d.ts +0 -12
  103. package/dist/domain/state.d.ts.map +0 -1
  104. package/dist/domain/state.js +0 -12
  105. package/dist/domain/unix-entry.d.ts +0 -44
  106. package/dist/domain/unix-entry.d.ts.map +0 -1
  107. package/dist/domain/unix-entry.js +0 -108
  108. package/dist/domain/user-input.d.ts +0 -27
  109. package/dist/domain/user-input.d.ts.map +0 -1
  110. package/dist/infrastructure/get-cwd.d.ts +0 -3
  111. package/dist/infrastructure/get-cwd.d.ts.map +0 -1
  112. package/dist/infrastructure/get-cwd.js +0 -15
  113. package/dist/infrastructure/get-dir-lazy-entries.d.ts +0 -6
  114. package/dist/infrastructure/get-dir-lazy-entries.d.ts.map +0 -1
  115. package/dist/infrastructure/get-dir-lazy-entries.js +0 -40
  116. /package/dist/{domain → tree-surfer-ui/domain}/effect.js +0 -0
  117. /package/dist/{domain → tree-surfer-ui/domain}/input-state.js +0 -0
  118. /package/dist/{domain → tree-surfer-ui/domain}/intent.js +0 -0
  119. /package/dist/{domain → tree-surfer-ui/domain}/user-input.js +0 -0
@@ -0,0 +1,29 @@
1
+ import { z } from 'zod';
2
+ import { UnixPath } from './unix-path.js';
3
+ import { Cursor, State } from '../tree-surfer/index.js';
4
+ import { FoldNode } from '../tree-surfer/fold-node/fold-node.types.js';
5
+ import { NavNode } from '../tree-surfer/nav-node/nav-node.types.js';
6
+ export declare const PosixNameSchema: z.ZodString;
7
+ export type PosixName = z.output<typeof PosixNameSchema>;
8
+ export type PosixNode = {
9
+ kind: 'file';
10
+ id: PosixName;
11
+ } | {
12
+ kind: 'symlink';
13
+ id: PosixName;
14
+ target: UnixPath;
15
+ } | {
16
+ kind: 'directory';
17
+ id: PosixName;
18
+ children: PosixNode[] | null;
19
+ };
20
+ export declare const PosixNodeApi: import("../tree-surfer/index.js").TreeNodeApi<string, PosixNode>;
21
+ export type PosixCursor = Cursor<PosixName>;
22
+ export declare const PosixCursorApi: import("../tree-surfer/cursor.js").CursorApi<string>;
23
+ export type PosixFoldNode = FoldNode<PosixName>;
24
+ export declare const PosixFoldNodeApi: import("../tree-surfer/index.js").FoldNodeApi<string>;
25
+ export type PosixNavNode = NavNode<PosixName, PosixNode>;
26
+ export declare const PosixNavApi: import("../tree-surfer/index.js").NavNodeApi<string, PosixNode>;
27
+ export type PosixState = State<PosixName, PosixNode>;
28
+ export declare const PosixStateApi: import("../tree-surfer/state.js").StateApi<string, PosixNode>;
29
+ //# sourceMappingURL=posix-node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"posix-node.d.ts","sourceRoot":"","sources":["../../src/domain/posix-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,OAAO,EAAmC,MAAM,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AACzF,OAAO,EAAE,QAAQ,EAAE,MAAM,6CAA6C,CAAC;AAEvE,OAAO,EAAE,OAAO,EAAE,MAAM,2CAA2C,CAAC;AAIpE,eAAO,MAAM,eAAe,aAQxB,CAAC;AAEL,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,eAAe,CAAC,CAAC;AAGzD,MAAM,MAAM,SAAS,GACjB;IACE,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,SAAS,CAAC;CACf,GACD;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,EAAE,EAAE,SAAS,CAAC;IACd,MAAM,EAAE,QAAQ,CAAC;CAClB,GACD;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,EAAE,EAAE,SAAS,CAAC;IACd,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;CAC9B,CAAC;AAEN,eAAO,MAAM,YAAY,kEAA4C,CAAC;AAStE,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;AAE5C,eAAO,MAAM,cAAc,sDAA+B,CAAC;AAG3D,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;AAEhD,eAAO,MAAM,gBAAgB,uDAAiC,CAAC;AAG/D,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AAEzD,eAAO,MAAM,WAAW,iEAIvB,CAAC;AAGF,MAAM,MAAM,UAAU,GAAG,KAAK,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AAErD,eAAO,MAAM,aAAa,+DAKzB,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { z } from 'zod';
2
+ import { createTreeNodeApi } from '../tree-surfer/tree-node/tree-node.impl.js';
3
+ import { createCursorApi, createStateApi } from '../tree-surfer/index.js';
4
+ import { createFoldNodeApi } from '../tree-surfer/fold-node/fold-node.impl.js';
5
+ import { createNavNodeApi } from '../tree-surfer/nav-node/nav-node.impl.js';
6
+ // Name
7
+ export const PosixNameSchema = z
8
+ .string()
9
+ .min(1)
10
+ .refine((value) => !value.includes('/'), {
11
+ message: "Entry name must not contain '/'",
12
+ })
13
+ .refine((value) => value !== '.' && value !== '..', {
14
+ message: "Entry name cannot be '.' or '..'",
15
+ });
16
+ export const PosixNodeApi = createTreeNodeApi();
17
+ export const PosixCursorApi = createCursorApi();
18
+ export const PosixFoldNodeApi = createFoldNodeApi();
19
+ export const PosixNavApi = createNavNodeApi(PosixNodeApi, PosixFoldNodeApi, PosixCursorApi);
20
+ export const PosixStateApi = createStateApi(PosixNodeApi, PosixFoldNodeApi, PosixCursorApi, PosixNavApi);
@@ -3,4 +3,4 @@ export declare const UnixPathSchema: z.ZodString;
3
3
  export type UnixPath = z.output<typeof UnixPathSchema>;
4
4
  export declare const UnixAbsolutePathSchema: z.ZodString;
5
5
  export type UnixAbsolutePath = z.output<typeof UnixAbsolutePathSchema>;
6
- //# sourceMappingURL=unix-path.d.ts.map
6
+ //# sourceMappingURL=unix-path.d.ts.map
@@ -1,14 +1,11 @@
1
1
  import { z } from 'zod';
2
2
  // UNIX PATHS
3
3
  export const UnixPathSchema = z
4
- .string()
5
- .min(1)
6
- .refine((value) => !value.includes('\0'), {
4
+ .string()
5
+ .min(1)
6
+ .refine((value) => !value.includes('\0'), {
7
7
  message: 'Unix paths must not contain null bytes',
8
- });
9
- export const UnixAbsolutePathSchema = UnixPathSchema.refine(
10
- (value) => value.startsWith('/'),
11
- {
8
+ });
9
+ export const UnixAbsolutePathSchema = UnixPathSchema.refine((value) => value.startsWith('/'), {
12
10
  message: 'Path must be an absolute Unix path',
13
- },
14
- );
11
+ });
package/dist/index.d.ts CHANGED
@@ -1,15 +1,10 @@
1
- export * from './application/user-input-to-intent.js';
2
- export * from './application/intent-to-effect.js';
3
- export * from './domain/cursor.js';
4
- export * from './domain/display-row.js';
5
- export * from './domain/effect.js';
6
- export * from './domain/fold-node.js';
7
- export * from './domain/input-state.js';
8
- export * from './domain/navigation-node.js';
9
- export * from './domain/state.js';
10
- export * from './domain/unix-entry.js';
1
+ export * from './tree-surfer-ui/application/user-input-to-intent.js';
2
+ export * from './tree-surfer-ui/application/intent-to-effect.js';
3
+ export * from './tree-surfer-ui/domain/effect.js';
4
+ export * from './tree-surfer-ui/domain/input-state.js';
5
+ export * from './tree-surfer-ui/domain/intent.js';
6
+ export * from './tree-surfer-ui/domain/user-input.js';
7
+ export * from './tree-surfer/index.js';
8
+ export * from './domain/posix-node.js';
11
9
  export * from './domain/unix-path.js';
12
- export * from './domain/user-input.js';
13
- export * from './infrastructure/get-cwd.js';
14
- export * from './infrastructure/get-dir-lazy-entries.js';
15
- //# sourceMappingURL=index.d.ts.map
10
+ //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uCAAuC,CAAC;AACtD,cAAc,mCAAmC,CAAC;AAElD,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mBAAmB,CAAC;AAClC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AAEvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,0CAA0C,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sDAAsD,CAAC;AACrE,cAAc,kDAAkD,CAAC;AAEjE,cAAc,mCAAmC,CAAC;AAClD,cAAc,wCAAwC,CAAC;AACvD,cAAc,mCAAmC,CAAC;AAClD,cAAc,uCAAuC,CAAC;AAEtD,cAAc,wBAAwB,CAAC;AAEvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC"}
package/dist/index.js CHANGED
@@ -1,14 +1,9 @@
1
- export * from './application/user-input-to-intent.js';
2
- export * from './application/intent-to-effect.js';
3
- export * from './domain/cursor.js';
4
- export * from './domain/display-row.js';
5
- export * from './domain/effect.js';
6
- export * from './domain/fold-node.js';
7
- export * from './domain/input-state.js';
8
- export * from './domain/navigation-node.js';
9
- export * from './domain/state.js';
10
- export * from './domain/unix-entry.js';
1
+ export * from './tree-surfer-ui/application/user-input-to-intent.js';
2
+ export * from './tree-surfer-ui/application/intent-to-effect.js';
3
+ export * from './tree-surfer-ui/domain/effect.js';
4
+ export * from './tree-surfer-ui/domain/input-state.js';
5
+ export * from './tree-surfer-ui/domain/intent.js';
6
+ export * from './tree-surfer-ui/domain/user-input.js';
7
+ export * from './tree-surfer/index.js';
8
+ export * from './domain/posix-node.js';
11
9
  export * from './domain/unix-path.js';
12
- export * from './domain/user-input.js';
13
- export * from './infrastructure/get-cwd.js';
14
- export * from './infrastructure/get-dir-lazy-entries.js';
@@ -0,0 +1,24 @@
1
+ export declare const CursorKind: {
2
+ readonly Entry: "entry";
3
+ readonly Fold: "fold";
4
+ };
5
+ export type CursorKind = (typeof CursorKind)[keyof typeof CursorKind];
6
+ export type CursorEntry<Id> = {
7
+ kind: typeof CursorKind.Entry;
8
+ parentPath: readonly Id[];
9
+ entryId: Id;
10
+ };
11
+ export type CursorFold<Id> = {
12
+ kind: typeof CursorKind.Fold;
13
+ parentPath: readonly Id[];
14
+ };
15
+ export type Cursor<Id> = CursorEntry<Id> | CursorFold<Id>;
16
+ export type CursorApi<Id> = {
17
+ isEntry(cursor: Cursor<Id>): cursor is CursorEntry<Id>;
18
+ isFold(cursor: Cursor<Id>): cursor is CursorFold<Id>;
19
+ equal(left: Cursor<Id>, right: Cursor<Id>): boolean;
20
+ getPath(cursor: Cursor<Id>): Id[] | undefined;
21
+ cursorBelongsToSubtree(cursor: Cursor<Id>, entryPath: readonly Id[]): boolean;
22
+ };
23
+ export declare function createCursorApi<Id>(): CursorApi<Id>;
24
+ //# sourceMappingURL=cursor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../src/tree-surfer/cursor.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU;;;CAGb,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC;AAEtE,MAAM,MAAM,WAAW,CAAC,EAAE,IAAI;IAC5B,IAAI,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAC9B,UAAU,EAAE,SAAS,EAAE,EAAE,CAAC;IAC1B,OAAO,EAAE,EAAE,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,UAAU,CAAC,EAAE,IAAI;IAC3B,IAAI,EAAE,OAAO,UAAU,CAAC,IAAI,CAAC;IAC7B,UAAU,EAAE,SAAS,EAAE,EAAE,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,MAAM,CAAC,EAAE,IAAI,WAAW,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC;AAE1D,MAAM,MAAM,SAAS,CAAC,EAAE,IAAI;IAC1B,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,MAAM,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC;IAEvD,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,MAAM,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IAErD,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC;IAEpD,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,GAAG,SAAS,CAAC;IAE9C,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,GAAG,OAAO,CAAC;CAC/E,CAAC;AAEF,wBAAgB,eAAe,CAAC,EAAE,KAAK,SAAS,CAAC,EAAE,CAAC,CA0CnD"}
@@ -0,0 +1,65 @@
1
+ export const CursorKind = {
2
+ Entry: 'entry',
3
+ Fold: 'fold',
4
+ };
5
+ export function createCursorApi() {
6
+ const cursorApi = {
7
+ isEntry(cursor) {
8
+ return cursor.kind === CursorKind.Entry;
9
+ },
10
+ isFold(cursor) {
11
+ return cursor.kind === CursorKind.Fold;
12
+ },
13
+ equal(left, right) {
14
+ if (!idPathEqual(left.parentPath, right.parentPath)) {
15
+ return false;
16
+ }
17
+ if (cursorApi.isFold(left)) {
18
+ return cursorApi.isFold(right);
19
+ }
20
+ return cursorApi.isEntry(right) && left.entryId === right.entryId;
21
+ },
22
+ getPath(cursor) {
23
+ if (cursorApi.isFold(cursor)) {
24
+ return undefined;
25
+ }
26
+ return [...cursor.parentPath, cursor.entryId];
27
+ },
28
+ cursorBelongsToSubtree(cursor, entryPath) {
29
+ if (cursorApi.isFold(cursor)) {
30
+ return isStrictPathPrefix(entryPath, cursor.parentPath);
31
+ }
32
+ const cursorPath = [...cursor.parentPath, cursor.entryId];
33
+ return isStrictPathPrefix(entryPath, cursorPath);
34
+ },
35
+ };
36
+ return cursorApi;
37
+ }
38
+ /**
39
+ * Returns true when both paths contain the same IDs in the same order.
40
+ */
41
+ function idPathEqual(left, right) {
42
+ if (left.length !== right.length) {
43
+ return false;
44
+ }
45
+ for (let index = 0; index < left.length; index += 1) {
46
+ if (left[index] !== right[index]) {
47
+ return false;
48
+ }
49
+ }
50
+ return true;
51
+ }
52
+ /**
53
+ * Returns true when `prefix` is a strict prefix of `path`.
54
+ */
55
+ function isStrictPathPrefix(prefix, path) {
56
+ if (prefix.length >= path.length) {
57
+ return false;
58
+ }
59
+ for (let index = 0; index < prefix.length; index += 1) {
60
+ if (prefix[index] !== path[index]) {
61
+ return false;
62
+ }
63
+ }
64
+ return true;
65
+ }
@@ -0,0 +1,5 @@
1
+ import { FoldNode, FoldNodeApi, FoldNodeService } from './fold-node.types.js';
2
+ import { SerializableKey } from '../tree-node/tree-node.types.js';
3
+ export declare function createFoldNodeApi<Id extends SerializableKey>(): FoldNodeApi<Id>;
4
+ export declare function createFoldNodeService<Id extends SerializableKey>(foldNodeApi: FoldNodeApi<Id>, createChild: (id: Id) => FoldNode<Id>): FoldNodeService<Id>;
5
+ //# sourceMappingURL=fold-node.impl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fold-node.impl.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/fold-node/fold-node.impl.ts"],"names":[],"mappings":"AACA,OAAO,EACL,QAAQ,EACR,WAAW,EAEX,eAAe,EAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAElE,wBAAgB,iBAAiB,CAAC,EAAE,SAAS,eAAe,KAAK,WAAW,CAAC,EAAE,CAAC,CAiC/E;AAED,wBAAgB,qBAAqB,CAAC,EAAE,SAAS,eAAe,EAC9D,WAAW,EAAE,WAAW,CAAC,EAAE,CAAC,EAC5B,WAAW,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,QAAQ,CAAC,EAAE,CAAC,GACpC,eAAe,CAAC,EAAE,CAAC,CAiLrB"}
@@ -0,0 +1,143 @@
1
+ import { createTreeNodeApi } from '../tree-node/tree-node.impl.js';
2
+ export function createFoldNodeApi() {
3
+ const treeNodeApi = createTreeNodeApi();
4
+ return {
5
+ getChildren(node) {
6
+ return node.children;
7
+ },
8
+ getChildById(node, id) {
9
+ return node.children.find((child) => child.id === id);
10
+ },
11
+ getAtPath(rootNode, path, selector) {
12
+ return treeNodeApi.getAtPath(rootNode.children, path, selector);
13
+ },
14
+ modifyAtPath(rootNode, path, modifier) {
15
+ const children = treeNodeApi.modifyAtPath(rootNode.children, path, modifier);
16
+ if (children === undefined) {
17
+ return undefined;
18
+ }
19
+ return {
20
+ ...rootNode,
21
+ children,
22
+ };
23
+ },
24
+ };
25
+ }
26
+ export function createFoldNodeService(foldNodeApi, createChild) {
27
+ return {
28
+ createEmptyRoot() {
29
+ return {
30
+ children: [],
31
+ folds: new Set(),
32
+ };
33
+ },
34
+ getIfEntryFoldedAtPath(rootNode, path, entryId) {
35
+ if (path.length === 0) {
36
+ return rootNode.folds.has(entryId);
37
+ }
38
+ const node = foldNodeApi.getAtPath(rootNode, path, (candidate) => candidate);
39
+ return node !== undefined && node.folds.has(entryId);
40
+ },
41
+ addFoldedEntryAtPath(rootNode, path, entryId) {
42
+ const ensuredRoot = ensurePath(rootNode, path);
43
+ if (path.length === 0) {
44
+ return addFoldedEntry(ensuredRoot, entryId);
45
+ }
46
+ return foldNodeApi.modifyAtPath(ensuredRoot, path, (node) => addFoldedEntry(node, entryId));
47
+ },
48
+ removeFoldedEntryAtPath(rootNode, path, entryId) {
49
+ if (path.length === 0) {
50
+ return removeFoldedEntry(rootNode, entryId);
51
+ }
52
+ return foldNodeApi.modifyAtPath(rootNode, path, (node) => removeFoldedEntry(node, entryId));
53
+ },
54
+ clearFoldedEntriesAtPath(rootNode, path) {
55
+ if (path.length === 0) {
56
+ return clearFoldedEntries(rootNode);
57
+ }
58
+ return foldNodeApi.modifyAtPath(rootNode, path, clearFoldedEntries);
59
+ },
60
+ };
61
+ // Helpers:
62
+ // `Node extends FoldNodeRoot<Id> | FoldNode<Id>` is used to create two
63
+ // versions of functions: one for the root and one for the children.
64
+ // "Flat" functions
65
+ //
66
+ // Adds entry name to the given node.
67
+ function addFoldedEntry(node, entryId) {
68
+ if (node.folds.has(entryId)) {
69
+ return node;
70
+ }
71
+ const folds = new Set(node.folds);
72
+ folds.add(entryId);
73
+ return {
74
+ ...node,
75
+ folds,
76
+ };
77
+ }
78
+ function removeFoldedEntry(node, entryId) {
79
+ if (!node.folds.has(entryId)) {
80
+ return node;
81
+ }
82
+ const folds = new Set(node.folds);
83
+ folds.delete(entryId);
84
+ return {
85
+ ...node,
86
+ folds,
87
+ };
88
+ }
89
+ function clearFoldedEntries(node) {
90
+ if (node.folds.size === 0) {
91
+ return node;
92
+ }
93
+ return {
94
+ ...node,
95
+ folds: new Set(),
96
+ };
97
+ }
98
+ /**
99
+ * Ensures that the requested path exists in the fold-state tree.
100
+ *
101
+ * This creates fold nodes only; it does not modify the buffer tree.
102
+ */
103
+ function ensurePath(rootNode, path) {
104
+ if (path.length === 0) {
105
+ return rootNode;
106
+ }
107
+ const children = ensureChildPath(rootNode.children, path, 0);
108
+ if (children === rootNode.children) {
109
+ return rootNode;
110
+ }
111
+ return {
112
+ ...rootNode,
113
+ children,
114
+ };
115
+ }
116
+ function ensureChildPath(children, path, pathIndex) {
117
+ const id = path[pathIndex];
118
+ if (id === undefined) {
119
+ return children;
120
+ }
121
+ const childIndex = children.findIndex((child) => child.id === id);
122
+ const child = childIndex === -1 ? createChild(id) : children[childIndex];
123
+ let updatedChild = child;
124
+ if (pathIndex < path.length - 1) {
125
+ const updatedChildren = ensureChildPath(child.children, path, pathIndex + 1);
126
+ if (updatedChildren !== child.children) {
127
+ updatedChild = {
128
+ ...child,
129
+ children: updatedChildren,
130
+ };
131
+ }
132
+ }
133
+ if (childIndex === -1) {
134
+ return [...children, updatedChild];
135
+ }
136
+ if (updatedChild === child) {
137
+ return children;
138
+ }
139
+ const result = [...children];
140
+ result[childIndex] = updatedChild;
141
+ return result;
142
+ }
143
+ }
@@ -0,0 +1,70 @@
1
+ import { TreeNodeModifier, TreeNodeSelector } from '../tree-node/tree-node.types.js';
2
+ /**
3
+ * The whole fold state for a tree-node tree.
4
+ *
5
+ * The root has no ID because it represents the fold at the root.
6
+ * Its `children` contain the fold nodes for the forest's root entries.
7
+ *
8
+ * `folds` contains the IDs folded at this root. Fold order is not
9
+ * represented here; the buffer tree determines entry order.
10
+ */
11
+ export type FoldNodeRoot<Id extends PropertyKey> = {
12
+ children: FoldNode<Id>[];
13
+ folds: ReadonlySet<Id>;
14
+ };
15
+ /**
16
+ * Fold state associated with a node in the buffer tree.
17
+ *
18
+ * A fold node has the shape of an open tree node: its children are always
19
+ * represented by an array, and an empty `children` array means that no child
20
+ * fold nodes are currently represented.
21
+ *
22
+ * The `folds` set contains the IDs of entries folded at this node. Fold
23
+ * order is not represented here; the buffer tree determines entry order.
24
+ *
25
+ * The type is structurally compatible with `TreeNode`, allowing the shared
26
+ * `TreeNodeApi` to be used for path traversal and immutable updates.
27
+ */
28
+ export type FoldNode<Id extends PropertyKey> = FoldNodeRoot<Id> & {
29
+ id: Id;
30
+ };
31
+ /**
32
+ * Operations for navigating and immutably updating fold-tree structure.
33
+ *
34
+ * This API is a projection of `TreeNodeApi` onto the fold-tree
35
+ * representation. Path operations are strict: they only operate on
36
+ * paths that already exist. Creation of missing fold paths belongs to
37
+ * `FoldNodeService`.
38
+ */
39
+ export type FoldNodeApi<Id extends PropertyKey> = {
40
+ /**
41
+ * Returns the children of either the fold root or a fold node.
42
+ */
43
+ getChildren(node: FoldNodeRoot<Id> | FoldNode<Id>): Iterable<FoldNode<Id>>;
44
+ /**
45
+ * Returns a direct child by ID.
46
+ */
47
+ getChildById(node: FoldNodeRoot<Id> | FoldNode<Id>, id: Id): FoldNode<Id> | undefined;
48
+ /**
49
+ * Selects a fold node at a path below the root.
50
+ */
51
+ getAtPath<Result>(rootNode: FoldNodeRoot<Id>, path: Id[], selector: TreeNodeSelector<FoldNode<Id>, Result>): Result | undefined;
52
+ /**
53
+ * Immutably modifies a fold node at a path below the root.
54
+ */
55
+ modifyAtPath(rootNode: FoldNodeRoot<Id>, path: Id[], modifier: TreeNodeModifier<FoldNode<Id>>): FoldNodeRoot<Id> | undefined;
56
+ };
57
+ /**
58
+ * Semantic operations for managing folded buffer entries.
59
+ *
60
+ * Unlike `FoldNodeApi`, the service may create missing fold paths when
61
+ * adding a fold. This allows an empty root to be populated lazily.
62
+ */
63
+ export type FoldNodeService<Id extends PropertyKey> = {
64
+ createEmptyRoot(): FoldNodeRoot<Id>;
65
+ getIfEntryFoldedAtPath(rootNode: FoldNodeRoot<Id>, path: Id[], entryId: Id): boolean;
66
+ addFoldedEntryAtPath(rootNode: FoldNodeRoot<Id>, path: Id[], entryId: Id): FoldNodeRoot<Id> | undefined;
67
+ removeFoldedEntryAtPath(rootNode: FoldNodeRoot<Id>, path: Id[], entryId: Id): FoldNodeRoot<Id> | undefined;
68
+ clearFoldedEntriesAtPath(rootNode: FoldNodeRoot<Id>, path: Id[]): FoldNodeRoot<Id> | undefined;
69
+ };
70
+ //# sourceMappingURL=fold-node.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fold-node.types.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/fold-node/fold-node.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAErF;;;;;;;;GAQG;AACH,MAAM,MAAM,YAAY,CAAC,EAAE,SAAS,WAAW,IAAI;IACjD,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;IACzB,KAAK,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC;CACxB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,QAAQ,CAAC,EAAE,SAAS,WAAW,IAAI,YAAY,CAAC,EAAE,CAAC,GAAG;IAChE,EAAE,EAAE,EAAE,CAAC;CACR,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,CAAC,EAAE,SAAS,WAAW,IAAI;IAChD;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,YAAY,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;IAE3E;;OAEG;IACH,YAAY,CACV,IAAI,EAAE,YAAY,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,EACrC,EAAE,EAAE,EAAE,GACL,QAAQ,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC;IAE5B;;OAEG;IACH,SAAS,CAAC,MAAM,EACd,QAAQ,EAAE,YAAY,CAAC,EAAE,CAAC,EAC1B,IAAI,EAAE,EAAE,EAAE,EACV,QAAQ,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,GAC/C,MAAM,GAAG,SAAS,CAAC;IAEtB;;OAEG;IACH,YAAY,CACV,QAAQ,EAAE,YAAY,CAAC,EAAE,CAAC,EAC1B,IAAI,EAAE,EAAE,EAAE,EACV,QAAQ,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,GACvC,YAAY,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC;CACjC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,eAAe,CACzB,EAAE,SAAS,WAAW,IACpB;IACF,eAAe,IAAI,YAAY,CAAC,EAAE,CAAC,CAAC;IAEpC,sBAAsB,CACpB,QAAQ,EAAE,YAAY,CAAC,EAAE,CAAC,EAC1B,IAAI,EAAE,EAAE,EAAE,EACV,OAAO,EAAE,EAAE,GACV,OAAO,CAAC;IAEX,oBAAoB,CAClB,QAAQ,EAAE,YAAY,CAAC,EAAE,CAAC,EAC1B,IAAI,EAAE,EAAE,EAAE,EACV,OAAO,EAAE,EAAE,GACV,YAAY,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC;IAEhC,uBAAuB,CACrB,QAAQ,EAAE,YAAY,CAAC,EAAE,CAAC,EAC1B,IAAI,EAAE,EAAE,EAAE,EACV,OAAO,EAAE,EAAE,GACV,YAAY,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC;IAEhC,wBAAwB,CACtB,QAAQ,EAAE,YAAY,CAAC,EAAE,CAAC,EAC1B,IAAI,EAAE,EAAE,EAAE,GACT,YAAY,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC;CACjC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ export * from './fold-node/fold-node.impl.js';
2
+ export * from './fold-node/fold-node.types.js';
3
+ export * from './nav-node/nav-node.impl.js';
4
+ export * from './nav-node/nav-node.types.js';
5
+ export * from './tree-node/tree-node.impl.js';
6
+ export * from './tree-node/tree-node.types.js';
7
+ export * from './cursor.js';
8
+ export * from './state.js';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tree-surfer/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAE/C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAE7C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAE/C,cAAc,aAAa,CAAC;AAE5B,cAAc,YAAY,CAAC"}
@@ -0,0 +1,8 @@
1
+ export * from './fold-node/fold-node.impl.js';
2
+ export * from './fold-node/fold-node.types.js';
3
+ export * from './nav-node/nav-node.impl.js';
4
+ export * from './nav-node/nav-node.types.js';
5
+ export * from './tree-node/tree-node.impl.js';
6
+ export * from './tree-node/tree-node.types.js';
7
+ export * from './cursor.js';
8
+ export * from './state.js';
@@ -0,0 +1,6 @@
1
+ import { SerializableKey, TreeNode, TreeNodeApi } from '../tree-node/tree-node.types.js';
2
+ import { FoldNodeApi } from '../fold-node/fold-node.types.js';
3
+ import { CursorApi } from '../cursor.js';
4
+ import { NavNodeApi } from './nav-node.types.js';
5
+ export declare function createNavNodeApi<Id extends SerializableKey, BufferNode extends TreeNode<Id, BufferNode>>(treeNodeApi: TreeNodeApi<Id, BufferNode>, foldNodeApi: FoldNodeApi<Id>, cursorApi: CursorApi<Id>): NavNodeApi<Id, BufferNode>;
6
+ //# sourceMappingURL=nav-node.impl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nav-node.impl.d.ts","sourceRoot":"","sources":["../../../src/tree-surfer/nav-node/nav-node.impl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,eAAe,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AACvG,OAAO,EAAE,WAAW,EAAgB,MAAM,iCAAiC,CAAC;AAC5E,OAAO,EAAU,SAAS,EAAc,MAAM,cAAc,CAAC;AAC7D,OAAO,EAA6C,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAE5F,wBAAgB,gBAAgB,CAC9B,EAAE,SAAS,eAAe,EAC1B,UAAU,SAAS,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,EAE3C,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,UAAU,CAAC,EACxC,WAAW,EAAE,WAAW,CAAC,EAAE,CAAC,EAC5B,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC,GACvB,UAAU,CAAC,EAAE,EAAE,UAAU,CAAC,CAqP5B"}