@voidhash/mimic 0.0.1-alpha.4 → 0.0.1-alpha.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voidhash/mimic",
3
- "version": "0.0.1-alpha.4",
3
+ "version": "0.0.1-alpha.5",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -19,7 +19,7 @@
19
19
  "typescript": "5.8.3",
20
20
  "vite-tsconfig-paths": "^5.1.4",
21
21
  "vitest": "^3.2.4",
22
- "@voidhash/tsconfig": "0.0.1-alpha.4"
22
+ "@voidhash/tsconfig": "0.0.1-alpha.5"
23
23
  },
24
24
  "peerDependencies": {
25
25
  "effect": "^3.19.12"
@@ -7,45 +7,67 @@ import * as Transform from "../Transform";
7
7
  import type { AnyPrimitive, InferState } from "../Primitive";
8
8
  import { StructPrimitive } from "./Struct";
9
9
 
10
+ /**
11
+ * Symbol used to identify the Self placeholder
12
+ */
13
+ const TreeNodeSelfSymbol = Symbol.for("TreeNode.Self");
10
14
 
11
15
  /**
12
- * Any TreeNodePrimitive type - used for generic constraints.
16
+ * Special placeholder for self-referential tree nodes.
17
+ * Use this in the children array when a node type can contain itself.
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * const FolderNode = TreeNode("folder", {
22
+ * data: Struct({ name: String() }),
23
+ * children: [Self], // Folder can contain other folders
24
+ * });
25
+ * ```
26
+ */
27
+ export const TreeNodeSelf = { _tag: "TreeNodeSelf", _symbol: TreeNodeSelfSymbol } as unknown as AnyTreeNodePrimitive;
28
+
29
+ /**
30
+ * Check if a value is the Self placeholder
13
31
  */
14
- export type AnyTreeNodePrimitive = TreeNodePrimitive<string, StructPrimitive<any>, readonly AnyTreeNodePrimitive[] | (() => readonly AnyTreeNodePrimitive[])>;
32
+ const isSelf = (value: unknown): boolean => {
33
+ return typeof value === "object" && value !== null && "_symbol" in value && (value as any)._symbol === TreeNodeSelfSymbol;
34
+ };
15
35
 
16
36
  /**
17
- * Resolves children type - handles both array and lazy thunk
37
+ * The type for children - either a direct array or a lazy function (for self-referential nodes).
38
+ * Using `Function` type allows self-references without explicit type annotations.
18
39
  */
19
- export type ResolveChildren<TChildren extends readonly AnyTreeNodePrimitive[] | (() => readonly AnyTreeNodePrimitive[])> =
20
- TChildren extends () => readonly AnyTreeNodePrimitive[] ? ReturnType<TChildren> : TChildren;
40
+ // eslint-disable-next-line @typescript-eslint/ban-types
41
+ export type TreeNodeChildren = readonly AnyTreeNodePrimitive[] | Function;
42
+
43
+ /**
44
+ * Any TreeNodePrimitive type - used for generic constraints.
45
+ */
46
+ export type AnyTreeNodePrimitive = TreeNodePrimitive<string, StructPrimitive<any>>;
21
47
 
22
48
  /**
23
49
  * Infer the data state type from a TreeNodePrimitive
24
50
  */
25
51
  export type InferTreeNodeDataState<T extends AnyTreeNodePrimitive> =
26
- T extends TreeNodePrimitive<any, infer TData, any> ? InferState<TData> : never;
52
+ T extends TreeNodePrimitive<any, infer TData> ? InferState<TData> : never;
27
53
 
28
54
  /**
29
55
  * Infer the type literal from a TreeNodePrimitive
30
56
  */
31
57
  export type InferTreeNodeType<T extends AnyTreeNodePrimitive> =
32
- T extends TreeNodePrimitive<infer TType, any, any> ? TType : never;
58
+ T extends TreeNodePrimitive<infer TType, any> ? TType : never;
33
59
 
34
60
  /**
35
- * Infer the allowed children from a TreeNodePrimitive
61
+ * Infer the allowed children from a TreeNodePrimitive (resolved at runtime)
36
62
  */
37
- export type InferTreeNodeChildren<T extends AnyTreeNodePrimitive> =
38
- T extends TreeNodePrimitive<any, any, infer TChildren> ? ResolveChildren<TChildren>[number] : never;
63
+ export type InferTreeNodeChildren<_T extends AnyTreeNodePrimitive> = AnyTreeNodePrimitive;
39
64
 
40
65
  /**
41
66
  * Configuration for a TreeNode primitive
42
67
  */
43
- export interface TreeNodeConfig<
44
- TData extends StructPrimitive<any>,
45
- TChildren extends readonly AnyTreeNodePrimitive[] | (() => readonly AnyTreeNodePrimitive[])
46
- > {
68
+ export interface TreeNodeConfig<TData extends StructPrimitive<any>> {
47
69
  readonly data: TData;
48
- readonly children: TChildren;
70
+ readonly children: TreeNodeChildren;
49
71
  }
50
72
 
51
73
  /**
@@ -53,20 +75,18 @@ export interface TreeNodeConfig<
53
75
  */
54
76
  export class TreeNodePrimitive<
55
77
  TType extends string,
56
- TData extends StructPrimitive<any>,
57
- TChildren extends readonly AnyTreeNodePrimitive[] | (() => readonly AnyTreeNodePrimitive[])
78
+ TData extends StructPrimitive<any>
58
79
  > {
59
80
  readonly _tag = "TreeNodePrimitive" as const;
60
81
  readonly _Type!: TType;
61
82
  readonly _Data!: TData;
62
- readonly _Children!: TChildren;
63
83
 
64
84
  private readonly _type: TType;
65
85
  private readonly _data: TData;
66
- private readonly _children: TChildren;
86
+ private readonly _children: TreeNodeChildren;
67
87
  private _resolvedChildren: readonly AnyTreeNodePrimitive[] | undefined;
68
88
 
69
- constructor(type: TType, config: TreeNodeConfig<TData, TChildren>) {
89
+ constructor(type: TType, config: TreeNodeConfig<TData>) {
70
90
  this._type = type;
71
91
  this._data = config.data;
72
92
  this._children = config.children;
@@ -82,14 +102,14 @@ export class TreeNodePrimitive<
82
102
  return this._data;
83
103
  }
84
104
 
85
- /** Get resolved children (resolves lazy thunk if needed) */
105
+ /** Get resolved children (resolves lazy thunk if needed, replaces Self with this node) */
86
106
  get children(): readonly AnyTreeNodePrimitive[] {
87
107
  if (this._resolvedChildren === undefined) {
88
- if (typeof this._children === "function") {
89
- this._resolvedChildren = (this._children as () => readonly AnyTreeNodePrimitive[])();
90
- } else {
91
- this._resolvedChildren = this._children as readonly AnyTreeNodePrimitive[];
92
- }
108
+ const resolved = typeof this._children === "function"
109
+ ? (this._children as () => readonly AnyTreeNodePrimitive[])()
110
+ : this._children;
111
+ // Replace Self placeholders with this node
112
+ this._resolvedChildren = resolved.map(child => isSelf(child) ? this : child);
93
113
  }
94
114
  return this._resolvedChildren;
95
115
  }
@@ -103,11 +123,10 @@ export class TreeNodePrimitive<
103
123
  /** Creates a new TreeNodePrimitive with the given type and config */
104
124
  export const TreeNode = <
105
125
  TType extends string,
106
- TData extends StructPrimitive<any>,
107
- TChildren extends readonly AnyTreeNodePrimitive[] | (() => readonly AnyTreeNodePrimitive[])
126
+ TData extends StructPrimitive<any>
108
127
  >(
109
128
  type: TType,
110
- config: TreeNodeConfig<TData, TChildren>
111
- ): TreeNodePrimitive<TType, TData, TChildren> =>
129
+ config: TreeNodeConfig<TData>
130
+ ): TreeNodePrimitive<TType, TData> =>
112
131
  new TreeNodePrimitive(type, config);
113
132