@yaasl/core 0.8.0-alpha.2 → 0.8.0-alpha.4

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.
@@ -1,6 +1,7 @@
1
1
  type Callback<Value> = (value: Value, previous: Value) => void;
2
2
  export declare class Stateful<Value = unknown> {
3
3
  protected value: Value;
4
+ didInit: PromiseLike<void> | boolean;
4
5
  private listeners;
5
6
  constructor(value: Value);
6
7
  /** Read the value of state.
@@ -17,5 +18,6 @@ export declare class Stateful<Value = unknown> {
17
18
  subscribe(callback: Callback<Value>): () => boolean;
18
19
  private emit;
19
20
  protected update(value: Value): void;
21
+ protected setDidInit(didInit: boolean | PromiseLike<void>): void;
20
22
  }
21
23
  export {};
@@ -12,7 +12,6 @@ export interface AtomConfig<Value> {
12
12
  export declare class Atom<Value = unknown> extends Stateful<Value> {
13
13
  readonly defaultValue: Value;
14
14
  readonly name: string;
15
- didInit: PromiseLike<void> | boolean;
16
15
  constructor({ defaultValue, name, middleware, }: AtomConfig<Value>);
17
16
  /** Set the value of the atom.
18
17
  *
@@ -20,11 +19,6 @@ export declare class Atom<Value = unknown> extends Stateful<Value> {
20
19
  * new value based off the previous value.
21
20
  */
22
21
  set(next: SetStateAction<Value>): void;
23
- /** Resolve the value of a promise and set as atom value.
24
- *
25
- * @param promise Promise to unwrap
26
- */
27
- unwrap(promise: Promise<Value>): Promise<Value>;
28
22
  }
29
23
  /** Creates an atom store.
30
24
  *
@@ -1,4 +1,5 @@
1
1
  export * from "./atom";
2
2
  export * from "./derive";
3
3
  export * from "./config";
4
+ export * from "./select";
4
5
  export * from "./Stateful";
@@ -0,0 +1,20 @@
1
+ import { Stateful } from "./Stateful";
2
+ type Selectable = Record<string | number, unknown>;
3
+ type DeepKeys<T> = T extends object ? {
4
+ [K in keyof T]: `${Exclude<K, symbol>}${"" | `.${DeepKeys<T[K]>}`}`;
5
+ }[keyof T] : never;
6
+ type DeepValue<T, Path> = T extends Record<string | number, unknown> ? Path extends `${infer Current}.${infer Next}` ? DeepValue<T[Current], Next> : T[Path & string] : never;
7
+ export declare class Select<Path extends DeepKeys<State>, State extends Selectable> extends Stateful<DeepValue<State, Path>> {
8
+ protected readonly parent: Stateful<State>;
9
+ protected readonly path: Path;
10
+ constructor(parent: Stateful<State>, path: Path);
11
+ }
12
+ /** Creates a value, selected from any stateful value.
13
+ *
14
+ * @param parent The parent element to select a value from. The internal state must be an object.
15
+ * @param path The path to the value you want to select.
16
+ *
17
+ * @returns A select instance.
18
+ **/
19
+ export declare const select: <Path extends DeepKeys<State>, State extends Selectable>(parent: Stateful<State>, path: Path) => Select<Path, State>;
20
+ export {};
@@ -4,6 +4,7 @@ exports.Stateful = void 0;
4
4
  class Stateful {
5
5
  constructor(value) {
6
6
  this.value = value;
7
+ this.didInit = false;
7
8
  this.listeners = new Set();
8
9
  }
9
10
  /** Read the value of state.
@@ -33,5 +34,15 @@ class Stateful {
33
34
  this.emit(value, previous);
34
35
  }
35
36
  }
37
+ setDidInit(didInit) {
38
+ if (typeof didInit === "boolean") {
39
+ this.didInit = true;
40
+ }
41
+ else {
42
+ this.didInit = didInit.then(() => {
43
+ this.didInit = true;
44
+ });
45
+ }
46
+ }
36
47
  }
37
48
  exports.Stateful = Stateful;
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.atom = exports.Atom = void 0;
13
4
  const Stateful_1 = require("./Stateful");
@@ -16,7 +7,6 @@ let key = 0;
16
7
  class Atom extends Stateful_1.Stateful {
17
8
  constructor({ defaultValue, name = `atom-${++key}`, middleware, }) {
18
9
  super(defaultValue);
19
- this.didInit = false;
20
10
  this.name = name;
21
11
  this.defaultValue = defaultValue;
22
12
  if (!middleware || middleware.length === 0) {
@@ -24,14 +14,7 @@ class Atom extends Stateful_1.Stateful {
24
14
  return;
25
15
  }
26
16
  const { didInit } = new MiddlewareDispatcher_1.MiddlewareDispatcher({ atom: this, middleware });
27
- if (typeof didInit === "boolean") {
28
- this.didInit = didInit;
29
- }
30
- else {
31
- this.didInit = didInit.then(() => {
32
- this.didInit = true;
33
- });
34
- }
17
+ this.setDidInit(didInit);
35
18
  }
36
19
  /** Set the value of the atom.
37
20
  *
@@ -42,17 +25,6 @@ class Atom extends Stateful_1.Stateful {
42
25
  const value = next instanceof Function ? next(this.get()) : next;
43
26
  super.update(value);
44
27
  }
45
- /** Resolve the value of a promise and set as atom value.
46
- *
47
- * @param promise Promise to unwrap
48
- */
49
- unwrap(promise) {
50
- return __awaiter(this, void 0, void 0, function* () {
51
- const value = yield promise;
52
- this.set(value);
53
- return value;
54
- });
55
- }
56
28
  }
