@ixfx/process 0.43.0 → 0.56.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2021-2024 Clint Heyer
3
+ Copyright (c) 2021-2025 Clint Heyer
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -88,3 +88,30 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
88
88
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
89
89
 
90
90
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
91
+
92
+ ----
93
+
94
+ Package: Kalman.js
95
+ https://github.com/wouterbulten/kalmanjs
96
+
97
+ MIT License
98
+
99
+ Copyright (c) 2019 Wouter Bulten
100
+
101
+ Permission is hereby granted, free of charge, to any person obtaining a copy
102
+ of this software and associated documentation files (the "Software"), to deal
103
+ in the Software without restriction, including without limitation the rights
104
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
105
+ copies of the Software, and to permit persons to whom the Software is
106
+ furnished to do so, subject to the following conditions:
107
+
108
+ The above copyright notice and this permission notice shall be included in all
109
+ copies or substantial portions of the Software.
110
+
111
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
112
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
113
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
114
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
115
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
116
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
117
+ SOFTWARE.
@@ -0,0 +1,69 @@
1
+ //#region src/types.d.ts
2
+ type Process<TIn, TOut> = (value: TIn) => TOut;
3
+ type ProcessFactory<TIn, TOut> = () => Process<TIn, TOut>;
4
+ type Processors1<T1, T2> = [Process<T1, T2>];
5
+ type Processors2<T1, T2, T3> = [Process<T1, T2>, Process<T2, T3>];
6
+ type Processors3<T1, T2, T3, T4> = [Process<T1, T2>, Process<T2, T3>, Process<T3, T4>];
7
+ type Processors4<T1, T2, T3, T4, T5> = [Process<T1, T2>, Process<T2, T3>, Process<T3, T4>, Process<T4, T5>];
8
+ type Processors5<T1, T2, T3, T4, T5, T6> = [Process<T1, T2>, Process<T2, T3>, Process<T3, T4>, Process<T4, T5>, Process<T5, T6>];
9
+ type Processors<T1, T2, T3, T4, T5, T6> = Processors1<T1, T2> | Processors2<T1, T2, T3> | Processors3<T1, T2, T3, T4> | Processors4<T1, T2, T3, T4, T5> | Processors5<T1, T2, T3, T4, T5, T6>;
10
+ /**
11
+ * A rank function that compares A and B.
12
+ * Returns the highest value, 'a' or 'b'.
13
+ * Returns 'eq' if values are equal
14
+ */
15
+ type RankFunction<T> = (a: T, b: T) => `a` | `b` | `eq`;
16
+ type RankOptions = {
17
+ /**
18
+ * If set, only values with this JS type are included
19
+ */
20
+ includeType?: `string` | `number` | `object` | `boolean`;
21
+ /**
22
+ * If _true_, also emits values when they rank equal with current highest.
23
+ * _false_ by default
24
+ */
25
+ emitEqualRanked?: boolean;
26
+ /**
27
+ * If _true_, emits the current highest value even if it hasn't changed.
28
+ * This means it will match the tempo of the incoming stream.
29
+ */
30
+ emitRepeatHighest?: boolean;
31
+ };
32
+ //#endregion
33
+ //#region src/basic.d.ts
34
+ /**
35
+ * Outputs the current largest-seen value
36
+ * @returns
37
+ */
38
+ declare const max: () => Process<number | number[], number>;
39
+ /**
40
+ * Outputs the current smallest-seen value
41
+ * @returns
42
+ */
43
+ declare const min: () => Process<number | number[], number>;
44
+ /**
45
+ * Returns a sum of values
46
+ * @returns
47
+ */
48
+ declare const sum: () => Process<number | number[], number>;
49
+ /**
50
+ * Returns the current average of input values
51
+ * @returns
52
+ */
53
+ declare const average: () => Process<number | number[], number>;
54
+ /**
55
+ * Returns the tally (ie number of) values
56
+ * @param countArrayItems
57
+ * @returns
58
+ */
59
+ declare const tally: (countArrayItems: boolean) => Process<any, number>;
60
+ /**
61
+ * Returns the 'best' value seen so far as determined by a ranking function.
62
+ * This is similar to min/max but usable for objects.
63
+ * @param r
64
+ * @param options
65
+ * @returns
66
+ */
67
+ declare function rank<In>(r: RankFunction<In>, options?: Partial<RankOptions>): (value: In) => In | undefined;
68
+ //#endregion
69
+ export { sum as a, ProcessFactory as c, Processors2 as d, Processors3 as f, RankOptions as g, RankFunction as h, rank as i, Processors as l, Processors5 as m, max as n, tally as o, Processors4 as p, min as r, Process as s, average as t, Processors1 as u };
@@ -0,0 +1,2 @@
1
+ import { a as sum, i as rank, n as max, o as tally, r as min, s as Process, t as average } from "./basic-DeFYZmGk.js";
2
+ export { Process, average, max, min, rank, sum, tally };
package/dist/basic.js ADDED
@@ -0,0 +1,112 @@
1
+ //#region src/basic.ts
2
+ /**
3
+ * Outputs the current largest-seen value
4
+ * @returns
5
+ */
6
+ const max = () => {
7
+ let max$1 = Number.MIN_SAFE_INTEGER;
8
+ const compute = (value) => {
9
+ const valueArray = Array.isArray(value) ? value : [value];
10
+ for (const subValue of valueArray) {
11
+ if (typeof subValue !== `number`) break;
12
+ max$1 = Math.max(subValue, max$1);
13
+ }
14
+ return max$1;
15
+ };
16
+ return compute;
17
+ };
18
+ /**
19
+ * Outputs the current smallest-seen value
20
+ * @returns
21
+ */
22
+ const min = () => {
23
+ let min$1 = Number.MAX_SAFE_INTEGER;
24
+ const compute = (value) => {
25
+ const valueArray = Array.isArray(value) ? value : [value];
26
+ for (const subValue of valueArray) {
27
+ if (typeof subValue !== `number`) break;
28
+ min$1 = Math.min(subValue, min$1);
29
+ }
30
+ return min$1;
31
+ };
32
+ return compute;
33
+ };
34
+ /**
35
+ * Returns a sum of values
36
+ * @returns
37
+ */
38
+ const sum = () => {
39
+ let t = 0;
40
+ const compute = (value) => {
41
+ const valueArray = Array.isArray(value) ? value : [value];
42
+ for (const subValue of valueArray) {
43
+ if (typeof subValue !== `number`) continue;
44
+ t += subValue;
45
+ }
46
+ return t;
47
+ };
48
+ return compute;
49
+ };
50
+ /**
51
+ * Returns the current average of input values
52
+ * @returns
53
+ */
54
+ const average = () => {
55
+ let total = 0;
56
+ let tally$1 = 0;
57
+ const compute = (value) => {
58
+ const valueArray = Array.isArray(value) ? value : [value];
59
+ for (const subValue of valueArray) {
60
+ if (typeof subValue !== `number`) continue;
61
+ tally$1++;
62
+ total += subValue;
63
+ }
64
+ return total / tally$1;
65
+ };
66
+ return compute;
67
+ };
68
+ /**
69
+ * Returns the tally (ie number of) values
70
+ * @param countArrayItems
71
+ * @returns
72
+ */
73
+ const tally = (countArrayItems) => {
74
+ let t = 0;
75
+ const compute = (value) => {
76
+ if (countArrayItems) if (Array.isArray(value)) t += value.length;
77
+ else t++;
78
+ else t++;
79
+ return t;
80
+ };
81
+ return compute;
82
+ };
83
+ /**
84
+ * Returns the 'best' value seen so far as determined by a ranking function.
85
+ * This is similar to min/max but usable for objects.
86
+ * @param r
87
+ * @param options
88
+ * @returns
89
+ */
90
+ function rank(r, options = {}) {
91
+ const includeType = options.includeType;
92
+ const emitEqualRanked = options.emitEqualRanked ?? false;
93
+ const emitRepeatHighest = options.emitRepeatHighest ?? false;
94
+ let best;
95
+ return (value) => {
96
+ if (includeType && typeof value !== includeType) return;
97
+ if (best === void 0) {
98
+ best = value;
99
+ return best;
100
+ } else {
101
+ const result = r(value, best);
102
+ if (result == `a`) {
103
+ best = value;
104
+ return best;
105
+ } else if (result === `eq` && emitEqualRanked) return best;
106
+ else if (emitRepeatHighest) return best;
107
+ }
108
+ };
109
+ }
110
+
111
+ //#endregion
112
+ export { average, max, min, rank, sum, tally };
@@ -0,0 +1,97 @@
1
+ import { a as sum, c as ProcessFactory, d as Processors2, f as Processors3, g as RankOptions, h as RankFunction, i as rank, l as Processors, m as Processors5, n as max, o as tally, p as Processors4, r as min, s as Process, t as average, u as Processors1 } from "./basic-DeFYZmGk.js";
2
+
3
+ //#region src/cancel-error.d.ts
4
+ declare class CancelError extends Error {
5
+ constructor(message: any);
6
+ }
7
+ //#endregion
8
+ //#region src/flow.d.ts
9
+ declare function flow<T1, T2>(...processors: [Process<T1, T2>]): (value: T1) => T2;
10
+ declare function flow<T1, T2, T3>(...processors: [Process<T1, T2>, Process<T2, T3>]): (value: T1) => T3;
11
+ declare function flow<T1, T2, T3, T4>(...processors: [Process<T1, T2>, Process<T2, T3>, Process<T3, T4>]): (value: T1) => T4;
12
+ declare function flow<T1, T2, T3, T4, T5>(...processors: [Process<T1, T2>, Process<T2, T3>, Process<T3, T4>, Process<T4, T5>]): (value: T1) => T5;
13
+ declare function flow<T1, T2, T3, T4, T5, T6>(...processors: [Process<T1, T2>, Process<T2, T3>, Process<T3, T4>, Process<T4, T5>, Process<T5, T6>]): (value: T1) => T6;
14
+ //#endregion
15
+ //#region src/if-undefined.d.ts
16
+ /**
17
+ * Calls a function if the input value is not undefined.
18
+ * Return value from function is passed to next function in flow.
19
+ *
20
+ * ```js
21
+ * const flow = Process.flow(
22
+ * Process.max(),
23
+ * Process.seenLastToUndefined(),
24
+ * Process.ifNotUndefined(v => {
25
+ * console.log(`v:`, v);
26
+ * })
27
+ * );
28
+ * flow(100); // Prints 'v:100'
29
+ * flow(90); // Nothing happens max value has not changed
30
+ * flow(110); // Prints 'v:110'
31
+ * ```
32
+ * @param fn
33
+ * @returns
34
+ */
35
+ declare function ifNotUndefined<TIn, TOut>(fn: (value: Exclude<TIn, undefined>) => TOut): (value: TIn) => TIn | TOut;
36
+ /**
37
+ * Cancels the remaining flow operations if _undefined_ is an input.
38
+ * See also {@link ifUndefined} or {@link ifNotUndefined}.
39
+ *
40
+ * ```js
41
+ * const c3 = Process.flow(
42
+ * Basic.max(),
43
+ * Process.seenLastToUndefined(),
44
+ * Process.cancelIfUndefined(),
45
+ * (v => {
46
+ * console.log(v);
47
+ * })
48
+ * );
49
+ * c3(100); // Prints '100'
50
+ * c3(90); // Doesn't print anything since max does not change
51
+ * c3(110); // Prints '110'
52
+ * ```
53
+ * @returns
54
+ */
55
+ declare function cancelIfUndefined<TIn>(): (value: TIn | undefined) => TIn;
56
+ /**
57
+ * Returns the output of `fn` if the input value is _undefined_.
58
+ * See also: {@link ifNotUndefined} and {@link cancelIfUndefined}.
59
+ * @param fn
60
+ * @returns
61
+ */
62
+ declare function ifUndefined<TIn, TOut>(fn: () => TOut): (value: TIn) => TOut | (TIn & ({} | null));
63
+ //#endregion
64
+ //#region src/seen.d.ts
65
+ /**
66
+ * If a value is same as the previous value, _undefined_ is emitted instead.
67
+ *
68
+ * @param eq Equality function. If not specified, === semantics are used.
69
+ * @returns
70
+ */
71
+ declare function seenLastToUndefined<TIn>(eq?: (a: TIn, b: TIn) => boolean): Process<TIn, TIn | undefined>;
72
+ /**
73
+ * If a value is same as any previously-seen value, _undefined_ is emitted instead.
74
+ *
75
+ * It stores all previous values and compares against them for each new value.
76
+ * This would likely be not very efficient compared to {@link seenToUndefinedByKey} which uses a one-time computed
77
+ * key and efficient storage of only the keys (using a Set).
78
+ *
79
+ * @param eq Equality function. If not specified, === semantics are used.
80
+ * @returns
81
+ */
82
+ declare function seenToUndefined<TIn>(eq?: (a: TIn, b: TIn) => boolean): Process<TIn, TIn | undefined>;
83
+ /**
84
+ * If a value is the same as any previously-seen value, _undefined_ is emitted instead.
85
+ *
86
+ * This version uses a function to create a string key of the object, by default JSON.stringify.
87
+ * Thus we don't need to store all previously seen objects, just their keys.
88
+ *
89
+ * Alternatively, if a key function doesn't make sense for the value, use
90
+ * {@link seenToUndefined}, which stores the values (less efficient).
91
+ *
92
+ * @param toString
93
+ * @returns
94
+ */
95
+ declare function seenToUndefinedByKey<TIn>(toString?: (value: TIn) => string): Process<TIn, TIn | undefined>;
96
+ //#endregion
97
+ export { CancelError, Process, ProcessFactory, Processors, Processors1, Processors2, Processors3, Processors4, Processors5, RankFunction, RankOptions, average, cancelIfUndefined, flow, ifNotUndefined, ifUndefined, max, min, rank, seenLastToUndefined, seenToUndefined, seenToUndefinedByKey, sum, tally };
package/dist/index.js ADDED
@@ -0,0 +1,182 @@
1
+ import { average, max, min, rank, sum, tally } from "./basic.js";
2
+
3
+ //#region src/cancel-error.ts
4
+ var CancelError = class extends Error {
5
+ constructor(message) {
6
+ super(message);
7
+ this.name = `CancelError`;
8
+ }
9
+ };
10
+
11
+ //#endregion
12
+ //#region src/flow.ts
13
+ /**
14
+ * Creates a flow of data processors (up to 5 are supported).
15
+ * The flow is encapsulated in a function that accepts an input value an returns an output.
16
+ *
17
+ * ```js
18
+ * const p = flow(
19
+ * (value:string) => value.toUpperCase(), // Convert to uppercase
20
+ * (value:string) => value.at(0) === 'A') // If first letter is an A, return true
21
+ * );
22
+ * p('apple'); // True
23
+ * ```
24
+ *
25
+ * Each processing function is expected to take in one input value and return one value.
26
+ * @param processors
27
+ * @returns
28
+ */
29
+ function flow(...processors) {
30
+ return (value) => {
31
+ let v = value;
32
+ for (const p of processors) try {
33
+ v = p(v);
34
+ } catch (err) {
35
+ if (err instanceof CancelError) break;
36
+ else throw err;
37
+ }
38
+ return v;
39
+ };
40
+ }
41
+
42
+ //#endregion
43
+ //#region src/if-undefined.ts
44
+ /**
45
+ * Calls a function if the input value is not undefined.
46
+ * Return value from function is passed to next function in flow.
47
+ *
48
+ * ```js
49
+ * const flow = Process.flow(
50
+ * Process.max(),
51
+ * Process.seenLastToUndefined(),
52
+ * Process.ifNotUndefined(v => {
53
+ * console.log(`v:`, v);
54
+ * })
55
+ * );
56
+ * flow(100); // Prints 'v:100'
57
+ * flow(90); // Nothing happens max value has not changed
58
+ * flow(110); // Prints 'v:110'
59
+ * ```
60
+ * @param fn
61
+ * @returns
62
+ */
63
+ function ifNotUndefined(fn) {
64
+ return (value) => {
65
+ if (value === void 0) return value;
66
+ return fn(value);
67
+ };
68
+ }
69
+ /**
70
+ * Cancels the remaining flow operations if _undefined_ is an input.
71
+ * See also {@link ifUndefined} or {@link ifNotUndefined}.
72
+ *
73
+ * ```js
74
+ * const c3 = Process.flow(
75
+ * Basic.max(),
76
+ * Process.seenLastToUndefined(),
77
+ * Process.cancelIfUndefined(),
78
+ * (v => {
79
+ * console.log(v);
80
+ * })
81
+ * );
82
+ * c3(100); // Prints '100'
83
+ * c3(90); // Doesn't print anything since max does not change
84
+ * c3(110); // Prints '110'
85
+ * ```
86
+ * @returns
87
+ */
88
+ function cancelIfUndefined() {
89
+ return (value) => {
90
+ if (value === void 0) throw new CancelError(`cancel`);
91
+ return value;
92
+ };
93
+ }
94
+ /**
95
+ * Returns the output of `fn` if the input value is _undefined_.
96
+ * See also: {@link ifNotUndefined} and {@link cancelIfUndefined}.
97
+ * @param fn
98
+ * @returns
99
+ */
100
+ function ifUndefined(fn) {
101
+ return (value) => {
102
+ if (value === void 0) return fn();
103
+ else return value;
104
+ };
105
+ }
106
+
107
+ //#endregion
108
+ //#region src/util.ts
109
+ /**
110
+ * Default comparer function is equiv to checking `a === b`.
111
+ * Use {@link isEqualValueDefault} to compare by value, via comparing JSON string representation.
112
+ */
113
+ const isEqualDefault = (a, b) => a === b;
114
+ /**
115
+ * A default converter to string that uses JSON.stringify if its an object, or the thing itself if it's a string
116
+ */
117
+ const toStringDefault = (itemToMakeStringFor) => typeof itemToMakeStringFor === `string` ? itemToMakeStringFor : JSON.stringify(itemToMakeStringFor);
118
+
119
+ //#endregion
120
+ //#region src/seen.ts
121
+ /**
122
+ * If a value is same as the previous value, _undefined_ is emitted instead.
123
+ *
124
+ * @param eq Equality function. If not specified, === semantics are used.
125
+ * @returns
126
+ */
127
+ function seenLastToUndefined(eq) {
128
+ if (typeof eq === `undefined`) eq = isEqualDefault;
129
+ let lastValue;
130
+ return (value) => {
131
+ if (value !== lastValue) {
132
+ lastValue = value;
133
+ return value;
134
+ }
135
+ };
136
+ }
137
+ /**
138
+ * If a value is same as any previously-seen value, _undefined_ is emitted instead.
139
+ *
140
+ * It stores all previous values and compares against them for each new value.
141
+ * This would likely be not very efficient compared to {@link seenToUndefinedByKey} which uses a one-time computed
142
+ * key and efficient storage of only the keys (using a Set).
143
+ *
144
+ * @param eq Equality function. If not specified, === semantics are used.
145
+ * @returns
146
+ */
147
+ function seenToUndefined(eq) {
148
+ const seen = [];
149
+ if (typeof eq === `undefined`) eq = isEqualDefault;
150
+ return (value) => {
151
+ if (value === void 0) return;
152
+ for (const s of seen) if (eq(s, value)) return;
153
+ seen.push(value);
154
+ return value;
155
+ };
156
+ }
157
+ /**
158
+ * If a value is the same as any previously-seen value, _undefined_ is emitted instead.
159
+ *
160
+ * This version uses a function to create a string key of the object, by default JSON.stringify.
161
+ * Thus we don't need to store all previously seen objects, just their keys.
162
+ *
163
+ * Alternatively, if a key function doesn't make sense for the value, use
164
+ * {@link seenToUndefined}, which stores the values (less efficient).
165
+ *
166
+ * @param toString
167
+ * @returns
168
+ */
169
+ function seenToUndefinedByKey(toString) {
170
+ const seen = /* @__PURE__ */ new Set();
171
+ if (typeof toString === `undefined`) toString = toStringDefault;
172
+ return (value) => {
173
+ if (value === void 0) return;
174
+ const key = toString(value);
175
+ if (seen.has(key)) return;
176
+ seen.add(key);
177
+ return value;
178
+ };
179
+ }
180
+
181
+ //#endregion
182
+ export { CancelError, average, cancelIfUndefined, flow, ifNotUndefined, ifUndefined, max, min, rank, seenLastToUndefined, seenToUndefined, seenToUndefinedByKey, sum, tally };
package/package.json CHANGED
@@ -1,27 +1,47 @@
1
1
  {
2
2
  "name": "@ixfx/process",
3
- "version": "0.43.0",
3
+ "version": "0.56.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "files": [
8
- "dist/",
9
- "bundle/"
8
+ "dist"
10
9
  ],
