cross-state 0.8.5 → 0.9.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 (43) hide show
  1. package/dist/cjs/cache.cjs +386 -0
  2. package/dist/cjs/cache.cjs.map +1 -0
  3. package/dist/cjs/index.cjs +21 -16
  4. package/dist/cjs/index.cjs.map +1 -1
  5. package/dist/cjs/react/index.cjs +163 -11
  6. package/dist/cjs/react/index.cjs.map +1 -1
  7. package/dist/cjs/react/register.cjs +12 -12
  8. package/dist/cjs/react/register.cjs.map +1 -1
  9. package/dist/cjs/scope.cjs +11 -379
  10. package/dist/cjs/scope.cjs.map +1 -1
  11. package/dist/cjs/store.cjs.map +1 -1
  12. package/dist/cjs/{scope2.cjs → useCache.cjs} +54 -40
  13. package/dist/cjs/useCache.cjs.map +1 -0
  14. package/dist/es/cache.mjs +387 -0
  15. package/dist/es/cache.mjs.map +1 -0
  16. package/dist/es/index.mjs +16 -11
  17. package/dist/es/index.mjs.map +1 -1
  18. package/dist/es/react/index.mjs +161 -9
  19. package/dist/es/react/index.mjs.map +1 -1
  20. package/dist/es/react/register.mjs +4 -4
  21. package/dist/es/scope.mjs +12 -380
  22. package/dist/es/scope.mjs.map +1 -1
  23. package/dist/es/store.mjs +3 -3
  24. package/dist/es/store.mjs.map +1 -1
  25. package/dist/es/{scope2.mjs → useCache.mjs} +58 -44
  26. package/dist/es/useCache.mjs.map +1 -0
  27. package/dist/types/lib/castArray.d.ts +1 -0
  28. package/dist/types/lib/path.d.ts +11 -9
  29. package/dist/types/lib/propAccess.d.ts +1 -1
  30. package/dist/types/lib/typeHelpers.d.ts +2 -1
  31. package/dist/types/lib/wildcardMatch.d.ts +3 -0
  32. package/dist/types/persist/persist.d.ts +6 -4
  33. package/dist/types/react/form.d.ts +48 -0
  34. package/dist/types/react/index.d.ts +1 -0
  35. package/dist/types/react/useProp.d.ts +5 -1
  36. package/dist/types/react/useStore.d.ts +5 -2
  37. package/package.json +23 -11
  38. package/dist/cjs/hash.cjs +0 -18
  39. package/dist/cjs/hash.cjs.map +0 -1
  40. package/dist/cjs/scope2.cjs.map +0 -1
  41. package/dist/es/hash.mjs +0 -19
  42. package/dist/es/hash.mjs.map +0 -1
  43. package/dist/es/scope2.mjs.map +0 -1
