@voidhash/mimic 0.0.1-alpha.7 → 0.0.1-alpha.9
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/.turbo/turbo-build.log +43 -15
- package/dist/Document-ChuFrTk1.cjs +571 -0
- package/dist/Document-CwiAFTIq.mjs +438 -0
- package/dist/Document-CwiAFTIq.mjs.map +1 -0
- package/dist/Presence-DKKP4v5X.d.cts +91 -0
- package/dist/Presence-DKKP4v5X.d.cts.map +1 -0
- package/dist/Presence-DdMVKcOv.mjs +110 -0
- package/dist/Presence-DdMVKcOv.mjs.map +1 -0
- package/dist/Presence-N8u7Eppr.d.mts +91 -0
- package/dist/Presence-N8u7Eppr.d.mts.map +1 -0
- package/dist/Presence-gWrmGBeu.cjs +126 -0
- package/dist/Primitive-CasheIbX.d.mts +1175 -0
- package/dist/Primitive-CasheIbX.d.mts.map +1 -0
- package/dist/Primitive-Cyvy7zvF.d.cts +1175 -0
- package/dist/Primitive-Cyvy7zvF.d.cts.map +1 -0
- package/dist/client/index.cjs +1456 -0
- package/dist/client/index.d.cts +692 -0
- package/dist/client/index.d.cts.map +1 -0
- package/dist/client/index.d.mts +692 -0
- package/dist/client/index.d.mts.map +1 -0
- package/dist/client/index.mjs +1413 -0
- package/dist/client/index.mjs.map +1 -0
- package/dist/index.cjs +226 -765
- package/dist/index.d.cts +5 -1152
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +5 -1152
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +71 -569
- package/dist/index.mjs.map +1 -1
- package/dist/server/index.cjs +191 -0
- package/dist/server/index.d.cts +148 -0
- package/dist/server/index.d.cts.map +1 -0
- package/dist/server/index.d.mts +148 -0
- package/dist/server/index.d.mts.map +1 -0
- package/dist/server/index.mjs +182 -0
- package/dist/server/index.mjs.map +1 -0
- package/package.json +17 -5
- package/src/primitives/Array.ts +25 -14
- package/src/primitives/Boolean.ts +29 -17
- package/src/primitives/Either.ts +30 -17
- package/src/primitives/Lazy.ts +16 -2
- package/src/primitives/Literal.ts +29 -18
- package/src/primitives/Number.ts +35 -24
- package/src/primitives/String.ts +36 -23
- package/src/primitives/Struct.ts +74 -26
- package/src/primitives/Tree.ts +30 -14
- package/src/primitives/TreeNode.ts +6 -0
- package/src/primitives/Union.ts +21 -21
- package/src/primitives/shared.ts +35 -34
- package/tests/primitives/Array.test.ts +108 -0
- package/tests/primitives/Struct.test.ts +2 -2
- package/tests/primitives/Tree.test.ts +128 -0
- package/tsdown.config.ts +1 -1
- /package/dist/{chunk-C6wwvPpM.mjs → chunk-CLMFDpHK.mjs} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["Document.make","_transactionOrder: string[]","Transaction.isEmpty"],"sources":["../../src/server/ServerDocument.ts","../../src/server/errors.ts"],"sourcesContent":["import * as Document from \"../Document\";\nimport * as Transaction from \"../Transaction\";\nimport type * as Primitive from \"../Primitive\";\n\n// =============================================================================\n// Server Message Types (matching client's Transport expectations)\n// =============================================================================\n\n/**\n * Message sent when broadcasting a committed transaction.\n */\nexport interface TransactionMessage {\n readonly type: \"transaction\";\n readonly transaction: Transaction.Transaction;\n /** Server-assigned version number for ordering */\n readonly version: number;\n}\n\n/**\n * Message sent when a transaction is rejected.\n */\nexport interface ErrorMessage {\n readonly type: \"error\";\n readonly transactionId: string;\n readonly reason: string;\n}\n\n/**\n * Message sent as a full state snapshot.\n */\nexport interface SnapshotMessage {\n readonly type: \"snapshot\";\n readonly state: unknown;\n readonly version: number;\n}\n\n/**\n * Union of all server messages that can be broadcast.\n */\nexport type ServerMessage = TransactionMessage | ErrorMessage | SnapshotMessage;\n\n// =============================================================================\n// Submit Result Types\n// =============================================================================\n\n/**\n * Result of submitting a transaction to the server.\n */\nexport type SubmitResult =\n | { readonly success: true; readonly version: number }\n | { readonly success: false; readonly reason: string };\n\n// =============================================================================\n// Server Document Types\n// =============================================================================\n\n/**\n * Options for creating a ServerDocument.\n */\nexport interface ServerDocumentOptions<TSchema extends Primitive.AnyPrimitive> {\n /** The schema defining the document structure */\n readonly schema: TSchema;\n /** Initial state (optional, will use schema defaults if not provided) */\n readonly initialState?: Primitive.InferState<TSchema>;\n /** Initial version number (optional, defaults to 0) */\n readonly initialVersion?: number;\n /** Called when a transaction is successfully applied and should be broadcast */\n readonly onBroadcast: (message: TransactionMessage) => void;\n /** Called when a transaction is rejected (optional, for logging/metrics) */\n readonly onRejection?: (transactionId: string, reason: string) => void;\n /** Maximum number of processed transaction IDs to track for deduplication */\n readonly maxTransactionHistory?: number;\n}\n\n/**\n * A ServerDocument maintains the authoritative state and processes client transactions.\n */\nexport interface ServerDocument<TSchema extends Primitive.AnyPrimitive> {\n /** The schema defining this document's structure */\n readonly schema: TSchema;\n\n /** Returns the current authoritative state */\n get(): Primitive.InferState<TSchema> | undefined;\n\n /** Returns the current version number */\n getVersion(): number;\n\n /**\n * Submits a transaction for processing.\n * Validates and applies the transaction if valid, or rejects it with a reason.\n * @param transaction - The transaction to process\n * @returns SubmitResult indicating success with version or failure with reason\n */\n submit(transaction: Transaction.Transaction): SubmitResult;\n\n /**\n * Returns a snapshot of the current state and version.\n * Used to initialize new clients or resync after drift.\n */\n getSnapshot(): SnapshotMessage;\n\n /**\n * Checks if a transaction has already been processed.\n * @param transactionId - The transaction ID to check\n */\n hasProcessed(transactionId: string): boolean;\n}\n\n// =============================================================================\n// Server Document Implementation\n// =============================================================================\n\n/**\n * Creates a new ServerDocument for the given schema.\n */\nexport const make = <TSchema extends Primitive.AnyPrimitive>(\n options: ServerDocumentOptions<TSchema>\n): ServerDocument<TSchema> => {\n const {\n schema,\n initialState,\n initialVersion = 0,\n onBroadcast,\n onRejection,\n maxTransactionHistory = 1000,\n } = options;\n\n // ==========================================================================\n // Internal State\n // ==========================================================================\n\n // The authoritative document\n let _document = Document.make(schema, { initial: initialState });\n\n // Current version number (incremented on each successful transaction)\n let _version = initialVersion;\n\n // Track processed transaction IDs for deduplication\n const _processedTransactions = new Set<string>();\n const _transactionOrder: string[] = [];\n\n // ==========================================================================\n // Helper Functions\n // ==========================================================================\n\n /**\n * Records a transaction as processed, maintaining the history limit.\n */\n const recordTransaction = (transactionId: string): void => {\n _processedTransactions.add(transactionId);\n _transactionOrder.push(transactionId);\n\n // Evict oldest transactions if over limit\n while (_transactionOrder.length > maxTransactionHistory) {\n const oldest = _transactionOrder.shift();\n if (oldest) {\n _processedTransactions.delete(oldest);\n }\n }\n };\n\n /**\n * Validates that the transaction can be applied to the current state.\n * Creates a temporary document and attempts to apply the operations.\n */\n const validateTransaction = (\n transaction: Transaction.Transaction\n ): { valid: true } | { valid: false; reason: string } => {\n // Check for empty transaction\n if (Transaction.isEmpty(transaction)) {\n return { valid: false, reason: \"Transaction is empty\" };\n }\n\n // Check for duplicate transaction\n if (_processedTransactions.has(transaction.id)) {\n return { valid: false, reason: \"Transaction has already been processed\" };\n }\n\n // Create a temporary document with current state to test the operations\n const currentState = _document.get();\n const tempDoc = Document.make(schema, { initial: currentState });\n\n try {\n // Attempt to apply all operations\n tempDoc.apply(transaction.ops);\n return { valid: true };\n } catch (error) {\n // Operations failed to apply\n const message = error instanceof Error ? error.message : String(error);\n return { valid: false, reason: message };\n }\n };\n\n // ==========================================================================\n // Public API\n // ==========================================================================\n\n const serverDocument: ServerDocument<TSchema> = {\n schema,\n\n get: (): Primitive.InferState<TSchema> | undefined => {\n return _document.get();\n },\n\n getVersion: (): number => {\n return _version;\n },\n\n submit: (transaction: Transaction.Transaction): SubmitResult => {\n // Validate the transaction\n const validation = validateTransaction(transaction);\n\n if (!validation.valid) {\n // Notify rejection callback if provided\n onRejection?.(transaction.id, validation.reason);\n\n return {\n success: false,\n reason: validation.reason,\n };\n }\n\n // Apply the transaction to the authoritative state\n try {\n _document.apply(transaction.ops);\n } catch (error) {\n // This shouldn't happen since we validated, but handle gracefully\n const reason = error instanceof Error ? error.message : String(error);\n onRejection?.(transaction.id, reason);\n return { success: false, reason };\n }\n\n // Increment version\n _version += 1;\n\n // Record as processed\n recordTransaction(transaction.id);\n\n // Broadcast the confirmed transaction\n const message: TransactionMessage = {\n type: \"transaction\",\n transaction,\n version: _version,\n };\n onBroadcast(message);\n\n return {\n success: true,\n version: _version,\n };\n },\n\n getSnapshot: (): SnapshotMessage => {\n return {\n type: \"snapshot\",\n state: _document.get(),\n version: _version,\n };\n },\n\n hasProcessed: (transactionId: string): boolean => {\n return _processedTransactions.has(transactionId);\n },\n };\n\n return serverDocument;\n};\n","import type * as Transaction from \"../Transaction\";\n\n// =============================================================================\n// Server Errors\n// =============================================================================\n\n/**\n * Base error class for all mimic-server errors.\n */\nexport class MimicServerError extends Error {\n readonly _tag: string = \"MimicServerError\";\n constructor(message: string) {\n super(message);\n this.name = \"MimicServerError\";\n }\n}\n\n/**\n * Error thrown when a transaction fails validation.\n */\nexport class ValidationError extends MimicServerError {\n override readonly _tag = \"ValidationError\";\n readonly transactionId: string;\n\n constructor(transactionId: string, message: string) {\n super(`Transaction ${transactionId} validation failed: ${message}`);\n this.name = \"ValidationError\";\n this.transactionId = transactionId;\n }\n}\n\n/**\n * Error thrown when an operation is invalid for the current schema.\n */\nexport class InvalidOperationError extends MimicServerError {\n override readonly _tag = \"InvalidOperationError\";\n readonly operationKind: string;\n readonly path: string;\n\n constructor(operationKind: string, path: string, message: string) {\n super(`Invalid operation ${operationKind} at path \"${path}\": ${message}`);\n this.name = \"InvalidOperationError\";\n this.operationKind = operationKind;\n this.path = path;\n }\n}\n\n/**\n * Error thrown when an operation cannot be applied to the current state.\n */\nexport class StateValidationError extends MimicServerError {\n override readonly _tag = \"StateValidationError\";\n readonly transactionId: string;\n override readonly cause?: Error;\n\n constructor(transactionId: string, message: string, cause?: Error) {\n super(`Transaction ${transactionId} cannot be applied to current state: ${message}`);\n this.name = \"StateValidationError\";\n this.transactionId = transactionId;\n this.cause = cause;\n }\n}\n\n/**\n * Error thrown when attempting to apply an empty transaction.\n */\nexport class EmptyTransactionError extends MimicServerError {\n override readonly _tag = \"EmptyTransactionError\";\n readonly transactionId: string;\n\n constructor(transactionId: string) {\n super(`Transaction ${transactionId} is empty and cannot be applied`);\n this.name = \"EmptyTransactionError\";\n this.transactionId = transactionId;\n }\n}\n\n/**\n * Error thrown when a duplicate transaction is submitted.\n */\nexport class DuplicateTransactionError extends MimicServerError {\n override readonly _tag = \"DuplicateTransactionError\";\n readonly transactionId: string;\n\n constructor(transactionId: string) {\n super(`Transaction ${transactionId} has already been processed`);\n this.name = \"DuplicateTransactionError\";\n this.transactionId = transactionId;\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voidhash/mimic",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -9,9 +9,21 @@
|
|
|
9
9
|
},
|
|
10
10
|
"main": "./src/index.ts",
|
|
11
11
|
"exports": {
|
|
12
|
-
".":
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/index.mjs",
|
|
14
|
+
"types": "./dist/index.d.mts",
|
|
15
|
+
"require": "./dist/index.cjs"
|
|
16
|
+
},
|
|
17
|
+
"./server": {
|
|
18
|
+
"import": "./dist/server/index.mjs",
|
|
19
|
+
"types": "./dist/server/index.d.mts",
|
|
20
|
+
"require": "./dist/server/index.cjs"
|
|
21
|
+
},
|
|
22
|
+
"./client": {
|
|
23
|
+
"import": "./dist/client/index.mjs",
|
|
24
|
+
"types": "./dist/client/index.d.mts",
|
|
25
|
+
"require": "./dist/client/index.cjs"
|
|
26
|
+
}
|
|
15
27
|
},
|
|
16
28
|
"devDependencies": {
|
|
17
29
|
"@effect/vitest": "^0.27.0",
|
|
@@ -19,7 +31,7 @@
|
|
|
19
31
|
"typescript": "5.8.3",
|
|
20
32
|
"vite-tsconfig-paths": "^5.1.4",
|
|
21
33
|
"vitest": "^3.2.4",
|
|
22
|
-
"@voidhash/tsconfig": "0.0.1-alpha.
|
|
34
|
+
"@voidhash/tsconfig": "0.0.1-alpha.9"
|
|
23
35
|
},
|
|
24
36
|
"peerDependencies": {
|
|
25
37
|
"effect": "^3.19.12"
|
package/src/primitives/Array.ts
CHANGED
|
@@ -5,10 +5,10 @@ import * as OperationPath from "../OperationPath";
|
|
|
5
5
|
import * as ProxyEnvironment from "../ProxyEnvironment";
|
|
6
6
|
import * as Transform from "../Transform";
|
|
7
7
|
import * as FractionalIndex from "../FractionalIndex";
|
|
8
|
-
import type { Primitive, PrimitiveInternal, MaybeUndefined, AnyPrimitive, Validator, InferState, InferProxy, InferSnapshot } from "../Primitive";
|
|
8
|
+
import type { Primitive, PrimitiveInternal, MaybeUndefined, AnyPrimitive, Validator, InferState, InferProxy, InferSnapshot, InferSetInput } from "../Primitive";
|
|
9
9
|
import { ValidationError } from "../Primitive";
|
|
10
|
-
import { runValidators, applyDefaults
|
|
11
|
-
import
|
|
10
|
+
import { runValidators, applyDefaults } from "./shared";
|
|
11
|
+
import { StructPrimitive, StructSetInput } from "./Struct";
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
/**
|
|
@@ -49,13 +49,16 @@ export type ArraySnapshot<TElement extends AnyPrimitive> = readonly ArrayEntrySn
|
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* Compute the input type for array element values.
|
|
52
|
-
*
|
|
53
|
-
*
|
|
52
|
+
* Uses StructSetInput directly for struct elements so that:
|
|
53
|
+
* - Fields that are required AND have no default must be provided
|
|
54
|
+
* - Fields that are optional OR have defaults can be omitted
|
|
55
|
+
*
|
|
56
|
+
* For non-struct elements, falls back to InferSetInput.
|
|
54
57
|
*/
|
|
55
|
-
export type ArrayElementSetInput<TElement extends AnyPrimitive> =
|
|
58
|
+
export type ArrayElementSetInput<TElement extends AnyPrimitive> =
|
|
56
59
|
TElement extends StructPrimitive<infer TFields, any, any>
|
|
57
60
|
? StructSetInput<TFields>
|
|
58
|
-
:
|
|
61
|
+
: InferSetInput<TElement>;
|
|
59
62
|
|
|
60
63
|
export interface ArrayProxy<TElement extends AnyPrimitive> {
|
|
61
64
|
/** Gets the current array entries (sorted by position) */
|
|
@@ -88,14 +91,22 @@ interface ArrayPrimitiveSchema<TElement extends AnyPrimitive> {
|
|
|
88
91
|
readonly validators: readonly Validator<ArrayState<TElement>>[];
|
|
89
92
|
}
|
|
90
93
|
|
|
91
|
-
|
|
92
|
-
|
|
94
|
+
/** Input type for array set() - an array of element set inputs */
|
|
95
|
+
export type ArraySetInput<TElement extends AnyPrimitive> = readonly ArrayElementSetInput<TElement>[];
|
|
96
|
+
|
|
97
|
+
/** Input type for array update() - same as set() for arrays */
|
|
98
|
+
export type ArrayUpdateInput<TElement extends AnyPrimitive> = readonly ArrayElementSetInput<TElement>[];
|
|
99
|
+
|
|
100
|
+
export class ArrayPrimitive<TElement extends AnyPrimitive, TRequired extends boolean = false, THasDefault extends boolean = false>
|
|
101
|
+
implements Primitive<ArrayState<TElement>, ArrayProxy<TElement>, TRequired, THasDefault, ArraySetInput<TElement>, ArrayUpdateInput<TElement>>
|
|
93
102
|
{
|
|
94
103
|
readonly _tag = "ArrayPrimitive" as const;
|
|
95
104
|
readonly _State!: ArrayState<TElement>;
|
|
96
105
|
readonly _Proxy!: ArrayProxy<TElement>;
|
|
97
|
-
readonly
|
|
106
|
+
readonly _TRequired!: TRequired;
|
|
98
107
|
readonly _THasDefault!: THasDefault;
|
|
108
|
+
readonly TSetInput!: ArraySetInput<TElement>;
|
|
109
|
+
readonly TUpdateInput!: ArrayUpdateInput<TElement>;
|
|
99
110
|
|
|
100
111
|
private readonly _schema: ArrayPrimitiveSchema<TElement>;
|
|
101
112
|
|
|
@@ -139,7 +150,7 @@ export class ArrayPrimitive<TElement extends AnyPrimitive, TDefined extends bool
|
|
|
139
150
|
}
|
|
140
151
|
|
|
141
152
|
/** Set a default value for this array */
|
|
142
|
-
default(defaultValue: ArrayState<TElement>): ArrayPrimitive<TElement,
|
|
153
|
+
default(defaultValue: ArrayState<TElement>): ArrayPrimitive<TElement, TRequired, true> {
|
|
143
154
|
return new ArrayPrimitive({
|
|
144
155
|
...this._schema,
|
|
145
156
|
defaultValue,
|
|
@@ -152,7 +163,7 @@ export class ArrayPrimitive<TElement extends AnyPrimitive, TDefined extends bool
|
|
|
152
163
|
}
|
|
153
164
|
|
|
154
165
|
/** Add a custom validation rule */
|
|
155
|
-
refine(fn: (value: ArrayState<TElement>) => boolean, message: string): ArrayPrimitive<TElement,
|
|
166
|
+
refine(fn: (value: ArrayState<TElement>) => boolean, message: string): ArrayPrimitive<TElement, TRequired, THasDefault> {
|
|
156
167
|
return new ArrayPrimitive({
|
|
157
168
|
...this._schema,
|
|
158
169
|
validators: [...this._schema.validators, { validate: fn, message }],
|
|
@@ -160,7 +171,7 @@ export class ArrayPrimitive<TElement extends AnyPrimitive, TDefined extends bool
|
|
|
160
171
|
}
|
|
161
172
|
|
|
162
173
|
/** Minimum array length */
|
|
163
|
-
minLength(length: number): ArrayPrimitive<TElement,
|
|
174
|
+
minLength(length: number): ArrayPrimitive<TElement, TRequired, THasDefault> {
|
|
164
175
|
return this.refine(
|
|
165
176
|
(v) => v.length >= length,
|
|
166
177
|
`Array must have at least ${length} elements`
|
|
@@ -168,7 +179,7 @@ export class ArrayPrimitive<TElement extends AnyPrimitive, TDefined extends bool
|
|
|
168
179
|
}
|
|
169
180
|
|
|
170
181
|
/** Maximum array length */
|
|
171
|
-
maxLength(length: number): ArrayPrimitive<TElement,
|
|
182
|
+
maxLength(length: number): ArrayPrimitive<TElement, TRequired, THasDefault> {
|
|
172
183
|
return this.refine(
|
|
173
184
|
(v) => v.length <= length,
|
|
174
185
|
`Array must have at most ${length} elements`
|
|
@@ -4,17 +4,22 @@ import * as Operation from "../Operation";
|
|
|
4
4
|
import * as OperationPath from "../OperationPath";
|
|
5
5
|
import * as ProxyEnvironment from "../ProxyEnvironment";
|
|
6
6
|
import * as Transform from "../Transform";
|
|
7
|
-
import type { Primitive, PrimitiveInternal, MaybeUndefined, Validator } from "./shared";
|
|
7
|
+
import type { Primitive, PrimitiveInternal, MaybeUndefined, Validator, NeedsValue } from "./shared";
|
|
8
8
|
import { runValidators, isCompatibleOperation, ValidationError } from "./shared";
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
type InferSetInput<TRequired extends boolean = false, THasDefault extends boolean = false> = NeedsValue<boolean, TRequired, THasDefault>
|
|
12
|
+
type InferUpdateInput<TRequired extends boolean = false, THasDefault extends boolean = false> = NeedsValue<boolean, TRequired, THasDefault>
|
|
13
|
+
|
|
14
|
+
export interface BooleanProxy<TRequired extends boolean = false, THasDefault extends boolean = false> {
|
|
12
15
|
/** Gets the current boolean value */
|
|
13
|
-
get(): MaybeUndefined<boolean,
|
|
16
|
+
get(): MaybeUndefined<boolean, TRequired, THasDefault>;
|
|
14
17
|
/** Sets the boolean value, generating a boolean.set operation */
|
|
15
|
-
set(value:
|
|
18
|
+
set(value: InferSetInput<TRequired, THasDefault>): void;
|
|
19
|
+
/** This is the same as set. Updates the boolean value, generating a boolean.set operation */
|
|
20
|
+
update(value: InferUpdateInput<TRequired, THasDefault>): void;
|
|
16
21
|
/** Returns a readonly snapshot of the boolean value for rendering */
|
|
17
|
-
toSnapshot(): MaybeUndefined<boolean,
|
|
22
|
+
toSnapshot(): MaybeUndefined<boolean, TRequired, THasDefault>;
|
|
18
23
|
}
|
|
19
24
|
|
|
20
25
|
interface BooleanPrimitiveSchema {
|
|
@@ -23,12 +28,14 @@ interface BooleanPrimitiveSchema {
|
|
|
23
28
|
readonly validators: readonly Validator<boolean>[];
|
|
24
29
|
}
|
|
25
30
|
|
|
26
|
-
export class BooleanPrimitive<
|
|
31
|
+
export class BooleanPrimitive<TRequired extends boolean = false, THasDefault extends boolean = false> implements Primitive<boolean, BooleanProxy<TRequired, THasDefault>, TRequired, THasDefault, InferSetInput<TRequired, THasDefault>, InferUpdateInput<TRequired, THasDefault>> {
|
|
27
32
|
readonly _tag = "BooleanPrimitive" as const;
|
|
28
33
|
readonly _State!: boolean;
|
|
29
|
-
readonly _Proxy!: BooleanProxy<
|
|
30
|
-
readonly
|
|
34
|
+
readonly _Proxy!: BooleanProxy<TRequired, THasDefault>;
|
|
35
|
+
readonly _TRequired!: TRequired;
|
|
31
36
|
readonly _THasDefault!: THasDefault;
|
|
37
|
+
readonly TUpdateInput!: InferUpdateInput<TRequired, THasDefault>;
|
|
38
|
+
readonly TSetInput!: InferSetInput<TRequired, THasDefault>;
|
|
32
39
|
|
|
33
40
|
private readonly _schema: BooleanPrimitiveSchema;
|
|
34
41
|
|
|
@@ -54,7 +61,7 @@ export class BooleanPrimitive<TDefined extends boolean = false, THasDefault exte
|
|
|
54
61
|
}
|
|
55
62
|
|
|
56
63
|
/** Set a default value for this boolean */
|
|
57
|
-
default(defaultValue: boolean): BooleanPrimitive<
|
|
64
|
+
default(defaultValue: boolean): BooleanPrimitive<TRequired, true> {
|
|
58
65
|
return new BooleanPrimitive({
|
|
59
66
|
...this._schema,
|
|
60
67
|
defaultValue,
|
|
@@ -62,29 +69,34 @@ export class BooleanPrimitive<TDefined extends boolean = false, THasDefault exte
|
|
|
62
69
|
}
|
|
63
70
|
|
|
64
71
|
/** Add a custom validation rule */
|
|
65
|
-
refine(fn: (value: boolean) => boolean, message: string): BooleanPrimitive<
|
|
72
|
+
refine(fn: (value: boolean) => boolean, message: string): BooleanPrimitive<TRequired, THasDefault> {
|
|
66
73
|
return new BooleanPrimitive({
|
|
67
74
|
...this._schema,
|
|
68
75
|
validators: [...this._schema.validators, { validate: fn, message }],
|
|
69
76
|
});
|
|
70
77
|
}
|
|
71
78
|
|
|
72
|
-
readonly _internal: PrimitiveInternal<boolean, BooleanProxy<
|
|
73
|
-
createProxy: (env: ProxyEnvironment.ProxyEnvironment, operationPath: OperationPath.OperationPath): BooleanProxy<
|
|
79
|
+
readonly _internal: PrimitiveInternal<boolean, BooleanProxy<TRequired, THasDefault>> = {
|
|
80
|
+
createProxy: (env: ProxyEnvironment.ProxyEnvironment, operationPath: OperationPath.OperationPath): BooleanProxy<TRequired, THasDefault> => {
|
|
74
81
|
const defaultValue = this._schema.defaultValue;
|
|
75
82
|
return {
|
|
76
|
-
get: (): MaybeUndefined<boolean,
|
|
83
|
+
get: (): MaybeUndefined<boolean, TRequired, THasDefault> => {
|
|
77
84
|
const state = env.getState(operationPath) as boolean | undefined;
|
|
78
|
-
return (state ?? defaultValue) as MaybeUndefined<boolean,
|
|
85
|
+
return (state ?? defaultValue) as MaybeUndefined<boolean, TRequired, THasDefault>;
|
|
86
|
+
},
|
|
87
|
+
set: (value: InferSetInput<TRequired, THasDefault>) => {
|
|
88
|
+
env.addOperation(
|
|
89
|
+
Operation.fromDefinition(operationPath, this._opDefinitions.set, value)
|
|
90
|
+
);
|
|
79
91
|
},
|
|
80
|
-
|
|
92
|
+
update: (value: InferUpdateInput<TRequired, THasDefault>) => {
|
|
81
93
|
env.addOperation(
|
|
82
94
|
Operation.fromDefinition(operationPath, this._opDefinitions.set, value)
|
|
83
95
|
);
|
|
84
96
|
},
|
|
85
|
-
toSnapshot: (): MaybeUndefined<boolean,
|
|
97
|
+
toSnapshot: (): MaybeUndefined<boolean, TRequired, THasDefault> => {
|
|
86
98
|
const state = env.getState(operationPath) as boolean | undefined;
|
|
87
|
-
return (state ?? defaultValue) as MaybeUndefined<boolean,
|
|
99
|
+
return (state ?? defaultValue) as MaybeUndefined<boolean, TRequired, THasDefault>;
|
|
88
100
|
},
|
|
89
101
|
};
|
|
90
102
|
},
|
package/src/primitives/Either.ts
CHANGED
|
@@ -4,7 +4,7 @@ import * as Operation from "../Operation";
|
|
|
4
4
|
import * as OperationPath from "../OperationPath";
|
|
5
5
|
import * as ProxyEnvironment from "../ProxyEnvironment";
|
|
6
6
|
import * as Transform from "../Transform";
|
|
7
|
-
import type { Primitive, PrimitiveInternal, MaybeUndefined, InferState } from "./shared";
|
|
7
|
+
import type { Primitive, PrimitiveInternal, MaybeUndefined, InferState, NeedsValue } from "./shared";
|
|
8
8
|
import { ValidationError } from "./shared";
|
|
9
9
|
import { StringPrimitive } from "./String";
|
|
10
10
|
import { NumberPrimitive } from "./Number";
|
|
@@ -15,6 +15,9 @@ import { LiteralPrimitive, LiteralValue } from "./Literal";
|
|
|
15
15
|
// Either Primitive - Simple Type Union
|
|
16
16
|
// =============================================================================
|
|
17
17
|
|
|
18
|
+
type InferSetInput<TVariants extends readonly ScalarPrimitive[], TRequired extends boolean = false, THasDefault extends boolean = false> = NeedsValue<InferEitherState<TVariants>, TRequired, THasDefault>
|
|
19
|
+
type InferUpdateInput<TVariants extends readonly ScalarPrimitive[], TRequired extends boolean = false, THasDefault extends boolean = false> = NeedsValue<InferEitherState<TVariants>, TRequired, THasDefault>
|
|
20
|
+
|
|
18
21
|
/**
|
|
19
22
|
* Scalar primitives that can be used as variants in Either
|
|
20
23
|
*/
|
|
@@ -49,18 +52,21 @@ export interface EitherMatchHandlers<R> {
|
|
|
49
52
|
/**
|
|
50
53
|
* Proxy for accessing Either values
|
|
51
54
|
*/
|
|
52
|
-
export interface EitherProxy<TVariants extends readonly ScalarPrimitive[],
|
|
55
|
+
export interface EitherProxy<TVariants extends readonly ScalarPrimitive[], TRequired extends boolean = false, THasDefault extends boolean = false> {
|
|
53
56
|
/** Gets the current value */
|
|
54
|
-
get(): MaybeUndefined<InferEitherState<TVariants>,
|
|
57
|
+
get(): MaybeUndefined<InferEitherState<TVariants>, TRequired, THasDefault>;
|
|
55
58
|
|
|
56
59
|
/** Sets the value to any of the allowed variant types */
|
|
57
|
-
set(value:
|
|
60
|
+
set(value: InferSetInput<TVariants, TRequired, THasDefault>): void;
|
|
61
|
+
|
|
62
|
+
/** This is the same as set. Updates the value, generating an either.set operation */
|
|
63
|
+
update(value: InferUpdateInput<TVariants, TRequired, THasDefault>): void;
|
|
58
64
|
|
|
59
65
|
/** Pattern match on the value type */
|
|
60
66
|
match<R>(handlers: EitherMatchHandlers<R>): R | undefined;
|
|
61
67
|
|
|
62
68
|
/** Returns a readonly snapshot of the value for rendering */
|
|
63
|
-
toSnapshot(): MaybeUndefined<InferEitherSnapshot<TVariants>,
|
|
69
|
+
toSnapshot(): MaybeUndefined<InferEitherSnapshot<TVariants>, TRequired, THasDefault>;
|
|
64
70
|
}
|
|
65
71
|
|
|
66
72
|
interface EitherPrimitiveSchema<TVariants extends readonly ScalarPrimitive[]> {
|
|
@@ -69,14 +75,16 @@ interface EitherPrimitiveSchema<TVariants extends readonly ScalarPrimitive[]> {
|
|
|
69
75
|
readonly variants: TVariants;
|
|
70
76
|
}
|
|
71
77
|
|
|
72
|
-
export class EitherPrimitive<TVariants extends readonly ScalarPrimitive[],
|
|
73
|
-
implements Primitive<InferEitherState<TVariants>, EitherProxy<TVariants,
|
|
78
|
+
export class EitherPrimitive<TVariants extends readonly ScalarPrimitive[], TRequired extends boolean = false, THasDefault extends boolean = false>
|
|
79
|
+
implements Primitive<InferEitherState<TVariants>, EitherProxy<TVariants, TRequired, THasDefault>, TRequired, THasDefault, InferSetInput<TVariants, TRequired, THasDefault>, InferUpdateInput<TVariants, TRequired, THasDefault>>
|
|
74
80
|
{
|
|
75
81
|
readonly _tag = "EitherPrimitive" as const;
|
|
76
82
|
readonly _State!: InferEitherState<TVariants>;
|
|
77
|
-
readonly _Proxy!: EitherProxy<TVariants,
|
|
78
|
-
readonly
|
|
83
|
+
readonly _Proxy!: EitherProxy<TVariants, TRequired, THasDefault>;
|
|
84
|
+
readonly _TRequired!: TRequired;
|
|
79
85
|
readonly _THasDefault!: THasDefault;
|
|
86
|
+
readonly TUpdateInput!: InferUpdateInput<TVariants, TRequired, THasDefault>;
|
|
87
|
+
readonly TSetInput!: InferSetInput<TVariants, TRequired, THasDefault>;
|
|
80
88
|
|
|
81
89
|
private readonly _schema: EitherPrimitiveSchema<TVariants>;
|
|
82
90
|
|
|
@@ -102,7 +110,7 @@ export class EitherPrimitive<TVariants extends readonly ScalarPrimitive[], TDefi
|
|
|
102
110
|
}
|
|
103
111
|
|
|
104
112
|
/** Set a default value for this either */
|
|
105
|
-
default(defaultValue: InferEitherState<TVariants>): EitherPrimitive<TVariants,
|
|
113
|
+
default(defaultValue: InferEitherState<TVariants>): EitherPrimitive<TVariants, TRequired, true> {
|
|
106
114
|
return new EitherPrimitive({
|
|
107
115
|
...this._schema,
|
|
108
116
|
defaultValue,
|
|
@@ -248,19 +256,24 @@ export class EitherPrimitive<TVariants extends readonly ScalarPrimitive[], TDefi
|
|
|
248
256
|
matchingVariant._internal.applyOperation(undefined, syntheticOp);
|
|
249
257
|
}
|
|
250
258
|
|
|
251
|
-
readonly _internal: PrimitiveInternal<InferEitherState<TVariants>, EitherProxy<TVariants,
|
|
259
|
+
readonly _internal: PrimitiveInternal<InferEitherState<TVariants>, EitherProxy<TVariants, TRequired, THasDefault>> = {
|
|
252
260
|
createProxy: (
|
|
253
261
|
env: ProxyEnvironment.ProxyEnvironment,
|
|
254
262
|
operationPath: OperationPath.OperationPath
|
|
255
|
-
): EitherProxy<TVariants,
|
|
263
|
+
): EitherProxy<TVariants, TRequired, THasDefault> => {
|
|
256
264
|
const defaultValue = this._schema.defaultValue;
|
|
257
265
|
|
|
258
266
|
return {
|
|
259
|
-
get: (): MaybeUndefined<InferEitherState<TVariants>,
|
|
267
|
+
get: (): MaybeUndefined<InferEitherState<TVariants>, TRequired, THasDefault> => {
|
|
260
268
|
const state = env.getState(operationPath) as InferEitherState<TVariants> | undefined;
|
|
261
|
-
return (state ?? defaultValue) as MaybeUndefined<InferEitherState<TVariants>,
|
|
269
|
+
return (state ?? defaultValue) as MaybeUndefined<InferEitherState<TVariants>, TRequired, THasDefault>;
|
|
270
|
+
},
|
|
271
|
+
set: (value: InferSetInput<TVariants, TRequired, THasDefault>) => {
|
|
272
|
+
env.addOperation(
|
|
273
|
+
Operation.fromDefinition(operationPath, this._opDefinitions.set, value)
|
|
274
|
+
);
|
|
262
275
|
},
|
|
263
|
-
|
|
276
|
+
update: (value: InferUpdateInput<TVariants, TRequired, THasDefault>) => {
|
|
264
277
|
env.addOperation(
|
|
265
278
|
Operation.fromDefinition(operationPath, this._opDefinitions.set, value)
|
|
266
279
|
);
|
|
@@ -286,9 +299,9 @@ export class EitherPrimitive<TVariants extends readonly ScalarPrimitive[], TDefi
|
|
|
286
299
|
return undefined;
|
|
287
300
|
}
|
|
288
301
|
},
|
|
289
|
-
toSnapshot: (): MaybeUndefined<InferEitherSnapshot<TVariants>,
|
|
302
|
+
toSnapshot: (): MaybeUndefined<InferEitherSnapshot<TVariants>, TRequired, THasDefault> => {
|
|
290
303
|
const state = env.getState(operationPath) as InferEitherState<TVariants> | undefined;
|
|
291
|
-
return (state ?? defaultValue) as MaybeUndefined<InferEitherSnapshot<TVariants>,
|
|
304
|
+
return (state ?? defaultValue) as MaybeUndefined<InferEitherSnapshot<TVariants>, TRequired, THasDefault>;
|
|
292
305
|
},
|
|
293
306
|
};
|
|
294
307
|
},
|
package/src/primitives/Lazy.ts
CHANGED
|
@@ -4,10 +4,20 @@ import * as Operation from "../Operation";
|
|
|
4
4
|
import * as OperationPath from "../OperationPath";
|
|
5
5
|
import * as ProxyEnvironment from "../ProxyEnvironment";
|
|
6
6
|
import * as Transform from "../Transform";
|
|
7
|
-
import type { Primitive, PrimitiveInternal, AnyPrimitive, InferState, InferProxy, InferSnapshot } from "../Primitive";
|
|
7
|
+
import type { Primitive, PrimitiveInternal, AnyPrimitive, InferState, InferProxy, InferSnapshot, InferSetInput, InferUpdateInput } from "../Primitive";
|
|
8
8
|
import { ValidationError } from "../Primitive";
|
|
9
9
|
import { runValidators } from "./shared";
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Type to infer SetInput from a lazy thunk
|
|
13
|
+
*/
|
|
14
|
+
export type InferLazySetInput<T extends () => AnyPrimitive> = InferSetInput<ReturnType<T>>;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Type to infer UpdateInput from a lazy thunk
|
|
18
|
+
*/
|
|
19
|
+
export type InferLazyUpdateInput<T extends () => AnyPrimitive> = InferUpdateInput<ReturnType<T>>;
|
|
20
|
+
|
|
11
21
|
|
|
12
22
|
/**
|
|
13
23
|
* Type to infer state from a lazy thunk
|
|
@@ -25,11 +35,15 @@ export type InferLazyProxy<T extends () => AnyPrimitive> = InferProxy<ReturnType
|
|
|
25
35
|
export type InferLazySnapshot<T extends () => AnyPrimitive> = InferSnapshot<ReturnType<T>>;
|
|
26
36
|
|
|
27
37
|
export class LazyPrimitive<TThunk extends () => AnyPrimitive>
|
|
28
|
-
implements Primitive<InferLazyState<TThunk>, InferLazyProxy<TThunk>>
|
|
38
|
+
implements Primitive<InferLazyState<TThunk>, InferLazyProxy<TThunk>, false, false, InferLazySetInput<TThunk>, InferLazyUpdateInput<TThunk>>
|
|
29
39
|
{
|
|
30
40
|
readonly _tag = "LazyPrimitive" as const;
|
|
31
41
|
readonly _State!: InferLazyState<TThunk>;
|
|
32
42
|
readonly _Proxy!: InferLazyProxy<TThunk>;
|
|
43
|
+
readonly _TRequired!: false;
|
|
44
|
+
readonly _THasDefault!: false;
|
|
45
|
+
readonly TSetInput!: InferLazySetInput<TThunk>;
|
|
46
|
+
readonly TUpdateInput!: InferLazyUpdateInput<TThunk>;
|
|
33
47
|
|
|
34
48
|
private readonly _thunk: TThunk;
|
|
35
49
|
private _resolved: ReturnType<TThunk> | undefined;
|
|
@@ -4,21 +4,25 @@ import * as Operation from "../Operation";
|
|
|
4
4
|
import * as OperationPath from "../OperationPath";
|
|
5
5
|
import * as ProxyEnvironment from "../ProxyEnvironment";
|
|
6
6
|
import * as Transform from "../Transform";
|
|
7
|
-
import type { Primitive, PrimitiveInternal, MaybeUndefined, AnyPrimitive, Validator } from "
|
|
8
|
-
import { ValidationError } from "
|
|
9
|
-
import { runValidators, isCompatibleOperation } from "./shared";
|
|
7
|
+
import type { Primitive, PrimitiveInternal, MaybeUndefined, AnyPrimitive, Validator, NeedsValue } from "./shared";
|
|
8
|
+
import { ValidationError, runValidators, isCompatibleOperation } from "./shared";
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
/** Valid literal types */
|
|
13
12
|
export type LiteralValue = string | number | boolean | null;
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
type InferSetInput<T extends LiteralValue, TRequired extends boolean = false, THasDefault extends boolean = false> = NeedsValue<T, TRequired, THasDefault>
|
|
15
|
+
type InferUpdateInput<T extends LiteralValue, TRequired extends boolean = false, THasDefault extends boolean = false> = NeedsValue<T, TRequired, THasDefault>
|
|
16
|
+
|
|
17
|
+
export interface LiteralProxy<T extends LiteralValue, TRequired extends boolean = false, THasDefault extends boolean = false> {
|
|
16
18
|
/** Gets the current literal value */
|
|
17
|
-
get(): MaybeUndefined<T,
|
|
19
|
+
get(): MaybeUndefined<T, TRequired, THasDefault>;
|
|
18
20
|
/** Sets the literal value (must match the exact literal type) */
|
|
19
|
-
set(value: T): void;
|
|
21
|
+
set(value: InferSetInput<T, TRequired, THasDefault>): void;
|
|
22
|
+
/** This is the same as set. Updates the literal value, generating a literal.set operation */
|
|
23
|
+
update(value: InferUpdateInput<T, TRequired, THasDefault>): void;
|
|
20
24
|
/** Returns a readonly snapshot of the literal value for rendering */
|
|
21
|
-
toSnapshot(): MaybeUndefined<T,
|
|
25
|
+
toSnapshot(): MaybeUndefined<T, TRequired, THasDefault>;
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
interface LiteralPrimitiveSchema<T extends LiteralValue> {
|
|
@@ -27,12 +31,14 @@ interface LiteralPrimitiveSchema<T extends LiteralValue> {
|
|
|
27
31
|
readonly literal: T;
|
|
28
32
|
}
|
|
29
33
|
|
|
30
|
-
export class LiteralPrimitive<T extends LiteralValue,
|
|
34
|
+
export class LiteralPrimitive<T extends LiteralValue, TRequired extends boolean = false, THasDefault extends boolean = false> implements Primitive<T, LiteralProxy<T, TRequired, THasDefault>, TRequired, THasDefault, InferSetInput<T, TRequired, THasDefault>, InferUpdateInput<T, TRequired, THasDefault>> {
|
|
31
35
|
readonly _tag = "LiteralPrimitive" as const;
|
|
32
36
|
readonly _State!: T;
|
|
33
|
-
readonly _Proxy!: LiteralProxy<T,
|
|
34
|
-
readonly
|
|
37
|
+
readonly _Proxy!: LiteralProxy<T, TRequired, THasDefault>;
|
|
38
|
+
readonly _TRequired!: TRequired;
|
|
35
39
|
readonly _THasDefault!: THasDefault;
|
|
40
|
+
readonly TUpdateInput!: InferUpdateInput<T, TRequired, THasDefault>;
|
|
41
|
+
readonly TSetInput!: InferSetInput<T, TRequired, THasDefault>;
|
|
36
42
|
|
|
37
43
|
private readonly _schema: LiteralPrimitiveSchema<T>;
|
|
38
44
|
|
|
@@ -58,7 +64,7 @@ export class LiteralPrimitive<T extends LiteralValue, TDefined extends boolean =
|
|
|
58
64
|
}
|
|
59
65
|
|
|
60
66
|
/** Set a default value for this literal */
|
|
61
|
-
default(defaultValue: T): LiteralPrimitive<T,
|
|
67
|
+
default(defaultValue: T): LiteralPrimitive<T, TRequired, true> {
|
|
62
68
|
return new LiteralPrimitive({
|
|
63
69
|
...this._schema,
|
|
64
70
|
defaultValue,
|
|
@@ -70,22 +76,27 @@ export class LiteralPrimitive<T extends LiteralValue, TDefined extends boolean =
|
|
|
70
76
|
return this._schema.literal;
|
|
71
77
|
}
|
|
72
78
|
|
|
73
|
-
readonly _internal: PrimitiveInternal<T, LiteralProxy<T,
|
|
74
|
-
createProxy: (env: ProxyEnvironment.ProxyEnvironment, operationPath: OperationPath.OperationPath): LiteralProxy<T,
|
|
79
|
+
readonly _internal: PrimitiveInternal<T, LiteralProxy<T, TRequired, THasDefault>> = {
|
|
80
|
+
createProxy: (env: ProxyEnvironment.ProxyEnvironment, operationPath: OperationPath.OperationPath): LiteralProxy<T, TRequired, THasDefault> => {
|
|
75
81
|
const defaultValue = this._schema.defaultValue;
|
|
76
82
|
return {
|
|
77
|
-
get: (): MaybeUndefined<T,
|
|
83
|
+
get: (): MaybeUndefined<T, TRequired, THasDefault> => {
|
|
78
84
|
const state = env.getState(operationPath) as T | undefined;
|
|
79
|
-
return (state ?? defaultValue) as MaybeUndefined<T,
|
|
85
|
+
return (state ?? defaultValue) as MaybeUndefined<T, TRequired, THasDefault>;
|
|
86
|
+
},
|
|
87
|
+
set: (value: InferSetInput<T, TRequired, THasDefault>) => {
|
|
88
|
+
env.addOperation(
|
|
89
|
+
Operation.fromDefinition(operationPath, this._opDefinitions.set, value)
|
|
90
|
+
);
|
|
80
91
|
},
|
|
81
|
-
|
|
92
|
+
update: (value: InferUpdateInput<T, TRequired, THasDefault>) => {
|
|
82
93
|
env.addOperation(
|
|
83
94
|
Operation.fromDefinition(operationPath, this._opDefinitions.set, value)
|
|
84
95
|
);
|
|
85
96
|
},
|
|
86
|
-
toSnapshot: (): MaybeUndefined<T,
|
|
97
|
+
toSnapshot: (): MaybeUndefined<T, TRequired, THasDefault> => {
|
|
87
98
|
const state = env.getState(operationPath) as T | undefined;
|
|
88
|
-
return (state ?? defaultValue) as MaybeUndefined<T,
|
|
99
|
+
return (state ?? defaultValue) as MaybeUndefined<T, TRequired, THasDefault>;
|
|
89
100
|
},
|
|
90
101
|
};
|
|
91
102
|
},
|