semantic-typescript 0.6.0 → 0.7.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 CHANGED
@@ -1,214 +1,213 @@
1
- # Semantic-TypeScript: A Paradigm-Shifting Stream Processing Library
2
-
3
- ## Introduction
4
- Semantic-TypeScript represents a significant advancement in stream processing technology, synthesising the most effective concepts from JavaScript GeneratorFunctions, Java Streams, and database indexing paradigms. Its foundational design principle is centred on constructing exceptionally efficient data processing pipelines through sophisticated, lazy evaluation and intelligent indexing. The library delivers a rigorously type-safe, functionally pure streaming operation experience specifically engineered for contemporary TypeScript and JavaScript development.
5
-
6
- In contrast to conventional synchronous processing architectures, Semantic-TypeScript implements a unified model that gracefully handles both synchronous (Iterable) and asynchronous (AsyncIterable) data sources. During stream generation, the flow and termination of data are precisely controlled by callback mechanisms, enabling the library to handle with exceptional grace:
7
-
8
- - Real-time data streams (DOM events, WebSockets, intervals) with deterministic control
9
- - Large-scale datasets through memory-efficient, lazy pipelines
10
- - Complex data transformations with a fluent, declarative API
11
-
12
- The library's innovative approach fundamentally reimagines how developers interact with sequences of data, providing both unprecedented performance characteristics and developer ergonomics in a single, cohesive package.
13
-
14
- ## Core Philosophy: Separation of Definition and Execution
15
- A key architectural insight of Semantic-TypeScript is the clear separation between a stream's definition and its execution:
16
-
17
- - **Semantic<E>**: An immutable, lazy blueprint of a data transformation pipeline. It defines what operations (filter, map, etc.) will be performed
18
- - **Collectable<E>**: A materialised, executable view of the stream. It is obtained from a Semantic and provides all terminal operations (collect, forEach, etc.) to execute the pipeline and produce a result
19
-
20
- This separation enforces a clean mental model and unlocks powerful optimisations, such as choosing an UnorderedCollectable to skip unnecessary sorting for maximum speed.
21
-
22
- ## Why Choose Semantic-TypeScript?
23
- Selecting the right library for data stream processing involves balancing performance, type safety, and expressiveness. Semantic-TypeScript is engineered to excel across all these dimensions.
24
-
25
- ### 1. A Unified, Type-Safe Paradigm for All Data Sequences
26
- It provides a consistent, declarative API for processing any data sequence—be it static arrays, real-time events, or asynchronous chunks—while leveraging TypeScript's full power to ensure end-to-end type safety. This eliminates a whole class of runtime errors and transforms stream manipulation into a predictable, compiler-verified activity.
27
-
28
- ### 2. Uncompromising Performance with Intelligent Laziness
29
- At its core, the library is built on lazy evaluation. Operations like filter, map, and flatMap merely compose a processing pipeline; no work is done until a terminal operation is invoked. This is coupled with short-circuiting capabilities (via limit, anyMatch, or custom interrupt callbacks), which allows processing to stop early, dramatically improving efficiency for large or infinite streams.
30
-
31
- ### 3. The Power of the `Collector<E, A, R>` Pattern
32
- Inspired by Java, the Collector pattern is the engine of flexibility. It decouples the specification of how to accumulate stream elements from the execution of the stream itself. The library provides a rich set of built-in collectors (toArray, groupBy, summate, etc.) for everyday tasks, while making it trivial to implement your own complex, reusable reduction logic. This is far more powerful and composable than a fixed set of terminal methods.
33
-
34
- ### 4. First-Class Support for Modern Web & Async Data
35
- Semantic-TypeScript is designed for contemporary development. It offers native factory methods for modern web sources:
36
-
37
- - `useFrom(iterable)`, `useRange()` for static data
38
- - `useInterval()`, `useAnimationFrame()` for time-based streams
39
- - `useBlob()` for chunked binary data processing
40
- - `useWebSocket()`, `useDocument()`, `useWindow()` for real-time event streams
41
-
42
- ### 5. Beyond Basic Aggregation: Built-in Statistical Analysis
43
- Move beyond simple sums and averages. The library provides dedicated NumericStatistics and BigIntStatistics interfaces, offering immediate access to advanced statistical measures directly from your streams—variance, standard deviation, median, skewness, and kurtosis. This turns complex data analysis into a one-liner.
44
-
45
- ### 6. Designed for Developer Ergonomics
46
- - **Fluent, Chainable API**: Write complex data pipelines as readable, sequential chains
47
- - **Comprehensive Utility Suite**: Essential guards (isFunction, isIterable), utilities (useCompare, useTraverse), and functional interfaces included
48
- - **Optional<T> Integration**: Safely models the absence of a value, eliminating null-pointer concerns
49
- - **Performance Guidance**: Clear guidance on when to use unordered collection for speed versus ordered for sequence
50
-
51
- ## Installation
52
- ```bash
53
- npm install semantic-typescript
54
- ```
55
-
56
- ## Core Concepts in Practice
57
-
58
- ### 1. Creating Streams (Semantic)
59
- Streams can be created from various sources using factory functions.
60
-
61
- ```typescript
62
- import { useFrom, useInterval, useDocument } from 'semantic-typescript';
63
-
64
- // From a static array
65
- const staticStream = useFrom([1, 2, 3, 4, 5]);
66
-
67
- // From an asynchronous generator
68
- const asyncStream = useFrom(async function*() {
69
- yield 1;
70
- yield 2;
71
- });
72
-
73
- // A time-based stream
74
- const tickStream = useInterval(1000); // emits every second
75
-
76
- // A DOM event stream (see crucial note below)
77
- const clickStream = useDocument('click');
78
- ```
79
-
80
- ### 2. Transforming Streams (Intermediate Operations)
81
- Operations are lazily chained to define the pipeline.
82
-
83
- ```typescript
84
- const processedStream = staticStream
85
- .filter(x => x % 2 === 0) // Keep only even numbers
86
- .map(x => x * 10) // Multiply by 10
87
- .flatMap(x => [x, x + 1]) // Transform each element into two
88
- .distinct(); // Remove duplicates
89
-
90
- // Nothing has been executed yet
91
- ```
92
-
93
- ### 3. Executing Streams (Terminal Operations)
94
- To get a result, you must obtain a Collectable and invoke a terminal operation.
95
-
96
- ```typescript
97
- // Get an unordered collectable for performance
98
- const resultArray = await processedStream.toUnordered().toArray();
99
- console.log(resultArray); // e.g., [20, 21, 40, 41]
100
-
101
- // Use a built-in collector
102
- const sum = await processedStream.toUnordered().collect(useSummate());
103
- console.log(sum);
104
-
105
- // Or use the generic collect method
106
- const customResult = await processedStream.toOrdered().collect(
107
- () => new Map<number, number>(),
108
- (map, element, index) => map.set(index, element),
109
- map => map
110
- );
111
- ```
112
-
113
- ### 4. Crucial: Working with Event Streams
114
- Event streams (useDocument, useWindow, useHTMLElement, useWebSocket) are infinite by nature. You must use operations like sub, takeWhile, or limit to define when to stop collecting events and complete the stream. Otherwise, the terminal operation will wait indefinitely.
115
-
116
- ```typescript
117
- import { useDocument } from 'semantic-typescript';
118
-
119
- // Collect only the first 5 clicks
120
- const first5Clicks = await useDocument('click')
121
- .limit(5) // <- Essential: limits the stream to 5 events
122
- .toUnordered()
123
- .toArray();
124
-
125
- // Collect clicks for a 10-second window
126
- const clicksIn10s = await useDocument('click')
127
- .takeWhile((_, index, startTime = Date.now()) => Date.now() - startTime < 10000)
128
- .toUnordered()
129
- .toArray();
130
-
131
- // Collect clicks from index 2 to 5 (0-based)
132
- const specificClicks = await useDocument('click')
133
- .sub(2n, 6n) // <- Takes elements with index 2, 3, 4, 5
134
- .toUnordered()
135
- .toArray();
136
- ```
137
-
138
- **Key Insight**: The event (e.g., a MouseEvent) and its sequential firing index (as a bigint) are passed together through the pipeline via the `accept(event, index)` callback.
139
-
140
- ### 5. Leveraging Statistics
141
- ```typescript
142
- const numericStream = useFrom([10, 20, 30, 40, 50]).toNumeric();
143
-
144
- const average = await numericStream.average();
145
- const median = await numericStream.median();
146
- const standardDeviation = await numericStream.standardDeviation();
147
- const skewness = await numericStream.skewness();
148
-
149
- console.log(`Average: ${average}, Median: ${median}, StdDev: ${standardDeviation}`);
150
- ```
151
-
152
- ## Main Features
153
- - **Dual Stream Types**: Full support for both SynchronousSemantic (for Iterable) and AsynchronousSemantic (for AsyncIterable and events)
154
- - **Rich Operation Set**: filter, map, flatMap, concat, distinct, sorted, limit, skip, peek, reverse, shuffle
155
- - **Flexible Terminal Operations**: collect (with custom collectors), toArray, toSet, toMap, forEach, reduce, findFirst, anyMatch, allMatch, count
156
- - **Advanced Collectors**: Built-in collectors for joining, groupingBy, partitioningBy, summing, averaging, maxBy, minBy
157
- - **Statistical Module**: Ready-to-use methods for mean, median, mode, variance, standardDeviation, range, quantiles, skewness, kurtosis on numeric/bigint streams
158
- - **Utility Functions**: Type guards (isPromise, isAsyncIterable), comparators (useCompare), traversal (useTraverse), and conversion hooks
159
- - **Optional<T>**: A monadic container for nullable values, integrated with find operations
160
-
161
- ## API Overview
162
- ### Core Classes & Interfaces
163
- - `Semantic<E>` / `AsynchronousSemantic<E>`: The abstract stream definition
164
- - `Collectable<E>` / `AsynchronousCollectable<E>`: The executable stream with terminal operations
165
- - `OrderedCollectable<E>` / `UnorderedCollectable<E>`: Materialised versions optimised for order-sensitive or order-insensitive operations
166
- - `Collector<E, A, R>`: The abstraction for mutable reduction operations
167
-
168
- ### Factory Functions (use*)
169
- - **From Sources**: useFrom, useRange, useFill, useEmpty
170
- - **From Time**: useInterval, useAnimationFrame
171
- - **From Web APIs**: useBlob, useDocument, useWindow, useHTMLElement, useWebSocket
172
- - **Collectors**: useToArray, useGroupBy, useSummate, useJoin, etc.
173
-
174
- ## Performance Notes
175
- - **Lazy Evaluation**: Pipelines are composed without execution until a terminal operation is called
176
- - **Short-Circuiting**: Operations like limit, anyMatch, and findFirst will stop processing elements as soon as the result is determined
177
- - **Ordered vs Unordered**:
178
- - Use `.toUnordered()` for terminal operations when the order of the source elements does not matter to your result (e.g., for sum, max, or toSet). This can allow internal optimisations that skip costly sorting steps
179
- - Use `.toOrdered()` when sequence is important (e.g., for toArray where order must be preserved)
180
-
181
- ## Getting Started Example
182
- ```typescript
183
- import { useFrom, useSummate, useGroupBy } from 'semantic-typescript';
184
-
185
- interface Transaction {
186
- id: number;
187
- amount: number;
188
- category: string;
189
- }
190
-
191
- const transactions: Transaction[] = [
192
- { id: 1, amount: 100, category: 'Food' },
193
- { id: 2, amount: 200, category: 'Electronics' },
194
- { id: 3, amount: 50, category: 'Food' },
195
- { id: 4, amount: 300, category: 'Electronics' },
196
- ];
197
-
198
- // Calculate total amount per category
199
- const totalsByCategory = await useFrom(transactions)
200
- .toUnordered()
201
- .collect(
202
- useGroupBy(
203
- t => t.category,
204
- t => t.amount,
205
- useSummate() // Collector for the values
206
- )
207
- );
208
-
209
- console.log(totalsByCategory); // Map { 'Food' => 150, 'Electronics' => 500 }
210
- ```
211
-
212
- Semantic-TypeScript is built for developers who seek a rigorously designed, type-safe, and high-performance stream processing library. It brings the power of enterprise-level data transformation patterns to the TypeScript ecosystem, perfectly suited for data-intensive front-end applications, Node.js data processing, and any scenario where elegant, efficient handling of sequences is required.
213
-
214
- [![GitHub](./GitHub.png)](https://github.com/eloyhere/semantic-typescript) [![NPM](./NPM.png)](https://www.npmjs.com/package/semantic-typescript)
1
+ # **Semantic-TypeScript**
2
+ **Flow, Indexed.** Your data, under precise control.
3
+
4
+ ---
5
+
6
+ ### Overview
7
+
8
+ Semantic-TypeScript marks a significant leap forward in stream processing technology, **synthesising** the most effective concepts from JavaScript `GeneratorFunction`, Java Streams, and MySQL-style indexing. Its core philosophy is both simple and powerful: construct exceptionally efficient data-processing pipelines through intelligent indexing, not through brute-force iteration.
9
+
10
+ Where conventional libraries impose synchronous loops or unwieldy promise chains, Semantic-TypeScript delivers a **fully asynchronous**, functionally pure, and rigorously type-safe experience, designed for the demands of modern front-end development.
11
+
12
+ In its elegant model, data only reaches the consumer when the upstream pipeline explicitly invokes the `accept` (and optionally `interrupt`) callbacks. You have complete control over the timing—exactly when it is needed.
13
+
14
+ ---
15
+
16
+ ### Why Developers Prefer It
17
+
18
+ - **Zero-Boilerplate Indexing** every element carries its natural or bespoke index.
19
+ - **Pure Functional Style** — with full TypeScript inference.
20
+ - **Leak-Proof Event Streams** `useWindow`, `useDocument`, `useHTMLElement`, and `useWebSocket` are built with safety in mind. You define the boundary—using `limit(n)`, `sub(start, end)`, or `takeWhile(predicate)`—and the library manages the cleanup. No lingering listeners, no memory leaks.
21
+ - **Built-in Statistics** — comprehensive numeric and bigint analytics including averages, medians, modes, variance, skewness, and kurtosis.
22
+ - **Predictable Performance** — choose between ordered or unordered collectors based on your requirements.
23
+ - **Memory-Efficient** streams are evaluated lazily, alleviating memory concerns.
24
+ - **No Undefined Behaviour** — TypeScript guarantees type safety and nullability. Input data remains unmodified unless explicitly altered within your callback functions.
25
+
26
+ ---
27
+
28
+ ### Installation
29
+
30
+ ```bash
31
+ npm install semantic-typescript
32
+ ```
33
+ or
34
+ ```bash
35
+ yarn add semantic-typescript
36
+ ```
37
+
38
+ ---
39
+
40
+ ### Quick Start
41
+
42
+ ```typescript
43
+ import { useOf, useFrom, useRange, useWindow, useHTMLElement, useWebSocket, useText, useStringify } from "semantic-typescript";
44
+
45
+ // Numeric statistics
46
+ let summate: number = useOf(10, 20, 30, 40)
47
+ .map((n: number): number => n * 2)
48
+ .toNumericStatistics() // Required before terminal operation
49
+ .summate(); // 200
50
+
51
+ // Bigint statistics
52
+ let summate: bigint = useOf(10n, 20n, 30n, 40n)
53
+ .map((n: bigint): bigint => n * 2)
54
+ .toBigIntStatistics() // Required before terminal operation
55
+ .summate(); // 200n
56
+
57
+ // Reverse a stream by index
58
+ useFrom([1, 2, 3, 4, 5])
59
+ .redirect((element: E, index: bigint): bigint => -index) // Negative index for reversal
60
+ .toOrdered() // Call toOrdered() to preserve index order
61
+ .toArray(); // [5, 4, 3, 2, 1]
62
+
63
+ // Shuffle a stream
64
+ useFrom([1, 2, 3, 4, 5])
65
+ .shuffle()
66
+ .toOrdered()
67
+ .toArray(); // e.g., [2, 5, 1, 4, 3]
68
+
69
+ // Translate elements within a stream
70
+ useFrom([1, 2, 3, 4, 5])
71
+ .translate(2) // Shift elements right by 2 positions
72
+ .toOrdered()
73
+ .toArray(); // [4, 5, 1, 2, 3]
74
+
75
+ useFrom([1, 2, 3, 4, 5])
76
+ .translate(-2) // Shift elements left by 2 positions
77
+ .toOrdered()
78
+ .toArray(); // [3, 4, 5, 1, 2]
79
+
80
+ // Infinite range with early termination
81
+ useRange(0n, 1_000_000n)
82
+ .filter(n => n % 17n === 0n)
83
+ .limit(10n) // Stop after 10 elements
84
+ .toUnordered()
85
+ .toArray();
86
+
87
+ // Real-time window resize (stops automatically after 5 events)
88
+ useWindow("resize")
89
+ .limit(5n) // Crucial for event streams
90
+ .toUnordered()
91
+ .forEach((ev, idx) => console.log(`Resize #${idx}`));
92
+
93
+ // Listen to an HTML element
94
+ // <input id="input" type="text"/>
95
+ useHTMLElement("#input", "change")
96
+ .limit(1)
97
+ .toUnordered()
98
+ .forEach((event: Event) => submit(event));
99
+
100
+ // Listen to multiple elements and events
101
+ useHTMLElement("input", ["change", "keyup"])
102
+ .takeWhile((event: Event): boolean => validate(event))
103
+ .toUnordered()
104
+ .forEach((event: Event) => submit(event));
105
+
106
+ // Listen to a WebSocket
107
+ let webSocket = new WebSocket("ws://localhost:8080");
108
+ webSocket.addEventListener("close", (): void => {
109
+ webSocket.close(); // Manage the WebSocket lifecycle manually
110
+ });
111
+ useWebSocket(webSocket, "message")
112
+ .limit(1)
113
+ .toUnordered()
114
+ .forEach((message: MessageEvent) => console.log(message.data));
115
+
116
+ // Iterate over a string by code point
117
+ useText("My emotion now is: 😊, and semantic is 👍")
118
+ .toUnordered()
119
+ .log(); // Outputs the string
120
+
121
+ // Safely stringify an object with circular references
122
+ let o = {
123
+ a: 1,
124
+ b: "text",
125
+ c: [o.a, o.b, o.c] // Circular reference
126
+ };
127
+ // let text: string = JSON.stringify(o); // Throws an error
128
+ let text: string = useStringify(o); // Safely yields `{a: 1, b: "text", c: []}`
129
+ ```
130
+
131
+ ---
132
+
133
+ ### Core Concepts
134
+
135
+ | Concept | Purpose | When to Use |
136
+ | :--- | :--- | :--- |
137
+ | `AsynchronousSemantic` | Core builder for asynchronous streams, events, and lazy pipelines. | Real-time events, WebSockets, DOM listeners, long-running or infinite streams. |
138
+ | `SynchronousSemantic` | Builder for synchronous, in-memory, or loop-based streams. | Static data, ranges, immediate iteration. |
139
+ | `toUnordered()` | Fastest terminal collector (Map-based indexing). | Performance-critical paths (O(n) time & space, no sorting). |
140
+ | `toOrdered()` | Sorted, index-stable collector. | When stable ordering or indexed access is required. |
141
+ | `toNumericStatistics()` | Rich numeric statistical analysis (mean, median, variance, skewness, kurtosis, etc.). | Data analytics and statistical computations. |
142
+ | `toBigIntStatistics()` | Rich bigint statistical analysis. | Data analytics and statistical computations for large integers. |
143
+ | `toWindow()` | Sliding and tumbling window support. | Time-series processing, batching, and windowed operations. |
144
+
145
+ ---
146
+
147
+ **Important Usage Rules**
148
+
149
+ 1. **Event streams** (`useWindow`, `useDocument`, `useHTMLElement`, `useWebSocket`, …) return an `AsynchronousSemantic`.
150
+ → You **must** call `.limit(n)`, `.sub(start, end)`, or `.takeWhile()` to cease listening. Otherwise, the listener remains active.
151
+
152
+ 2. **Terminal operations** (`.toArray()`, `.count()`, `.average()`, `.reduce()`, `.findFirst()`, etc.) are **only available after** conversion to a collector:
153
+ ```typescript
154
+ .toUnordered() // O(n) time & space, no sorting
155
+ // or
156
+ .toOrdered() // Sorted, maintains order
157
+ ```
158
+
159
+ ---
160
+
161
+ ### Performance Characteristics
162
+
163
+ | Collector | Time Complexity | Space Complexity | Sorted? | Best For |
164
+ | :--- | :--- | :--- | :--- | :--- |
165
+ | `toUnordered()` | O(n) | O(n) | No | Raw speed, order not required. |
166
+ | `toOrdered()` | O(2n) | O(n) | Yes | Stable ordering, indexed access, analytics. |
167
+ | `toNumericStatistics()` | O(2n) | O(n) | Yes | Statistical operations requiring sorted data. |
168
+ | `toBigIntStatistics()` | O(2n) | O(n) | Yes | Statistical operations for bigint. |
169
+ | `toWindow()` | O(2n) | O(n) | Yes | Time-based windowing operations. |
170
+
171
+ Opt for `toUnordered()` when speed is paramount. Use `toOrdered()` only when you require stable ordering or statistical methods that depend on sorted data.
172
+
173
+ ---
174
+
175
+ **Comparison with Other Front-End Stream Processors**
176
+
177
+ | Feature | Semantic-TypeScript | RxJS | Native Async Iterators / Generators | Most.js |
178
+ | :--- | :--- | :--- | :--- | :--- |
179
+ | **TypeScript Integration** | First-class, deeply typed with native index awareness. | Excellent, but involves complex generics. | Good, requires manual typing. | Strong, functional-first style. |
180
+ | **Built-in Statistical Analysis** | Comprehensive native support for `number` and `bigint`. | Not available natively (requires custom operators). | None. | None. |
181
+ | **Indexing & Position Awareness** | Native, powerful bigint indexing on every element. | Requires custom operators (`scan`, `withLatestFrom`). | Manual counter required. | Basic, no built-in index. |
182
+ | **Event Stream Management** | Dedicated, type-safe factories with explicit early-stop control. | Powerful but requires manual subscription management. | Manual event listener + cancellation. | Good `fromEvent`, lightweight. |
183
+ | **Performance & Memory Efficiency** | Exceptional – optimised `toUnordered()` and `toOrdered()` collectors. | Very good, but operator chains add overhead. | Excellent (zero overhead). | Excellent. |
184
+ | **Bundle Size** | Very lightweight. | Large (even with tree-shaking). | Zero (native). | Small. |
185
+ | **API Design Philosophy** | Functional collector pattern with explicit indexing. | Reactive Observable pattern. | Iterator / Generator pattern. | Functional, point-free. |
186
+ | **Early Termination & Control** | Explicit (`interrupt`, `.limit()`, `.takeWhile()`, `.sub()`). | Good (`take`, `takeUntil`, `first`). | Manual (`break` in `for await…of`). | Good (`take`, `until`). |
187
+ | **Synchronous & Asynchronous Support** | Unified API – first-class support for both. | Primarily asynchronous. | Both, but manual. | Primarily asynchronous. |
188
+ | **Learning Curve** | Gentle for developers familiar with functional and indexed pipelines. | Steeper (many operators, hot/cold observables). | Low. | Moderate. |
189
+
190
+ **Key Advantages of Semantic-TypeScript**
191
+
192
+ * Unique built-in statistical and indexing capabilities, eliminating the need for manual `reduce` or external libraries.
193
+ * Explicit control over event streams prevents the memory leaks common in RxJS.
194
+ * A unified synchronous/asynchronous design provides a single, consistent API for diverse use cases.
195
+
196
+ This comparison illustrates why Semantic-TypeScript is particularly well-suited for modern TypeScript front-end applications that demand performance, type safety, and rich analytics without the ceremony of traditional reactive libraries.
197
+
198
+ ---
199
+
200
+ ### Ready to Explore?
201
+
202
+ Semantic-TypeScript transforms complex data flows into readable, composable, and high-performance pipelines. Whether you are handling real-time UI events, processing large datasets, or building analytics dashboards, it provides the power of database-grade indexing with the elegance of functional programming.
203
+
204
+ **Next Steps:**
205
+
206
+ * Browse the fully typed API in your IDE (all exports are from the main package).
207
+ * Join the growing community of developers who have replaced convoluted async iterators with clean Semantic pipelines.
208
+
209
+ **Semantic-TypeScript** where streams meet structure.
210
+
211
+ Begin building today and experience the difference that thoughtful indexing delivers.
212
+
213
+ **Build with clarity, proceed with confidence, and transform data with intent.**