57
29
  exports.Atom = Atom;
58
30
  /** Creates an atom store.
@@ -3,6 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.derive = exports.SettableDerive = exports.Derive = void 0;
4
4
  const utils_1 = require("@yaasl/utils");
5
5
  const Stateful_1 = require("./Stateful");
6
+ const allDidInit = (atoms) => {
7
+ const inits = atoms
8
+ .map(atom => atom.didInit)
9
+ .filter((didInit) => typeof didInit !== "boolean");
10
+ return inits.length === 0 ? true : Promise.all(inits).then(utils_1.toVoid);
11
+ };
6
12
  class Derive extends Stateful_1.Stateful {
7
13
  constructor(getter) {
8
14
  super(undefined);
@@ -10,6 +16,7 @@ class Derive extends Stateful_1.Stateful {
10
16
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
17
  this.getterDependencies = new Set();
12
18
  this.value = getter({ get: dep => this.addGetDependency(dep) });
19
+ this.setDidInit(allDidInit(Array.from(this.getterDependencies)));
13
20
  }
14
21
  addGetDependency(dependency) {
15
22
  if (!this.getterDependencies.has(dependency)) {
@@ -17,4 +17,5 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./atom"), exports);
18
18
  __exportStar(require("./derive"), exports);
19
19
  __exportStar(require("./config"), exports);
20
+ __exportStar(require("./select"), exports);
20
21
  __exportStar(require("./Stateful"), exports);
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.select = exports.Select = void 0;
4
+ const Stateful_1 = require("./Stateful");
5
+ const selectValue = (state, path) => path
6
+ .split(".")
7
+ .reduce((result, key) => result[key], state);
8
+ class Select extends Stateful_1.Stateful {
9
+ constructor(parent, path) {
10
+ super(selectValue(parent.get(), path));
11
+ this.parent = parent;
12
+ this.path = path;
13
+ parent.subscribe(state => this.update(selectValue(state, path)));
14
+ this.setDidInit(parent.didInit);
15
+ }
16
+ }
17
+ exports.Select = Select;
18
+ /** Creates a value, selected from any stateful value.
19
+ *
20
+ * @param parent The parent element to select a value from. The internal state must be an object.
21
+ * @param path The path to the value you want to select.
22
+ *
23
+ * @returns A select instance.
24
+ **/
25
+ const select = (parent, path) => new Select(parent, path);
26
+ exports.select = select;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MiddlewareDispatcher = void 0;
4
- const isPromiseLike_1 = require("../utils/isPromiseLike");
4
+ const utils_1 = require("@yaasl/utils");
5
5
  const Scheduler_1 = require("../utils/Scheduler");
