@vorplex/core 0.0.4 → 0.0.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/dist/consts/mime-type.const.d.ts +456 -0
- package/dist/consts/mime-type.const.js +456 -0
- package/dist/consts/unit.const.d.ts +22 -0
- package/dist/consts/unit.const.js +22 -0
- package/dist/functions/debounce.function.d.ts +1 -0
- package/dist/functions/debounce.function.js +12 -0
- package/dist/functions/is-node-environment.function.d.ts +1 -0
- package/dist/functions/is-node-environment.function.js +3 -0
- package/dist/functions/parse-path-selector.function.d.ts +2 -0
- package/dist/functions/parse-path-selector.function.js +17 -0
- package/dist/functions/parse-url.function.d.ts +12 -0
- package/dist/functions/parse-url.function.js +25 -0
- package/dist/index.d.ts +92 -0
- package/dist/index.js +93 -0
- package/dist/interfaces/group.interface.d.ts +4 -0
- package/dist/interfaces/group.interface.js +0 -0
- package/dist/interfaces/key-value.interface.d.ts +4 -0
- package/dist/interfaces/key-value.interface.js +0 -0
- package/dist/modules/api/socket.model.d.ts +26 -0
- package/dist/modules/api/socket.model.js +66 -0
- package/dist/modules/api/web-client.model.d.ts +16 -0
- package/dist/modules/api/web-client.model.js +34 -0
- package/dist/modules/array/array.util.d.ts +17 -0
- package/dist/modules/array/array.util.js +105 -0
- package/dist/modules/changes/changes.util.d.ts +45 -0
- package/dist/modules/changes/changes.util.js +330 -0
- package/dist/modules/color/color-data.interface.d.ts +10 -0
- package/dist/modules/color/color-data.interface.js +0 -0
- package/dist/modules/color/color-formats.const.d.ts +9 -0
- package/dist/modules/color/color-formats.const.js +8 -0
- package/dist/modules/color/color.type.d.ts +4 -0
- package/dist/modules/color/color.type.js +0 -0
- package/dist/modules/color/color.util.d.ts +41 -0
- package/dist/modules/color/color.util.js +327 -0
- package/dist/modules/color/colors.const.d.ts +151 -0
- package/dist/modules/color/colors.const.js +150 -0
- package/dist/modules/color/hsl.interface.d.ts +6 -0
- package/dist/modules/color/hsl.interface.js +0 -0
- package/dist/modules/color/hsv.interface.d.ts +6 -0
- package/dist/modules/color/hsv.interface.js +0 -0
- package/dist/modules/color/rgb.interface.d.ts +6 -0
- package/dist/modules/color/rgb.interface.js +0 -0
- package/dist/modules/compression/compression.util.d.ts +4 -0
- package/dist/modules/compression/compression.util.js +52 -0
- package/dist/modules/date/date.util.d.ts +37 -0
- package/dist/modules/date/date.util.js +84 -0
- package/dist/modules/enum/enum.util.d.ts +17 -0
- package/dist/modules/enum/enum.util.js +69 -0
- package/dist/modules/hash/hash.util.d.ts +3 -0
- package/dist/modules/hash/hash.util.js +9 -0
- package/dist/modules/id/id.util.d.ts +7 -0
- package/dist/modules/id/id.util.js +33 -0
- package/dist/modules/injector/decorators/inject-token.decorator.d.ts +14 -0
- package/dist/modules/injector/decorators/inject-token.decorator.js +12 -0
- package/dist/modules/injector/decorators/injectable.decorator.d.ts +9 -0
- package/dist/modules/injector/decorators/injectable.decorator.js +7 -0
- package/dist/modules/injector/injector.model.d.ts +25 -0
- package/dist/modules/injector/injector.model.js +152 -0
- package/dist/modules/injector/provider-scopes.enum.d.ts +5 -0
- package/dist/modules/injector/provider-scopes.enum.js +6 -0
- package/dist/modules/injector/provider.interface.d.ts +10 -0
- package/dist/modules/injector/provider.interface.js +0 -0
- package/dist/modules/json-filter/json-filter.function.d.ts +41 -0
- package/dist/modules/json-filter/json-filter.function.js +75 -0
- package/dist/modules/logging/console-logger.model.d.ts +36 -0
- package/dist/modules/logging/console-logger.model.js +44 -0
- package/dist/modules/logging/logger.model.d.ts +6 -0
- package/dist/modules/logging/logger.model.js +7 -0
- package/dist/modules/logging/task.d.ts +38 -0
- package/dist/modules/logging/task.js +133 -0
- package/dist/modules/math/line.d.ts +12 -0
- package/dist/modules/math/line.js +50 -0
- package/dist/modules/math/point.d.ts +34 -0
- package/dist/modules/math/point.js +71 -0
- package/dist/modules/math/polygon.d.ts +45 -0
- package/dist/modules/math/polygon.js +273 -0
- package/dist/modules/math/rect.d.ts +6 -0
- package/dist/modules/math/rect.js +0 -0
- package/dist/modules/math/size.d.ts +4 -0
- package/dist/modules/math/size.js +0 -0
- package/dist/modules/number/number.util.d.ts +9 -0
- package/dist/modules/number/number.util.js +27 -0
- package/dist/modules/object/object.util.d.ts +7 -0
- package/dist/modules/object/object.util.js +63 -0
- package/dist/modules/path/path.util.d.ts +11 -0
- package/dist/modules/path/path.util.js +59 -0
- package/dist/modules/random/random.util.d.ts +17 -0
- package/dist/modules/random/random.util.js +57 -0
- package/dist/modules/readable-stream/readable-stream.util.d.ts +3 -0
- package/dist/modules/readable-stream/readable-stream.util.js +26 -0
- package/dist/modules/reflection/interfaces/parameter.interface.d.ts +4 -0
- package/dist/modules/reflection/interfaces/parameter.interface.js +0 -0
- package/dist/modules/reflection/models/attribute.model.d.ts +12 -0
- package/dist/modules/reflection/models/attribute.model.js +17 -0
- package/dist/modules/reflection/models/class-attribute.model.d.ts +4 -0
- package/dist/modules/reflection/models/class-attribute.model.js +6 -0
- package/dist/modules/reflection/models/method-attribute.model.d.ts +5 -0
- package/dist/modules/reflection/models/method-attribute.model.js +8 -0
- package/dist/modules/reflection/models/parameter-attribute.model.d.ts +7 -0
- package/dist/modules/reflection/models/parameter-attribute.model.js +21 -0
- package/dist/modules/reflection/models/property-attribute.model.d.ts +5 -0
- package/dist/modules/reflection/models/property-attribute.model.js +8 -0
- package/dist/modules/reflection/models/property-proxy-attribute.model.d.ts +15 -0
- package/dist/modules/reflection/models/property-proxy-attribute.model.js +19 -0
- package/dist/modules/reflection/types/constructor.type.d.ts +2 -0
- package/dist/modules/reflection/types/constructor.type.js +0 -0
- package/dist/modules/reflection/types/instance.type.d.ts +7 -0
- package/dist/modules/reflection/types/instance.type.js +0 -0
- package/dist/modules/reflection/types/type.type.d.ts +2 -0
- package/dist/modules/reflection/types/type.type.js +0 -0
- package/dist/modules/reflection/utils/decorator.util.d.ts +70 -0
- package/dist/modules/reflection/utils/decorator.util.js +135 -0
- package/dist/modules/reflection/utils/reflection.util.d.ts +140 -0
- package/dist/modules/reflection/utils/reflection.util.js +311 -0
- package/dist/modules/router/router.util.d.ts +33 -0
- package/dist/modules/router/router.util.js +59 -0
- package/dist/modules/state/adaptors/array/array-adaptor.util.d.ts +25 -0
- package/dist/modules/state/adaptors/array/array-adaptor.util.js +97 -0
- package/dist/modules/state/adaptors/entity/entity-adaptor.util.d.ts +35 -0
- package/dist/modules/state/adaptors/entity/entity-adaptor.util.js +158 -0
- package/dist/modules/state/adaptors/entity/entity-map.type.d.ts +4 -0
- package/dist/modules/state/adaptors/entity/entity-map.type.js +0 -0
- package/dist/modules/state/adaptors/entity/entity.interface.d.ts +3 -0
- package/dist/modules/state/adaptors/entity/entity.interface.js +0 -0
- package/dist/modules/state/state.model.d.ts +46 -0
- package/dist/modules/state/state.model.js +129 -0
- package/dist/modules/state/update.type.d.ts +2 -0
- package/dist/modules/state/update.type.js +0 -0
- package/dist/modules/string/string.util.d.ts +11 -0
- package/dist/modules/string/string.util.js +42 -0
- package/dist/modules/subscribable/subscribable.model.d.ts +10 -0
- package/dist/modules/subscribable/subscribable.model.js +34 -0
- package/dist/modules/subscribable/subscription.interface.d.ts +3 -0
- package/dist/modules/subscribable/subscription.interface.js +0 -0
- package/dist/modules/tson/error.d.ts +8 -0
- package/dist/modules/tson/error.js +13 -0
- package/dist/modules/tson/schema.d.ts +10 -0
- package/dist/modules/tson/schema.js +0 -0
- package/dist/modules/tson/schemas/any.d.ts +14 -0
- package/dist/modules/tson/schemas/any.js +27 -0
- package/dist/modules/tson/schemas/array.d.ts +21 -0
- package/dist/modules/tson/schemas/array.js +80 -0
- package/dist/modules/tson/schemas/boolean.d.ts +14 -0
- package/dist/modules/tson/schemas/boolean.js +38 -0
- package/dist/modules/tson/schemas/enum.d.ts +15 -0
- package/dist/modules/tson/schemas/enum.js +43 -0
- package/dist/modules/tson/schemas/number.d.ts +20 -0
- package/dist/modules/tson/schemas/number.js +66 -0
- package/dist/modules/tson/schemas/object.d.ts +33 -0
- package/dist/modules/tson/schemas/object.js +88 -0
- package/dist/modules/tson/schemas/schema-base.d.ts +12 -0
- package/dist/modules/tson/schemas/schema-base.js +14 -0
- package/dist/modules/tson/schemas/string.d.ts +19 -0
- package/dist/modules/tson/schemas/string.js +60 -0
- package/dist/modules/tson/schemas/union.d.ts +16 -0
- package/dist/modules/tson/schemas/union.js +56 -0
- package/dist/modules/tson/tson.d.ts +41 -0
- package/dist/modules/tson/tson.js +138 -0
- package/dist/modules/tson/type.d.ts +53 -0
- package/dist/modules/tson/type.js +0 -0
- package/dist/modules/value/value.util.d.ts +18 -0
- package/dist/modules/value/value.util.js +180 -0
- package/dist/types/awaitable.type.d.ts +1 -0
- package/dist/types/awaitable.type.js +0 -0
- package/dist/types/camel-to-kebab.type.d.ts +1 -0
- package/dist/types/camel-to-kebab.type.js +0 -0
- package/dist/types/has-key.type.d.ts +3 -0
- package/dist/types/has-key.type.js +0 -0
- package/dist/types/is-union.type.d.ts +1 -0
- package/dist/types/is-union.type.js +0 -0
- package/dist/types/keys-of-type.type.d.ts +5 -0
- package/dist/types/keys-of-type.type.js +0 -0
- package/dist/types/keys-with-fix.type.d.ts +3 -0
- package/dist/types/keys-with-fix.type.js +0 -0
- package/dist/types/optional-keys.type.d.ts +6 -0
- package/dist/types/optional-keys.type.js +0 -0
- package/dist/types/partial.type.d.ts +6 -0
- package/dist/types/partial.type.js +0 -0
- package/dist/types/predicate.type.d.ts +1 -0
- package/dist/types/predicate.type.js +0 -0
- package/dist/types/recursive-readonly.type.d.ts +3 -0
- package/dist/types/recursive-readonly.type.js +0 -0
- package/dist/types/recursive-value.type.d.ts +3 -0
- package/dist/types/recursive-value.type.js +0 -0
- package/dist/types/selector.type.d.ts +1 -0
- package/dist/types/selector.type.js +0 -0
- package/package.json +1 -1
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { State } from '../../state.model';
|
|
2
|
+
export class MapAdaptor {
|
|
3
|
+
constructor() { }
|
|
4
|
+
static delete(records, ...keys) {
|
|
5
|
+
records = { ...records };
|
|
6
|
+
for (const key of keys) {
|
|
7
|
+
delete records[key];
|
|
8
|
+
}
|
|
9
|
+
return records;
|
|
10
|
+
}
|
|
11
|
+
static set(records, items) {
|
|
12
|
+
records = { ...records };
|
|
13
|
+
for (const key in items) {
|
|
14
|
+
if (items[key] === undefined)
|
|
15
|
+
delete records[key];
|
|
16
|
+
else
|
|
17
|
+
records[key] = items[key];
|
|
18
|
+
}
|
|
19
|
+
return records;
|
|
20
|
+
}
|
|
21
|
+
static map(records, map) {
|
|
22
|
+
return MapAdaptor.fromArray(Object.values(records), map);
|
|
23
|
+
}
|
|
24
|
+
static fromArray(records, map) {
|
|
25
|
+
return records.reduce((records, record) => {
|
|
26
|
+
const [key, value] = map(record);
|
|
27
|
+
records[key] = value;
|
|
28
|
+
return records;
|
|
29
|
+
}, {});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export class EntityAdaptor {
|
|
33
|
+
key;
|
|
34
|
+
constructor(key) {
|
|
35
|
+
this.key = key;
|
|
36
|
+
}
|
|
37
|
+
static create(items, ...entities) {
|
|
38
|
+
items = { ...items };
|
|
39
|
+
for (const entity of entities) {
|
|
40
|
+
if (!items[entity.id]) {
|
|
41
|
+
items[entity.id] = entity;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
throw new Error(`Entity with ID ${entity.id} already exists.`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return items;
|
|
48
|
+
}
|
|
49
|
+
create(...entities) {
|
|
50
|
+
return (state) => ({
|
|
51
|
+
[this.key]: EntityAdaptor.create(state[this.key], ...entities),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
static updateAll(items, ...updates) {
|
|
55
|
+
items = { ...items };
|
|
56
|
+
for (const id in items) {
|
|
57
|
+
items[id] = State.update(items[id], ...updates);
|
|
58
|
+
}
|
|
59
|
+
return items;
|
|
60
|
+
}
|
|
61
|
+
updateAll(...updates) {
|
|
62
|
+
return (state) => ({
|
|
63
|
+
[this.key]: EntityAdaptor.updateAll(state[this.key], ...updates),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
static updateById(items, id, ...updates) {
|
|
67
|
+
items = { ...items };
|
|
68
|
+
return EntityAdaptor.updateByIds(items, [id], ...updates);
|
|
69
|
+
}
|
|
70
|
+
updateById(id, ...updates) {
|
|
71
|
+
return (state) => ({
|
|
72
|
+
[this.key]: EntityAdaptor.updateById(state[this.key], id, ...updates),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
static updateByIds(items, ids, ...updates) {
|
|
76
|
+
items = { ...items };
|
|
77
|
+
for (const id of ids) {
|
|
78
|
+
if (items[id]) {
|
|
79
|
+
items[id] = State.update(items[id], ...updates);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
throw new Error(`Entity with ID ${id} doesn't exist.`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return items;
|
|
86
|
+
}
|
|
87
|
+
updateByIds(ids, ...updates) {
|
|
88
|
+
return (state) => ({
|
|
89
|
+
[this.key]: EntityAdaptor.updateByIds(state[this.key], ids, ...updates),
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
static updateWhere(items, predicate, ...updates) {
|
|
93
|
+
items = { ...items };
|
|
94
|
+
for (const item of Object.values(items).filter(predicate)) {
|
|
95
|
+
items[item.id] = State.update(item, ...updates);
|
|
96
|
+
}
|
|
97
|
+
return items;
|
|
98
|
+
}
|
|
99
|
+
updateWhere(predicate, ...updates) {
|
|
100
|
+
return (state) => ({
|
|
101
|
+
[this.key]: EntityAdaptor.updateWhere(state[this.key], predicate, ...updates),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
static upsert(items, ...entities) {
|
|
105
|
+
items = { ...items };
|
|
106
|
+
for (const entity of entities) {
|
|
107
|
+
items[entity.id] = Object.assign({}, items[entity.id], entity);
|
|
108
|
+
}
|
|
109
|
+
return items;
|
|
110
|
+
}
|
|
111
|
+
static upsertBy(items, predicate, ...entities) {
|
|
112
|
+
items = { ...items };
|
|
113
|
+
for (const entity of entities) {
|
|
114
|
+
const existing = Object.values(items).find(existing => predicate(existing, entity));
|
|
115
|
+
items[existing?.id ?? entity.id] = Object.assign({}, existing, entity);
|
|
116
|
+
}
|
|
117
|
+
return items;
|
|
118
|
+
}
|
|
119
|
+
upsertBy(predicate, ...entities) {
|
|
120
|
+
return (state) => ({
|
|
121
|
+
[this.key]: EntityAdaptor.upsertBy(state[this.key], predicate, ...entities),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
upsert(...entities) {
|
|
125
|
+
return (state) => ({
|
|
126
|
+
[this.key]: EntityAdaptor.upsert(state[this.key], ...entities),
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
static delete(items, ...ids) {
|
|
130
|
+
items = { ...items };
|
|
131
|
+
for (const id of ids) {
|
|
132
|
+
delete items[id];
|
|
133
|
+
}
|
|
134
|
+
return items;
|
|
135
|
+
}
|
|
136
|
+
delete(...ids) {
|
|
137
|
+
return (state) => ({
|
|
138
|
+
[this.key]: EntityAdaptor.delete(state[this.key], ...ids),
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
static deleteWhere(items, predicate) {
|
|
142
|
+
items = { ...items };
|
|
143
|
+
for (const item of Object.values(items)) {
|
|
144
|
+
if (predicate(item)) {
|
|
145
|
+
delete items[item.id];
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return items;
|
|
149
|
+
}
|
|
150
|
+
deleteWhere(predicate) {
|
|
151
|
+
return (state) => ({
|
|
152
|
+
[this.key]: EntityAdaptor.deleteWhere(state[this.key], predicate),
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
static fromArray(entities) {
|
|
156
|
+
return entities.reduce((map, entity) => ({ ...map, [entity.id]: entity }), {});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Constructor } from '../reflection/types/constructor.type';
|
|
2
|
+
import { Subscribable } from '../subscribable/subscribable.model';
|
|
3
|
+
import type { Subscription } from '../subscribable/subscription.interface';
|
|
4
|
+
import { ArrayAdaptor } from './adaptors/array/array-adaptor.util';
|
|
5
|
+
import { EntityAdaptor } from './adaptors/entity/entity-adaptor.util';
|
|
6
|
+
import type { EntityMap } from './adaptors/entity/entity-map.type';
|
|
7
|
+
import type { IEntity } from './adaptors/entity/entity.interface';
|
|
8
|
+
import type { Update } from './update.type';
|
|
9
|
+
export interface StateChange<T> {
|
|
10
|
+
previousValue: T;
|
|
11
|
+
value: T;
|
|
12
|
+
}
|
|
13
|
+
export type StateEffect<T> = (value: T) => T;
|
|
14
|
+
export declare class State<T = any, TReducer extends Constructor = Constructor> extends Subscribable<StateChange<T>> {
|
|
15
|
+
private reducer?;
|
|
16
|
+
private _value;
|
|
17
|
+
get value(): T;
|
|
18
|
+
constructor(state?: T, reducer?: TReducer);
|
|
19
|
+
static combineLatest<T extends any[]>(states: {
|
|
20
|
+
[K in keyof T]: State<T[K]>;
|
|
21
|
+
}, callback: (values: T) => void): Subscription;
|
|
22
|
+
reduce(update: (reducer: {
|
|
23
|
+
update: {
|
|
24
|
+
<V>(path: (state: T) => V, update: (value: V) => Partial<V>): Update<T>;
|
|
25
|
+
<V>(path: (state: T) => V, value: Partial<V>): Update<T>;
|
|
26
|
+
};
|
|
27
|
+
} & {
|
|
28
|
+
[K in keyof T]: T[K] extends EntityMap<IEntity> ? {
|
|
29
|
+
entity: EntityAdaptor<T, T[K] extends EntityMap<infer U> ? U : never, K & any>;
|
|
30
|
+
} & (K extends keyof InstanceType<TReducer> ? InstanceType<TReducer>[K & keyof InstanceType<TReducer>] : {}) : T[K] extends any[] ? {
|
|
31
|
+
array: ArrayAdaptor<T, T[K] extends (infer U)[] ? U : never, K & any>;
|
|
32
|
+
} & (K extends keyof InstanceType<TReducer> ? InstanceType<TReducer>[K & keyof InstanceType<TReducer>] : {}) : {
|
|
33
|
+
value: {
|
|
34
|
+
set: (value: T[K]) => Update<T> & (K extends keyof InstanceType<TReducer> ? InstanceType<TReducer>[K & keyof InstanceType<TReducer>] : {});
|
|
35
|
+
} & (K extends keyof InstanceType<TReducer> ? InstanceType<TReducer>[K & keyof InstanceType<TReducer>] : {});
|
|
36
|
+
};
|
|
37
|
+
}) => Update<T>[]): void;
|
|
38
|
+
subscribe(emit: (event: StateChange<T>, subscription: Subscription) => void): Subscription;
|
|
39
|
+
static update<TState>(state: TState, ...updates: Update<TState>[]): TState;
|
|
40
|
+
update(...updates: Update<T>[]): void;
|
|
41
|
+
set(value: T): void;
|
|
42
|
+
asReadOnly(): Subscribable<StateChange<T>> & {
|
|
43
|
+
readonly value: T;
|
|
44
|
+
};
|
|
45
|
+
sync(config: State<T>): Subscription;
|
|
46
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { $Reflection } from '../reflection/utils/reflection.util';
|
|
2
|
+
import { Subscribable } from '../subscribable/subscribable.model';
|
|
3
|
+
import { $Value } from '../value/value.util';
|
|
4
|
+
import { ArrayAdaptor } from './adaptors/array/array-adaptor.util';
|
|
5
|
+
import { EntityAdaptor } from './adaptors/entity/entity-adaptor.util';
|
|
6
|
+
export class State extends Subscribable {
|
|
7
|
+
reducer;
|
|
8
|
+
_value;
|
|
9
|
+
get value() {
|
|
10
|
+
return this._value;
|
|
11
|
+
}
|
|
12
|
+
constructor(state, reducer) {
|
|
13
|
+
super();
|
|
14
|
+
this.reducer = reducer;
|
|
15
|
+
this._value = state;
|
|
16
|
+
}
|
|
17
|
+
static combineLatest(states, callback) {
|
|
18
|
+
const empty = Symbol();
|
|
19
|
+
const values = new State(states.map(() => empty));
|
|
20
|
+
const subscriptions = [
|
|
21
|
+
values.subscribe((values) => {
|
|
22
|
+
if (values.value.every((i) => i !== empty)) {
|
|
23
|
+
callback(values.value);
|
|
24
|
+
}
|
|
25
|
+
}),
|
|
26
|
+
];
|
|
27
|
+
for (const [index, state] of states.entries()) {
|
|
28
|
+
const subscription = state.subscribe((state) => {
|
|
29
|
+
values.update((values) => {
|
|
30
|
+
values[index] = state.value;
|
|
31
|
+
return values;
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
subscriptions.push(subscription);
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
unsubscribe: () => {
|
|
38
|
+
for (const subscription of subscriptions) {
|
|
39
|
+
subscription.unsubscribe();
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
reduce(update) {
|
|
45
|
+
const reducer = new Proxy({
|
|
46
|
+
update: (path, update) => {
|
|
47
|
+
return (state) => $Value.update(state, path, update);
|
|
48
|
+
},
|
|
49
|
+
}, {
|
|
50
|
+
get: (target, property) => {
|
|
51
|
+
if (property === 'update')
|
|
52
|
+
return target.update;
|
|
53
|
+
const reducer = {
|
|
54
|
+
entity: new EntityAdaptor(property),
|
|
55
|
+
array: new ArrayAdaptor(property),
|
|
56
|
+
value: {
|
|
57
|
+
set: (value) => ({
|
|
58
|
+
[property]: value,
|
|
59
|
+
}),
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
Object.assign(reducer, (this.reducer && new this.reducer()[property]) || {});
|
|
63
|
+
return reducer;
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
this.update(...update(reducer));
|
|
67
|
+
}
|
|
68
|
+
subscribe(emit) {
|
|
69
|
+
const subscription = super.subscribe(emit);
|
|
70
|
+
const event = {
|
|
71
|
+
previousValue: this.value,
|
|
72
|
+
value: this.value,
|
|
73
|
+
};
|
|
74
|
+
emit(event, subscription);
|
|
75
|
+
return subscription;
|
|
76
|
+
}
|
|
77
|
+
static update(state, ...updates) {
|
|
78
|
+
for (const update of updates) {
|
|
79
|
+
if ($Reflection.isFunction(update)) {
|
|
80
|
+
state = State.update(state, update(state));
|
|
81
|
+
}
|
|
82
|
+
else if ($Reflection.isObject(update)) {
|
|
83
|
+
const prototype = Object.getPrototypeOf(state ?? update);
|
|
84
|
+
state = Object.assign({}, state, update);
|
|
85
|
+
Object.setPrototypeOf(state, prototype);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
state = update;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return state;
|
|
92
|
+
}
|
|
93
|
+
update(...updates) {
|
|
94
|
+
this.set(State.update(this.value, ...updates));
|
|
95
|
+
}
|
|
96
|
+
set(value) {
|
|
97
|
+
const previousValue = this.value;
|
|
98
|
+
this._value = value;
|
|
99
|
+
this.emit({
|
|
100
|
+
previousValue,
|
|
101
|
+
value: this.value
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
asReadOnly() {
|
|
105
|
+
return this;
|
|
106
|
+
}
|
|
107
|
+
sync(config) {
|
|
108
|
+
let localValue;
|
|
109
|
+
let refValue;
|
|
110
|
+
const targetSubscription = config.subscribe(state => {
|
|
111
|
+
if (state.value !== localValue) {
|
|
112
|
+
refValue = state.value;
|
|
113
|
+
this.set(state.value);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
const localSubscription = this.subscribe(state => {
|
|
117
|
+
if (state.value !== refValue) {
|
|
118
|
+
localValue = state.value;
|
|
119
|
+
config.set(state.value);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
return {
|
|
123
|
+
unsubscribe: () => {
|
|
124
|
+
targetSubscription.unsubscribe();
|
|
125
|
+
localSubscription.unsubscribe();
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare class $String {
|
|
2
|
+
static indent(string: string, spaces: number): string;
|
|
3
|
+
static toAlphanumeric(string: string, specialCharacterReplacement?: string): string;
|
|
4
|
+
static indexesOf(string: string, pattern: string): number[];
|
|
5
|
+
static upperCaseFirst(string: string): string;
|
|
6
|
+
static getWords(string: string): string[];
|
|
7
|
+
static camelCase(string: string): string;
|
|
8
|
+
static kebabCase(string: string): string;
|
|
9
|
+
static isNullOrEmpty(value: string): boolean;
|
|
10
|
+
static sanitizeForRegex(string: string): string;
|
|
11
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export class $String {
|
|
2
|
+
static indent(string, spaces) {
|
|
3
|
+
return string?.replace(/^/gm, ' '.repeat(spaces));
|
|
4
|
+
}
|
|
5
|
+
static toAlphanumeric(string, specialCharacterReplacement) {
|
|
6
|
+
return string.replace(/[^a-zA-Z0-9]/g, specialCharacterReplacement ?? '');
|
|
7
|
+
}
|
|
8
|
+
static indexesOf(string, pattern) {
|
|
9
|
+
const indexes = [];
|
|
10
|
+
let index = string.indexOf(pattern);
|
|
11
|
+
while (index > -1) {
|
|
12
|
+
indexes.push(index);
|
|
13
|
+
index = string.indexOf(pattern, index + 1);
|
|
14
|
+
}
|
|
15
|
+
return indexes;
|
|
16
|
+
}
|
|
17
|
+
static upperCaseFirst(string) {
|
|
18
|
+
return string.slice(0, 1).toUpperCase() + string.slice(1);
|
|
19
|
+
}
|
|
20
|
+
static getWords(string) {
|
|
21
|
+
const regex = new RegExp(['[A-Z][a-z]+', '[A-Z]+(?=[A-Z][a-z])', '[A-Z]+', '[a-z]+', '[0-9]+'].join('|'), 'g');
|
|
22
|
+
return string.match(regex) ?? [];
|
|
23
|
+
}
|
|
24
|
+
static camelCase(string) {
|
|
25
|
+
return $String
|
|
26
|
+
.getWords(string)
|
|
27
|
+
.map((word, index) => (index === 0 ? word.toLowerCase() : $String.upperCaseFirst(word.toLowerCase())))
|
|
28
|
+
.join('');
|
|
29
|
+
}
|
|
30
|
+
static kebabCase(string) {
|
|
31
|
+
return $String
|
|
32
|
+
.getWords(string)
|
|
33
|
+
.map((word) => word.toLowerCase())
|
|
34
|
+
.join('-');
|
|
35
|
+
}
|
|
36
|
+
static isNullOrEmpty(value) {
|
|
37
|
+
return value == null || value === '';
|
|
38
|
+
}
|
|
39
|
+
static sanitizeForRegex(string) {
|
|
40
|
+
return string.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Subscription } from './subscription.interface';
|
|
2
|
+
export declare class Subscribable<T> {
|
|
3
|
+
private listeners;
|
|
4
|
+
protected emit(event: T): void;
|
|
5
|
+
until(predicate: (value: T) => boolean): Promise<T>;
|
|
6
|
+
subscribe(emit: (event: T, subscription: Subscription) => void): Subscription;
|
|
7
|
+
}
|
|
8
|
+
export declare class Emitter<T> extends Subscribable<T> {
|
|
9
|
+
emit(event: T): void;
|
|
10
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { $Array } from '../array/array.util';
|
|
2
|
+
export class Subscribable {
|
|
3
|
+
listeners = [];
|
|
4
|
+
emit(event) {
|
|
5
|
+
for (const listener of this.listeners) {
|
|
6
|
+
listener(event);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
until(predicate) {
|
|
10
|
+
return new Promise((resolve) => {
|
|
11
|
+
this.subscribe((event, subscription) => {
|
|
12
|
+
if (predicate(event)) {
|
|
13
|
+
subscription.unsubscribe();
|
|
14
|
+
resolve(event);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
subscribe(emit) {
|
|
20
|
+
const listener = event => emit(event, subscription);
|
|
21
|
+
const subscription = {
|
|
22
|
+
unsubscribe: () => {
|
|
23
|
+
this.listeners = $Array.remove(this.listeners, listener);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
this.listeners.push(listener);
|
|
27
|
+
return subscription;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export class Emitter extends Subscribable {
|
|
31
|
+
emit(event) {
|
|
32
|
+
super.emit(event);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TsonAny, TsonAnyDefinition } from './schemas/any';
|
|
2
|
+
import type { TsonArray, TsonArrayDefinition } from './schemas/array';
|
|
3
|
+
import type { TsonBoolean, TsonBooleanDefinition } from './schemas/boolean';
|
|
4
|
+
import type { TsonEnum, TsonEnumDefinition } from './schemas/enum';
|
|
5
|
+
import type { TsonNumber, TsonNumberDefinition } from './schemas/number';
|
|
6
|
+
import type { TsonObject, TsonObjectDefinition } from './schemas/object';
|
|
7
|
+
import type { TsonString, TsonStringDefinition } from './schemas/string';
|
|
8
|
+
import type { TsonUnion, TsonUnionDefinition } from './schemas/union';
|
|
9
|
+
export type TsonDefinition = TsonEnumDefinition | TsonAnyDefinition | TsonArrayDefinition | TsonBooleanDefinition | TsonAnyDefinition | TsonNumberDefinition | TsonObjectDefinition | TsonStringDefinition | TsonUnionDefinition;
|
|
10
|
+
export type TsonSchema = TsonString | TsonNumber | TsonBoolean | TsonArray | TsonEnum | TsonObject | TsonAny | TsonUnion;
|
|
File without changes
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { TsonDefinition } from '../schema';
|
|
2
|
+
import { type TsonDefinitionBase, TsonSchemaBase } from './schema-base';
|
|
3
|
+
export interface TsonAnyDefinition extends TsonDefinitionBase {
|
|
4
|
+
type: 'any';
|
|
5
|
+
default?: any;
|
|
6
|
+
}
|
|
7
|
+
export declare class TsonAny extends TsonSchemaBase<any> {
|
|
8
|
+
definition: TsonAnyDefinition;
|
|
9
|
+
constructor(definition?: TsonAnyDefinition);
|
|
10
|
+
default(value: any): TsonAny;
|
|
11
|
+
getDefault(): any;
|
|
12
|
+
accepts(definition: TsonDefinition | null | undefined): boolean;
|
|
13
|
+
parse(value: any): any;
|
|
14
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { TsonSchemaBase } from './schema-base';
|
|
2
|
+
export class TsonAny extends TsonSchemaBase {
|
|
3
|
+
definition;
|
|
4
|
+
constructor(definition = {
|
|
5
|
+
type: 'any',
|
|
6
|
+
}) {
|
|
7
|
+
super();
|
|
8
|
+
this.definition = definition;
|
|
9
|
+
}
|
|
10
|
+
default(value) {
|
|
11
|
+
return new TsonAny({
|
|
12
|
+
...this.definition,
|
|
13
|
+
default: value,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
getDefault() {
|
|
17
|
+
return this.definition.default ?? undefined;
|
|
18
|
+
}
|
|
19
|
+
accepts(definition) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
parse(value) {
|
|
23
|
+
if (this.parseDefault(value))
|
|
24
|
+
return this.definition.default;
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { TsonDefinition } from '../schema';
|
|
2
|
+
import type { TsonType } from '../type';
|
|
3
|
+
import { type TsonDefinitionBase, TsonSchemaBase } from './schema-base';
|
|
4
|
+
export interface TsonArrayDefinition<T = any> extends TsonDefinitionBase {
|
|
5
|
+
readonly type: 'array';
|
|
6
|
+
min?: number;
|
|
7
|
+
max?: number;
|
|
8
|
+
default?: T[];
|
|
9
|
+
itemDefinition?: TsonDefinition;
|
|
10
|
+
}
|
|
11
|
+
export declare class TsonArray<T extends TsonDefinition = any> extends TsonSchemaBase<TsonType<T>[]> {
|
|
12
|
+
definition: TsonArrayDefinition<TsonType<T>>;
|
|
13
|
+
constructor(definition?: TsonArrayDefinition<TsonType<T>>);
|
|
14
|
+
default(value: any): TsonArray<T>;
|
|
15
|
+
minLength(length: number): TsonArray<T>;
|
|
16
|
+
maxLength(length: number): TsonArray<T>;
|
|
17
|
+
item(schema: TsonDefinition): TsonArray<T>;
|
|
18
|
+
getDefault(): TsonType<T>[];
|
|
19
|
+
accepts(definition: TsonDefinition | null | undefined): boolean;
|
|
20
|
+
parse(value: any): TsonType<T>[];
|
|
21
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { TsonError } from '../error';
|
|
2
|
+
import { $Tson } from '../tson';
|
|
3
|
+
import { TsonSchemaBase } from './schema-base';
|
|
4
|
+
export class TsonArray extends TsonSchemaBase {
|
|
5
|
+
definition;
|
|
6
|
+
constructor(definition = {
|
|
7
|
+
type: 'array',
|
|
8
|
+
}) {
|
|
9
|
+
super();
|
|
10
|
+
this.definition = definition;
|
|
11
|
+
}
|
|
12
|
+
default(value) {
|
|
13
|
+
return new TsonArray({
|
|
14
|
+
...this.definition,
|
|
15
|
+
default: value,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
minLength(length) {
|
|
19
|
+
return new TsonArray({
|
|
20
|
+
...this.definition,
|
|
21
|
+
min: length,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
maxLength(length) {
|
|
25
|
+
return new TsonArray({
|
|
26
|
+
...this.definition,
|
|
27
|
+
max: length,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
item(schema) {
|
|
31
|
+
return new TsonArray({
|
|
32
|
+
...this.definition,
|
|
33
|
+
itemDefinition: schema,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
getDefault() {
|
|
37
|
+
return (this.definition.default ?? this.definition.itemDefinition) ? [$Tson.parse(this.definition.itemDefinition).getDefault()] : [];
|
|
38
|
+
}
|
|
39
|
+
accepts(definition) {
|
|
40
|
+
if (definition == null && this.definition.default !== undefined)
|
|
41
|
+
return true;
|
|
42
|
+
if (definition.type === 'any')
|
|
43
|
+
return true;
|
|
44
|
+
if (this.definition.default === undefined && definition.default !== undefined)
|
|
45
|
+
return false;
|
|
46
|
+
if (definition.type !== 'array')
|
|
47
|
+
return false;
|
|
48
|
+
if (this.definition.max != null && this.definition.max < definition.max)
|
|
49
|
+
return false;
|
|
50
|
+
if (this.definition.min != null && this.definition.min < definition.min)
|
|
51
|
+
return false;
|
|
52
|
+
if (this.definition.itemDefinition != null && !$Tson.parse(this.definition.itemDefinition).accepts(definition.itemDefinition))
|
|
53
|
+
return false;
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
parse(value) {
|
|
57
|
+
if (this.parseDefault(value))
|
|
58
|
+
return this.definition.default;
|
|
59
|
+
if (value != null && !Array.isArray(value))
|
|
60
|
+
throw new TsonError('Array expected', value, this);
|
|
61
|
+
const array = value;
|
|
62
|
+
if (this.definition.min != null && array.length < this.definition.min)
|
|
63
|
+
throw new TsonError(`Array min length of ${this.definition.min} expected`, value, this);
|
|
64
|
+
if (this.definition.max != null && array.length > this.definition.max)
|
|
65
|
+
throw new TsonError(`Array max length of ${this.definition.max} expected`, value, this);
|
|
66
|
+
if (this.definition.itemDefinition) {
|
|
67
|
+
for (const [index, item] of array.entries()) {
|
|
68
|
+
try {
|
|
69
|
+
array[index] = $Tson.parse(this.definition.itemDefinition).parse(item);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
if (!(error instanceof TsonError))
|
|
73
|
+
throw error;
|
|
74
|
+
throw new TsonError(`Invalid item in array. ${error.message}`, item, this, `[${index}]${error.path}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return value;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { TsonDefinition } from '../schema';
|
|
2
|
+
import { type TsonDefinitionBase, TsonSchemaBase } from './schema-base';
|
|
3
|
+
export interface TsonBooleanDefinition extends TsonDefinitionBase {
|
|
4
|
+
readonly type: 'boolean';
|
|
5
|
+
default?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare class TsonBoolean extends TsonSchemaBase<boolean> {
|
|
8
|
+
definition: TsonBooleanDefinition;
|
|
9
|
+
constructor(definition?: TsonBooleanDefinition);
|
|
10
|
+
default(value: any): TsonBoolean;
|
|
11
|
+
getDefault(): boolean;
|
|
12
|
+
accepts(definition: TsonDefinition | null | undefined): boolean;
|
|
13
|
+
parse(value: any): boolean;
|
|
14
|
+
}
|