@jarenjs/core 0.9.2
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/ARCHITECTURE.md +800 -0
- package/LICENSE +21 -0
- package/README.md +68 -0
- package/dist/types/array.d.ts +28 -0
- package/dist/types/bigint.d.ts +5 -0
- package/dist/types/dates.d.ts +79 -0
- package/dist/types/float.d.ts +32 -0
- package/dist/types/function.d.ts +22 -0
- package/dist/types/index.d.ts +119 -0
- package/dist/types/integer.d.ts +24 -0
- package/dist/types/math/float64.d.ts +121 -0
- package/dist/types/math/index.d.ts +5 -0
- package/dist/types/math/int32.d.ts +41 -0
- package/dist/types/math/vec2f64.d.ts +346 -0
- package/dist/types/math/vec2i32.d.ts +43 -0
- package/dist/types/math/vec3f64.d.ts +61 -0
- package/dist/types/number.d.ts +39 -0
- package/dist/types/object.d.ts +44 -0
- package/dist/types/scan.d.ts +64 -0
- package/dist/types/string.d.ts +65 -0
- package/dist/types/text/base64.d.ts +4 -0
- package/dist/types/text/basic.d.ts +5 -0
- package/dist/types/text/email.d.ts +3 -0
- package/dist/types/text/host.d.ts +14 -0
- package/dist/types/text/i18n.d.ts +13 -0
- package/dist/types/text/identifiers.d.ts +5 -0
- package/dist/types/text/index.d.ts +8 -0
- package/dist/types/text/iregexp.d.ts +36 -0
- package/dist/types/text/misc.d.ts +4 -0
- package/dist/types/text/punycode.d.ts +86 -0
- package/package.json +101 -0
- package/src/array.js +57 -0
- package/src/bigint.js +30 -0
- package/src/dates.js +371 -0
- package/src/float.js +107 -0
- package/src/function.js +56 -0
- package/src/index.js +223 -0
- package/src/integer.js +77 -0
- package/src/math/float64.js +316 -0
- package/src/math/index.js +5 -0
- package/src/math/int32.js +235 -0
- package/src/math/vec2f64.js +706 -0
- package/src/math/vec2i32.js +250 -0
- package/src/math/vec3f64.js +225 -0
- package/src/number.js +63 -0
- package/src/object.js +240 -0
- package/src/scan.js +96 -0
- package/src/string.js +194 -0
- package/src/text/base64.js +54 -0
- package/src/text/basic.js +23 -0
- package/src/text/email.js +61 -0
- package/src/text/host.js +335 -0
- package/src/text/i18n.js +294 -0
- package/src/text/identifiers.js +27 -0
- package/src/text/index.js +11 -0
- package/src/text/iregexp.js +308 -0
- package/src/text/misc.js +19 -0
- package/src/text/punycode.js +407 -0
package/ARCHITECTURE.md
ADDED
|
@@ -0,0 +1,800 @@
|
|
|
1
|
+
# @jarenjs/core Architecture
|
|
2
|
+
|
|
3
|
+
> **The foundational utility layer of the Jaren JSON Schema Validator ecosystem**
|
|
4
|
+
|
|
5
|
+
***IMPORTANT*** Update this doc ONLY AND WHEN you introduce architectural changes! ONLY if there are more architects like you, make sure you have a democratic vote majority on the changes you are making!
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
1. [Overview](#overview)
|
|
12
|
+
2. [Design Philosophy](#design-philosophy)
|
|
13
|
+
3. [Module Architecture](#module-architecture)
|
|
14
|
+
4. [Package Relationships](#package-relationships)
|
|
15
|
+
5. [Module Deep Dive](#module-deep-dive)
|
|
16
|
+
6. [Performance Considerations](#performance-considerations)
|
|
17
|
+
7. [Type Safety](#type-safety)
|
|
18
|
+
8. [Contributing Guidelines](#contributing-guidelines)
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Overview
|
|
23
|
+
|
|
24
|
+
`@jarenjs/core` is the foundational utility package that provides the essential building blocks for the entire Jaren ecosystem. It is designed as a **zero-dependency**, vanilla JavaScript library that offers:
|
|
25
|
+
|
|
26
|
+
- **Type checking and validation utilities** for JavaScript primitives
|
|
27
|
+
- **String manipulation and validation** for common formats
|
|
28
|
+
- **Date/Time parsing and validation** per RFC 3339 and ISO 8601
|
|
29
|
+
- **Mathematical operations** with both integer and floating-point precision
|
|
30
|
+
- **Vector mathematics** for 2D/3D computations
|
|
31
|
+
- **Deep equality and object manipulation** utilities
|
|
32
|
+
|
|
33
|
+
This package is intentionally **decoupled** from JSON Schema concepts, making it reusable for any JavaScript application requiring robust type checking and data validation.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Design Philosophy
|
|
38
|
+
|
|
39
|
+
### 1. Zero Dependencies
|
|
40
|
+
The core package has **zero external dependencies**. This ensures:
|
|
41
|
+
- Predictable bundle sizes
|
|
42
|
+
- No supply chain attack vectors
|
|
43
|
+
- Full control over performance characteristics
|
|
44
|
+
- Easy auditing and maintenance
|
|
45
|
+
|
|
46
|
+
### 2. Vanilla JavaScript with TypeScript Support
|
|
47
|
+
While implemented in vanilla JavaScript, the package generates TypeScript declarations from its JSDoc into `dist/types` during the build. This approach:
|
|
48
|
+
- Avoids transpilation overhead
|
|
49
|
+
- Provides direct control over JIT optimization hints
|
|
50
|
+
- Maintains readability without TypeScript boilerplate
|
|
51
|
+
- Leverages JSDoc for inline documentation
|
|
52
|
+
|
|
53
|
+
### 3. Functional Programming Style
|
|
54
|
+
Most utilities are pure functions that:
|
|
55
|
+
- Take explicit inputs
|
|
56
|
+
- Return predictable outputs
|
|
57
|
+
- Have no side effects
|
|
58
|
+
- Are easily testable and composable
|
|
59
|
+
|
|
60
|
+
### 4. Performance-First
|
|
61
|
+
The codebase includes explicit performance optimizations:
|
|
62
|
+
- `| 0` bitwise operations for integer coercion
|
|
63
|
+
- `+` unary operators for float64 hinting
|
|
64
|
+
- Inline fast paths for common cases (e.g., ASCII string detection)
|
|
65
|
+
- Lazy initialization of expensive objects (e.g., `Intl.Segmenter`)
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Module Architecture
|
|
70
|
+
|
|
71
|
+
```mermaid
|
|
72
|
+
flowchart TB
|
|
73
|
+
subgraph CorePackage["@jarenjs/core"]
|
|
74
|
+
direction TB
|
|
75
|
+
|
|
76
|
+
subgraph CoreModule["Core Module (index.js)"]
|
|
77
|
+
TypeChecks["Type Checks<br/>isFn, isStringType, isNumberType..."]
|
|
78
|
+
TypeGetters["Type Getters<br/>getStringType, getNumberType..."]
|
|
79
|
+
ObjectChecks["Object Checks<br/>isObjectClass, isArrayClass..."]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
subgraph ScalarModules["Scalar Type Modules"]
|
|
83
|
+
Integer["integer.js<br/>Int8/16/32/64 validation"]
|
|
84
|
+
Float["float.js<br/>Float16/32/64 validation"]
|
|
85
|
+
BigIntModule["bigint.js<br/>BigInt utilities"]
|
|
86
|
+
NumberModule["number.js<br/>Number coercion"]
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
subgraph CollectionModules["Collection Modules"]
|
|
90
|
+
ArrayModule["array.js<br/>Array/Set operations"]
|
|
91
|
+
ObjectModule["object.js<br/>Deep equality, Map/Set merge"]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
subgraph TextModules["Text Processing"]
|
|
95
|
+
TextIndex["text/index.js"]
|
|
96
|
+
Basic["basic.js<br/>Alpha, numeric, hex"]
|
|
97
|
+
Email["email.js<br/>Email validation"]
|
|
98
|
+
Host["host.js<br/>URL, IP, hostname"]
|
|
99
|
+
Identifiers["identifiers.js<br/>UUID, GUID"]
|
|
100
|
+
Base64["base64.js<br/>Base64 validation"]
|
|
101
|
+
Punycode["punycode.js<br/>IDN encoding"]
|
|
102
|
+
I18n["i18n.js<br/>Unicode category checks"]
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
subgraph DateModule["Date Processing"]
|
|
106
|
+
Dates["dates.js<br/>RFC 3339 / ISO 8601"]
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
subgraph MathModules["Mathematics"]
|
|
110
|
+
MathIndex["math/index.js"]
|
|
111
|
+
Int32Math["int32.js<br/>Fixed-point math"]
|
|
112
|
+
Float64Math["float64.js<br/>Float64 utilities"]
|
|
113
|
+
Vec2I32["vec2i32.js<br/>2D integer vectors"]
|
|
114
|
+
Vec2F64["vec2f64.js<br/>2D float vectors"]
|
|
115
|
+
Vec3F64["vec3f64.js<br/>3D float vectors"]
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
subgraph FunctionModule["Function Utilities"]
|
|
119
|
+
FunctionUtil["function.js<br/>trueThat, falseThat"]
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
subgraph StringModule["String Utilities"]
|
|
123
|
+
StringUtil["string.js<br/>RegExp, grapheme counting"]
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
CoreModule --> ScalarModules
|
|
128
|
+
CoreModule --> CollectionModules
|
|
129
|
+
CoreModule --> StringModule
|
|
130
|
+
CoreModule --> FunctionModule
|
|
131
|
+
|
|
132
|
+
TextIndex --> Basic
|
|
133
|
+
TextIndex --> Email
|
|
134
|
+
TextIndex --> Host
|
|
135
|
+
TextIndex --> Identifiers
|
|
136
|
+
TextIndex --> Base64
|
|
137
|
+
TextIndex --> Punycode
|
|
138
|
+
TextIndex --> I18n
|
|
139
|
+
|
|
140
|
+
MathIndex --> Int32Math
|
|
141
|
+
MathIndex --> Float64Math
|
|
142
|
+
MathIndex --> Vec2I32
|
|
143
|
+
MathIndex --> Vec2F64
|
|
144
|
+
MathIndex --> Vec3F64
|
|
145
|
+
|
|
146
|
+
style CorePackage fill:#e1f5fe
|
|
147
|
+
style CoreModule fill:#bbdefb
|
|
148
|
+
style TextModules fill:#c8e6c9
|
|
149
|
+
style MathModules fill:#ffccbc
|
|
150
|
+
style DateModule fill:#fff9c4
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Package Relationships
|
|
156
|
+
|
|
157
|
+
```mermaid
|
|
158
|
+
flowchart TB
|
|
159
|
+
subgraph Ecosystem["Jaren Ecosystem"]
|
|
160
|
+
direction TB
|
|
161
|
+
|
|
162
|
+
Core["@jarenjs/core<br/>(This Package)<br/>✅ Zero Dependencies"]
|
|
163
|
+
|
|
164
|
+
subgraph Dependents["Dependent Packages"]
|
|
165
|
+
Json["@jarenjs/json<br/>JSON Addressing Standards"]
|
|
166
|
+
Validate["@jarenjs/validate<br/>JSON Schema Compiler"]
|
|
167
|
+
Formats["@jarenjs/formats<br/>Format Validators"]
|
|
168
|
+
Refs["@jarenjs/refs<br/>Schema References"]
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
subgraph External["External / Higher Level"]
|
|
172
|
+
RootProject["jarenjs (root)<br/>Aggregator Package"]
|
|
173
|
+
Website["@jarenjs/website<br/>Documentation Site"]
|
|
174
|
+
UserApps["User Applications"]
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
Core --> Json
|
|
179
|
+
Core --> Validate
|
|
180
|
+
Core --> Formats
|
|
181
|
+
Core --> Refs
|
|
182
|
+
|
|
183
|
+
Validate --> RootProject
|
|
184
|
+
Formats --> RootProject
|
|
185
|
+
Refs --> RootProject
|
|
186
|
+
|
|
187
|
+
RootProject --> UserApps
|
|
188
|
+
|
|
189
|
+
Website -.-> Core
|
|
190
|
+
Website -.-> Validate
|
|
191
|
+
Website -.-> Formats
|
|
192
|
+
|
|
193
|
+
style Core fill:#81c784,stroke:#2e7d32,stroke-width:3px
|
|
194
|
+
style Dependents fill:#64b5f6
|
|
195
|
+
style External fill:#ffb74d
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Dependency Flow
|
|
199
|
+
|
|
200
|
+
| Package | Depends On | Purpose |
|
|
201
|
+
|---------|-----------|---------|
|
|
202
|
+
| `@jarenjs/core` | None | Foundational utilities |
|
|
203
|
+
| `@jarenjs/json` | `@jarenjs/core` (peer) | JSON addressing standards |
|
|
204
|
+
| `@jarenjs/validate` | `@jarenjs/core` | JSON Schema compilation |
|
|
205
|
+
| `@jarenjs/formats` | `@jarenjs/core` (peer) | Format validators |
|
|
206
|
+
| `@jarenjs/refs` | None | Schema reference data |
|
|
207
|
+
| `jarenjs` (root) | All packages | Public API aggregation |
|
|
208
|
+
|
|
209
|
+
> **Note:** For broader Jaren architecture, see the root [`ARCHITECTURE.md`](../../ARCHITECTURE.md). For development guides, see [`HOWTO.md`](../../HOWTO.md).
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Module Deep Dive
|
|
214
|
+
|
|
215
|
+
### 1. Core Type System (`index.js`)
|
|
216
|
+
|
|
217
|
+
The foundation of the package. Provides runtime type checking that goes beyond JavaScript's `typeof` operator.
|
|
218
|
+
|
|
219
|
+
```mermaid
|
|
220
|
+
flowchart LR
|
|
221
|
+
subgraph TypeCategories["Type Categories"]
|
|
222
|
+
direction TB
|
|
223
|
+
|
|
224
|
+
Scalars["Scalar Types"]
|
|
225
|
+
Scalars --> String["string"]
|
|
226
|
+
Scalars --> Number["number"]
|
|
227
|
+
Scalars --> Boolean["boolean<br/>(strict: true \| false)"]
|
|
228
|
+
Scalars --> Integer["integer<br/>(Number.isInteger)"]
|
|
229
|
+
Scalars --> BigInt["bigint"]
|
|
230
|
+
|
|
231
|
+
Objects["Object Types"]
|
|
232
|
+
Objects --> ObjectLit["Object literal<br/>(constructor === Object)"]
|
|
233
|
+
Objects --> Array["Array"]
|
|
234
|
+
Objects --> Map["Map"]
|
|
235
|
+
Objects --> Set["Set"]
|
|
236
|
+
Objects --> TypedArray["TypedArray<br/>(Uint8Array, etc.)"]
|
|
237
|
+
|
|
238
|
+
Functions["Function Types"]
|
|
239
|
+
Functions --> Fn["Function<br/>(typeof === 'function')"]
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
subgraph Operations["Operations"]
|
|
243
|
+
Is["isXxxType()<br/>Boolean check"]
|
|
244
|
+
Get["getXxxType()<br/>Extract with default"]
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
TypeCategories --> Operations
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**Key Functions:**
|
|
251
|
+
|
|
252
|
+
| Function | Purpose | Example |
|
|
253
|
+
|----------|---------|---------|
|
|
254
|
+
| `isFn(data)` | Check if function | `isFn(() => {}) // true` |
|
|
255
|
+
| `isStringType(data)` | Strict string check | `isStringType('') // true` |
|
|
256
|
+
| `isBooleanType(data)` | Strict boolean check | `isBooleanType(true) // true` (excludes truthy values) |
|
|
257
|
+
| `isNumberType(data)` | Number check (includes NaN) | `isNumberType(42) // true` |
|
|
258
|
+
| `isIntegerType(data)` | Integer check | `isIntegerType(42.0) // true` |
|
|
259
|
+
| `isObjectClass(data)` | Plain object check | `isObjectClass({}) // true` |
|
|
260
|
+
| `isArrayClass(data)` | Array check | `isArrayClass([]) // true` |
|
|
261
|
+
|
|
262
|
+
**Design Pattern: Getter with Default**
|
|
263
|
+
|
|
264
|
+
```javascript
|
|
265
|
+
// Instead of:
|
|
266
|
+
const value = isStringType(data) ? data : undefined;
|
|
267
|
+
|
|
268
|
+
// Use:
|
|
269
|
+
const value = getStringType(data); // undefined if not string
|
|
270
|
+
const value = getStringType(data, 'default'); // 'default' if not string
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### 2. Integer Module (`integer.js`)
|
|
274
|
+
|
|
275
|
+
Provides constants and validation for fixed-width integers.
|
|
276
|
+
|
|
277
|
+
```mermaid
|
|
278
|
+
flowchart TB
|
|
279
|
+
subgraph IntegerTypes["Integer Types"]
|
|
280
|
+
Int8["Int8<br/>-128 to 127"]
|
|
281
|
+
UInt8["UInt8<br/>0 to 255"]
|
|
282
|
+
Int16["Int16<br/>-32768 to 32767"]
|
|
283
|
+
UInt16["UInt16<br/>0 to 65535"]
|
|
284
|
+
Int32["Int32<br/>-(2^31) to 2^31-1"]
|
|
285
|
+
UInt32["UInt32<br/>0 to 2^32-1"]
|
|
286
|
+
Int64["Int64<br/>MIN_SAFE_INTEGER to MAX_SAFE_INTEGER"]
|
|
287
|
+
UInt64["UInt64<br/>0 to MAX_SAFE_INTEGER"]
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
subgraph Validation["Validation Pattern"]
|
|
291
|
+
Check1["1. isIntegerType(value)"]
|
|
292
|
+
Check2["2. value >= MIN"]
|
|
293
|
+
Check3["3. value <= MAX"]
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
IntegerTypes --> Validation
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**Usage Example:**
|
|
300
|
+
|
|
301
|
+
```javascript
|
|
302
|
+
import { isValidInt32, INT32_MIN, INT32_MAX } from '@jarenjs/core/integer';
|
|
303
|
+
|
|
304
|
+
// Validate int32 range
|
|
305
|
+
if (isValidInt32(someValue)) {
|
|
306
|
+
// Safe to use as int32
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Used by @jarenjs/formats for format validators
|
|
310
|
+
// e.g., format: 'int32' in JSON Schema
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### 3. Float Module (`float.js`)
|
|
314
|
+
|
|
315
|
+
IEEE 754 floating-point validation with explicit width support.
|
|
316
|
+
|
|
317
|
+
```mermaid
|
|
318
|
+
flowchart LR
|
|
319
|
+
subgraph FloatTypes["Float Types"]
|
|
320
|
+
F16["Float16<br/>5 exp + 10 frac bits"]
|
|
321
|
+
F32["Float32<br/>8 exp + 23 frac bits"]
|
|
322
|
+
F64["Float64<br/>11 exp + 52 frac bits"]
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
subgraph Constants["Per-Type Constants"]
|
|
326
|
+
MAX["MAX<br/>Maximum representable"]
|
|
327
|
+
MIN["MIN<br/>Minimum normal"]
|
|
328
|
+
EPS["EPS<br/>Machine epsilon"]
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
subgraph Operations["Operations"]
|
|
332
|
+
Validate["isValidFloatXX()"]
|
|
333
|
+
Get["getValidFloatXX()"]
|
|
334
|
+
Inc["FloatXX_increment()"]
|
|
335
|
+
Dec["FloatXX_decrement()"]
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
FloatTypes --> Constants --> Operations
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**Special Features:**
|
|
342
|
+
- Increment/decrement functions that respect float precision boundaries
|
|
343
|
+
- Proper handling of infinity at range boundaries
|
|
344
|
+
- Used for JSON Schema `format: 'float32'`, `format: 'float64'`
|
|
345
|
+
|
|
346
|
+
### 4. String Module (`string.js`)
|
|
347
|
+
|
|
348
|
+
String utilities with Unicode awareness.
|
|
349
|
+
|
|
350
|
+
```mermaid
|
|
351
|
+
flowchart TB
|
|
352
|
+
subgraph StringUtils["String Utilities"]
|
|
353
|
+
Basic["Basic Checks"]
|
|
354
|
+
Basic --> Empty["isStringEmpty()"]
|
|
355
|
+
Basic --> WhiteSpace["isStringWhiteSpace()"]
|
|
356
|
+
Basic --> Case["isStringUpperCase()<br/>isStringLowerCase()"]
|
|
357
|
+
|
|
358
|
+
RegExpUtils["RegExp Utilities"]
|
|
359
|
+
RegExpUtils --> IsRegExp["isRegExpType()"]
|
|
360
|
+
RegExpUtils --> IsStringRegExp["isStringRegExp()<br/>(tests if valid pattern)"]
|
|
361
|
+
RegExpUtils --> CreateRegExp["createRegExp()<br/>(handles /pattern/flags syntax)"]
|
|
362
|
+
|
|
363
|
+
Unicode["Unicode Support"]
|
|
364
|
+
Unicode --> Ascii["isAsciiString()"]
|
|
365
|
+
Unicode --> Graphemes["getStringLength()<br/>with grapheme counting"]
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
subgraph IntlSegmenter["Intl.Segmenter Caching"]
|
|
369
|
+
Cache["Lazy-initialized<br/>segmenterCache"]
|
|
370
|
+
FastPath["Fast path for ASCII<br/>(charCodeAt > 127 check)"]
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
StringUtils --> Unicode --> IntlSegmenter
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
**Grapheme Cluster Support:**
|
|
377
|
+
|
|
378
|
+
```javascript
|
|
379
|
+
import { getStringLength } from '@jarenjs/core/string';
|
|
380
|
+
|
|
381
|
+
// Emoji "👨👩👧👦" is 1 grapheme but 11 UTF-16 code units
|
|
382
|
+
getStringLength("👨👩👧👦", false); // 11 (code units)
|
|
383
|
+
getStringLength("👨👩👧👦", true); // 1 (grapheme cluster)
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### 5. Date Module (`dates.js`)
|
|
387
|
+
|
|
388
|
+
RFC 3339 and ISO 8601 compliant date/time parsing.
|
|
389
|
+
|
|
390
|
+
```mermaid
|
|
391
|
+
flowchart TB
|
|
392
|
+
subgraph DateFormats["Supported Formats"]
|
|
393
|
+
RFC3339["RFC 3339<br/>(strict - timezone required)"]
|
|
394
|
+
ISO8601["ISO 8601<br/>(optional timezone)"]
|
|
395
|
+
Duration["Duration<br/>P1Y2M3DT4H5M6S"]
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
subgraph RFC3339Types["RFC 3339 Types"]
|
|
399
|
+
RDate["full-date<br/>YYYY-MM-DD"]
|
|
400
|
+
RTime["full-time<br/>HH:MM:SS±HH:MM"]
|
|
401
|
+
RDateTime["date-time<br/>full-date T full-time"]
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
subgraph ISO8601Types["ISO 8601 Types"]
|
|
405
|
+
IDateTime["iso-date-time"]
|
|
406
|
+
ITime["iso-time"]
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
subgraph ValidationFeatures["Validation Features"]
|
|
410
|
+
LeapYear["Leap year handling"]
|
|
411
|
+
LeapSecond["Leap second support<br/>(23:59:60 UTC)"]
|
|
412
|
+
Timezone["Timezone offset validation"]
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
DateFormats --> RFC3339Types
|
|
416
|
+
DateFormats --> ISO8601Types
|
|
417
|
+
RFC3339Types --> ValidationFeatures
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**Constants Provided:**
|
|
421
|
+
|
|
422
|
+
```javascript
|
|
423
|
+
import {
|
|
424
|
+
CONST_TICKS_SECOND, // 1000
|
|
425
|
+
CONST_TICKS_HOUR, // 3600000
|
|
426
|
+
CONST_TICKS_DAY, // 86400000
|
|
427
|
+
CONST_RFC3339_DAYS, // Days per month array
|
|
428
|
+
CONST_RFC3339_REGEX_ISDATE, // Date regex
|
|
429
|
+
CONST_RFC3339_REGEX_ISTIME, // Time regex
|
|
430
|
+
} from '@jarenjs/core/dates';
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### 6. Text Module (`text/`)
|
|
434
|
+
|
|
435
|
+
Comprehensive string format validation organized by domain.
|
|
436
|
+
|
|
437
|
+
```mermaid
|
|
438
|
+
flowchart TB
|
|
439
|
+
subgraph TextModule["text/ Module Structure"]
|
|
440
|
+
direction TB
|
|
441
|
+
|
|
442
|
+
subgraph Basic["basic.js"]
|
|
443
|
+
Alpha["isValidAlpha()<br/>[a-zA-Z]+"]
|
|
444
|
+
Numeric["isValidNumeric()<br/>[0-9]+"]
|
|
445
|
+
AlphaNum["isValidAlphaNumeric()"]
|
|
446
|
+
Hex["isValidHexaDecimal()"]
|
|
447
|
+
Color["isValidHexColor()<br/>#RGB or #RRGGBB"]
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
subgraph Identifiers["identifiers.js"]
|
|
451
|
+
UUID["isValidUUID()<br/>RFC 4122"]
|
|
452
|
+
GUID["isValidGUID()<br/>Microsoft format"]
|
|
453
|
+
CIdent["isValidIdentifier()<br/>C-style identifiers"]
|
|
454
|
+
HTML["isValidHtmlIdentifier()<br/>HTML id attr"]
|
|
455
|
+
CSS["isValidCssIdentifier()<br/>CSS class names"]
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
subgraph EmailModule["email.js"]
|
|
459
|
+
Email["isValidEmail()<br/>Basic RFC 5322"]
|
|
460
|
+
EmailFull["isValidEmailFull()<br/>Comprehensive"]
|
|
461
|
+
IDNEmail["isValidIdnEmail()<br/>Internationalized"]
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
subgraph HostModule["host.js"]
|
|
465
|
+
URL["isValidUrl() / isValidUrlFull()"]
|
|
466
|
+
URI["isValidUri() / isValidUriFull()"]
|
|
467
|
+
IPv4["isValidIPv4()"]
|
|
468
|
+
IPv6["isValidIPv6()"]
|
|
469
|
+
Hostname["isValidHostname()<br/>RFC 1034"]
|
|
470
|
+
IDNHost["isValidIdnHostname()<br/>Internationalized"]
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
subgraph Base64Module["base64.js"]
|
|
474
|
+
B64["isValidBase64()<br/>Multiple implementations"]
|
|
475
|
+
B64Fast["isValidBase64Fast()<br/>Optimized"]
|
|
476
|
+
B64Full["isValidBase64Full()<br/>Strict padding"]
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
subgraph PunycodeModule["punycode.js"]
|
|
480
|
+
ToASCII["toASCII()<br/>Unicode → Punycode"]
|
|
481
|
+
ToUnicode["toUnicode()<br/>Punycode → Unicode"]
|
|
482
|
+
Encode["encode()<br/>Raw encoding"]
|
|
483
|
+
Decode["decode()<br/>Raw decoding"]
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
subgraph I18nModule["i18n.js"]
|
|
487
|
+
UnicodeCats["Unicode category checks"]
|
|
488
|
+
Latin["isLatinLowercaseL()"]
|
|
489
|
+
Greek["isGreek()"]
|
|
490
|
+
Hebrew["isHebrew()"]
|
|
491
|
+
Arabic["isArabicIndicDigit()"]
|
|
492
|
+
CJK["isHiragana() / isKatakana() / isHan()"]
|
|
493
|
+
Contextual["checkContextualRules()<br/>IDN label rules"]
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
subgraph Misc["misc.js"]
|
|
497
|
+
ISBN["ISBN-10 / ISBN-13 validation"]
|
|
498
|
+
Country["isValidCountryAlpha2()<br/>ISO 3166-1"]
|
|
499
|
+
IBAN["isValidIBAN()"]
|
|
500
|
+
end
|
|
501
|
+
end
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
**Usage Pattern:**
|
|
505
|
+
|
|
506
|
+
```javascript
|
|
507
|
+
// Import specific validators
|
|
508
|
+
import { isValidUUID, isValidEmail } from '@jarenjs/core/text';
|
|
509
|
+
|
|
510
|
+
// Or import entire categories
|
|
511
|
+
import * as identifiers from '@jarenjs/core/text/identifiers';
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
### 7. Math Module (`math/`)
|
|
515
|
+
|
|
516
|
+
High-performance mathematical operations with explicit type annotations for JIT optimization.
|
|
517
|
+
|
|
518
|
+
```mermaid
|
|
519
|
+
flowchart TB
|
|
520
|
+
subgraph MathModule["math/ Module"]
|
|
521
|
+
direction TB
|
|
522
|
+
|
|
523
|
+
subgraph Int32["int32.js - Int32 Class"]
|
|
524
|
+
FixedPoint["Fixed-point arithmetic<br/>Multiplier: 10000"]
|
|
525
|
+
Trig["Trigonometry<br/>sinLp, cosLp (linear approx)"]
|
|
526
|
+
Collision["Collision detection<br/>intersectsRect, intersectsRange"]
|
|
527
|
+
VectorOps["Vector operations<br/>dot, cross, mag, mag2"]
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
subgraph Float64["float64.js - Float64 Class"]
|
|
531
|
+
Standard["Standard math<br/>sqrt, pow, sin, cos"]
|
|
532
|
+
GCD["GCD calculation"]
|
|
533
|
+
InverseSqrt["Fast inverse square root<br/>(Quake III algorithm)"]
|
|
534
|
+
Interpolation["Interpolation<br/>lerp, norm, map"]
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
subgraph Vec2I32["vec2i32.js"]
|
|
538
|
+
V2I32Pure["Pure operators<br/>add, sub, mul, div"]
|
|
539
|
+
V2I32Impure["Impure operators<br/>iadd, isub, imul, idiv"]
|
|
540
|
+
V2I32Product["Product operators<br/>dot, mag, mag2"]
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
subgraph Vec2F64["vec2f64.js"]
|
|
544
|
+
V2F64Ops["2D Vector operations"]
|
|
545
|
+
V2F64Geom["Geometric operations<br/>rotate, about, lerp"]
|
|
546
|
+
V2F64Unit["Unit operations<br/>unit, theta, phi"]
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
subgraph Vec3F64["vec3f64.js"]
|
|
550
|
+
V3F64Ops["3D Vector operations"]
|
|
551
|
+
V3F64Cross["Cross product"]
|
|
552
|
+
end
|
|
553
|
+
end
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
**Optimization Technique: ASM.js-style Type Annotations**
|
|
557
|
+
|
|
558
|
+
```javascript
|
|
559
|
+
// The + prefix hints to JIT that this is float64
|
|
560
|
+
// The | 0 suffix hints to JIT that this is int32
|
|
561
|
+
|
|
562
|
+
// From int32.js
|
|
563
|
+
static clamp(value = 0, min = 0, max = 0) {
|
|
564
|
+
value = value | 0; // Force int32
|
|
565
|
+
min = min | 0;
|
|
566
|
+
max = max | 0;
|
|
567
|
+
return (
|
|
568
|
+
mathi32_min(
|
|
569
|
+
mathi32_max(value, mathi32_min(min, max)),
|
|
570
|
+
mathi32_max(min, max),
|
|
571
|
+
) | 0 // Return int32
|
|
572
|
+
);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// From float64.js
|
|
576
|
+
static clamp(value = 0.0, min = 0.0, max = 0.0) {
|
|
577
|
+
return +mathf64_min(+mathf64_max(+value, +mathf64_min(+min, +max)), +mathf64_max(+min, +max));
|
|
578
|
+
}
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
**Pure vs Impure Operators:**
|
|
582
|
+
|
|
583
|
+
| Type | Pattern | Returns | Use Case |
|
|
584
|
+
|------|---------|---------|----------|
|
|
585
|
+
| Pure | `Vec2f64.add(a, b)` | New Vec2f64 | Functional style, no side effects |
|
|
586
|
+
| Impure | `a.iadd(b)` | Modified `this` | Performance-critical loops |
|
|
587
|
+
|
|
588
|
+
### 8. JSON Module — moved to `@jarenjs/json`
|
|
589
|
+
|
|
590
|
+
The JSON addressing standards (JSON validation helpers, JSON Pointer per RFC 6901 and the compiling JSONPath engine per RFC 9535) now live in the [`@jarenjs/json`](../json) package; see its README for the module deep dive.
|
|
591
|
+
|
|
592
|
+
### 9. Object Module (`object.js`)
|
|
593
|
+
|
|
594
|
+
Deep equality and collection manipulation.
|
|
595
|
+
|
|
596
|
+
```mermaid
|
|
597
|
+
flowchart TB
|
|
598
|
+
subgraph ObjectModule["object.js"]
|
|
599
|
+
EqualsDeep["equalsDeep(target, source)<br/>Recursive equality check"]
|
|
600
|
+
|
|
601
|
+
subgraph SupportedTypes["Supports"]
|
|
602
|
+
Objects["Plain objects"]
|
|
603
|
+
Arrays["Arrays"]
|
|
604
|
+
Maps["Maps"]
|
|
605
|
+
Sets["Sets"]
|
|
606
|
+
TypedArrays["TypedArrays"]
|
|
607
|
+
RegExp["RegExp"]
|
|
608
|
+
Functions["Functions (toString comparison)"]
|
|
609
|
+
end
|
|
610
|
+
|
|
611
|
+
MergeMap["mergeMap()<br/>Combine multiple Maps"]
|
|
612
|
+
MergeSet["mergeSet()<br/>Combine multiple Sets"]
|
|
613
|
+
end
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
### 10. Array Module (`array.js`)
|
|
617
|
+
|
|
618
|
+
Array and array-like utilities.
|
|
619
|
+
|
|
620
|
+
```mermaid
|
|
621
|
+
flowchart TB
|
|
622
|
+
subgraph ArrayModule["array.js"]
|
|
623
|
+
IsArrayish["isArrayish()<br/>Array, Set, or TypedArray"]
|
|
624
|
+
UniqueArray["getUniqueArray()<br/>Deduplicate with Set fallback"]
|
|
625
|
+
IsUnique["isUniqueArray()<br/>Check if all elements unique"]
|
|
626
|
+
IncludesAll["includesAll()<br/>Array subset check"]
|
|
627
|
+
end
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
### 11. Function Module (`function.js`)
|
|
631
|
+
|
|
632
|
+
Utility functions for validator composition.
|
|
633
|
+
|
|
634
|
+
```mermaid
|
|
635
|
+
flowchart TB
|
|
636
|
+
subgraph FunctionModule["function.js"]
|
|
637
|
+
TrueThat["trueThat()<br/>Always returns true"]
|
|
638
|
+
FalseThat["falseThat()<br/>Always returns false"]
|
|
639
|
+
Fallback["fallbackFn()<br/>Use compiled or fallback"]
|
|
640
|
+
AddToArray["addFunctionToArray()<br/>Batch function collection"]
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
subgraph Usage["Validator Pattern"]
|
|
644
|
+
Schema["Schema compilation"]
|
|
645
|
+
Schema --> Compiled["Compiled validator function"]
|
|
646
|
+
Compiled -->|null/undefined| Fallback
|
|
647
|
+
Fallback --> TrueThat
|
|
648
|
+
end
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
---
|
|
652
|
+
|
|
653
|
+
## Performance Considerations
|
|
654
|
+
|
|
655
|
+
### 1. JIT Optimization Hints
|
|
656
|
+
|
|
657
|
+
The codebase uses ASM.js-inspired type annotations to help JavaScript engines optimize hot paths:
|
|
658
|
+
|
|
659
|
+
```javascript
|
|
660
|
+
// int32 hint: | 0
|
|
661
|
+
const int32Value = (someNumber + 1) | 0;
|
|
662
|
+
|
|
663
|
+
// float64 hint: + prefix
|
|
664
|
+
const float64Value = +someNumber;
|
|
665
|
+
|
|
666
|
+
// Combined
|
|
667
|
+
const result = +((+a * +b) + (+c * +d));
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
### 2. Lazy Initialization
|
|
671
|
+
|
|
672
|
+
Expensive objects are created only when needed:
|
|
673
|
+
|
|
674
|
+
```javascript
|
|
675
|
+
let segmenterCache = null;
|
|
676
|
+
export function getSegmenter() {
|
|
677
|
+
if (segmenterCache === null) {
|
|
678
|
+
segmenterCache = new Intl.Segmenter(undefined, { granularity: "grapheme" });
|
|
679
|
+
}
|
|
680
|
+
return segmenterCache;
|
|
681
|
+
}
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
### 3. Fast Paths
|
|
685
|
+
|
|
686
|
+
Common cases are handled inline before falling back to slower algorithms:
|
|
687
|
+
|
|
688
|
+
```javascript
|
|
689
|
+
export function getStringLength(str, useGrapheme = false) {
|
|
690
|
+
if (!useGrapheme) {
|
|
691
|
+
return str.length; // Fast path: ASCII length
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
// Check if ASCII inline to avoid function call overhead
|
|
695
|
+
const len = str.length;
|
|
696
|
+
for (let i = 0; i < len; i++) {
|
|
697
|
+
if (str.charCodeAt(i) > 127) {
|
|
698
|
+
// Non-ASCII found - use grapheme counting
|
|
699
|
+
// ...
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
return len; // Was ASCII after all
|
|
703
|
+
}
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
### 4. Regex Caching
|
|
707
|
+
|
|
708
|
+
Constant regex patterns are defined at module load time:
|
|
709
|
+
|
|
710
|
+
```javascript
|
|
711
|
+
const CONST_REGEXP_UUID = /^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i;
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
---
|
|
715
|
+
|
|
716
|
+
## Type Safety
|
|
717
|
+
|
|
718
|
+
### TypeScript Definitions
|
|
719
|
+
|
|
720
|
+
The build generates declarations for the root entry point and every exported subpath:
|
|
721
|
+
|
|
722
|
+
```typescript
|
|
723
|
+
// Type guards
|
|
724
|
+
export function isStringType(data: unknown): data is string;
|
|
725
|
+
export function isValidInt8(value: number): boolean;
|
|
726
|
+
|
|
727
|
+
// Vector classes with full type support
|
|
728
|
+
export class Vec2F64 {
|
|
729
|
+
constructor(x?: number, y?: number);
|
|
730
|
+
get x(): number;
|
|
731
|
+
set x(value: number);
|
|
732
|
+
add(other: Vec2F64): Vec2F64;
|
|
733
|
+
iadd(other: Vec2F64): Vec2F64; // impure
|
|
734
|
+
}
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
### JSDoc Annotations
|
|
738
|
+
|
|
739
|
+
All functions include JSDoc for IDE support:
|
|
740
|
+
|
|
741
|
+
```javascript
|
|
742
|
+
/**
|
|
743
|
+
* Checks if the given data is of number type.
|
|
744
|
+
* @param {any} data - The data to check.
|
|
745
|
+
* @returns {boolean} - True if the data is a number, otherwise false.
|
|
746
|
+
*/
|
|
747
|
+
export function isNumberType(data) {
|
|
748
|
+
return data != null && typeof data === 'number';
|
|
749
|
+
}
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
---
|
|
753
|
+
|
|
754
|
+
## Contributing Guidelines
|
|
755
|
+
|
|
756
|
+
### Adding New Type Checkers
|
|
757
|
+
|
|
758
|
+
1. Add the `isXxxType()` function to `index.js`
|
|
759
|
+
2. Add the corresponding `getXxxType()` function
|
|
760
|
+
3. Add accurate JSDoc so the generated declaration contains the proper type guard
|
|
761
|
+
4. Add tests in `test/core/`
|
|
762
|
+
|
|
763
|
+
### Adding New Format Validators
|
|
764
|
+
|
|
765
|
+
1. Identify the appropriate text submodule (or create one)
|
|
766
|
+
2. Define the regex/pattern as a `CONST_` at module level
|
|
767
|
+
3. Export the `isValidXxx()` function
|
|
768
|
+
4. Update `text/index.js` exports
|
|
769
|
+
5. Add accurate JSDoc and run `npm run build:types --workspace=@jarenjs/core`
|
|
770
|
+
|
|
771
|
+
### Adding Math Operations
|
|
772
|
+
|
|
773
|
+
1. For scalar: Add to `int32.js` or `float64.js`
|
|
774
|
+
2. For vector: Add pure static method, then impure instance method
|
|
775
|
+
3. Use explicit type annotations (`| 0` for int32, `+` for float64)
|
|
776
|
+
4. Document mathematical formula/references in comments
|
|
777
|
+
|
|
778
|
+
### Code Style
|
|
779
|
+
|
|
780
|
+
- Use `@ts-check` at the top of every file
|
|
781
|
+
- Prefer `===` and `!==` over `==` and `!=`
|
|
782
|
+
- Use early returns to reduce nesting
|
|
783
|
+
- Cache regex patterns at module level
|
|
784
|
+
- Use `// eslint-disable-next-line` sparingly with justification
|
|
785
|
+
|
|
786
|
+
---
|
|
787
|
+
|
|
788
|
+
## Summary
|
|
789
|
+
|
|
790
|
+
`@jarenjs/core` is the **bedrock** of the Jaren ecosystem. It provides:
|
|
791
|
+
|
|
792
|
+
1. **Reliable type checking** that goes beyond JavaScript's built-in operators
|
|
793
|
+
2. **Format validation** for common string patterns (emails, URLs, UUIDs, etc.)
|
|
794
|
+
3. **Date/Time parsing** compliant with RFC 3339 and ISO 8601
|
|
795
|
+
4. **High-performance math** with explicit type annotations
|
|
796
|
+
5. **Zero dependencies** for maximum reliability
|
|
797
|
+
|
|
798
|
+
When contributing, remember: this package is used by `@jarenjs/validate` and `@jarenjs/formats`. Changes here have downstream effects. Maintain backward compatibility, optimize for performance, and keep the API predictable.
|
|
799
|
+
|
|
800
|
+
For questions about the broader architecture, see the root [`ARCHITECTURE.md`](../../ARCHITECTURE.md). For development workflows, see [`HOWTO.md`](../../HOWTO.md).
|