6
6
  class MiddlewareDispatcher {
7
7
  constructor({ atom, middleware }) {
@@ -13,7 +13,7 @@ class MiddlewareDispatcher {
13
13
  this.subscribeSetters(atom);
14
14
  this.callMiddlewareAction("didInit", atom);
15
15
  const { queue } = this.scheduler;
16
- if (!(0, isPromiseLike_1.isPromiseLike)(queue)) {
16
+ if (!(0, utils_1.isPromiseLike)(queue)) {
17
17
  this.didInit = true;
18
18
  return;
19
19
  }
@@ -1,17 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Scheduler = void 0;
4
- const isPromiseLike_1 = require("./isPromiseLike");
5
- const Thenable_1 = require("./Thenable");
6
- const toVoid = () => {
7
- // omit args
8
- };
4
+ const utils_1 = require("@yaasl/utils");
9
5
  class Scheduler {
10
6
  constructor() {
11
7
  this.queue = null;
12
8
  }
13
9
  run(...tasks) {
14
- const run = () => this.execute(tasks.flat()).then(toVoid);
10
+ const run = () => this.execute(tasks.flat()).then(utils_1.toVoid);
15
11
  const promise = this.queue ? this.queue.then(run) : run();
16
12
  this.queue = promise;
17
13
  return promise.then(() => {
@@ -23,9 +19,9 @@ class Scheduler {
23
19
  execute(tasks) {
24
20
  const result = tasks.map(task => {
25
21
  const result = task();
26
- return (0, isPromiseLike_1.isPromiseLike)(result) ? result : new Thenable_1.Thenable(result);
22
+ return (0, utils_1.isPromiseLike)(result) ? result : new utils_1.Thenable(result);
27
23
  });
28
- return Thenable_1.Thenable.all(result);
24
+ return utils_1.Thenable.all(result);
29
25
  }
30
26
  }
31
27
  exports.Scheduler = Scheduler;
@@ -1,6 +1,7 @@
1
1
  export class Stateful {
2
2
  constructor(value) {
3
3
  this.value = value;
4
+ this.didInit = false;
4
5
  this.listeners = new Set();
5
6
  }
6
7
  /** Read the value of state.
@@ -30,4 +31,14 @@ export class Stateful {
30
31
  this.emit(value, previous);
31
32
  }
32
33
  }
34
+ setDidInit(didInit) {
35
+ if (typeof didInit === "boolean") {
36
+ this.didInit = true;
37
+ }
38
+ else {
39
+ this.didInit = didInit.then(() => {
40
+ this.didInit = true;
41
+ });
42
+ }
43
+ }
33
44
  }
@@ -4,7 +4,6 @@ let key = 0;
4
4
  export class Atom extends Stateful {
5
5
  constructor({ defaultValue, name = `atom-${++key}`, middleware, }) {
6
6
  super(defaultValue);
7
- this.didInit = false;
8
7
  this.name = name;
9
8
  this.defaultValue = defaultValue;
10
9
  if (!middleware || middleware.length === 0) {
@@ -12,14 +11,7 @@ export class Atom extends Stateful {
12
11
  return;
13
12
  }
14
13
  const { didInit } = new MiddlewareDispatcher({ atom: this, middleware });
15
- if (typeof didInit === "boolean") {
16
- this.didInit = didInit;
17
- }
18
- else {
19
- this.didInit = didInit.then(() => {
20
- this.didInit = true;
21
- });
22
- }
14
+ this.setDidInit(didInit);
23
15
  }
24
16
  /** Set the value of the atom.
25
17
  *
@@ -30,15 +22,6 @@ export class Atom extends Stateful {
30
22
  const value = next instanceof Function ? next(this.get()) : next;
31
23
  super.update(value);
32
24
  }
33
- /** Resolve the value of a promise and set as atom value.
34
- *
35
- * @param promise Promise to unwrap
36
- */
37
- async unwrap(promise) {
38
- const value = await promise;
39
- this.set(value);
40
- return value;
41
- }
42
25
  }
43
26
  /** Creates an atom store.
44
27
  *
@@ -1,5 +1,11 @@
1
- import { consoleMessage } from "@yaasl/utils";
1
+ import { consoleMessage, toVoid } from "@yaasl/utils";
2
2
  import { Stateful } from "./Stateful";
3
+ const allDidInit = (atoms) => {
4
+ const inits = atoms
5
+ .map(atom => atom.didInit)
6
+ .filter((didInit) => typeof didInit !== "boolean");
7
+ return inits.length === 0 ? true : Promise.all(inits).then(toVoid);
8
+ };
3
9
  export class Derive extends Stateful {
4
10
  constructor(getter) {
5
11
  super(undefined);
@@ -7,6 +13,7 @@ export class Derive extends Stateful {
7
13
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
14
  this.getterDependencies = new Set();
9
15
  this.value = getter({ get: dep => this.addGetDependency(dep) });
16
+ this.setDidInit(allDidInit(Array.from(this.getterDependencies)));
10
17
  }
11
18
  addGetDependency(dependency) {
12
19
  if (!this.getterDependencies.has(dependency)) {
@@ -1,4 +1,5 @@
1
1
  export * from "./atom";
2
2
  export * from "./derive";
3
3
  export * from "./config";
4
+ export * from "./select";
4
5
  export * from "./Stateful";
@@ -0,0 +1,21 @@
1
+ import { Stateful } from "./Stateful";
2
+ const selectValue = (state, path) => path
3
+ .split(".")
4
+ .reduce((result, key) => result[key], state);
5
+ export class Select extends Stateful {
6
+ constructor(parent, path) {
7
+ super(selectValue(parent.get(), path));
8
+ this.parent = parent;
9
+ this.path = path;
10
+ parent.subscribe(state => this.update(selectValue(state, path)));
11
+ this.setDidInit(parent.didInit);
12
+ }
13
+ }
14
+ /** Creates a value, selected from any stateful value.
15
+ *
16
+ * @param parent The parent element to select a value from. The internal state must be an object.
17
+ * @param path The path to the value you want to select.
18
+ *
19
+ * @returns A select instance.
20
+ **/
21
+ export const select = (parent, path) => new Select(parent, path);
@@ -1,4 +1,4 @@
1
- import { isPromiseLike } from "../utils/isPromiseLike";
1
+ import { isPromiseLike } from "@yaasl/utils";
2
2
  import { Scheduler } from "../utils/Scheduler";
3
3
  export class MiddlewareDispatcher {
4
4
  constructor({ atom, middleware }) {
@@ -1,8 +1,4 @@
1
- import { isPromiseLike } from "./isPromiseLike";
2
- import { Thenable } from "./Thenable";
3
- const toVoid = () => {
4
- // omit args
5
- };
1
+ import { toVoid, isPromiseLike, Thenable } from "@yaasl/utils";
6
2
  export class Scheduler {
7
3
  constructor() {
8
4
  this.queue = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yaasl/core",
3
- "version": "0.8.0-alpha.2",
3
+ "version": "0.8.0-alpha.4",
4
4
  "description": "yet another atomic store library (vanilla-js)",
5
5
  "author": "PrettyCoffee",
6
6
  "license": "MIT",
@@ -38,7 +38,7 @@
38
38
  "validate": "run-s lint test build"
39
39
  },
40
40
  "dependencies": {
41
- "@yaasl/utils": "0.8.0-alpha.2"
41
+ "@yaasl/utils": "0.8.0-alpha.4"
42
42
  },
43
43
  "eslintConfig": {
44
44
  "extends": [
@@ -1,9 +0,0 @@
1
- type Executor<T, R> = ((value: T) => R | PromiseLike<R>) | undefined | null;
2
- export declare class Thenable<T = undefined> implements PromiseLike<T> {
3
- private value?;
4
- constructor(value?: T | undefined);
5
- then<Result = T, Reject = never>(onfulfilled?: Executor<T, Result>, onrejected?: Executor<any, Reject>): PromiseLike<Result | Reject>;
6
- static isThenable(item: unknown): boolean;
7
- static all(items: PromiseLike<any>[]): Promise<any[]> | Thenable<unknown[]>;
8
- }
9
- export {};
@@ -1 +0,0 @@
1
- export declare const isPromise: (value: unknown) => value is Promise<any>;
@@ -1 +0,0 @@
1
- export declare const isPromiseLike: (value: unknown) => value is PromiseLike<any>;
@@ -1,36 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Thenable = void 0;
4
- const isPromiseLike_1 = require("./isPromiseLike");
5
- class Thenable {
6
- constructor(value) {
7
- this.value = value;
8
- }
9
- then(onfulfilled, onrejected) {
10
- try {
11
- const result = !onfulfilled ? this.value : onfulfilled(this.value);
12
- return (0, isPromiseLike_1.isPromiseLike)(result) ? result : new Thenable(result);
13
- }
14
- catch (error) {
15
- if (!onrejected)
16
- throw error;
17
- const result = onrejected(error);
18
- return (0, isPromiseLike_1.isPromiseLike)(result) ? result : new Thenable(result);
19
- }
20
- }
21
- static isThenable(item) {
22
- return item instanceof Thenable;
23
- }
24
- static all(items) {
25
- const onlyThenables = items.every(item => this.isThenable(item));
26
- if (!onlyThenables) {
27
- return Promise.all(items);
28
- }
29
- const result = [];
30
- items.forEach(item => void item.then(value => {
31
- result.push(value);
32
- }));
33
- return new Thenable(result);
34
- }
35
- }
36
- exports.Thenable = Thenable;
@@ -1,5 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isPromise = void 0;
4
- const isPromise = (value) => value instanceof Promise;
5
- exports.isPromise = isPromise;
@@ -1,8 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isPromiseLike = void 0;
4
- const isPromiseLike = (value) => typeof value === "object" &&
5
- value !== null &&
6
- "then" in value &&
7
- typeof value.then === "function";
8
- exports.isPromiseLike = isPromiseLike;
@@ -1,32 +0,0 @@
1
- import { isPromiseLike } from "./isPromiseLike";
2
- export class Thenable {
3
- constructor(value) {
4
- this.value = value;
5
- }
6
- then(onfulfilled, onrejected) {
7
- try {
8
- const result = !onfulfilled ? this.value : onfulfilled(this.value);
9
- return isPromiseLike(result) ? result : new Thenable(result);
10
- }
11
- catch (error) {
12
- if (!onrejected)
13
- throw error;
14
- const result = onrejected(error);
15
- return isPromiseLike(result) ? result : new Thenable(result);
16
- }
17
- }
18
- static isThenable(item) {
19
- return item instanceof Thenable;
20
- }
21
- static all(items) {
22
- const onlyThenables = items.every(item => this.isThenable(item));
23
- if (!onlyThenables) {
24
- return Promise.all(items);
25
- }
26
- const result = [];
27
- items.forEach(item => void item.then(value => {
28
- result.push(value);
29
- }));
30
- return new Thenable(result);
31
- }
32
- }
@@ -1 +0,0 @@
1
- export const isPromise = (value) => value instanceof Promise;
@@ -1,4 +0,0 @@
1
- export const isPromiseLike = (value) => typeof value === "object" &&
2
- value !== null &&
3
- "then" in value &&
4
- typeof value.then === "function";