@volynets/reflex-store 0.0.0-stage → 0.0.1
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/LICENSE +21 -0
- package/README.md +239 -2
- package/SPECIFICATION.md +137 -0
- package/dist/advanced.d.ts +13 -0
- package/dist/advanced.js +9 -0
- package/dist/chunks/compiler-CW_P8WsZ.js +2526 -0
- package/dist/chunks/createStore-DHj16Ehk.js +12 -0
- package/dist/chunks/hydrate-Bdtl9XyA.js +137 -0
- package/dist/chunks/keyed-C-QvvUv4.js +647 -0
- package/dist/chunks/names-BF36AyM3.js +11 -0
- package/dist/chunks/shared-BHHficW8.js +202 -0
- package/dist/compiled-store.d.ts +4 -0
- package/dist/compiled-store.js +4 -0
- package/dist/compiler/swc.wasm +0 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +7 -0
- package/dist/licenses/NOTICE.txt +1 -0
- package/dist/licenses/SWC-APACHE-2.0.txt +202 -0
- package/dist/runtime/core.d.ts +2 -0
- package/dist/runtime/core.js +1 -0
- package/dist/runtime/internal.d.ts +3 -0
- package/dist/runtime/internal.js +41 -0
- package/dist/runtime/types.d.ts +45 -0
- package/dist/runtime/types.js +1 -0
- package/dist/runtime.d.ts +25 -0
- package/dist/runtime.js +78 -0
- package/dist/selectors/index.d.ts +13 -0
- package/dist/selectors/index.js +15 -0
- package/dist/selectors/shared.d.ts +3 -0
- package/dist/selectors/shared.js +2 -0
- package/dist/store.d.ts +9 -0
- package/dist/store.js +4 -0
- package/dist/types/contracts-BCsRPdQb.d.ts +78 -0
- package/dist/types/createStore-BJ66-pfq.d.ts +43 -0
- package/dist/types/internal-BIzJSPwN.d.ts +18 -0
- package/dist/types/keyed-CdSYzIOc.d.ts +18 -0
- package/dist/types/shared-CdTKzvLe.d.ts +114 -0
- package/dist/vite.d.ts +68 -0
- package/dist/vite.js +87 -0
- package/examples/task-board/README.md +15 -0
- package/examples/task-board/src/task-board.ts +159 -0
- package/examples/task-board/vite.config.ts +6 -0
- package/package.json +125 -4
- package/src/store/README.md +59 -0
- package/src/store/TRANSFORM_SPEC.md +85 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/// <reference lib="esnext.disposable" />
|
|
2
|
+
import { c as StoreProjectionOptions, P as ProjectionOptions } from '../types/shared-CdTKzvLe.js';
|
|
3
|
+
export { K as KeyedOptions } from '../types/shared-CdTKzvLe.js';
|
|
4
|
+
import { S as StoreDisposable, A as Accessor, a as DisposableAccessor } from '../types/keyed-CdSYzIOc.js';
|
|
5
|
+
export { c as createKeyedProjection, b as createSelector } from '../types/keyed-CdSYzIOc.js';
|
|
6
|
+
import '../types/createStore-BJ66-pfq.js';
|
|
7
|
+
|
|
8
|
+
declare function createStoreProjection<T extends object>(fn: (draft: T) => void | T, seed: Partial<T>, options?: StoreProjectionOptions<T>): T & StoreDisposable;
|
|
9
|
+
|
|
10
|
+
declare function createProjection<T extends object>(fn: (draft: T) => void | T, seed: Partial<T>, options?: StoreProjectionOptions<T>): T & StoreDisposable;
|
|
11
|
+
declare function createProjection<T, K, R>(source: Accessor<T>, keyOf: (value: T) => K, project: (value: T) => R, options?: ProjectionOptions<K, R>): DisposableAccessor<K, R | undefined>;
|
|
12
|
+
|
|
13
|
+
export { ProjectionOptions, StoreProjectionOptions, createProjection, createStoreProjection };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { d as createKeyedProjection, e as createStoreProjection } from '../chunks/keyed-C-QvvUv4.js';
|
|
2
|
+
export { a as createSelector } from '../chunks/keyed-C-QvvUv4.js';
|
|
3
|
+
import '@volynets/reflex-runtime/internal';
|
|
4
|
+
import '../chunks/shared-BHHficW8.js';
|
|
5
|
+
import '../chunks/names-BF36AyM3.js';
|
|
6
|
+
import '@volynets/reflex';
|
|
7
|
+
|
|
8
|
+
function createProjection(sourceOrProject, keyOrSeed, projectOrOptions, options) {
|
|
9
|
+
if (typeof keyOrSeed === "function" && typeof projectOrOptions === "function") {
|
|
10
|
+
return createKeyedProjection(sourceOrProject, keyOrSeed, projectOrOptions, options ?? {});
|
|
11
|
+
}
|
|
12
|
+
return createStoreProjection(sourceOrProject, keyOrSeed, projectOrOptions ?? {});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { createKeyedProjection, createProjection, createStoreProjection };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/// <reference lib="esnext.disposable" />
|
|
2
|
+
export { K as KeyedOptions, M as Missing, P as ProjectionOptions, c as StoreProjectionOptions, k as cloneProjectionValue, l as createStoreReaderProxy, m as getMissing, n as isObject, p as readProjectionPath, q as sameValue } from '../types/shared-CdTKzvLe.js';
|
|
3
|
+
import '../types/createStore-BJ66-pfq.js';
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/// <reference lib="esnext.disposable" />
|
|
2
|
+
export { C as CompiledStore, b as StoreShape, c as createStore } from './types/createStore-BJ66-pfq.js';
|
|
3
|
+
import { C as CompiledStoreTransformOptions, a as CompiledStoreTransformResult } from './types/contracts-BCsRPdQb.js';
|
|
4
|
+
export { b as CompiledStoreDiagnostic, c as CompiledStoreLoweringTarget, d as CompiledStoreLoweringTargetOptions, e as CompiledStorePathContext, f as CompiledStoreTemporaryContext, g as CompiledStoreTransformError } from './types/contracts-BCsRPdQb.js';
|
|
5
|
+
|
|
6
|
+
declare function compileStore(code: string, id?: string, options?: CompiledStoreTransformOptions): CompiledStoreTransformResult;
|
|
7
|
+
declare function transformCompiledStore(code: string, id?: string, options?: CompiledStoreTransformOptions): CompiledStoreTransformResult;
|
|
8
|
+
|
|
9
|
+
export { CompiledStoreTransformOptions, CompiledStoreTransformResult, compileStore, transformCompiledStore };
|
package/dist/store.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/// <reference lib="esnext.disposable" />
|
|
2
|
+
interface CompiledStorePathContext {
|
|
3
|
+
path: readonly string[];
|
|
4
|
+
mangledPath: string;
|
|
5
|
+
}
|
|
6
|
+
interface CompiledStoreTemporaryContext {
|
|
7
|
+
index: number;
|
|
8
|
+
label: string;
|
|
9
|
+
}
|
|
10
|
+
interface CompiledStoreLoweringTarget {
|
|
11
|
+
runtimeModule: string;
|
|
12
|
+
scope: {
|
|
13
|
+
exportName: string;
|
|
14
|
+
localName: string;
|
|
15
|
+
actionMethod: string;
|
|
16
|
+
/** Legacy factory targets may return a zero-argument constructor. */
|
|
17
|
+
curried?: boolean;
|
|
18
|
+
};
|
|
19
|
+
signal: {
|
|
20
|
+
/** Defaults to runtimeModule for custom targets. */
|
|
21
|
+
runtimeModule?: string;
|
|
22
|
+
exportName: string;
|
|
23
|
+
localName: string;
|
|
24
|
+
};
|
|
25
|
+
identifiers: {
|
|
26
|
+
context: string;
|
|
27
|
+
value: string;
|
|
28
|
+
read: (context: CompiledStorePathContext) => string;
|
|
29
|
+
set: (context: CompiledStorePathContext) => string;
|
|
30
|
+
write: (context: CompiledStorePathContext) => string;
|
|
31
|
+
temporary: (context: CompiledStoreTemporaryContext) => string;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
type CompiledStoreLoweringTargetOptions = {
|
|
35
|
+
runtimeModule?: string;
|
|
36
|
+
scope?: Partial<CompiledStoreLoweringTarget["scope"]>;
|
|
37
|
+
/** @deprecated Use scope. Legacy model targets are invoked as factories. */
|
|
38
|
+
model?: Partial<CompiledStoreLoweringTarget["scope"]>;
|
|
39
|
+
signal?: Partial<CompiledStoreLoweringTarget["signal"]>;
|
|
40
|
+
identifiers?: Partial<CompiledStoreLoweringTarget["identifiers"]>;
|
|
41
|
+
};
|
|
42
|
+
type DiagnosticCode = "unsupported-shape" | "unsupported-binding" | "unsupported-write" | "dynamic-access" | "branch-alias" | "spread-reflection" | "delete" | "optional-chain";
|
|
43
|
+
interface CompiledStoreDiagnostic {
|
|
44
|
+
code: DiagnosticCode;
|
|
45
|
+
message: string;
|
|
46
|
+
}
|
|
47
|
+
interface CompiledStoreTransformOptions {
|
|
48
|
+
/**
|
|
49
|
+
* Emits the runtime import needed by generated code.
|
|
50
|
+
*
|
|
51
|
+
* Test harnesses can disable this and provide `__reflex_createStoreScope` and
|
|
52
|
+
* `__reflex_signal` in scope manually.
|
|
53
|
+
*/
|
|
54
|
+
importRuntime?: boolean;
|
|
55
|
+
/** Omit the facade when every store use lowers directly to a declared leaf. */
|
|
56
|
+
eraseFacade?: boolean;
|
|
57
|
+
/** Store scope module used by generated code. */
|
|
58
|
+
runtimeModule?: string;
|
|
59
|
+
/** Customize every runtime symbol emitted by the canonical lowering. */
|
|
60
|
+
loweringTarget?: CompiledStoreLoweringTargetOptions;
|
|
61
|
+
/**
|
|
62
|
+
* `throw` is the compiler default because unsupported store syntax should be
|
|
63
|
+
* found during development, not discovered as a runtime semantic mismatch.
|
|
64
|
+
*/
|
|
65
|
+
onDiagnostic?: "throw" | "collect";
|
|
66
|
+
}
|
|
67
|
+
interface CompiledStoreTransformResult {
|
|
68
|
+
code: string;
|
|
69
|
+
diagnostics: CompiledStoreDiagnostic[];
|
|
70
|
+
map: string | null;
|
|
71
|
+
}
|
|
72
|
+
declare class CompiledStoreTransformError extends Error {
|
|
73
|
+
readonly diagnostics: CompiledStoreDiagnostic[];
|
|
74
|
+
constructor(diagnostics: CompiledStoreDiagnostic[]);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export { CompiledStoreTransformError as g };
|
|
78
|
+
export type { CompiledStoreTransformOptions as C, CompiledStoreTransformResult as a, CompiledStoreDiagnostic as b, CompiledStoreLoweringTarget as c, CompiledStoreLoweringTargetOptions as d, CompiledStorePathContext as e, CompiledStoreTemporaryContext as f };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/// <reference lib="esnext.disposable" />
|
|
2
|
+
declare const storeBoundary: unique symbol;
|
|
3
|
+
type StoreBoundary<T> = T & {
|
|
4
|
+
readonly [storeBoundary]: T;
|
|
5
|
+
};
|
|
6
|
+
/** Marks one compiled store value as a replaceable leaf. */
|
|
7
|
+
declare function leaf<T>(value: T): StoreBoundary<T>;
|
|
8
|
+
|
|
9
|
+
type StoreLeaf = string | number | boolean | bigint | symbol | null | undefined | readonly unknown[] | ((...args: any[]) => unknown) | StoreBoundary<unknown>;
|
|
10
|
+
declare const compiledShape: unique symbol;
|
|
11
|
+
type Same<A, B> = (<T>() => T extends A ? 1 : 2) extends <T>() => T extends B ? 1 : 2 ? true : false;
|
|
12
|
+
type StoreData<T> = {
|
|
13
|
+
[K in keyof T as T[K] extends (...args: any[]) => unknown ? never : Same<Pick<T, K>, {
|
|
14
|
+
-readonly [P in K]: T[P];
|
|
15
|
+
}> extends true ? K : never]: T[K] extends StoreBoundary<infer V> ? V : T[K] extends StoreShape ? StoreData<T[K]> : T[K];
|
|
16
|
+
};
|
|
17
|
+
interface StoreOptions {
|
|
18
|
+
name?: string;
|
|
19
|
+
}
|
|
20
|
+
type StoreShape = {
|
|
21
|
+
[key: string]: StoreLeaf | StoreShape;
|
|
22
|
+
};
|
|
23
|
+
type CompiledValue<T> = T extends StoreBoundary<infer TLeaf> ? TLeaf : T extends StoreShape ? CompiledBranch<T> : T;
|
|
24
|
+
type CompiledBranch<TShape extends StoreShape> = {
|
|
25
|
+
-readonly [K in keyof TShape]: CompiledValue<TShape[K]>;
|
|
26
|
+
};
|
|
27
|
+
type CompiledStore<TShape extends StoreShape> = CompiledBranch<TShape> & {
|
|
28
|
+
readonly [compiledShape]: TShape;
|
|
29
|
+
dispose(): void;
|
|
30
|
+
[Symbol.dispose](): void;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Declares a compile-time store shape for the compiled-store transform.
|
|
34
|
+
*
|
|
35
|
+
* Data properties become leaf cells; methods become batched actions; getters
|
|
36
|
+
* become lazy computed values. leaf() and opaque() mark object values as
|
|
37
|
+
* replaceable leaves. If this function executes at runtime, the transform did
|
|
38
|
+
* not run.
|
|
39
|
+
*/
|
|
40
|
+
declare function createStore<TShape extends StoreShape>(_shape: TShape, _options?: StoreOptions): CompiledStore<TShape>;
|
|
41
|
+
|
|
42
|
+
export { createStore as c, leaf as l };
|
|
43
|
+
export type { CompiledStore as C, StoreData as S, StoreOptions as a, StoreShape as b, StoreBoundary as d };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/// <reference lib="esnext.disposable" />
|
|
2
|
+
import '@volynets/reflex-runtime/internal';
|
|
3
|
+
|
|
4
|
+
interface StoreCell<T> {
|
|
5
|
+
(): T;
|
|
6
|
+
set(value: T): void;
|
|
7
|
+
peek(): T;
|
|
8
|
+
collect(): void;
|
|
9
|
+
dispose(): void;
|
|
10
|
+
[Symbol.dispose](): void;
|
|
11
|
+
}
|
|
12
|
+
/** Compiler target: a direct leaf address, materialized only by a tracked read. */
|
|
13
|
+
declare function createStoreCell<T>(initial: T, options?: {
|
|
14
|
+
name?: string;
|
|
15
|
+
}): StoreCell<T>;
|
|
16
|
+
|
|
17
|
+
export { createStoreCell as c };
|
|
18
|
+
export type { StoreCell as S };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/// <reference lib="esnext.disposable" />
|
|
2
|
+
import { K as KeyedOptions, P as ProjectionOptions } from './shared-CdTKzvLe.js';
|
|
3
|
+
|
|
4
|
+
interface StoreDisposable {
|
|
5
|
+
[Symbol.dispose](): void;
|
|
6
|
+
}
|
|
7
|
+
type Destructor = () => void;
|
|
8
|
+
type Accessor<T> = () => T;
|
|
9
|
+
type DisposableAccessor<K, V> = ((key: K) => V) & StoreDisposable & {
|
|
10
|
+
collect(): void;
|
|
11
|
+
dispose(): void;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
declare function createSelector<T>(source: Accessor<T>, options?: KeyedOptions<T>): DisposableAccessor<T, boolean>;
|
|
15
|
+
declare function createKeyedProjection<T, K, R>(source: Accessor<T>, keyOf: (value: T) => K, project: (value: T) => R, options?: ProjectionOptions<K, R>): DisposableAccessor<K, R | undefined>;
|
|
16
|
+
|
|
17
|
+
export { createSelector as b, createKeyedProjection as c };
|
|
18
|
+
export type { Accessor as A, Destructor as D, StoreDisposable as S, DisposableAccessor as a };
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/// <reference lib="esnext.disposable" />
|
|
2
|
+
import { d as StoreBoundary, b as StoreShape, C as CompiledStore, S as StoreData } from './createStore-BJ66-pfq.js';
|
|
3
|
+
|
|
4
|
+
/** Publish a synchronous logical action at one runtime batch boundary. */
|
|
5
|
+
declare function transaction<T>(action: () => T): T;
|
|
6
|
+
interface ReactiveMapOptions<V> {
|
|
7
|
+
name?: string;
|
|
8
|
+
/** Values are reference boundaries; equivalent replacements retain the old value. */
|
|
9
|
+
equals?: (previous: V, next: V) => boolean;
|
|
10
|
+
}
|
|
11
|
+
declare class ReactiveMap<K, V> implements Iterable<[K, V]> {
|
|
12
|
+
private initial?;
|
|
13
|
+
private readonly options;
|
|
14
|
+
private data?;
|
|
15
|
+
private disposed;
|
|
16
|
+
private readonly valuesByKey;
|
|
17
|
+
private readonly existsByKey;
|
|
18
|
+
private sizeNode?;
|
|
19
|
+
private keysNode?;
|
|
20
|
+
private valuesNode?;
|
|
21
|
+
constructor(initial?: (Iterable<readonly [K, V]> | (() => Iterable<readonly [K, V]>)) | undefined, options?: ReactiveMapOptions<V>);
|
|
22
|
+
private backing;
|
|
23
|
+
get size(): number;
|
|
24
|
+
get [Symbol.toStringTag](): string;
|
|
25
|
+
get(key: K): V | undefined;
|
|
26
|
+
has(key: K): boolean;
|
|
27
|
+
set(key: K, value: V): this;
|
|
28
|
+
private commitSet;
|
|
29
|
+
delete(key: K): boolean;
|
|
30
|
+
clear(): void;
|
|
31
|
+
keys(): MapIterator<K>;
|
|
32
|
+
values(): MapIterator<V>;
|
|
33
|
+
entries(): MapIterator<[K, V]>;
|
|
34
|
+
[Symbol.iterator](): MapIterator<[K, V]>;
|
|
35
|
+
forEach(callback: (value: V, key: K, map: ReactiveMap<K, V>) => void, thisArg?: unknown): void;
|
|
36
|
+
collect(): void;
|
|
37
|
+
[Symbol.dispose](): void;
|
|
38
|
+
dispose(): void;
|
|
39
|
+
}
|
|
40
|
+
/** A native Set-shaped membership collection over keyed reactive observations. */
|
|
41
|
+
declare class ReactiveSet<T> implements Iterable<T> {
|
|
42
|
+
private readonly members;
|
|
43
|
+
constructor(initial?: Iterable<T> | (() => Iterable<T>), options?: {
|
|
44
|
+
name?: string;
|
|
45
|
+
});
|
|
46
|
+
get size(): number;
|
|
47
|
+
get [Symbol.toStringTag](): string;
|
|
48
|
+
has(value: T): boolean;
|
|
49
|
+
add(value: T): this;
|
|
50
|
+
delete(value: T): boolean;
|
|
51
|
+
clear(): void;
|
|
52
|
+
values(): MapIterator<T>;
|
|
53
|
+
keys(): MapIterator<T>;
|
|
54
|
+
entries(): IterableIterator<[T, T]>;
|
|
55
|
+
[Symbol.iterator](): MapIterator<T>;
|
|
56
|
+
forEach(callback: (value: T, key: T, set: ReactiveSet<T>) => void, thisArg?: unknown): void;
|
|
57
|
+
collect(): void;
|
|
58
|
+
dispose(): void;
|
|
59
|
+
[Symbol.dispose](): void;
|
|
60
|
+
}
|
|
61
|
+
declare function reactiveSet<T>(initial?: Iterable<T> | (() => Iterable<T>), options?: {
|
|
62
|
+
name?: string;
|
|
63
|
+
}): ReactiveSet<T>;
|
|
64
|
+
declare function createReactiveMap<K, V>(initial?: Iterable<readonly [K, V]> | (() => Iterable<readonly [K, V]>), options?: ReactiveMapOptions<V>): ReactiveMap<K, V>;
|
|
65
|
+
|
|
66
|
+
type Depth = "deep" | "shallow" | "ref" | "opaque";
|
|
67
|
+
declare const deep: <T extends object>(value: T) => T;
|
|
68
|
+
declare const shallow: <T extends object>(value: T) => T;
|
|
69
|
+
declare const ref: <T extends object>(value: T) => T;
|
|
70
|
+
declare const opaque: <T extends object>(value: T) => StoreBoundary<T>;
|
|
71
|
+
/** Copy structural data, retaining explicit reference boundaries and foreign objects. */
|
|
72
|
+
declare function cloneValue<T>(value: T, seen?: Map<object, unknown>): T;
|
|
73
|
+
/** An untracked backing view. Mutating it bypasses reactivity and is unsupported. */
|
|
74
|
+
declare function raw<K, V>(store: ReactiveMap<K, V>): Map<K, V>;
|
|
75
|
+
declare function raw<T>(store: ReactiveSet<T>): Set<T>;
|
|
76
|
+
declare function raw<T>(store: T): T;
|
|
77
|
+
type Snapshot<T> = T extends ReactiveSet<infer V> ? ReadonlySet<V> : T extends Set<infer V> ? ReadonlySet<V> : T extends ReactiveMap<infer K, infer V> ? ReadonlyMap<K, Snapshot<V>> : T extends Map<infer K, infer V> ? ReadonlyMap<K, Snapshot<V>> : T extends readonly (infer V)[] ? readonly Snapshot<V>[] : T extends object ? {
|
|
78
|
+
readonly [K in keyof T]: Snapshot<T[K]>;
|
|
79
|
+
} : T;
|
|
80
|
+
/** An untracked point-in-time copy. Opaque/foreign values remain by reference. */
|
|
81
|
+
declare function snapshot<T extends StoreShape>(store: CompiledStore<T>): Snapshot<StoreData<T>>;
|
|
82
|
+
declare function snapshot<T>(store: T): Snapshot<T>;
|
|
83
|
+
declare function disposeStore(store: object): void;
|
|
84
|
+
/** Reclaim locations with no consumers at an explicit owner lifecycle boundary. */
|
|
85
|
+
declare function collectStore(store: object): void;
|
|
86
|
+
|
|
87
|
+
declare const MISSING: unique symbol;
|
|
88
|
+
type AnyRecord = Record<PropertyKey, unknown>;
|
|
89
|
+
type Missing = typeof MISSING;
|
|
90
|
+
interface KeyedOptions<T> {
|
|
91
|
+
name?: string;
|
|
92
|
+
equals?: (prev: T, next: T) => boolean;
|
|
93
|
+
}
|
|
94
|
+
interface ProjectionOptions<K, R> {
|
|
95
|
+
name?: string;
|
|
96
|
+
keyEquals?: (prev: K, next: K) => boolean;
|
|
97
|
+
equals?: (prev: R, next: R) => boolean;
|
|
98
|
+
fallback?: R;
|
|
99
|
+
}
|
|
100
|
+
interface StoreProjectionOptions<T extends object> {
|
|
101
|
+
name?: string;
|
|
102
|
+
clone?: (value: T) => T;
|
|
103
|
+
equals?: (previous: T, next: T) => boolean;
|
|
104
|
+
depth?: "deep" | "shallow";
|
|
105
|
+
}
|
|
106
|
+
declare function sameValue<T>(prev: T, next: T): boolean;
|
|
107
|
+
declare function getMissing(): Missing;
|
|
108
|
+
declare function isObject(value: unknown): value is AnyRecord;
|
|
109
|
+
|
|
110
|
+
declare function readProjectionPath(value: unknown, path: readonly PropertyKey[]): unknown;
|
|
111
|
+
declare function createStoreReaderProxy<T extends object>(readState: () => T, path?: readonly PropertyKey[]): T;
|
|
112
|
+
|
|
113
|
+
export { ReactiveMap as R, ReactiveSet as b, collectStore as d, createReactiveMap as e, deep as f, disposeStore as g, reactiveSet as h, ref as i, snapshot as j, cloneValue as k, createStoreReaderProxy as l, getMissing as m, isObject as n, opaque as o, readProjectionPath as p, sameValue as q, raw as r, shallow as s, transaction as t };
|
|
114
|
+
export type { Depth as D, KeyedOptions as K, Missing as M, ProjectionOptions as P, Snapshot as S, ReactiveMapOptions as a, StoreProjectionOptions as c };
|
package/dist/vite.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/// <reference lib="esnext.disposable" />
|
|
2
|
+
import { d as CompiledStoreLoweringTargetOptions } from './types/contracts-BCsRPdQb.js';
|
|
3
|
+
|
|
4
|
+
type TransformResult = {
|
|
5
|
+
code: string;
|
|
6
|
+
map: null | {
|
|
7
|
+
version: 3;
|
|
8
|
+
sources: string[];
|
|
9
|
+
names: string[];
|
|
10
|
+
mappings: string;
|
|
11
|
+
sourcesContent?: (string | null)[];
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
interface ReflexStorePlugin {
|
|
15
|
+
name: string;
|
|
16
|
+
enforce: "pre";
|
|
17
|
+
transform(this: DiagnosticReporter, code: string, id: string): TransformResult | null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type Selector = string | RegExp | readonly (string | RegExp)[];
|
|
21
|
+
type DiagnosticMode = "error" | "warn" | "collect";
|
|
22
|
+
type DiagnosticReporter = {
|
|
23
|
+
warn(warning: string): void;
|
|
24
|
+
error(error: string): never;
|
|
25
|
+
};
|
|
26
|
+
interface ReflexStoreVitePluginOptions {
|
|
27
|
+
/**
|
|
28
|
+
* Files eligible for the compiled-store transform.
|
|
29
|
+
*
|
|
30
|
+
* @default /\.[cm]?[jt]sx?$/
|
|
31
|
+
*/
|
|
32
|
+
include?: Selector;
|
|
33
|
+
/**
|
|
34
|
+
* Files excluded from the compiled-store transform.
|
|
35
|
+
*
|
|
36
|
+
* @default /\/node_modules\//
|
|
37
|
+
*/
|
|
38
|
+
exclude?: Selector;
|
|
39
|
+
/**
|
|
40
|
+
* Runtime module used by generated code.
|
|
41
|
+
*
|
|
42
|
+
* @default "@volynets/reflex"
|
|
43
|
+
*/
|
|
44
|
+
runtimeModule?: string;
|
|
45
|
+
eraseFacade?: boolean;
|
|
46
|
+
/** Customize the runtime primitives and every generated identifier. */
|
|
47
|
+
loweringTarget?: CompiledStoreLoweringTargetOptions;
|
|
48
|
+
/**
|
|
49
|
+
* Compile bare `createStore({ ... })` calls even when the file does not
|
|
50
|
+
* import `createStore` from `@volynets/reflex-store`.
|
|
51
|
+
*
|
|
52
|
+
* The default keeps the plugin conservative and avoids touching unrelated
|
|
53
|
+
* libraries that also expose a `createStore` function.
|
|
54
|
+
*
|
|
55
|
+
* @default false
|
|
56
|
+
*/
|
|
57
|
+
compileBareCreateStore?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* How unsupported phase-1 syntax is surfaced through Vite.
|
|
60
|
+
*
|
|
61
|
+
* @default "error"
|
|
62
|
+
*/
|
|
63
|
+
diagnostics?: DiagnosticMode;
|
|
64
|
+
}
|
|
65
|
+
declare function reflexStoreVitePlugin(options?: ReflexStoreVitePluginOptions): ReflexStorePlugin;
|
|
66
|
+
|
|
67
|
+
export { reflexStoreVitePlugin as default, reflexStoreVitePlugin as reflexStore, reflexStoreVitePlugin };
|
|
68
|
+
export type { ReflexStorePlugin, ReflexStoreVitePluginOptions };
|
package/dist/vite.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { c as compileStore, C as CompiledStoreTransformError } from './chunks/compiler-CW_P8WsZ.js';
|
|
2
|
+
import 'util';
|
|
3
|
+
import 'fs';
|
|
4
|
+
|
|
5
|
+
const DEFAULT_INCLUDE = /\.[cm]?[jt]sx?$/;
|
|
6
|
+
const DEFAULT_EXCLUDE = /\/node_modules\//;
|
|
7
|
+
const STORE_IMPORT_RE = /from\s*["'](?:@volynets\/reflex-store|@reflex\/store)(?:\/(?:store|compiled-store|advanced))?["']/;
|
|
8
|
+
function reflexStoreVitePlugin(options = {}) {
|
|
9
|
+
const include = options.include ?? DEFAULT_INCLUDE;
|
|
10
|
+
const exclude = options.exclude ?? DEFAULT_EXCLUDE;
|
|
11
|
+
const diagnostics = options.diagnostics ?? "error";
|
|
12
|
+
return {
|
|
13
|
+
name: "reflex-store",
|
|
14
|
+
enforce: "pre",
|
|
15
|
+
transform (code, id) {
|
|
16
|
+
const normalizedId = normalizeId(id);
|
|
17
|
+
if (!matchesSelector(include, normalizedId)) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
if (matchesSelector(exclude, normalizedId)) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
if (!shouldCompileCode(code, options.compileBareCreateStore ?? false)) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const result = compileStore(code, normalizedId, {
|
|
28
|
+
importRuntime: true,
|
|
29
|
+
eraseFacade: options.eraseFacade,
|
|
30
|
+
onDiagnostic: diagnostics === "error" ? "throw" : "collect",
|
|
31
|
+
loweringTarget: options.loweringTarget,
|
|
32
|
+
runtimeModule: options.runtimeModule
|
|
33
|
+
});
|
|
34
|
+
reportDiagnostics(this, result.diagnostics, diagnostics);
|
|
35
|
+
return {
|
|
36
|
+
code: result.code,
|
|
37
|
+
map: parseSourceMap(result.map)
|
|
38
|
+
};
|
|
39
|
+
} catch (error) {
|
|
40
|
+
if (error instanceof CompiledStoreTransformError) {
|
|
41
|
+
this.error(formatDiagnostics(error.diagnostics));
|
|
42
|
+
}
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function shouldCompileCode(code, compileBareCreateStore) {
|
|
49
|
+
if (!code.includes("createStore")) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
return compileBareCreateStore || STORE_IMPORT_RE.test(code);
|
|
53
|
+
}
|
|
54
|
+
function normalizeId(id) {
|
|
55
|
+
return id.split("?")[0].replace(/\\/g, "/");
|
|
56
|
+
}
|
|
57
|
+
function matchesSelector(selector, id) {
|
|
58
|
+
if (isSelectorArray(selector)) {
|
|
59
|
+
return selector.some((item)=>matchesSelector(item, id));
|
|
60
|
+
}
|
|
61
|
+
if (typeof selector === "string") {
|
|
62
|
+
return id.includes(selector);
|
|
63
|
+
}
|
|
64
|
+
return selector.test(id);
|
|
65
|
+
}
|
|
66
|
+
function isSelectorArray(selector) {
|
|
67
|
+
return Array.isArray(selector);
|
|
68
|
+
}
|
|
69
|
+
function parseSourceMap(map) {
|
|
70
|
+
return map === null ? null : JSON.parse(map);
|
|
71
|
+
}
|
|
72
|
+
function reportDiagnostics(context, diagnostics, mode) {
|
|
73
|
+
if (diagnostics.length === 0 || mode === "collect") {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const message = formatDiagnostics(diagnostics);
|
|
77
|
+
if (mode === "warn") {
|
|
78
|
+
context.warn(message);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
context.error(message);
|
|
82
|
+
}
|
|
83
|
+
function formatDiagnostics(diagnostics) {
|
|
84
|
+
return diagnostics.map((diagnostic)=>diagnostic.message).join("\n");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export { reflexStoreVitePlugin as default, reflexStoreVitePlugin as reflexStore, reflexStoreVitePlugin };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Task board example
|
|
2
|
+
|
|
3
|
+
The example uses reactiveMap for dynamic task IDs, createStore for closed UI
|
|
4
|
+
state, selector for selection observations, derive for summary fields and action
|
|
5
|
+
for coherent mutations. The Vite plugin enables compilation.
|
|
6
|
+
|
|
7
|
+
The implementation is [src/task-board.ts](./src/task-board.ts). Run its contracts:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pnpm --filter @volynets/reflex-store test:integration
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The tests cover summary-field precision, keyed map reads, selection locality,
|
|
14
|
+
batching, pull freshness, ownership and no-op moves. The package also includes
|
|
15
|
+
production contracts for compiled methods/getters and snapshot/hydration.
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { createRuntime, effect } from "@volynets/reflex-store/runtime";
|
|
2
|
+
import {
|
|
3
|
+
action,
|
|
4
|
+
createStore,
|
|
5
|
+
derive,
|
|
6
|
+
reactiveMap,
|
|
7
|
+
selector,
|
|
8
|
+
} from "@volynets/reflex-store";
|
|
9
|
+
|
|
10
|
+
export type TaskStatus = "backlog" | "active" | "done";
|
|
11
|
+
|
|
12
|
+
export interface Task {
|
|
13
|
+
id: string;
|
|
14
|
+
title: string;
|
|
15
|
+
assignee: string;
|
|
16
|
+
status: TaskStatus;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface BoardSummary {
|
|
20
|
+
total: number;
|
|
21
|
+
visible: number;
|
|
22
|
+
completed: number;
|
|
23
|
+
activeTitle: string;
|
|
24
|
+
filterLabel: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const taskBoardRuntime = createRuntime({ effectStrategy: "flush" });
|
|
28
|
+
|
|
29
|
+
const INITIAL_TASKS: readonly Task[] = [
|
|
30
|
+
{ id: "T-101", title: "Design checkout", assignee: "Ada", status: "active" },
|
|
31
|
+
{ id: "T-102", title: "Add audit log", assignee: "Lin", status: "backlog" },
|
|
32
|
+
{ id: "T-103", title: "Ship billing", assignee: "Ada", status: "done" },
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
export const tasks = reactiveMap<string, Task>(
|
|
36
|
+
INITIAL_TASKS.map((task) => [task.id, task] as const),
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const ui = createStore({
|
|
40
|
+
filter: {
|
|
41
|
+
status: "all" as TaskStatus | "all",
|
|
42
|
+
query: "",
|
|
43
|
+
},
|
|
44
|
+
selection: {
|
|
45
|
+
taskId: "T-101",
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const EMPTY_TASK: Readonly<Task> = Object.freeze({
|
|
50
|
+
id: "",
|
|
51
|
+
title: "No task selected",
|
|
52
|
+
assignee: "",
|
|
53
|
+
status: "backlog",
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export const isTaskSelected = selector(() => ui.selection.taskId);
|
|
57
|
+
|
|
58
|
+
export const taskById = (taskId: string): Task | undefined => tasks.get(taskId);
|
|
59
|
+
|
|
60
|
+
export const summary = derive<BoardSummary>(() => {
|
|
61
|
+
const allTasks = [...tasks.values()];
|
|
62
|
+
const status = ui.filter.status;
|
|
63
|
+
const normalizedQuery = ui.filter.query.trim().toLocaleLowerCase();
|
|
64
|
+
const selectedTask = tasks.get(ui.selection.taskId) ?? EMPTY_TASK;
|
|
65
|
+
|
|
66
|
+
let completed = 0;
|
|
67
|
+
let visible = 0;
|
|
68
|
+
|
|
69
|
+
for (const task of allTasks) {
|
|
70
|
+
if (task.status === "done") completed++;
|
|
71
|
+
|
|
72
|
+
if (
|
|
73
|
+
(status === "all" || task.status === status) &&
|
|
74
|
+
(normalizedQuery === "" ||
|
|
75
|
+
task.title.toLocaleLowerCase().includes(normalizedQuery))
|
|
76
|
+
) {
|
|
77
|
+
visible++;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
total: allTasks.length,
|
|
83
|
+
completed,
|
|
84
|
+
visible,
|
|
85
|
+
activeTitle: selectedTask.title,
|
|
86
|
+
filterLabel:
|
|
87
|
+
normalizedQuery === "" ? status : status + ":" + normalizedQuery,
|
|
88
|
+
};
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const resetBoard = action(() => {
|
|
92
|
+
tasks.clear();
|
|
93
|
+
for (const task of INITIAL_TASKS) tasks.set(task.id, task);
|
|
94
|
+
ui.filter.status = "all";
|
|
95
|
+
ui.filter.query = "";
|
|
96
|
+
ui.selection.taskId = "T-101";
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
export const boardActions = {
|
|
100
|
+
select: action((taskId: string) => {
|
|
101
|
+
if (ui.selection.taskId !== taskId) ui.selection.taskId = taskId;
|
|
102
|
+
}),
|
|
103
|
+
|
|
104
|
+
setFilter: action((status: TaskStatus | "all", query = "") => {
|
|
105
|
+
if (ui.filter.status !== status) ui.filter.status = status;
|
|
106
|
+
if (ui.filter.query !== query) ui.filter.query = query;
|
|
107
|
+
}),
|
|
108
|
+
|
|
109
|
+
move: action((taskId: string, status: TaskStatus) => {
|
|
110
|
+
const task = tasks.get(taskId);
|
|
111
|
+
if (!task || task.status === status) return;
|
|
112
|
+
tasks.set(taskId, { ...task, status });
|
|
113
|
+
}),
|
|
114
|
+
|
|
115
|
+
reset() {
|
|
116
|
+
resetBoard();
|
|
117
|
+
taskBoardRuntime.flush();
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
flush() {
|
|
121
|
+
taskBoardRuntime.flush();
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export function runTaskBoardScenario() {
|
|
126
|
+
const renders: string[] = [];
|
|
127
|
+
|
|
128
|
+
const stop = effect(() => {
|
|
129
|
+
renders.push(
|
|
130
|
+
summary.filterLabel +
|
|
131
|
+
"|" +
|
|
132
|
+
summary.visible +
|
|
133
|
+
"|" +
|
|
134
|
+
summary.completed +
|
|
135
|
+
"|" +
|
|
136
|
+
summary.activeTitle,
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
boardActions.setFilter("active");
|
|
141
|
+
boardActions.select("T-102");
|
|
142
|
+
taskBoardRuntime.flush();
|
|
143
|
+
|
|
144
|
+
boardActions.move("T-102", "active");
|
|
145
|
+
taskBoardRuntime.flush();
|
|
146
|
+
|
|
147
|
+
stop();
|
|
148
|
+
|
|
149
|
+
const activeTask = taskById("T-102");
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
activeTask: activeTask === undefined ? undefined : activeTask.title,
|
|
153
|
+
completed: summary.completed,
|
|
154
|
+
isSelected: isTaskSelected("T-102"),
|
|
155
|
+
renders,
|
|
156
|
+
total: summary.total,
|
|
157
|
+
visible: summary.visible,
|
|
158
|
+
};
|
|
159
|
+
}
|