11
- "dependencies": {},
10
+ "types": "./dist/index.d.ts",
12
11
  "exports": {
13
- ".": {
14
- "types": "./dist/src/index.d.ts",
15
- "import": "./dist/src/index.js"
16
- },
17
- "./basic": {
18
- "types": "./dist/src/basic.d.ts",
19
- "import": "./dist/src/basic.js"
12
+ ".": "./dist/index.js",
13
+ "./basic": "./dist/basic.js",
14
+ "./package.json": "./package.json"
15
+ },
16
+ "typesVersions": {
17
+ "*": {
18
+ "*": [
19
+ "./dist/*",
20
+ "./*"
21
+ ]
20
22
  }
21
23
  },
22
- "scripts": {
23
- "package-bundle": "tsdown",
24
- "clean": "rm -rf dist && rm -rf bundle"
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "description": "ixfx guards",
28
+ "keywords": [
29
+ "ixfx",
30
+ "interactivity",
31
+ "guards"
32
+ ],
33
+ "homepage": "https://ixfxfun.dev",
34
+ "bugs": {
35
+ "url": "https://github.com/@ixfxfun/ixfx/issues"
36
+ },
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "git+https://github.com/@ixfxfun/ixfx.git",
40
+ "directory": "packages/guards"
41
+ },
42
+ "author": "Clint Heyer <clint@thestaticvoid.net>",
43
+ "engines": {
44
+ "node": ">=20.19.0"
25
45
  },
26
- "main": "dist/src/index.js"
46
+ "scripts": {}
27
47
  }