@@ -1,9 +1,159 @@
1
- import { u as useCache } from "../scope2.mjs";
2
- import { S, r, b, a, c } from "../scope2.mjs";
3
- import { useState, useRef, useEffect, useMemo, startTransition } from "react";
4
- import { h as debounce, t as throttle } from "../store.mjs";
5
- import { h as hash } from "../hash.mjs";
6
- import "react/jsx-runtime";
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { createContext, useMemo, useContext, useState, useRef, useEffect, startTransition } from "react";
3
+ import { u as useScope, a as useStore, b as useCache } from "../useCache.mjs";
4
+ import { S, r, c } from "../useCache.mjs";
5
+ import { b as castArrayPath, g as get, h as deepEqual, i as debounce, t as throttle } from "../store.mjs";
6
+ import { S as Scope, h as hash } from "../scope.mjs";
7
+ function wildcardMatch(s, w) {
8
+ if (typeof s === "string") {
9
+ s = castArrayPath(s);
10
+ }
11
+ if (typeof w === "string") {
12
+ w = castArrayPath(w);
13
+ }
14
+ return s.length === w.length && s.every((s2, i) => w[i] === "*" || s2 === w[i]);
15
+ }
16
+ function getWildCardMatches(object, path) {
17
+ const matches = {};
18
+ const [first, ...rest] = castArrayPath(path);
19
+ if (first === void 0) {
20
+ return object;
21
+ }
22
+ if (!(object instanceof Object)) {
23
+ return {};
24
+ }
25
+ if (first === "*") {
26
+ for (const [key, value] of Object.entries(object)) {
27
+ matches[key] = getWildCardMatches(value, rest);
28
+ }
29
+ } else {
30
+ matches[first] = getWildCardMatches(object[first], rest);
31
+ }
32
+ return matches;
33
+ }
34
+ class Form {
35
+ constructor(options) {
36
+ this.options = options;
37
+ this.context = createContext({
38
+ original: void 0,
39
+ options: this.options
40
+ });
41
+ this.state = new Scope({});
42
+ this.Provider = this.Provider.bind(this);
43
+ }
44
+ Provider({
45
+ children,
46
+ original,
47
+ defaultValue = this.options.defaultValue,
48
+ validations = this.options.validations
49
+ }) {
50
+ const value = useMemo(
51
+ () => ({ original, options: { defaultValue, validations } }),
52
+ [original, defaultValue, validations]
53
+ );
54
+ return /* @__PURE__ */ jsx(this.context.Provider, { value, children: /* @__PURE__ */ jsx(this.state.Provider, { children }) });
55
+ }
56
+ useForm() {
57
+ const { original, options } = useContext(this.context);
58
+ const state = useScope(this.state);
59
+ return useMemo(
60
+ () => ({
61
+ original,
62
+ draft: state.map(
63
+ (state2) => state2.draft ?? original ?? options.defaultValue,
64
+ (draft) => (state2) => ({ ...state2, draft })
65
+ ),
66
+ getField(path) {
67
+ const { draft } = this;
68
+ return {
69
+ get originalValue() {
70
+ return original !== void 0 ? get(original, path) : void 0;
71
+ },
72
+ get value() {
73
+ return get(draft.get(), path);
74
+ },
75
+ setValue(update) {
76
+ draft.set(path, update);
77
+ },
78
+ get isDirty() {
79
+ return state.get().hasTriggeredValidations || !deepEqual(this.originalValue, this.value);
80
+ },
81
+ get error() {
82
+ const blocks = Object.entries(
83
+ options.validations ?? {}
84
+ ).filter(([key]) => wildcardMatch(path, key)).map(([, value2]) => value2);
85
+ const value = this.value;
86
+ const draftValue = draft.get();
87
+ for (const block of blocks ?? []) {
88
+ for (const [validationName, validate] of Object.entries(block)) {
89
+ if (!validate(value, { draft: draftValue, original, field: path })) {
90
+ return validationName;
91
+ }
92
+ }
93
+ }
94
+ return void 0;
95
+ }
96
+ };
97
+ },
98
+ hasChanges() {
99
+ const { draft } = state.get();
100
+ return !!draft && !deepEqual(draft, original);
101
+ },
102
+ getErrors() {
103
+ const draft = this.draft.get();
104
+ const errors = /* @__PURE__ */ new Set();
105
+ for (const [path, block] of Object.entries(options.validations ?? {})) {
106
+ for (const [validationName, validate] of Object.entries(
107
+ block
108
+ )) {
109
+ for (const [field, value] of Object.entries(getWildCardMatches(draft, path))) {
110
+ if (!validate(value, { draft, original, field })) {
111
+ errors.add(`${field}.${validationName}`);
112
+ }
113
+ }
114
+ }
115
+ }
116
+ return [...errors];
117
+ },
118
+ isValid() {
119
+ return this.getErrors().length === 0;
120
+ },
121
+ validate() {
122
+ state.set("hasTriggeredValidations", true);
123
+ return this.isValid();
124
+ },
125
+ reset() {
126
+ state.set("draft", void 0);
127
+ }
128
+ }),
129
+ [original, options, state]
130
+ );
131
+ }
132
+ useField(path, useStoreOptions) {
133
+ const form = this.useForm();
134
+ const state = useScope(this.state);
135
+ useStore(
136
+ form.draft.map((draft) => get(draft, path)),
137
+ useStoreOptions
138
+ );
139
+ useStore(
140
+ state.map((state2) => state2.hasTriggeredValidations),
141
+ useStoreOptions
142
+ );
143
+ return form.getField(path);
144
+ }
145
+ useHasChanges() {
146
+ const form = this.useForm();
147
+ return useStore(form.draft.map(() => form.hasChanges()));
148
+ }
149
+ useIsValid() {
150
+ const form = this.useForm();
151
+ return useStore(form.draft.map(() => form.isValid()));
152
+ }
153
+ }
154
+ function createForm(options) {
155
+ return new Form(options);
156
+ }
7
157
  function read(cache, options) {
8
158
  const { status, value, error } = useCache(cache, options);
9
159
  if (status === "value") {
@@ -43,13 +193,15 @@ function useDecoupledState(value, onChange, options = {}) {
43
193
  return [dirty ? dirty.v : value, update];
44
194
  }
45
195
  export {
196
+ Form,
46
197
  S as ScopeProvider,
198
+ createForm,
47
199
  r as reactMethods,
48
200
  read,
49
201
  useCache,
50
202
  useDecoupledState,
51
- b as useProp,
52
- a as useScope,
53
- c as useStore
203
+ c as useProp,
204
+ useScope,
205
+ useStore
54
206
  };
55
207
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../../../src/react/read.ts","../../../src/react/useDecoupledState.ts"],"sourcesContent":["import { useCache } from './useCache';\nimport type { UseStoreOptions } from './useStore';\nimport type { Cache } from '@core';\n\nexport function read<T>(cache: Cache<T>, options?: UseStoreOptions): T {\n const { status, value, error } = useCache(cache, options);\n\n if (status === 'value') {\n return value;\n }\n\n if (status === 'error') {\n throw error;\n }\n\n throw cache.state.once((state) => state.status !== 'pending');\n}\n","import { startTransition, useEffect, useMemo, useRef, useState } from 'react';\nimport { type Duration } from '@core';\nimport { debounce } from '@lib/debounce';\nimport { hash } from '@lib/hash';\nimport { throttle } from '@lib/throttle';\n\nexport interface UseDecoupledStateOptions<T> {\n debounce?: Duration;\n throttle?: Duration;\n onCommit?: (value: T) => void;\n}\n\nexport function useDecoupledState<T>(\n value: T,\n onChange: (value: T) => void,\n options: UseDecoupledStateOptions<T> = {},\n): [state: T, setState: (value: T) => void] {\n const [dirty, setDirty] = useState<{ v: T }>();\n const ref = useRef({ onChange, onCommit: options.onCommit });\n\n useEffect(() => {\n ref.current = { onChange, onCommit: options.onCommit };\n }, [onChange]);\n\n const update = useMemo(() => {\n const { onChange, onCommit } = ref.current;\n\n const update = (value: T) => {\n onChange(value);\n setDirty(undefined);\n onCommit?.(value);\n };\n\n let delayedUpdate: (value: T) => void;\n\n if (options.debounce) {\n delayedUpdate = debounce(update, options.debounce);\n } else if (options.throttle) {\n delayedUpdate = throttle(update, options.throttle);\n } else {\n delayedUpdate = (value) => startTransition(() => update(value));\n }\n\n return (value: T) => {\n setDirty({ v: value });\n delayedUpdate(value);\n };\n }, [hash([options.debounce, options.throttle])]);\n\n return [dirty ? dirty.v : value, update];\n}\n"],"names":["onChange","update","value"],"mappings":";;;;;;AAIgB,SAAA,KAAQ,OAAiB,SAA8B;AACrE,QAAM,EAAE,QAAQ,OAAO,MAAU,IAAA,SAAS,OAAO,OAAO;AAExD,MAAI,WAAW,SAAS;AACf,WAAA;AAAA,EACT;AAEA,MAAI,WAAW,SAAS;AAChB,UAAA;AAAA,EACR;AAEA,QAAM,MAAM,MAAM,KAAK,CAAC,UAAU,MAAM,WAAW,SAAS;AAC9D;ACJO,SAAS,kBACd,OACA,UACA,UAAuC,CAAA,GACG;AAC1C,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAmB;AAC7C,QAAM,MAAM,OAAO,EAAE,UAAU,UAAU,QAAQ,UAAU;AAE3D,YAAU,MAAM;AACd,QAAI,UAAU,EAAE,UAAU,UAAU,QAAQ;EAAS,GACpD,CAAC,QAAQ,CAAC;AAEP,QAAA,SAAS,QAAQ,MAAM;AAC3B,UAAM,EAAE,UAAAA,WAAU,SAAA,IAAa,IAAI;AAE7BC,UAAAA,UAAS,CAACC,WAAa;AAC3BF,gBAASE,MAAK;AACd,eAAS,MAAS;AAClB,2CAAWA;AAAAA,IAAK;AAGd,QAAA;AAEJ,QAAI,QAAQ,UAAU;AACJ,sBAAA,SAASD,SAAQ,QAAQ,QAAQ;AAAA,IAAA,WACxC,QAAQ,UAAU;AACX,sBAAA,SAASA,SAAQ,QAAQ,QAAQ;AAAA,IAAA,OAC5C;AACL,sBAAgB,CAACC,WAAU,gBAAgB,MAAMD,QAAOC,MAAK,CAAC;AAAA,IAChE;AAEA,WAAO,CAACA,WAAa;AACV,eAAA,EAAE,GAAGA,OAAAA,CAAO;AACrB,oBAAcA,MAAK;AAAA,IAAA;AAAA,EACrB,GACC,CAAC,KAAK,CAAC,QAAQ,UAAU,QAAQ,QAAQ,CAAC,CAAC,CAAC;AAE/C,SAAO,CAAC,QAAQ,MAAM,IAAI,OAAO,MAAM;AACzC;"}
1
+ {"version":3,"file":"index.mjs","sources":["../../../src/lib/wildcardMatch.ts","../../../src/react/form.tsx","../../../src/react/read.ts","../../../src/react/useDecoupledState.ts"],"sourcesContent":["import { type KeyType } from './path';\nimport { castArrayPath } from './propAccess';\n\nexport function wildcardMatch(s: KeyType[] | string, w: KeyType[] | string): boolean {\n if (typeof s === 'string') {\n s = castArrayPath(s);\n }\n\n if (typeof w === 'string') {\n w = castArrayPath(w);\n }\n\n return s.length === w.length && s.every((s, i) => w[i] === '*' || s === w[i]);\n}\n\nexport function getWildCardMatches(object: any, path: KeyType[] | string): Record<KeyType, any> {\n const matches: Record<KeyType, any> = {};\n const [first, ...rest] = castArrayPath(path);\n\n if (first === undefined) {\n return object;\n }\n\n if (!(object instanceof Object)) {\n return {};\n }\n\n if (first === '*') {\n for (const [key, value] of Object.entries(object)) {\n matches[key] = getWildCardMatches(value, rest);\n }\n } else {\n matches[first] = getWildCardMatches(object[first], rest);\n }\n\n return matches;\n}\n","/* eslint-disable react-hooks/rules-of-hooks */\n\nimport { createContext, useContext, useMemo, type ReactNode } from 'react';\nimport { useScope } from './scope';\nimport { useStore, type UseStoreOptions } from './useStore';\nimport { Scope } from '@core';\nimport { deepEqual } from '@lib/equals';\nimport {\n type PathAsString,\n type Value,\n type WildcardMatch,\n type WildcardPathAsString,\n type WildcardValue,\n} from '@lib/path';\nimport { get } from '@lib/propAccess';\nimport { getWildCardMatches, wildcardMatch } from '@lib/wildcardMatch';\n\nexport interface FormOptions<\n TDraft,\n TOriginal,\n TValidations extends Validations<TDraft, TOriginal>,\n> {\n defaultValue: TDraft;\n validations?: TValidations;\n}\n\nexport type Validation<TValue, TDraft, TOriginal> = (\n value: TValue,\n context: { draft: TDraft; original: TOriginal; field: PathAsString<TDraft> },\n) => boolean;\n\nexport type Validations<TDraft, TOriginal> = {\n [P in WildcardPathAsString<TDraft>]?: Record<\n string,\n Validation<WildcardValue<TDraft, P>, TDraft, TOriginal>\n >;\n};\n\nexport interface Field<\n TDraft,\n TOriginal,\n TPath extends PathAsString<TDraft>,\n TValidations extends Validations<TDraft, TOriginal>,\n> {\n originalValue: Value<TOriginal, TPath> | undefined;\n value: Value<TDraft, TPath>;\n setValue: (\n value: Value<TDraft, TPath> | ((value: Value<TDraft, TPath>) => Value<TDraft, TPath>),\n ) => void;\n isDirty: boolean;\n error?: keyof {\n [P in keyof TValidations as WildcardMatch<TPath, P> extends true\n ? keyof TValidations[P]\n : never]: 1;\n };\n}\n\nexport class Form<\n TDraft,\n TOriginal extends TDraft = TDraft,\n TValidations extends Validations<TDraft, TOriginal> = {},\n> {\n private context = createContext({\n original: undefined as TOriginal | undefined,\n options: this.options,\n });\n\n private state = new Scope<{\n draft?: TDraft;\n hasTriggeredValidations?: boolean;\n }>({});\n\n constructor(public readonly options: FormOptions<TDraft, TOriginal, TValidations>) {\n this.Provider = this.Provider.bind(this);\n }\n\n Provider({\n children,\n original,\n defaultValue = this.options.defaultValue,\n validations = this.options.validations,\n }: { children?: ReactNode; original?: TOriginal } & Partial<\n FormOptions<TDraft, TOriginal, TValidations>\n >) {\n const value = useMemo(\n () => ({ original, options: { defaultValue, validations } }),\n [original, defaultValue, validations],\n );\n\n return (\n <this.context.Provider value={value}>\n <this.state.Provider>{children}</this.state.Provider>\n </this.context.Provider>\n );\n }\n\n useForm() {\n const { original, options } = useContext(this.context);\n const state = useScope(this.state);\n\n return useMemo(\n () => ({\n original,\n\n draft: state.map(\n (state) => state.draft ?? original ?? options.defaultValue,\n (draft) => (state) => ({ ...state, draft }),\n ),\n\n getField<TPath extends PathAsString<TDraft>>(\n path: TPath,\n ): Field<TDraft, TOriginal, TPath, TValidations> {\n const { draft } = this;\n\n return {\n get originalValue() {\n return original !== undefined ? get(original as any, path as any) : undefined;\n },\n\n get value() {\n return get(draft.get(), path);\n },\n\n setValue(update) {\n draft.set(path, update);\n },\n\n get isDirty() {\n return (\n state.get().hasTriggeredValidations || !deepEqual(this.originalValue, this.value)\n );\n },\n\n get error() {\n const blocks: Record<string, Validation<any, any, any>>[] = Object.entries(\n options.validations ?? {},\n )\n .filter(([key]) => wildcardMatch(path, key))\n .map(([, value]) => value);\n\n const value = this.value;\n const draftValue = draft.get();\n\n for (const block of blocks ?? []) {\n for (const [validationName, validate] of Object.entries(block)) {\n if (!validate(value, { draft: draftValue, original, field: path })) {\n return validationName as any;\n }\n }\n }\n\n return undefined;\n },\n };\n },\n\n hasChanges() {\n const { draft } = state.get();\n return !!draft && !deepEqual(draft, original);\n },\n\n getErrors(): (keyof {\n [Field in PathAsString<TDraft> as keyof {\n [Pattern in keyof TValidations as WildcardMatch<Field, Pattern> extends true\n ? `${Field}.${keyof TValidations[Pattern] & string}`\n : never]: 1;\n }]: 1;\n })[] {\n const draft = this.draft.get();\n const errors = new Set<string>();\n\n for (const [path, block] of Object.entries(options.validations ?? {})) {\n for (const [validationName, validate] of Object.entries(\n block as Record<string, Validation<any, any, any>>,\n )) {\n for (const [field, value] of Object.entries(getWildCardMatches(draft, path))) {\n if (!validate(value, { draft, original, field })) {\n errors.add(`${field}.${validationName}`);\n }\n }\n }\n }\n\n return [...errors] as any;\n },\n\n isValid() {\n return this.getErrors().length === 0;\n },\n\n validate() {\n state.set('hasTriggeredValidations', true);\n return this.isValid();\n },\n\n reset() {\n state.set('draft', undefined);\n },\n }),\n [original, options, state],\n );\n }\n\n useField<TPath extends PathAsString<TDraft>>(path: TPath, useStoreOptions?: UseStoreOptions) {\n const form = this.useForm();\n const state = useScope(this.state);\n\n useStore(\n form.draft.map((draft) => get(draft, path)),\n useStoreOptions,\n );\n\n useStore(\n state.map((state) => state.hasTriggeredValidations),\n useStoreOptions,\n );\n\n return form.getField(path);\n }\n\n useHasChanges() {\n const form = this.useForm();\n\n return useStore(form.draft.map(() => form.hasChanges()));\n }\n\n useIsValid() {\n const form = this.useForm();\n\n return useStore(form.draft.map(() => form.isValid()));\n }\n}\n\nexport function createForm<\n TDraft,\n TOriginal extends TDraft = TDraft,\n TValidations extends Validations<TDraft, TOriginal> = {},\n>(options: FormOptions<TDraft, TOriginal, TValidations>) {\n return new Form(options);\n}\n\n/* eslint-enable react-hooks/rules-of-hooks */\n","import { useCache } from './useCache';\nimport type { UseStoreOptions } from './useStore';\nimport type { Cache } from '@core';\n\nexport function read<T>(cache: Cache<T>, options?: UseStoreOptions): T {\n const { status, value, error } = useCache(cache, options);\n\n if (status === 'value') {\n return value;\n }\n\n if (status === 'error') {\n throw error;\n }\n\n throw cache.state.once((state) => state.status !== 'pending');\n}\n","import { startTransition, useEffect, useMemo, useRef, useState } from 'react';\nimport { type Duration } from '@core';\nimport { debounce } from '@lib/debounce';\nimport { hash } from '@lib/hash';\nimport { throttle } from '@lib/throttle';\n\nexport interface UseDecoupledStateOptions<T> {\n debounce?: Duration;\n throttle?: Duration;\n onCommit?: (value: T) => void;\n}\n\nexport function useDecoupledState<T>(\n value: T,\n onChange: (value: T) => void,\n options: UseDecoupledStateOptions<T> = {},\n): [state: T, setState: (value: T) => void] {\n const [dirty, setDirty] = useState<{ v: T }>();\n const ref = useRef({ onChange, onCommit: options.onCommit });\n\n useEffect(() => {\n ref.current = { onChange, onCommit: options.onCommit };\n }, [onChange]);\n\n const update = useMemo(() => {\n const { onChange, onCommit } = ref.current;\n\n const update = (value: T) => {\n onChange(value);\n setDirty(undefined);\n onCommit?.(value);\n };\n\n let delayedUpdate: (value: T) => void;\n\n if (options.debounce) {\n delayedUpdate = debounce(update, options.debounce);\n } else if (options.throttle) {\n delayedUpdate = throttle(update, options.throttle);\n } else {\n delayedUpdate = (value) => startTransition(() => update(value));\n }\n\n return (value: T) => {\n setDirty({ v: value });\n delayedUpdate(value);\n };\n }, [hash([options.debounce, options.throttle])]);\n\n return [dirty ? dirty.v : value, update];\n}\n"],"names":["s","state","value","onChange","update"],"mappings":";;;;;;AAGgB,SAAA,cAAc,GAAuB,GAAgC;AAC/E,MAAA,OAAO,MAAM,UAAU;AACzB,QAAI,cAAc,CAAC;AAAA,EACrB;AAEI,MAAA,OAAO,MAAM,UAAU;AACzB,QAAI,cAAc,CAAC;AAAA,EACrB;AAEA,SAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,CAACA,IAAG,MAAM,EAAE,CAAC,MAAM,OAAOA,OAAM,EAAE,CAAC,CAAC;AAC9E;AAEgB,SAAA,mBAAmB,QAAa,MAAgD;AAC9F,QAAM,UAAgC,CAAA;AACtC,QAAM,CAAC,OAAO,GAAG,IAAI,IAAI,cAAc,IAAI;AAE3C,MAAI,UAAU,QAAW;AAChB,WAAA;AAAA,EACT;AAEI,MAAA,EAAE,kBAAkB,SAAS;AAC/B,WAAO;EACT;AAEA,MAAI,UAAU,KAAK;AACjB,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,cAAQ,GAAG,IAAI,mBAAmB,OAAO,IAAI;AAAA,IAC/C;AAAA,EAAA,OACK;AACL,YAAQ,KAAK,IAAI,mBAAmB,OAAO,KAAK,GAAG,IAAI;AAAA,EACzD;AAEO,SAAA;AACT;ACqBO,MAAM,KAIX;AAAA,EAWA,YAA4B,SAAuD;AAAvD,SAAA,UAAA;AAV5B,SAAQ,UAAU,cAAc;AAAA,MAC9B,UAAU;AAAA,MACV,SAAS,KAAK;AAAA,IAAA,CACf;AAED,SAAQ,QAAQ,IAAI,MAGjB,CAAE,CAAA;AAGH,SAAK,WAAW,KAAK,SAAS,KAAK,IAAI;AAAA,EACzC;AAAA,EAEA,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA,eAAe,KAAK,QAAQ;AAAA,IAC5B,cAAc,KAAK,QAAQ;AAAA,EAAA,GAG1B;AACD,UAAM,QAAQ;AAAA,MACZ,OAAO,EAAE,UAAU,SAAS,EAAE,cAAc,YAAc,EAAA;AAAA,MAC1D,CAAC,UAAU,cAAc,WAAW;AAAA,IAAA;AAGtC,WACG,oBAAA,KAAK,QAAQ,UAAb,EAAsB,OACrB,UAAC,oBAAA,KAAK,MAAM,UAAX,EAAqB,SAAS,CAAA,EACjC,CAAA;AAAA,EAEJ;AAAA,EAEA,UAAU;AACR,UAAM,EAAE,UAAU,QAAA,IAAY,WAAW,KAAK,OAAO;AAC/C,UAAA,QAAQ,SAAS,KAAK,KAAK;AAE1B,WAAA;AAAA,MACL,OAAO;AAAA,QACL;AAAA,QAEA,OAAO,MAAM;AAAA,UACX,CAACC,WAAUA,OAAM,SAAS,YAAY,QAAQ;AAAA,UAC9C,CAAC,UAAU,CAACA,YAAW,EAAE,GAAGA,QAAO,MAAM;AAAA,QAC3C;AAAA,QAEA,SACE,MAC+C;AACzC,gBAAA,EAAE,MAAU,IAAA;AAEX,iBAAA;AAAA,YACL,IAAI,gBAAgB;AAClB,qBAAO,aAAa,SAAY,IAAI,UAAiB,IAAW,IAAI;AAAA,YACtE;AAAA,YAEA,IAAI,QAAQ;AACV,qBAAO,IAAI,MAAM,IAAI,GAAG,IAAI;AAAA,YAC9B;AAAA,YAEA,SAAS,QAAQ;AACT,oBAAA,IAAI,MAAM,MAAM;AAAA,YACxB;AAAA,YAEA,IAAI,UAAU;AAEV,qBAAA,MAAM,IAAM,EAAA,2BAA2B,CAAC,UAAU,KAAK,eAAe,KAAK,KAAK;AAAA,YAEpF;AAAA,YAEA,IAAI,QAAQ;AACV,oBAAM,SAAsD,OAAO;AAAA,gBACjE,QAAQ,eAAe,CAAC;AAAA,gBAEvB,OAAO,CAAC,CAAC,GAAG,MAAM,cAAc,MAAM,GAAG,CAAC,EAC1C,IAAI,CAAC,CAAGC,EAAAA,MAAK,MAAMA,MAAK;AAE3B,oBAAM,QAAQ,KAAK;AACb,oBAAA,aAAa,MAAM;AAEd,yBAAA,SAAS,UAAU,IAAI;AAChC,2BAAW,CAAC,gBAAgB,QAAQ,KAAK,OAAO,QAAQ,KAAK,GAAG;AAC1D,sBAAA,CAAC,SAAS,OAAO,EAAE,OAAO,YAAY,UAAU,OAAO,KAAK,CAAC,GAAG;AAC3D,2BAAA;AAAA,kBACT;AAAA,gBACF;AAAA,cACF;AAEO,qBAAA;AAAA,YACT;AAAA,UAAA;AAAA,QAEJ;AAAA,QAEA,aAAa;AACX,gBAAM,EAAE,MAAA,IAAU,MAAM,IAAI;AAC5B,iBAAO,CAAC,CAAC,SAAS,CAAC,UAAU,OAAO,QAAQ;AAAA,QAC9C;AAAA,QAEA,YAMK;AACG,gBAAA,QAAQ,KAAK,MAAM,IAAI;AACvB,gBAAA,6BAAa;AAER,qBAAA,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,QAAQ,eAAe,CAAA,CAAE,GAAG;AACrE,uBAAW,CAAC,gBAAgB,QAAQ,KAAK,OAAO;AAAA,cAC9C;AAAA,YAAA,GACC;AACU,yBAAA,CAAC,OAAO,KAAK,KAAK,OAAO,QAAQ,mBAAmB,OAAO,IAAI,CAAC,GAAG;AACxE,oBAAA,CAAC,SAAS,OAAO,EAAE,OAAO,UAAU,MAAA,CAAO,GAAG;AACzC,yBAAA,IAAI,GAAG,SAAS,gBAAgB;AAAA,gBACzC;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAEO,iBAAA,CAAC,GAAG,MAAM;AAAA,QACnB;AAAA,QAEA,UAAU;AACD,iBAAA,KAAK,YAAY,WAAW;AAAA,QACrC;AAAA,QAEA,WAAW;AACH,gBAAA,IAAI,2BAA2B,IAAI;AACzC,iBAAO,KAAK;QACd;AAAA,QAEA,QAAQ;AACA,gBAAA,IAAI,SAAS,MAAS;AAAA,QAC9B;AAAA,MAAA;AAAA,MAEF,CAAC,UAAU,SAAS,KAAK;AAAA,IAAA;AAAA,EAE7B;AAAA,EAEA,SAA6C,MAAa,iBAAmC;AACrF,UAAA,OAAO,KAAK;AACZ,UAAA,QAAQ,SAAS,KAAK,KAAK;AAEjC;AAAA,MACE,KAAK,MAAM,IAAI,CAAC,UAAU,IAAI,OAAO,IAAI,CAAC;AAAA,MAC1C;AAAA,IAAA;AAGF;AAAA,MACE,MAAM,IAAI,CAACD,WAAUA,OAAM,uBAAuB;AAAA,MAClD;AAAA,IAAA;AAGK,WAAA,KAAK,SAAS,IAAI;AAAA,EAC3B;AAAA,EAEA,gBAAgB;AACR,UAAA,OAAO,KAAK;AAEX,WAAA,SAAS,KAAK,MAAM,IAAI,MAAM,KAAK,WAAY,CAAA,CAAC;AAAA,EACzD;AAAA,EAEA,aAAa;AACL,UAAA,OAAO,KAAK;AAEX,WAAA,SAAS,KAAK,MAAM,IAAI,MAAM,KAAK,QAAS,CAAA,CAAC;AAAA,EACtD;AACF;AAEO,SAAS,WAId,SAAuD;AAChD,SAAA,IAAI,KAAK,OAAO;AACzB;AC3OgB,SAAA,KAAQ,OAAiB,SAA8B;AACrE,QAAM,EAAE,QAAQ,OAAO,MAAU,IAAA,SAAS,OAAO,OAAO;AAExD,MAAI,WAAW,SAAS;AACf,WAAA;AAAA,EACT;AAEA,MAAI,WAAW,SAAS;AAChB,UAAA;AAAA,EACR;AAEA,QAAM,MAAM,MAAM,KAAK,CAAC,UAAU,MAAM,WAAW,SAAS;AAC9D;ACJO,SAAS,kBACd,OACA,UACA,UAAuC,CAAA,GACG;AAC1C,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAmB;AAC7C,QAAM,MAAM,OAAO,EAAE,UAAU,UAAU,QAAQ,UAAU;AAE3D,YAAU,MAAM;AACd,QAAI,UAAU,EAAE,UAAU,UAAU,QAAQ;EAAS,GACpD,CAAC,QAAQ,CAAC;AAEP,QAAA,SAAS,QAAQ,MAAM;AAC3B,UAAM,EAAE,UAAAE,WAAU,SAAA,IAAa,IAAI;AAE7BC,UAAAA,UAAS,CAACF,WAAa;AAC3BC,gBAASD,MAAK;AACd,eAAS,MAAS;AAClB,2CAAWA;AAAAA,IAAK;AAGd,QAAA;AAEJ,QAAI,QAAQ,UAAU;AACJ,sBAAA,SAASE,SAAQ,QAAQ,QAAQ;AAAA,IAAA,WACxC,QAAQ,UAAU;AACX,sBAAA,SAASA,SAAQ,QAAQ,QAAQ;AAAA,IAAA,OAC5C;AACL,sBAAgB,CAACF,WAAU,gBAAgB,MAAME,QAAOF,MAAK,CAAC;AAAA,IAChE;AAEA,WAAO,CAACA,WAAa;AACV,eAAA,EAAE,GAAGA,OAAAA,CAAO;AACrB,oBAAcA,MAAK;AAAA,IAAA;AAAA,EACrB,GACC,CAAC,KAAK,CAAC,QAAQ,UAAU,QAAQ,QAAQ,CAAC,CAAC,CAAC;AAE/C,SAAO,CAAC,QAAQ,MAAM,IAAI,OAAO,MAAM;AACzC;"}
@@ -1,9 +1,9 @@
1
- import { r as reactMethods, u as useCache, a as useScope, d as useScopeStore, e as useScopeProp, S as ScopeProvider } from "../scope2.mjs";
1
+ import { r as reactMethods, b as useCache, u as useScope, d as useScopeStore, e as useScopeProp, S as ScopeProvider } from "../useCache.mjs";
2
2
  import { S as Store } from "../store.mjs";
3
- import { C as Cache, S as Scope } from "../scope.mjs";
4
- import "react";
3
+ import { C as Cache } from "../cache.mjs";
4
+ import { S as Scope } from "../scope.mjs";
5
5
  import "react/jsx-runtime";
6
- import "../hash.mjs";
6
+ import "react";
7
7
  const cacheMethods = {
8
8
  useCache(options) {
9
9
  return useCache(this, options);
package/dist/es/scope.mjs CHANGED
@@ -1,381 +1,18 @@
1
- import { S as Store, c as createStore, a as calcDuration, i as makeSelector } from "./store.mjs";
2
- import { h as hash } from "./hash.mjs";
3
- class ResourceGroup {
4
- constructor(name) {
5
- this.name = name;
6
- this.refMap = /* @__PURE__ */ new WeakMap();
7
- this.refSet = /* @__PURE__ */ new Set();
8
- this.add = this.add.bind(this);
9
- this.delete = this.delete.bind(this);
10
- this.invalidateAll = this.invalidateAll.bind(this);
11
- this.clearAll = this.clearAll.bind(this);
1
+ function hash(value) {
2
+ if (value instanceof Set) {
3
+ return `s[${[...value].map(hash).sort().join(",")}]`;
12
4
  }
13
- add(resource) {
14
- const ref = new WeakRef(resource);
15
- this.refMap.set(resource, ref);
16
- this.refSet.add(ref);
5
+ if (value instanceof Map) {
6
+ return `m[${[...value.entries()].map(hash).sort().join(",")}]`;
17
7
  }
18
- delete(resource) {
19
- const ref = this.refMap.get(resource);
20
- if (ref) {
21
- this.refMap.delete(resource);
22
- this.refSet.delete(ref);
23
- }
24
- }
25
- invalidateAll() {
26
- for (const ref of this.refSet) {
27
- const resource = ref.deref();
28
- if (resource) {
29
- resource.invalidateAll();
30
- } else {
31
- this.refSet.delete(ref);
32
- }
33
- }
34
- }
35
- clearAll() {
36
- for (const ref of this.refSet) {
37
- const resource = ref.deref();
38
- if (resource) {
39
- resource.clearAll();
40
- } else {
41
- this.refSet.delete(ref);
42
- }
43
- }
44
- }
45
- }
46
- const allResources = /* @__PURE__ */ new ResourceGroup();
47
- function createResourceGroup(name) {
48
- return new ResourceGroup(name);
49
- }
50
- class InstanceCache {
51
- constructor(factory, cacheTime) {
52
- this.factory = factory;
53
- this.cacheTime = cacheTime;
54
- this.cache = /* @__PURE__ */ new Map();
55
- this.interval = this.cacheTime ? setInterval(() => this.cleanup(), Math.max(this.cacheTime / 10, 1)) : void 0;
56
- }
57
- cleanup() {
58
- var _a;
59
- const cutoff = this.now() - (this.cacheTime ?? 0);
60
- for (const [key, entry] of this.cache.entries()) {
61
- if (entry.ref && entry.t <= cutoff) {
62
- delete entry.ref;
63
- }
64
- if (!entry.ref && !((_a = entry.weakRef) == null ? void 0 : _a.deref())) {
65
- this.cache.delete(key);
66
- }
67
- }
68
- }
69
- get(...args) {
70
- var _a;
71
- const key = hash(args);
72
- let entry = this.cache.get(key);
73
- let value = (entry == null ? void 0 : entry.ref) ?? ((_a = entry == null ? void 0 : entry.weakRef) == null ? void 0 : _a.deref());
74
- if (!entry || !value) {
75
- value = this.factory(...args);
76
- entry = {
77
- t: this.now(),
78
- ref: value,
79
- weakRef: new WeakRef(value)
80
- };
81
- this.cache.set(key, entry);
82
- } else {
83
- entry.t = this.now();
84
- entry.ref ?? (entry.ref = value);
85
- }
86
- return value;
87
- }
88
- values() {
89
- return [...this.cache.values()].map((entry) => {
90
- var _a;
91
- return entry.ref ?? ((_a = entry.weakRef) == null ? void 0 : _a.deref());
92
- }).filter((value) => !!value);
93
- }
94
- stop() {
95
- if (this.interval) {
96
- clearInterval(this.interval);
97
- }
98
- }
99
- stats() {
100
- return {
101
- count: this.cache.size,
102
- withRef: [...this.cache.values()].filter((x) => !!x.ref).length,
103
- withWeakRef: [...this.cache.values()].filter((x) => {
104
- var _a;
105
- return !!((_a = x.weakRef) == null ? void 0 : _a.deref());
106
- }).length
107
- };
108
- }
109
- now() {
110
- return performance.now();
111
- }
112
- }
113
- class PromiseWithState extends Promise {
114
- constructor(value, state = { status: "pending" }) {
115
- super((resolve) => resolve(value));
116
- this.state = state;
117
- value.then((value2) => {
118
- this.state = { status: "value", value: value2 };
119
- }).catch((error) => {
120
- this.state = { status: "error", error };
121
- });
122
- }
123
- static resolve(value) {
124
- return new PromiseWithState(Promise.resolve(value), {
125
- status: "value",
126
- value
127
- });
128
- }
129
- static reject(error) {
130
- return new PromiseWithState(Promise.reject(error), { status: "error", error });
131
- }
132
- }
133
- class Cache extends Store {
134
- constructor(getter, options = {}, derivedFromCache, _call) {
135
- super(
136
- function() {
137
- let result = getter.apply(this);
138
- if (result instanceof Function) {
139
- result = result(this);
140
- }
141
- return result;
142
- },
143
- options,
144
- void 0,
145
- _call
146
- );
147
- this.options = options;
148
- this.derivedFromCache = derivedFromCache;
149
- this.state = createStore({
150
- status: "pending",
151
- isStale: true,
152
- isUpdating: false
153
- });
154
- this.invalidate = this.invalidate.bind(this);
155
- this.clear = this.clear.bind(this);
156
- this.mapValue = this.mapValue.bind(this);
157
- this.calculationHelper.options.onInvalidate = () => this.invalidate({ invalidateDependencies: false });
158
- this.watchPromise();
159
- this.watchFocus();
160
- }
161
- get({ update = "whenStale", backgroundUpdate = false } = {}) {
162
- var _a;
163
- const promise = (_a = this._value) == null ? void 0 : _a.v;
164
- const stalePromise = this.stalePromise;
165
- if (update === "whenMissing" && !promise && !stalePromise || update === "whenStale" && !promise || update === "force") {
166
- this.calculationHelper.execute();
167
- if (!promise && !stalePromise || !backgroundUpdate) {
168
- return super.get();
169
- }
170
- }
171
- if (!promise || stalePromise && backgroundUpdate) {
172
- return stalePromise;
173
- }
174
- return promise;
175
- }
176
- updateValue(value) {
177
- this.set(PromiseWithState.resolve(value));
178
- }
179
- updateError(error) {
180
- this.set(PromiseWithState.reject(error));
181
- }
182
- invalidate({ invalidateDependencies = true } = {}) {
183
- var _a;
184
- const { clearOnInvalidate = createCache.defaultOptions.clearOnInvalidate } = this.options;
185
- if (clearOnInvalidate) {
186
- return this.clear({ invalidateDependencies });
187
- }
188
- if (invalidateDependencies) {
189
- this.calculationHelper.invalidateDependencies();
190
- }
191
- const { status, isStale, isUpdating } = this.state.get();
192
- if (status !== "pending" && !isStale && !isUpdating) {
193
- this.stalePromise = (_a = this._value) == null ? void 0 : _a.v;
194
- }
195
- this.state.set((state) => ({
196
- ...state,
197
- isStale: true,
198
- isUpdating: false
199
- }));
200
- this.calculationHelper.stop();
201
- super.reset();
202
- }
203
- clear({ invalidateDependencies = true } = {}) {
204
- if (invalidateDependencies) {
205
- this.calculationHelper.invalidateDependencies();
206
- }
207
- this.state.set({
208
- status: "pending",
209
- isStale: true,
210
- isUpdating: false
211
- });
212
- delete this.stalePromise;
213
- this.calculationHelper.stop();
214
- super.reset();
215
- }
216
- mapValue(_selector) {
217
- const selector = makeSelector(_selector);
218
- const derivedFromCache = {
219
- cache: this.derivedFromCache ? this.derivedFromCache.cache : this,
220
- selectors: this.derivedFromCache ? [...this.derivedFromCache.selectors, _selector] : [_selector]
221
- };
222
- const that = this;
223
- return new Cache(
224
- async function() {
225
- const value = await this.use(that);
226
- return selector(value);
227
- },
228
- {},
229
- derivedFromCache
230
- );
231
- }
232
- watchPromise() {
233
- this.subscribe(
234
- async (promise) => {
235
- var _a, _b;
236
- if (promise instanceof PromiseWithState) {
237
- this.state.set({
238
- ...promise.state,
239
- isStale: false,
240
- isUpdating: false
241
- });
242
- delete this.stalePromise;
243
- this.setTimers();
244
- return;
245
- }
246
- this.state.set((state) => ({
247
- ...state,
248
- isUpdating: true
249
- }));
250
- this.setTimers();
251
- try {
252
- const value = await promise;
253
- if (promise !== ((_a = this._value) == null ? void 0 : _a.v)) {
254
- return;
255
- }
256
- this.state.set({
257
- status: "value",
258
- value,
259
- isStale: false,
260
- isUpdating: false
261
- });
262
- delete this.stalePromise;
263
- this.setTimers();
264
- } catch (error) {
265
- if (promise !== ((_b = this._value) == null ? void 0 : _b.v)) {
266
- return;
267
- }
268
- this.state.set({
269
- status: "error",
270
- error,
271
- isStale: false,
272
- isUpdating: false
273
- });
274
- delete this.stalePromise;
275
- this.setTimers();
276
- }
277
- },
278
- { passive: true }
279
- );
8
+ if (Array.isArray(value)) {
9
+ return `[${value.map(hash).join(",")}]`;
280
10
  }
281
- setTimers() {
282
- if (this.invalidationTimer) {
283
- clearTimeout(this.invalidationTimer);
284
- }
285
- this.invalidationTimer = void 0;
286
- const state = this.state.get();
287
- let { invalidateAfter = createCache.defaultOptions.invalidateAfter } = this.options;
288
- const ref = new WeakRef(this);
289
- if (state.status === "pending") {
290
- return;
291
- }
292
- if (invalidateAfter instanceof Function) {
293
- invalidateAfter = invalidateAfter(state);
294
- }
295
- if (invalidateAfter !== null && invalidateAfter !== void 0) {
296
- this.invalidationTimer = setTimeout(
297
- () => {
298
- var _a;
299
- return (_a = ref == null ? void 0 : ref.deref()) == null ? void 0 : _a.invalidate();
300
- },
301
- calcDuration(invalidateAfter)
302
- );
303
- }
304
- }
305
- watchFocus() {
306
- const { invalidateOnWindowFocus = createCache.defaultOptions.invalidateOnWindowFocus } = this.options;
307
- if (!invalidateOnWindowFocus || typeof document === "undefined" || typeof document.addEventListener === "undefined") {
308
- return;
309
- }
310
- const ref = new WeakRef(this);
311
- const onFocus = () => {
312
- const that = ref == null ? void 0 : ref.deref();
313
- if (!that) {
314
- document.removeEventListener("visibilitychange", onFocus);
315
- return;
316
- }
317
- if (!document.hidden) {
318
- that.invalidate();
319
- }
320
- };
321
- document.addEventListener("visibilitychange", onFocus);
11
+ if (value instanceof Object) {
12
+ return `o[${Object.entries(value).map(hash).sort().join(",")}]`;
322
13
  }
14
+ return JSON.stringify(value);
323
15
  }
324
- function create(cacheFunction, options) {
325
- const { clearUnusedAfter = createCache.defaultOptions.clearUnusedAfter, resourceGroup } = options ?? {};
326
- let baseInstance;
327
- const instanceCache = new InstanceCache(
328
- (...args) => {
329
- if (args.length === 0 && baseInstance) {
330
- return baseInstance;
331
- }
332
- return new Cache(function() {
333
- return cacheFunction.apply(this, args);
334
- }, options);
335
- },
336
- clearUnusedAfter ? calcDuration(clearUnusedAfter) : void 0
337
- );
338
- const get = (...args) => {
339
- return instanceCache.get(...args);
340
- };
341
- const invalidateAll = () => {
342
- for (const instance of instanceCache.values()) {
343
- instance.invalidate();
344
- }
345
- };
346
- const clearAll = () => {
347
- for (const instance of instanceCache.values()) {
348
- instance.clear();
349
- }
350
- };
351
- baseInstance = Object.assign(
352
- new Cache(
353
- function() {
354
- return cacheFunction.apply(this);
355
- },
356
- options,
357
- void 0,
358
- get
359
- ),
360
- {
361
- invalidateAll,
362
- clearAll
363
- }
364
- );
365
- const groups = Array.isArray(resourceGroup) ? resourceGroup : resourceGroup ? [resourceGroup] : [];
366
- for (const group of groups.concat(allResources)) {
367
- group.add(baseInstance);
368
- }
369
- get(...[]);
370
- return baseInstance;
371
- }
372
- const createCache = /* @__PURE__ */ Object.assign(create, {
373
- defaultOptions: {
374
- invalidateOnWindowFocus: true,
375
- invalidateOnActivation: true,
376
- clearUnusedAfter: { days: 1 }
377
- }
378
- });
379
16
  class Scope {
380
17
  constructor(defaultValue) {
381
18
  this.defaultValue = defaultValue;
@@ -388,13 +25,8 @@ function createScope(defaultValue) {
388
25
  return new Scope(defaultValue);
389
26
  }
390
27
  export {
391
- Cache as C,
392
- InstanceCache as I,
393
- ResourceGroup as R,
394
28
  Scope as S,
395
- allResources as a,
396
- createResourceGroup as b,
397
- createCache as c,
398
- createScope as d
29
+ createScope as c,
30
+ hash as h
399
31
  };
400
32
  //# sourceMappingURL=scope.mjs.map