@ecosy/core 0.1.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.
- package/README.md +237 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1 -0
- package/dist/index.mjs +1 -0
- package/dist/subscriber.d.ts +99 -0
- package/dist/subscriber.js +1 -0
- package/dist/subscriber.mjs +1 -0
- package/dist/types/built-in.d.ts +22 -0
- package/dist/types/built-in.js +1 -0
- package/dist/types/built-in.mjs +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/index.mjs +1 -0
- package/dist/utilities/clone.d.ts +18 -0
- package/dist/utilities/clone.js +1 -0
- package/dist/utilities/clone.mjs +1 -0
- package/dist/utilities/freeze.d.ts +17 -0
- package/dist/utilities/freeze.js +1 -0
- package/dist/utilities/freeze.mjs +1 -0
- package/dist/utilities/index.d.ts +8 -0
- package/dist/utilities/index.js +1 -0
- package/dist/utilities/index.mjs +1 -0
- package/dist/utilities/is-equal.d.ts +17 -0
- package/dist/utilities/is-equal.js +1 -0
- package/dist/utilities/is-equal.mjs +1 -0
- package/dist/utilities/is-function.d.ts +15 -0
- package/dist/utilities/is-function.js +1 -0
- package/dist/utilities/is-function.mjs +1 -0
- package/dist/utilities/merge.d.ts +18 -0
- package/dist/utilities/merge.js +1 -0
- package/dist/utilities/merge.mjs +1 -0
- package/dist/utilities/object.d.ts +43 -0
- package/dist/utilities/object.js +1 -0
- package/dist/utilities/object.mjs +1 -0
- package/dist/utilities/to-string.d.ts +13 -0
- package/dist/utilities/to-string.js +1 -0
- package/dist/utilities/to-string.mjs +1 -0
- package/dist/utilities/ucfirst.d.ts +12 -0
- package/dist/utilities/ucfirst.js +1 -0
- package/dist/utilities/ucfirst.mjs +1 -0
- package/package.json +74 -0
package/README.md
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# @ecosy/core
|
|
2
|
+
|
|
3
|
+
Lightweight utilities, pub/sub subscriber, and types for TypeScript applications.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @ecosy/core
|
|
9
|
+
# or
|
|
10
|
+
yarn add @ecosy/core
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Modules
|
|
14
|
+
|
|
15
|
+
| Entry point | Description |
|
|
16
|
+
|--|--|
|
|
17
|
+
| `@ecosy/core` | Re-exports utilities + subscriber |
|
|
18
|
+
| `@ecosy/core/types` | TypeScript type utilities |
|
|
19
|
+
| `@ecosy/core/utilities` | Runtime utility functions |
|
|
20
|
+
| `@ecosy/core/subscriber` | Pub/sub event emitter with state |
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Types
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import type {
|
|
28
|
+
primitive,
|
|
29
|
+
LiteralObject,
|
|
30
|
+
LiteralFunction,
|
|
31
|
+
Objectable,
|
|
32
|
+
Freezable,
|
|
33
|
+
PartialLiteral,
|
|
34
|
+
ToString,
|
|
35
|
+
Promisable,
|
|
36
|
+
AtomicObject,
|
|
37
|
+
} from "@ecosy/core/types";
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
| Type | Description |
|
|
41
|
+
|--|--|
|
|
42
|
+
| `primitive` | `string \| number \| boolean \| bigint \| symbol \| undefined \| null` |
|
|
43
|
+
| `LiteralObject` | Plain object type (`Record<PropertyKey, unknown> \| object`) |
|
|
44
|
+
| `LiteralFunction<R, A>` | Generic function type `(...args: A) => R` |
|
|
45
|
+
| `Objectable` | `LiteralObject \| Array \| LiteralFunction` |
|
|
46
|
+
| `Freezable<T>` | Recursively readonly version of `T` |
|
|
47
|
+
| `PartialLiteral<T>` | Deep partial that respects built-in types (Map, Set, Promise, etc.) |
|
|
48
|
+
| `ToString<T>` | Converts type to its string literal representation |
|
|
49
|
+
| `Promisable<V>` | `V \| Promise<V>` |
|
|
50
|
+
| `AtomicObject<K, V>` | `{ [K]: V }` |
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Utilities
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import {
|
|
58
|
+
clone,
|
|
59
|
+
freeze,
|
|
60
|
+
isEqual,
|
|
61
|
+
isFunction,
|
|
62
|
+
isObject,
|
|
63
|
+
isLiteralObject,
|
|
64
|
+
isComplexObject,
|
|
65
|
+
isObjectable,
|
|
66
|
+
hasOwnProperty,
|
|
67
|
+
merge,
|
|
68
|
+
toString,
|
|
69
|
+
ucfirst,
|
|
70
|
+
} from "@ecosy/core/utilities";
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### `clone<T>(data: T): T`
|
|
74
|
+
|
|
75
|
+
Deep clones a value. Handles circular references, Date, RegExp, Map, Set, ArrayBuffer, TypedArrays, arrays, and plain objects. Skips non-cloneable types (Error, Promise, WeakMap, DOM nodes, etc.).
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
const original = { a: 1, b: { c: [2, 3] } };
|
|
79
|
+
const cloned = clone(original);
|
|
80
|
+
cloned.b.c.push(4);
|
|
81
|
+
original.b.c.length; // 3 — unaffected
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### `freeze<T>(data: T): Freezable<T>`
|
|
85
|
+
|
|
86
|
+
Deep freezes a value by cloning first, then recursively calling `Object.freeze`.
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
const frozen = freeze({ a: { b: 1 } });
|
|
90
|
+
frozen.a.b = 2; // throws in strict mode
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### `isEqual(a: unknown, b: unknown): boolean`
|
|
94
|
+
|
|
95
|
+
Deep structural equality check. Supports primitives, arrays, plain objects, Date, RegExp, Map, Set, ArrayBuffer, and TypedArrays.
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
isEqual({ a: [1, 2] }, { a: [1, 2] }); // true
|
|
99
|
+
isEqual(new Date(0), new Date(0)); // true
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### `merge<T>(source, target, cloneDeep?): T`
|
|
103
|
+
|
|
104
|
+
Deep merges `target` into `source`. Prototype-polluting keys (`__proto__`, `constructor`, `prototype`) are rejected.
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
merge({ a: 1, b: { c: 2 } }, { b: { d: 3 } });
|
|
108
|
+
// { a: 1, b: { c: 2, d: 3 } }
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### `isFunction(value): value is LiteralFunction`
|
|
112
|
+
|
|
113
|
+
Checks if a value is a function (sync, async, or generator).
|
|
114
|
+
|
|
115
|
+
### `isObject(value): value is object`
|
|
116
|
+
|
|
117
|
+
Checks if a value is a non-null object.
|
|
118
|
+
|
|
119
|
+
### `isLiteralObject(value): value is LiteralObject`
|
|
120
|
+
|
|
121
|
+
Checks if a value is a plain object (`{}` or `Object.create(null)`).
|
|
122
|
+
|
|
123
|
+
### `isComplexObject<T>(value): value is T`
|
|
124
|
+
|
|
125
|
+
Checks if a value is a non-array object (e.g., class instance).
|
|
126
|
+
|
|
127
|
+
### `isObjectable(value): value is Objectable`
|
|
128
|
+
|
|
129
|
+
Checks if a value is an object, array, or function.
|
|
130
|
+
|
|
131
|
+
### `hasOwnProperty(obj, key): boolean`
|
|
132
|
+
|
|
133
|
+
Type-safe `Object.prototype.hasOwnProperty.call()`.
|
|
134
|
+
|
|
135
|
+
### `toString(value): string`
|
|
136
|
+
|
|
137
|
+
Returns the internal `[[Class]]` tag via `Object.prototype.toString`.
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
toString([]); // "[object Array]"
|
|
141
|
+
toString(null); // "[object Null]"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### `ucfirst<T>(str: T): Capitalize<T>`
|
|
145
|
+
|
|
146
|
+
Capitalizes the first character of a string.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Subscriber
|
|
151
|
+
|
|
152
|
+
A pub/sub event emitter with built-in state management.
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
import { Subscriber } from "@ecosy/core/subscriber";
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Basic usage
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
const sub = new Subscriber({ count: 0 });
|
|
162
|
+
|
|
163
|
+
// Subscribe to state changes
|
|
164
|
+
const unsub = sub.onStateChange((state) => {
|
|
165
|
+
console.log("Count:", state.count);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// Update state
|
|
169
|
+
sub.setState({ count: 1 }); // logs "Count: 1"
|
|
170
|
+
|
|
171
|
+
// Cleanup
|
|
172
|
+
unsub();
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Custom channels
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
sub.subscribe("user:login", (user) => {
|
|
179
|
+
console.log("Logged in:", user.name);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
sub.dispatch("user:login", { name: "Alice" });
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Async once
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
const payload = await sub.subscribeAsyncOnce("data:ready");
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
> [!WARNING]
|
|
192
|
+
> If the channel is never dispatched and no `AbortSignal` is provided, the returned Promise will never resolve, causing a **memory leak**. Always pass an `AbortSignal` or ensure the channel will eventually be dispatched.
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
const controller = new AbortController();
|
|
196
|
+
setTimeout(() => controller.abort(), 5000); // timeout after 5s
|
|
197
|
+
|
|
198
|
+
try {
|
|
199
|
+
const payload = await sub.subscribeAsyncOnce("data:ready", undefined, controller.signal);
|
|
200
|
+
} catch {
|
|
201
|
+
console.log("Timed out or cancelled");
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Wiring events
|
|
206
|
+
|
|
207
|
+
```ts
|
|
208
|
+
const events = {
|
|
209
|
+
auth: {
|
|
210
|
+
login: "$auth:login",
|
|
211
|
+
logout: "$auth:logout",
|
|
212
|
+
},
|
|
213
|
+
} as const;
|
|
214
|
+
|
|
215
|
+
const wired = Subscriber.wire(sub, events);
|
|
216
|
+
|
|
217
|
+
// Dispatch
|
|
218
|
+
wired.auth.login({ user: "Alice" });
|
|
219
|
+
|
|
220
|
+
// Listen
|
|
221
|
+
wired.auth.onLogin((payload) => {
|
|
222
|
+
console.log(payload.user);
|
|
223
|
+
});
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Related packages
|
|
229
|
+
|
|
230
|
+
| Package | Description |
|
|
231
|
+
|--|--|
|
|
232
|
+
| [`@ecosy/store`](https://github.com/material-atomic/ecosy-store) | State management with slices and reducers |
|
|
233
|
+
| [`@ecosy/react`](https://github.com/material-atomic/ecosy-react) | React hooks for `@ecosy/store` |
|
|
234
|
+
|
|
235
|
+
## License
|
|
236
|
+
|
|
237
|
+
MIT
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var e=require("./subscriber.js"),i=require("./utilities/clone.js"),r=require("./utilities/freeze.js"),s=require("./utilities/is-equal.js"),t=require("./utilities/is-function.js"),u=require("./utilities/object.js"),o=require("./utilities/merge.js"),c=require("./utilities/to-string.js"),l=require("./utilities/ucfirst.js");exports.Subscriber=e.Subscriber,exports.clone=i.clone,exports.freeze=r.freeze,exports.isEqual=s.isEqual,exports.isFunction=t.isFunction,exports.hasOwnProperty=u.hasOwnProperty,exports.isComplexObject=u.isComplexObject,exports.isLiteralObject=u.isLiteralObject,exports.isObject=u.isObject,exports.isObjectable=u.isObjectable,exports.merge=o.merge,exports.toString=c.toString,exports.ucfirst=l.ucfirst;
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{Subscriber}from"./subscriber.mjs";export{clone}from"./utilities/clone.mjs";export{freeze}from"./utilities/freeze.mjs";export{isEqual}from"./utilities/is-equal.mjs";export{isFunction}from"./utilities/is-function.mjs";export{hasOwnProperty,isComplexObject,isLiteralObject,isObject,isObjectable}from"./utilities/object.mjs";export{merge}from"./utilities/merge.mjs";export{toString}from"./utilities/to-string.mjs";export{ucfirst}from"./utilities/ucfirst.mjs";
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { Freezable, LiteralObject, PartialLiteral, ToString } from "@ecosy/core/types";
|
|
2
|
+
export type SubscribeChannel = string;
|
|
3
|
+
export type SubcribeHandler<Payload = never> = [Payload] extends [never] ? () => void : (payload: Payload) => void;
|
|
4
|
+
export interface Shallow {
|
|
5
|
+
merge<AsType>(source: unknown, target: unknown, cloneDeep?: (data: unknown) => unknown): AsType;
|
|
6
|
+
clone<DataType>(data: DataType): DataType;
|
|
7
|
+
isEqual(value1: unknown, value2: unknown): boolean;
|
|
8
|
+
}
|
|
9
|
+
export type ExtendedEventExpect = {
|
|
10
|
+
readonly [key: string]: {
|
|
11
|
+
readonly [key: string]: SubscribeChannel;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
export type WiredEventDomain<Domain extends Record<string, SubscribeChannel>> = {
|
|
15
|
+
[K in keyof Domain]: <Payload>(payload?: Payload) => void;
|
|
16
|
+
} & {
|
|
17
|
+
[K in keyof Domain as `on${Capitalize<ToString<K>>}`]: <Payload>(handler: SubcribeHandler<Payload>) => () => void;
|
|
18
|
+
};
|
|
19
|
+
export type WiredEvents<Events extends ExtendedEventExpect> = {
|
|
20
|
+
readonly [K in keyof Events]: Readonly<WiredEventDomain<Events[K]>>;
|
|
21
|
+
};
|
|
22
|
+
declare const defaultEvents: {
|
|
23
|
+
readonly state: {
|
|
24
|
+
readonly change: string;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
type DefaultEvents = typeof defaultEvents;
|
|
28
|
+
export type SubscriberInstance<State extends LiteralObject = LiteralObject, Events = {}> = InstanceType<typeof Subscriber<State, Events>>;
|
|
29
|
+
/**
|
|
30
|
+
* Generic pub/sub event emitter with built-in state management.
|
|
31
|
+
* Provides subscribe/dispatch for arbitrary channels and state change notifications.
|
|
32
|
+
*
|
|
33
|
+
* @typeParam State - The shape of the internal state object.
|
|
34
|
+
* @typeParam Events - Extended event definitions to wire onto the instance.
|
|
35
|
+
*/
|
|
36
|
+
export declare class Subscriber<State extends LiteralObject, Events = {}> {
|
|
37
|
+
private _state;
|
|
38
|
+
private listeners;
|
|
39
|
+
private _shallow;
|
|
40
|
+
readonly _events: Freezable<DefaultEvents & Events>;
|
|
41
|
+
get shallow(): Freezable<Shallow>;
|
|
42
|
+
set shallow(shallow: Shallow | Partial<Shallow>);
|
|
43
|
+
constructor(initialState?: State | PartialLiteral<State>, events?: Events);
|
|
44
|
+
/**
|
|
45
|
+
* Subscribes a handler to a named channel.
|
|
46
|
+
*
|
|
47
|
+
* @param channel - The event channel name.
|
|
48
|
+
* @param handler - Callback invoked when the channel is dispatched.
|
|
49
|
+
* @returns An unsubscribe function.
|
|
50
|
+
*/
|
|
51
|
+
subscribe<Payload = never>(channel: SubscribeChannel, handler: SubcribeHandler<Payload>): () => void;
|
|
52
|
+
/**
|
|
53
|
+
* Dispatches a payload to all handlers subscribed to the given channel.
|
|
54
|
+
*
|
|
55
|
+
* @param channel - The event channel name.
|
|
56
|
+
* @param payload - Optional data to pass to each handler.
|
|
57
|
+
*/
|
|
58
|
+
dispatch<Payload = unknown>(channel: SubscribeChannel, payload?: Payload): void;
|
|
59
|
+
/** Returns the current state. */
|
|
60
|
+
getState(): State;
|
|
61
|
+
/**
|
|
62
|
+
* Merges new state and dispatches a state change event if the state has changed.
|
|
63
|
+
*
|
|
64
|
+
* @param state - Full or partial state to merge.
|
|
65
|
+
*/
|
|
66
|
+
setState(state: State | PartialLiteral<State>): void;
|
|
67
|
+
/**
|
|
68
|
+
* Shorthand to subscribe to state change events.
|
|
69
|
+
*
|
|
70
|
+
* @param handler - Callback receiving the new state.
|
|
71
|
+
* @returns An unsubscribe function.
|
|
72
|
+
*/
|
|
73
|
+
onStateChange(handler: SubcribeHandler<State>): () => void;
|
|
74
|
+
/**
|
|
75
|
+
* Subscribes to a channel, resolving a Promise with the first dispatched payload.
|
|
76
|
+
* Supports cancellation via an `AbortSignal`.
|
|
77
|
+
*
|
|
78
|
+
* @warning If the channel is never dispatched and no `AbortSignal` is provided,
|
|
79
|
+
* the returned Promise will never resolve, causing a memory leak. Always pass an
|
|
80
|
+
* `AbortSignal` or ensure the channel will eventually be dispatched.
|
|
81
|
+
*
|
|
82
|
+
* @param channel - The event channel name.
|
|
83
|
+
* @param handler - Optional callback invoked on payload.
|
|
84
|
+
* @param signal - Optional AbortSignal to cancel the subscription.
|
|
85
|
+
* @returns A promise that resolves with the first payload dispatched to the channel.
|
|
86
|
+
*/
|
|
87
|
+
subscribeAsyncOnce<Payload = never>(channel: SubscribeChannel, handler?: SubcribeHandler<Payload>, signal?: AbortSignal): Promise<Payload>;
|
|
88
|
+
/**
|
|
89
|
+
* Wires event domains onto a `Subscriber` instance, creating typed dispatch and
|
|
90
|
+
* listener methods (e.g. `instance.domainName.eventName()` and
|
|
91
|
+
* `instance.domainName.onEventName()`).
|
|
92
|
+
*
|
|
93
|
+
* @param $instance - The subscriber instance to extend.
|
|
94
|
+
* @param events - Event definitions mapping domain → channel names.
|
|
95
|
+
* @returns The instance with wired event methods.
|
|
96
|
+
*/
|
|
97
|
+
static wire<ExtendedEvents extends ExtendedEventExpect, State extends LiteralObject, Instance extends SubscriberInstance<State, ExtendedEvents>>($instance: Instance, events: ExtendedEvents): Instance & Freezable<WiredEvents<ExtendedEvents>>;
|
|
98
|
+
}
|
|
99
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var e=require("./utilities/clone.js"),s=require("./utilities/freeze.js"),t=require("./utilities/is-equal.js"),i=require("./utilities/object.js"),r=require("./utilities/merge.js"),l=require("./utilities/ucfirst.js");class n extends Set{}class a extends Map{}const h=s.freeze({state:{change:"$state:change"}});exports.Subscriber=class{get shallow(){return s.freeze({merge:this._shallow.merge,clone:this._shallow.clone,isEqual:this._shallow.isEqual})}set shallow(e){this._shallow=this._shallow.merge(this._shallow,e)}constructor(i,l){this._state={},this.listeners=new a,this._shallow={merge:r.merge,clone:e.clone,isEqual:t.isEqual},this._events=s.freeze(h),this._state=null!=i?i:{},this._events=s.freeze(Object.assign(Object.assign({},this._events),l))}subscribe(e,s){return this.listeners.has(e)||this.listeners.set(e,new n),this.listeners.get(e).add(s),()=>{var t;null===(t=this.listeners.get(e))||void 0===t||t.delete(s)}}dispatch(e,s){this.listeners.has(e)&&this.listeners.get(e).forEach(e=>{e(...void 0===s?[]:[s])})}getState(){return this._state}setState(e){const s=this._shallow.merge(this._state,e);this._shallow.isEqual(this._state,s)||(this._state=s,this.dispatch(this._events.state.change,this._shallow.clone(s)))}onStateChange(e){return this.subscribe(this._events.state.change,e)}async subscribeAsyncOnce(e,s,t){let i,r;try{return await new Promise((l,n)=>{if(null==t?void 0:t.aborted)return n(new Error("Operation cancelled"));i=this.subscribe(e,e=>{null==s||s(e),l(e)}),t&&(r=()=>n(new Error("Operation cancelled")),t.addEventListener("abort",r,{once:!0}))})}finally{null==i||i(),t&&r&&t.removeEventListener("abort",r)}}static wire(e,t){for(const r in t){if(r in e)throw new Error(`[Subscriber.wire] "${r}" is invalid.`);const n=t[r];if(!i.isLiteralObject(n))continue;const a=Object.keys(n).reduce((s,t)=>{const i=n[t];return s[t]=s=>{e.dispatch(i,s)},s[`on${l.ucfirst(t)}`]=s=>e.subscribe(i,s),s},{});Object.defineProperty(e,r,{value:s.freeze(a),writable:!1,enumerable:!0,configurable:!1})}return e}};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{clone as e}from"./utilities/clone.mjs";import{freeze as t}from"./utilities/freeze.mjs";import{isEqual as s}from"./utilities/is-equal.mjs";import{isLiteralObject as i}from"./utilities/object.mjs";import{merge as r}from"./utilities/merge.mjs";import{ucfirst as n}from"./utilities/ucfirst.mjs";class l extends Set{}class a extends Map{}const o=t({state:{change:"$state:change"}});class h{get shallow(){return t({merge:this._shallow.merge,clone:this._shallow.clone,isEqual:this._shallow.isEqual})}set shallow(e){this._shallow=this._shallow.merge(this._shallow,e)}constructor(i,n){this._state={},this.listeners=new a,this._shallow={merge:r,clone:e,isEqual:s},this._events=t(o),this._state=null!=i?i:{},this._events=t(Object.assign(Object.assign({},this._events),n))}subscribe(e,t){return this.listeners.has(e)||this.listeners.set(e,new l),this.listeners.get(e).add(t),()=>{var s;null===(s=this.listeners.get(e))||void 0===s||s.delete(t)}}dispatch(e,t){this.listeners.has(e)&&this.listeners.get(e).forEach(e=>{e(...void 0===t?[]:[t])})}getState(){return this._state}setState(e){const t=this._shallow.merge(this._state,e);this._shallow.isEqual(this._state,t)||(this._state=t,this.dispatch(this._events.state.change,this._shallow.clone(t)))}onStateChange(e){return this.subscribe(this._events.state.change,e)}async subscribeAsyncOnce(e,t,s){let i,r;try{return await new Promise((n,l)=>{if(null==s?void 0:s.aborted)return l(new Error("Operation cancelled"));i=this.subscribe(e,e=>{null==t||t(e),n(e)}),s&&(r=()=>l(new Error("Operation cancelled")),s.addEventListener("abort",r,{once:!0}))})}finally{null==i||i(),s&&r&&s.removeEventListener("abort",r)}}static wire(e,s){for(const r in s){if(r in e)throw new Error(`[Subscriber.wire] "${r}" is invalid.`);const l=s[r];if(!i(l))continue;const a=Object.keys(l).reduce((t,s)=>{const i=l[s];return t[s]=t=>{e.dispatch(i,t)},t[`on${n(s)}`]=t=>e.subscribe(i,t),t},{});Object.defineProperty(e,r,{value:t(a),writable:!1,enumerable:!0,configurable:!1})}return e}}export{h as Subscriber};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type primitive = string | number | boolean | bigint | symbol | undefined | null;
|
|
2
|
+
export type PrimitiveClass = Date | RegExp | File | FileList | URL | Blob | ArrayBuffer | SharedArrayBuffer | DataView | Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array | FormData | Headers | Request | Response | URLSearchParams | AbortController | AbortSignal | ReadableStream | WritableStream | TransformStream | Event | CustomEvent | EventTarget | MutationObserver | IntersectionObserver | ResizeObserver | Worker | MessageChannel | MessagePort | BroadcastChannel | Generator | AsyncGenerator | Element | HTMLElement | Node | Document | Window | Error | TypeError | RangeError | SyntaxError | ReferenceError | EvalError | AggregateError | URIError;
|
|
3
|
+
export type BuiltInPrimitive = primitive | PrimitiveClass;
|
|
4
|
+
export type LiteralObject<Keys extends PropertyKey = PropertyKey> = Record<Keys, unknown> | {
|
|
5
|
+
[K in Keys]: unknown;
|
|
6
|
+
} | object;
|
|
7
|
+
export type AtomicObject<Key extends PropertyKey = PropertyKey, Value = unknown> = {
|
|
8
|
+
[K in Key]: Value;
|
|
9
|
+
};
|
|
10
|
+
export type LiteralFunction<R = unknown, A extends unknown[] = unknown[]> = (...args: A) => R;
|
|
11
|
+
export type Objectable = LiteralObject | Array<unknown> | LiteralFunction;
|
|
12
|
+
export type Promisable<Value> = Value | Promise<Value>;
|
|
13
|
+
export type ExtendedFunction<F = LiteralFunction, O = LiteralObject> = F & O;
|
|
14
|
+
export type Freezable<T> = T extends primitive ? T : T extends (...args: unknown[]) => unknown ? T : T extends Array<infer U> ? ReadonlyArray<Freezable<U>> : T extends object ? {
|
|
15
|
+
readonly [K in keyof T]: Freezable<T[K]>;
|
|
16
|
+
} : T;
|
|
17
|
+
export type PartialLiteral<T> = T extends Map<infer K, infer V> ? Map<PartialLiteral<K>, PartialLiteral<V>> : T extends WeakMap<infer K, infer V> ? WeakMap<PartialLiteral<K>, PartialLiteral<V>> : T extends ReadonlyMap<infer K, infer V> ? ReadonlyMap<PartialLiteral<K>, PartialLiteral<V>> : T extends Set<infer U> ? Set<PartialLiteral<U>> : T extends WeakSet<infer U> ? WeakSet<PartialLiteral<U>> : T extends ReadonlySet<infer U> ? ReadonlySet<PartialLiteral<U>> : T extends Promise<infer U> ? Promise<PartialLiteral<U>> : T extends WeakRef<infer U> ? WeakRef<PartialLiteral<U>> : T extends FinalizationRegistry<infer U> ? FinalizationRegistry<PartialLiteral<U>> : T extends BuiltInPrimitive ? T : T extends ExtendedFunction ? T extends ExtendedFunction<infer F> ? F & {
|
|
18
|
+
[K in keyof T]?: PartialLiteral<T[K]>;
|
|
19
|
+
} : T : T extends LiteralObject ? {
|
|
20
|
+
[K in keyof T]?: PartialLiteral<T[K]>;
|
|
21
|
+
} : T extends Array<infer U> ? Array<PartialLiteral<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<PartialLiteral<U>> : T;
|
|
22
|
+
export type ToString<T> = T extends string | number | bigint | boolean ? `${T}` : T extends symbol ? string : T extends null ? "null" : T extends undefined ? "undefined" : never;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type * from "./built-in";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deep clones a value, handling circular references, built-in types (Date, RegExp, Map, Set,
|
|
3
|
+
* ArrayBuffer, TypedArrays), arrays, and plain objects. Skips non-cloneable types like
|
|
4
|
+
* Error, Promise, WeakMap, DOM nodes, etc.
|
|
5
|
+
*
|
|
6
|
+
* @param data - The value to clone.
|
|
7
|
+
* @param cache - Internal WeakMap used to track circular references.
|
|
8
|
+
* @returns A deep copy of the input value.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const original = { a: 1, b: { c: 2 } };
|
|
13
|
+
* const cloned = clone(original);
|
|
14
|
+
* cloned.b.c = 3;
|
|
15
|
+
* original.b.c; // still 2
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function clone<DataType>(data: DataType, cache?: WeakMap<object, unknown>): DataType;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var e=require("./is-function.js"),t=require("./object.js");const r={[Date.toString()]:e=>new Date(e.getTime()),[RegExp.toString()]:e=>new RegExp(e.source,e.flags),[Map.toString()]:(e,t)=>{const r=new Map;return t.set(e,r),e.forEach((e,n)=>{r.set(s(n,t),s(e,t))}),r},[Set.toString()]:(e,t)=>{const r=new Set;return t.set(e,r),e.forEach(e=>{r.add(s(e,t))}),r},[ArrayBuffer.toString()]:e=>e.slice(0)},n=[Date,RegExp,Map,Set,ArrayBuffer],o=[Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array,BigInt64Array,BigUint64Array,DataView],i=Array.from(new Set([Error,Promise,Blob,"undefined"!=typeof WeakMap&&WeakMap,"undefined"!=typeof WeakSet&&WeakSet,"undefined"!=typeof Symbol&&Symbol,"undefined"!=typeof Window&&Window,"undefined"!=typeof File&&File,"undefined"!=typeof FormData&&FormData,"undefined"!=typeof Headers&&Headers,"undefined"!=typeof Request&&Request,"undefined"!=typeof Response&&Response,"undefined"!=typeof Worker&&Worker,"undefined"!=typeof AbortController&&AbortController,"undefined"!=typeof Node&&Node,"undefined"!=typeof FileList&&FileList]));function a(e,t){return t.includes(e)}function s(f,c=new WeakMap){var u;if(!t.isObjectable(f)||e.isFunction(f)||t.hasOwnProperty(f,"$$typeof")||f.constructor&&a(f.constructor,i))return f;if(c.has(f))return c.get(f);if(f.constructor&&a(f.constructor,o)){const e=f,t=new(0,f.constructor)(e.buffer.slice(0),e.byteOffset,e.byteLength);return c.set(f,t),t}const y=f.constructor;if(n.includes(y)){const e=y.toString(),t=(0,r[e])(f,c);return c.set(f,t),t}const d=Array.isArray(f)?new((null===(u=Object.getPrototypeOf(f))||void 0===u?void 0:u.constructor)||Array):Object.create(Object.getPrototypeOf(f));c.set(f,d);const p=Reflect.ownKeys(f);for(const e of p){const t=Object.getOwnPropertyDescriptor(f,e);t&&("value"in t&&(t.value=s(t.value,c)),Object.defineProperty(d,e,t))}return d}exports.clone=s;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{isFunction as e}from"./is-function.mjs";import{isObjectable as t,hasOwnProperty as r}from"./object.mjs";const n={[Date.toString()]:e=>new Date(e.getTime()),[RegExp.toString()]:e=>new RegExp(e.source,e.flags),[Map.toString()]:(e,t)=>{const r=new Map;return t.set(e,r),e.forEach((e,n)=>{r.set(s(n,t),s(e,t))}),r},[Set.toString()]:(e,t)=>{const r=new Set;return t.set(e,r),e.forEach(e=>{r.add(s(e,t))}),r},[ArrayBuffer.toString()]:e=>e.slice(0)},o=[Date,RegExp,Map,Set,ArrayBuffer],i=[Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array,BigInt64Array,BigUint64Array,DataView],f=Array.from(new Set([Error,Promise,Blob,"undefined"!=typeof WeakMap&&WeakMap,"undefined"!=typeof WeakSet&&WeakSet,"undefined"!=typeof Symbol&&Symbol,"undefined"!=typeof Window&&Window,"undefined"!=typeof File&&File,"undefined"!=typeof FormData&&FormData,"undefined"!=typeof Headers&&Headers,"undefined"!=typeof Request&&Request,"undefined"!=typeof Response&&Response,"undefined"!=typeof Worker&&Worker,"undefined"!=typeof AbortController&&AbortController,"undefined"!=typeof Node&&Node,"undefined"!=typeof FileList&&FileList]));function a(e,t){return t.includes(e)}function s(c,u=new WeakMap){var d;if(!t(c)||e(c)||r(c,"$$typeof")||c.constructor&&a(c.constructor,f))return c;if(u.has(c))return u.get(c);if(c.constructor&&a(c.constructor,i)){const e=c,t=new(0,c.constructor)(e.buffer.slice(0),e.byteOffset,e.byteLength);return u.set(c,t),t}const y=c.constructor;if(o.includes(y)){const e=y.toString(),t=(0,n[e])(c,u);return u.set(c,t),t}const p=Array.isArray(c)?new((null===(d=Object.getPrototypeOf(c))||void 0===d?void 0:d.constructor)||Array):Object.create(Object.getPrototypeOf(c));u.set(c,p);const l=Reflect.ownKeys(c);for(const e of l){const t=Object.getOwnPropertyDescriptor(c,e);t&&("value"in t&&(t.value=s(t.value,u)),Object.defineProperty(p,e,t))}return p}export{s as clone};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Freezable } from "../types";
|
|
2
|
+
import { clone } from "./clone";
|
|
3
|
+
/**
|
|
4
|
+
* Deep freezes a value by first cloning it, then recursively calling `Object.freeze`.
|
|
5
|
+
* Primitives are returned as-is.
|
|
6
|
+
*
|
|
7
|
+
* @param data - The value to freeze.
|
|
8
|
+
* @param cloneDeep - Custom clone function (defaults to `clone`).
|
|
9
|
+
* @returns A deeply frozen copy of the input.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* const frozen = freeze({ a: { b: 1 } });
|
|
14
|
+
* frozen.a.b = 2; // throws in strict mode
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare function freeze<DataType>(data: DataType, cloneDeep?: typeof clone): Freezable<DataType>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var e=require("./clone.js"),t=require("./object.js");function r(e){const c=Reflect.ownKeys(e);for(const n of c){const c=e[n];t.isObject(c)&&r(c)}return Object.freeze(e)}exports.freeze=function(c,n=e.clone){return t.isObject(c)?r(n(c)):c};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{clone as o}from"./clone.mjs";import{isObject as t}from"./object.mjs";function e(o){const r=Reflect.ownKeys(o);for(const n of r){const r=o[n];t(r)&&e(r)}return Object.freeze(o)}function r(r,n=o){if(!t(r))return r;return e(n(r))}export{r as freeze};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { clone } from "./clone";
|
|
2
|
+
export { freeze } from "./freeze";
|
|
3
|
+
export { isEqual } from "./is-equal";
|
|
4
|
+
export { isFunction } from "./is-function";
|
|
5
|
+
export { isLiteralObject, isComplexObject, isObject, isObjectable, hasOwnProperty } from "./object";
|
|
6
|
+
export { merge } from "./merge";
|
|
7
|
+
export { toString } from "./to-string";
|
|
8
|
+
export { ucfirst } from "./ucfirst";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var e=require("./clone.js"),r=require("./freeze.js"),s=require("./is-equal.js"),t=require("./is-function.js"),i=require("./object.js"),o=require("./merge.js"),c=require("./to-string.js"),u=require("./ucfirst.js");exports.clone=e.clone,exports.freeze=r.freeze,exports.isEqual=s.isEqual,exports.isFunction=t.isFunction,exports.hasOwnProperty=i.hasOwnProperty,exports.isComplexObject=i.isComplexObject,exports.isLiteralObject=i.isLiteralObject,exports.isObject=i.isObject,exports.isObjectable=i.isObjectable,exports.merge=o.merge,exports.toString=c.toString,exports.ucfirst=u.ucfirst;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{clone}from"./clone.mjs";export{freeze}from"./freeze.mjs";export{isEqual}from"./is-equal.mjs";export{isFunction}from"./is-function.mjs";export{hasOwnProperty,isComplexObject,isLiteralObject,isObject,isObjectable}from"./object.mjs";export{merge}from"./merge.mjs";export{toString}from"./to-string.mjs";export{ucfirst}from"./ucfirst.mjs";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Performs a deep structural equality check between two values.
|
|
3
|
+
* Supports primitives, arrays, plain objects, Date, RegExp, Map, Set,
|
|
4
|
+
* ArrayBuffer, and TypedArrays.
|
|
5
|
+
*
|
|
6
|
+
* @param value1 - The first value to compare.
|
|
7
|
+
* @param value2 - The second value to compare.
|
|
8
|
+
* @returns `true` if both values are deeply equal.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* isEqual({ a: 1 }, { a: 1 }); // true
|
|
13
|
+
* isEqual([1, 2], [1, 3]); // false
|
|
14
|
+
* isEqual(new Date(0), new Date(0)); // true
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare function isEqual(value1: unknown, value2: unknown): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var r=require("./object.js");function e(r,e){if(r.byteLength!==e.byteLength)return!1;const t=ArrayBuffer.isView(r)?r.buffer:r,i=ArrayBuffer.isView(r)?r.byteOffset:0,f=ArrayBuffer.isView(e)?e.buffer:e,n=ArrayBuffer.isView(e)?e.byteOffset:0,s=new Uint8Array(t,i,r.byteLength),u=new Uint8Array(f,n,e.byteLength);for(let r=0;r<s.length;r++)if(s[r]!==u[r])return!1;return!0}const t=new Map([[Date,(r,e)=>Object.is(r.getTime(),e.getTime())],[RegExp,(r,e)=>Object.is(r.source,e.source)&&Object.is(r.flags,e.flags)],[ArrayBuffer,e],[Map,(r,e)=>{if(r.size!==e.size)return!1;for(const[t,f]of r)if(!e.has(t)||!i(f,e.get(t)))return!1;return!0}],[Set,(r,e)=>{if(r.size!==e.size)return!1;for(const t of r){let r=!1;for(const f of e)if(i(t,f)){r=!0;break}if(!r)return!1}return!0}]]);function i(f,n){if(!r.isObject(f)||!r.isObject(n))return Object.is(f,n);if(f.constructor!==n.constructor)return!1;if(Array.isArray(f)){if(!Array.isArray(n)||f.length!==n.length)return!1;for(let r=0;r<f.length;r++)if(!i(f[r],n[r]))return!1;return!0}if(ArrayBuffer.isView(f)&&ArrayBuffer.isView(n))return e(f,n);if(f.constructor&&t.has(f.constructor))return t.get(f.constructor)(f,n);if(!r.isLiteralObject(f)||!r.isLiteralObject(n))return f===n;const s=Object.keys(f),u=Object.keys(n);if(s.length!==u.length)return!1;for(const e of s)if(!r.hasOwnProperty(n,e)||!i(f[e],n[e]))return!1;return!0}exports.isEqual=i;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{isObject as r,isLiteralObject as e,hasOwnProperty as t}from"./object.mjs";function f(r,e){if(r.byteLength!==e.byteLength)return!1;const t=ArrayBuffer.isView(r)?r.buffer:r,f=ArrayBuffer.isView(r)?r.byteOffset:0,n=ArrayBuffer.isView(e)?e.buffer:e,i=ArrayBuffer.isView(e)?e.byteOffset:0,s=new Uint8Array(t,f,r.byteLength),u=new Uint8Array(n,i,e.byteLength);for(let r=0;r<s.length;r++)if(s[r]!==u[r])return!1;return!0}const n=new Map([[Date,(r,e)=>Object.is(r.getTime(),e.getTime())],[RegExp,(r,e)=>Object.is(r.source,e.source)&&Object.is(r.flags,e.flags)],[ArrayBuffer,f],[Map,(r,e)=>{if(r.size!==e.size)return!1;for(const[t,f]of r)if(!e.has(t)||!i(f,e.get(t)))return!1;return!0}],[Set,(r,e)=>{if(r.size!==e.size)return!1;for(const t of r){let r=!1;for(const f of e)if(i(t,f)){r=!0;break}if(!r)return!1}return!0}]]);function i(s,u){if(!r(s)||!r(u))return Object.is(s,u);if(s.constructor!==u.constructor)return!1;if(Array.isArray(s)){if(!Array.isArray(u)||s.length!==u.length)return!1;for(let r=0;r<s.length;r++)if(!i(s[r],u[r]))return!1;return!0}if(ArrayBuffer.isView(s)&&ArrayBuffer.isView(u))return f(s,u);if(s.constructor&&n.has(s.constructor))return n.get(s.constructor)(s,u);if(!e(s)||!e(u))return s===u;const o=Object.keys(s),c=Object.keys(u);if(o.length!==c.length)return!1;for(const r of o)if(!t(u,r)||!i(s[r],u[r]))return!1;return!0}export{i as isEqual};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { LiteralFunction } from "@ecosy/core/types";
|
|
2
|
+
/**
|
|
3
|
+
* Checks whether a value is a function (including async and generator functions).
|
|
4
|
+
*
|
|
5
|
+
* @param value - The value to check.
|
|
6
|
+
* @returns `true` if the value is a function.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* isFunction(() => {}); // true
|
|
11
|
+
* isFunction(async () => {}); // true
|
|
12
|
+
* isFunction(42); // false
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare function isFunction(value: unknown): value is LiteralFunction;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var t=require("./to-string.js");exports.isFunction=function(n){return"function"==typeof n||["[object Function]","[object AsyncFunction]","[object GeneratorFunction]"].includes(t.toString(n))};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{toString as n}from"./to-string.mjs";function t(t){return"function"==typeof t||["[object Function]","[object AsyncFunction]","[object GeneratorFunction]"].includes(n(t))}export{t as isFunction};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { clone } from "./clone";
|
|
2
|
+
/**
|
|
3
|
+
* Deep merges `target` into `source`. If both are plain objects, properties are merged
|
|
4
|
+
* recursively. Otherwise, `target` replaces `source`. Prototype-polluting keys
|
|
5
|
+
* (`__proto__`, `constructor`, `prototype`) are rejected.
|
|
6
|
+
*
|
|
7
|
+
* @param source - The base object.
|
|
8
|
+
* @param target - The object whose values are merged into `source`.
|
|
9
|
+
* @param cloneDeep - Custom deep clone function (defaults to `clone`).
|
|
10
|
+
* @returns The merged result.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* merge({ a: 1, b: { c: 2 } }, { b: { d: 3 } });
|
|
15
|
+
* // { a: 1, b: { c: 2, d: 3 } }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function merge<AsType>(source: unknown, target: unknown, cloneDeep?: typeof clone): AsType;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var e=require("./clone.js"),t=require("./object.js");exports.merge=function r(i,c,o=e.clone){if(void 0===c)return o(i);if(t.isLiteralObject(i)&&t.isLiteralObject(c)){const e=Object.assign({},i);return Object.keys(c).forEach(i=>{if(!function(e){return"__proto__"!==e&&"constructor"!==e&&"prototype"!==e}(i))return;const n=e[i],s=c[i];t.isLiteralObject(n)&&t.isLiteralObject(s)?e[i]=r(n,s,o):e[i]=o(s)}),e}return o(c)};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{clone as r}from"./clone.mjs";import{isLiteralObject as t}from"./object.mjs";function o(n,e,c=r){if(void 0===e)return c(n);if(t(n)&&t(e)){const r=Object.assign({},n);return Object.keys(e).forEach(n=>{if(!function(r){return"__proto__"!==r&&"constructor"!==r&&"prototype"!==r}(n))return;const i=r[n],f=e[n];t(i)&&t(f)?r[n]=o(i,f,c):r[n]=c(f)}),r}return c(e)}export{o as merge};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { LiteralObject, Objectable } from "@ecosy/core/types";
|
|
2
|
+
/**
|
|
3
|
+
* Checks whether a value is a non-null object.
|
|
4
|
+
*
|
|
5
|
+
* @param value - The value to check.
|
|
6
|
+
* @returns `true` if the value is of type `object` and is not `null`.
|
|
7
|
+
*/
|
|
8
|
+
export declare function isObject(value: unknown): value is object;
|
|
9
|
+
/**
|
|
10
|
+
* Checks whether a value is a plain object (created by `{}` or `Object.create(null)`).
|
|
11
|
+
*
|
|
12
|
+
* @param value - The value to check.
|
|
13
|
+
* @returns `true` if the value is a plain literal object.
|
|
14
|
+
*/
|
|
15
|
+
export declare function isLiteralObject(value: unknown): value is LiteralObject;
|
|
16
|
+
/**
|
|
17
|
+
* Checks whether a value is a complex (non-array) object, such as a class instance.
|
|
18
|
+
*
|
|
19
|
+
* @param value - The value to check.
|
|
20
|
+
* @returns `true` if the value is a non-array object.
|
|
21
|
+
*/
|
|
22
|
+
export declare function isComplexObject<Target extends LiteralObject>(value: unknown): value is Target;
|
|
23
|
+
/**
|
|
24
|
+
* Checks whether a value is an object, array, or function.
|
|
25
|
+
*
|
|
26
|
+
* @param value - The value to check.
|
|
27
|
+
* @returns `true` if the value is "objectable" (object, array, or function).
|
|
28
|
+
*/
|
|
29
|
+
export declare function isObjectable(value: unknown): value is Objectable;
|
|
30
|
+
/**
|
|
31
|
+
* Type-safe check for own property existence on an object.
|
|
32
|
+
*
|
|
33
|
+
* @param obj - The object to check.
|
|
34
|
+
* @param key - The property key to look for.
|
|
35
|
+
* @returns `true` if the object has the specified own property.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* hasOwnProperty({ a: 1 }, "a"); // true
|
|
40
|
+
* hasOwnProperty({ a: 1 }, "b"); // false
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare function hasOwnProperty<Obj, Key extends PropertyKey, As = unknown>(obj: Obj, key: Key): obj is Obj & Record<Key, As>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var t=require("./is-function.js");function r(t){return"object"==typeof t&&null!==t}exports.hasOwnProperty=function(t,r){return Object.prototype.hasOwnProperty.call(t,r)},exports.isComplexObject=function(t){return r(t)&&!Array.isArray(t)},exports.isLiteralObject=function(t){if(!r(t)||Array.isArray(t))return!1;const e=Object.getPrototypeOf(t);return null===e||e===Object.prototype},exports.isObject=r,exports.isObjectable=function(e){return r(e)||t.isFunction(e)};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{isFunction as r}from"./is-function.mjs";function t(r){return"object"==typeof r&&null!==r}function n(r){if(!t(r)||Array.isArray(r))return!1;const n=Object.getPrototypeOf(r);return null===n||n===Object.prototype}function o(r){return t(r)&&!Array.isArray(r)}function e(n){return t(n)||r(n)}function u(r,t){return Object.prototype.hasOwnProperty.call(r,t)}export{u as hasOwnProperty,o as isComplexObject,n as isLiteralObject,t as isObject,e as isObjectable};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the internal `[[Class]]` tag of a value using `Object.prototype.toString`.
|
|
3
|
+
*
|
|
4
|
+
* @param value - The value to get the string tag for.
|
|
5
|
+
* @returns A string like `"[object Type]"`.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* toString([]); // "[object Array]"
|
|
10
|
+
* toString(null); // "[object Null]"
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export declare function toString(value: unknown): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";exports.toString=function(t){return Object.prototype.toString.call(t)};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function t(t){return Object.prototype.toString.call(t)}export{t as toString};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capitalizes the first character of a string.
|
|
3
|
+
*
|
|
4
|
+
* @param str - The string to capitalize.
|
|
5
|
+
* @returns The string with its first character in uppercase.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* ucfirst("hello"); // "Hello"
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export declare function ucfirst<T extends string>(str: T): Capitalize<T>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";exports.ucfirst=function(t){return t.charAt(0).toUpperCase()+t.slice(1)};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(e){return e.charAt(0).toUpperCase()+e.slice(1)}export{e as ucfirst};
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ecosy/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Lightweight utilities, pub/sub subscriber, and types for TypeScript applications",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"main": "./dist/index.js",
|
|
11
|
+
"module": "./dist/index.mjs",
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"import": "./dist/index.mjs",
|
|
20
|
+
"require": "./dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./types": {
|
|
23
|
+
"types": "./dist/types/index.d.ts",
|
|
24
|
+
"import": "./dist/types/index.mjs",
|
|
25
|
+
"require": "./dist/types/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./utilities": {
|
|
28
|
+
"types": "./dist/utilities/index.d.ts",
|
|
29
|
+
"import": "./dist/utilities/index.mjs",
|
|
30
|
+
"require": "./dist/utilities/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./subscriber": {
|
|
33
|
+
"types": "./dist/subscriber.d.ts",
|
|
34
|
+
"import": "./dist/subscriber.mjs",
|
|
35
|
+
"require": "./dist/subscriber.js"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"clean": "rimraf dist",
|
|
40
|
+
"build": "eslint src/ && rollup -c",
|
|
41
|
+
"prepublishOnly": "yarn clean && yarn build",
|
|
42
|
+
"dev": "rollup -c --watch",
|
|
43
|
+
"lint": "eslint src/",
|
|
44
|
+
"lint:fix": "eslint src/ --fix",
|
|
45
|
+
"format": "prettier --write src/",
|
|
46
|
+
"format:check": "prettier --check src/"
|
|
47
|
+
},
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "https://github.com/material-atomic/ecosy-core.git"
|
|
51
|
+
},
|
|
52
|
+
"keywords": [
|
|
53
|
+
"ecosy",
|
|
54
|
+
"core",
|
|
55
|
+
"subscriber",
|
|
56
|
+
"utilities"
|
|
57
|
+
],
|
|
58
|
+
"author": "material-atomic",
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@eslint/js": "^10.0.1",
|
|
61
|
+
"@rollup/plugin-terser": "^1.0.0",
|
|
62
|
+
"@rollup/plugin-typescript": "^12.3.0",
|
|
63
|
+
"@typescript-eslint/eslint-plugin": "^8.57.1",
|
|
64
|
+
"@typescript-eslint/parser": "^8.57.1",
|
|
65
|
+
"eslint": "^10.1.0",
|
|
66
|
+
"eslint-config-prettier": "^10.1.8",
|
|
67
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
68
|
+
"glob": "^13.0.6",
|
|
69
|
+
"prettier": "^3.8.1",
|
|
70
|
+
"rimraf": "^6.1.3",
|
|
71
|
+
"rollup": "^4.59.1",
|
|
72
|
+
"typescript": "^5.9.3"
|
|
73
|
+
}
|
|
74
|
+
}
|