@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/src/dates.js
ADDED
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
//@ts-check
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
isStringType,
|
|
5
|
+
isObjectOfClass,
|
|
6
|
+
} from './index.js';
|
|
7
|
+
|
|
8
|
+
//#region Dates Constants
|
|
9
|
+
export const CONST_TICKS_SECOND = 1000;
|
|
10
|
+
export const CONST_TICKS_HOUR = CONST_TICKS_SECOND * 60 * 60;
|
|
11
|
+
export const CONST_TICKS_DAY = CONST_TICKS_HOUR * 24;
|
|
12
|
+
|
|
13
|
+
export const CONST_TIME_INSERTDATE = '1970-01-01T';
|
|
14
|
+
export const CONST_DATE_APPENDTIME = 'T00:00:00Z';
|
|
15
|
+
|
|
16
|
+
export const CONST_RFC3339_DAYS = Object.freeze(
|
|
17
|
+
[0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
// full-date from http://tools.ietf.org/html/rfc3339#section-5.6
|
|
21
|
+
export const CONST_RFC3339_REGEX_ISDATE = /^(\d\d\d\d)-([0-1]\d)-([0-3]\d)z?$/i;
|
|
22
|
+
|
|
23
|
+
// full-date from http://tools.ietf.org/html/rfc3339#section-5.6
|
|
24
|
+
export const CONST_RFC3339_REGEX_ISTIME = /^(\d\d):(\d\d):(\d\d)(\.\d{1,6})?(z|(([+-])(\d\d):(\d\d)))$/i;
|
|
25
|
+
|
|
26
|
+
//#endregion
|
|
27
|
+
|
|
28
|
+
//#region Dates Compare
|
|
29
|
+
export function isDateType(data) {
|
|
30
|
+
return isObjectOfClass(data, Date);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function isDateishType(data) {
|
|
34
|
+
return isDateType(data)
|
|
35
|
+
|| !Number.isNaN(Date.parse(data));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function isLeapYear(year) {
|
|
39
|
+
// https://tools.ietf.org/html/rfc3339#appendix-C
|
|
40
|
+
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function isDateOnlyInRange(year = 0, month = 0, day = 0) {
|
|
44
|
+
return month >= 1
|
|
45
|
+
&& month <= 12
|
|
46
|
+
&& day >= 1
|
|
47
|
+
&& day <= (month === 2 && isLeapYear(year)
|
|
48
|
+
? 29
|
|
49
|
+
: CONST_RFC3339_DAYS[month]);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function isDateOnlyRFC3339(str) {
|
|
53
|
+
if (!isStringType(str))
|
|
54
|
+
return false;
|
|
55
|
+
|
|
56
|
+
const r = str.match(CONST_RFC3339_REGEX_ISDATE);
|
|
57
|
+
if (r == null)
|
|
58
|
+
return false;
|
|
59
|
+
|
|
60
|
+
const y = parseInt(r[1], 10) | 0;
|
|
61
|
+
const m = parseInt(r[2], 10) | 0;
|
|
62
|
+
const d = parseInt(r[3], 10) | 0;
|
|
63
|
+
return isDateOnlyInRange(y, m, d);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function isTimeOnlyInRange(hrs = 0, min = 0, sec = 0, tzh = 0, tzm = 0, tzSign = 1) {
|
|
67
|
+
// Validate timezone offset range
|
|
68
|
+
if (tzh < 0 || tzh > 23 || tzm < 0 || tzm > 59)
|
|
69
|
+
return false;
|
|
70
|
+
|
|
71
|
+
// For leap seconds (sec === 60), we need to check if the corresponding UTC time
|
|
72
|
+
// is 23:59:60. A leap second is only valid at the very end of a UTC day.
|
|
73
|
+
if (sec === 60) {
|
|
74
|
+
// Calculate what the UTC time would be
|
|
75
|
+
// UTC = local - offset (if offset is positive, local is ahead of UTC)
|
|
76
|
+
// So: UTC = local + (tzSign * tzh) hours + (tzSign * tzm) minutes
|
|
77
|
+
let utcHrs = hrs - (tzSign * tzh);
|
|
78
|
+
let utcMin = min - (tzSign * tzm);
|
|
79
|
+
|
|
80
|
+
// Handle wrap-around
|
|
81
|
+
while (utcMin < 0) {
|
|
82
|
+
utcMin += 60;
|
|
83
|
+
utcHrs -= 1;
|
|
84
|
+
}
|
|
85
|
+
while (utcMin >= 60) {
|
|
86
|
+
utcMin -= 60;
|
|
87
|
+
utcHrs += 1;
|
|
88
|
+
}
|
|
89
|
+
while (utcHrs < 0) {
|
|
90
|
+
utcHrs += 24;
|
|
91
|
+
}
|
|
92
|
+
utcHrs = utcHrs % 24;
|
|
93
|
+
|
|
94
|
+
// Leap second is only valid at 23:59:60 UTC
|
|
95
|
+
return utcHrs === 23 && utcMin === 59 && sec === 60;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Normal time validation (sec 0-59)
|
|
99
|
+
return hrs >= 0 && hrs <= 23
|
|
100
|
+
&& min >= 0 && min <= 59
|
|
101
|
+
&& sec >= 0 && sec <= 59;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function isTimeOnlyRFC3339(str) {
|
|
105
|
+
if (!isStringType(str))
|
|
106
|
+
return false;
|
|
107
|
+
|
|
108
|
+
const r = str.match(CONST_RFC3339_REGEX_ISTIME);
|
|
109
|
+
if (r == null)
|
|
110
|
+
return false;
|
|
111
|
+
|
|
112
|
+
const h = parseInt(r[1], 10) | 0;
|
|
113
|
+
const m = parseInt(r[2], 10) | 0;
|
|
114
|
+
const s = parseInt(r[3], 10) | 0;
|
|
115
|
+
const th = parseInt(r[8], 10) | 0;
|
|
116
|
+
const tm = parseInt(r[9], 10) | 0;
|
|
117
|
+
// r[7] is the timezone sign (+ or -)
|
|
118
|
+
// + means local time is ahead of UTC, so we subtract to get UTC
|
|
119
|
+
// - means local time is behind UTC, so we add to get UTC
|
|
120
|
+
const tzSign = r[7] === '-' ? -1 : 1;
|
|
121
|
+
return isTimeOnlyInRange(h, m, s, th, tm, tzSign);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function isDateTimeRFC3339(str) {
|
|
125
|
+
// http://tools.ietf.org/html/rfc3339#section-5.6
|
|
126
|
+
if (!isStringType(str)) return false;
|
|
127
|
+
const dateTime = str.split(/t|\s/i);
|
|
128
|
+
return dateTime.length === 2
|
|
129
|
+
&& isDateOnlyRFC3339(dateTime[0])
|
|
130
|
+
&& isTimeOnlyRFC3339(dateTime[1]);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
//#endregion
|
|
134
|
+
|
|
135
|
+
//#region Dates Getters
|
|
136
|
+
export function getDateTypeOfDateOnlyRFC3339(str, def = undefined) {
|
|
137
|
+
return isDateOnlyRFC3339(str)
|
|
138
|
+
? new Date(Date.parse(str))
|
|
139
|
+
: def;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function getDateTypeOfTimeOnlyRFC3339(str, def = undefined) {
|
|
143
|
+
return isTimeOnlyRFC3339(str)
|
|
144
|
+
? new Date(Date.parse(CONST_TIME_INSERTDATE + str))
|
|
145
|
+
: def;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function getDateTypeOfDateTimeRFC3339(str, def = undefined) {
|
|
149
|
+
return isDateTimeRFC3339(str)
|
|
150
|
+
? new Date(Date.parse(str))
|
|
151
|
+
: def;
|
|
152
|
+
}
|
|
153
|
+
//#endregion
|
|
154
|
+
|
|
155
|
+
//#region Duration Validation (RFC 3339)
|
|
156
|
+
// Duration format: P[n]Y[n]M[n]DT[n]H[n]M[n]S or P[n]W
|
|
157
|
+
// Examples: P1Y2M3DT4H5M6S, P1W, PT1H, P1Y
|
|
158
|
+
// https://tools.ietf.org/html/rfc3339#appendix-A
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Validates a duration string per RFC 3339.
|
|
162
|
+
* Duration format: P[n]Y[n]M[n]DT[n]H[n]M[n]S or P[n]W
|
|
163
|
+
*
|
|
164
|
+
* @param {string} str - The duration string to validate
|
|
165
|
+
* @returns {boolean} - True if the string is a valid duration
|
|
166
|
+
* @example
|
|
167
|
+
* isValidDuration('P1Y2M3DT4H5M6S'); // true (1 year, 2 months, 3 days, 4 hours, 5 minutes, 6 seconds)
|
|
168
|
+
* isValidDuration('P1W'); // true (1 week)
|
|
169
|
+
* isValidDuration('PT1H'); // true (1 hour)
|
|
170
|
+
* isValidDuration('P1Y'); // true (1 year)
|
|
171
|
+
* isValidDuration('P'); // false (empty duration)
|
|
172
|
+
* isValidDuration('1Y'); // false (missing P)
|
|
173
|
+
*/
|
|
174
|
+
export function isValidDuration(str) {
|
|
175
|
+
if (!isStringType(str))
|
|
176
|
+
return false;
|
|
177
|
+
|
|
178
|
+
// Must start with P
|
|
179
|
+
if (!str.startsWith('P'))
|
|
180
|
+
return false;
|
|
181
|
+
|
|
182
|
+
// Cannot be just "P"
|
|
183
|
+
if (str.length < 2)
|
|
184
|
+
return false;
|
|
185
|
+
|
|
186
|
+
// Parse and validate components
|
|
187
|
+
// Remove the 'P' prefix
|
|
188
|
+
const rest = str.slice(1);
|
|
189
|
+
|
|
190
|
+
// Check for week format: P[n]W (cannot be combined with other components)
|
|
191
|
+
if (rest.endsWith('W')) {
|
|
192
|
+
const weekPart = rest.slice(0, -1);
|
|
193
|
+
return weekPart.length > 0 && /^\d+$/.test(weekPart);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Split into date and time parts
|
|
197
|
+
const tIndex = rest.indexOf('T');
|
|
198
|
+
const datePart = tIndex >= 0 ? rest.slice(0, tIndex) : rest;
|
|
199
|
+
const timePart = tIndex >= 0 ? rest.slice(tIndex + 1) : '';
|
|
200
|
+
|
|
201
|
+
// Must have at least one component
|
|
202
|
+
if (!datePart && !timePart)
|
|
203
|
+
return false;
|
|
204
|
+
|
|
205
|
+
// If there's a T, there must be at least one time component
|
|
206
|
+
if (tIndex >= 0 && !timePart)
|
|
207
|
+
return false;
|
|
208
|
+
|
|
209
|
+
// Validate date part components (Y, M, D)
|
|
210
|
+
if (datePart) {
|
|
211
|
+
// Must match pattern: optional number+Y, optional number+M, optional number+D
|
|
212
|
+
// in that order, at least one must be present
|
|
213
|
+
const dateRegex = /^(\d+Y)?(\d+M)?(\d+D)?$/;
|
|
214
|
+
if (!dateRegex.test(datePart))
|
|
215
|
+
return false;
|
|
216
|
+
// Must have at least one component
|
|
217
|
+
if (!/\d+[YMD]/.test(datePart))
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Validate time part components (H, M, S)
|
|
222
|
+
if (timePart) {
|
|
223
|
+
const timeRegex = /^(\d+H)?(\d+M)?(\d+(?:\.\d+)?S)?$/;
|
|
224
|
+
if (!timeRegex.test(timePart))
|
|
225
|
+
return false;
|
|
226
|
+
// Must have at least one component
|
|
227
|
+
if (!/\d+[HMS]/.test(timePart))
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
//#endregion
|
|
234
|
+
|
|
235
|
+
//#region ISO Date-Time and ISO Time (with optional timezone)
|
|
236
|
+
// ISO 8601 date-time with optional timezone (like 2024-01-15T12:30:00)
|
|
237
|
+
// ISO 8601 time with optional timezone (like 12:30:00)
|
|
238
|
+
|
|
239
|
+
// Regex for iso-date-time: allows with or without timezone
|
|
240
|
+
const CONST_ISO_REGEX_DATETIME = /^(\d{4})-([0-1]\d)-([0-3]\d)[T\s](\d{2}):(\d{2}):(\d{2})(\.\d{1,6})?(?:(Z)|([+-])(\d{2}):(\d{2}))?$/i;
|
|
241
|
+
|
|
242
|
+
// Regex for iso-time: allows with or without timezone
|
|
243
|
+
const CONST_ISO_REGEX_TIME = /^(\d{2}):(\d{2}):(\d{2})(\.\d{1,6})?(?:(Z)|([+-])(\d{2}):(\d{2}))?$/i;
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Validates an ISO 8601 date-time string with optional timezone.
|
|
247
|
+
* Unlike RFC 3339, the timezone is optional.
|
|
248
|
+
*
|
|
249
|
+
* @param {string} str - The date-time string to validate
|
|
250
|
+
* @returns {boolean} - True if the string is a valid ISO date-time
|
|
251
|
+
* @example
|
|
252
|
+
* isValidISODateTime('2024-01-15T12:30:00Z'); // true
|
|
253
|
+
* isValidISODateTime('2024-01-15T12:30:00+01:00'); // true
|
|
254
|
+
* isValidISODateTime('2024-01-15T12:30:00'); // true (no timezone)
|
|
255
|
+
* isValidISODateTime('2024-01-15 12:30:00'); // true (space separator)
|
|
256
|
+
* isValidISODateTime('2024-13-15T12:30:00'); // false (invalid month)
|
|
257
|
+
*/
|
|
258
|
+
export function isValidISODateTime(str) {
|
|
259
|
+
if (!isStringType(str))
|
|
260
|
+
return false;
|
|
261
|
+
|
|
262
|
+
const r = str.match(CONST_ISO_REGEX_DATETIME);
|
|
263
|
+
if (r == null)
|
|
264
|
+
return false;
|
|
265
|
+
|
|
266
|
+
const y = parseInt(r[1], 10) | 0;
|
|
267
|
+
const m = parseInt(r[2], 10) | 0;
|
|
268
|
+
const d = parseInt(r[3], 10) | 0;
|
|
269
|
+
const h = parseInt(r[4], 10) | 0;
|
|
270
|
+
const min = parseInt(r[5], 10) | 0;
|
|
271
|
+
const s = parseInt(r[6], 10) | 0;
|
|
272
|
+
|
|
273
|
+
// Validate date portion
|
|
274
|
+
if (!isDateOnlyInRange(y, m, d))
|
|
275
|
+
return false;
|
|
276
|
+
|
|
277
|
+
// Validate time portion (no leap seconds for ISO date-time without explicit timezone)
|
|
278
|
+
if (h < 0 || h > 23 || min < 0 || min > 59 || s < 0 || s > 59)
|
|
279
|
+
return false;
|
|
280
|
+
|
|
281
|
+
// Validate timezone if present
|
|
282
|
+
if (r[9] != null) {
|
|
283
|
+
const tzh = parseInt(r[10], 10) | 0;
|
|
284
|
+
const tzm = parseInt(r[11], 10) | 0;
|
|
285
|
+
if (tzh < 0 || tzh > 23 || tzm < 0 || tzm > 59)
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Validates an ISO 8601 time string with optional timezone.
|
|
294
|
+
* Unlike RFC 3339, the timezone is optional.
|
|
295
|
+
*
|
|
296
|
+
* @param {string} str - The time string to validate
|
|
297
|
+
* @returns {boolean} - True if the string is a valid ISO time
|
|
298
|
+
* @example
|
|
299
|
+
* isValidISOTime('12:30:00Z'); // true
|
|
300
|
+
* isValidISOTime('12:30:00+01:00'); // true
|
|
301
|
+
* isValidISOTime('12:30:00'); // true (no timezone)
|
|
302
|
+
* isValidISOTime('25:00:00'); // false (invalid hour)
|
|
303
|
+
*/
|
|
304
|
+
export function isValidISOTime(str) {
|
|
305
|
+
if (!isStringType(str))
|
|
306
|
+
return false;
|
|
307
|
+
|
|
308
|
+
const r = str.match(CONST_ISO_REGEX_TIME);
|
|
309
|
+
if (r == null)
|
|
310
|
+
return false;
|
|
311
|
+
|
|
312
|
+
const h = parseInt(r[1], 10) | 0;
|
|
313
|
+
const m = parseInt(r[2], 10) | 0;
|
|
314
|
+
const s = parseInt(r[3], 10) | 0;
|
|
315
|
+
|
|
316
|
+
// Validate time portion (no leap seconds for ISO time without explicit timezone)
|
|
317
|
+
if (h < 0 || h > 23 || m < 0 || m > 59 || s < 0 || s > 59)
|
|
318
|
+
return false;
|
|
319
|
+
|
|
320
|
+
// Validate timezone if present
|
|
321
|
+
if (r[7] != null) {
|
|
322
|
+
const tzh = parseInt(r[8], 10) | 0;
|
|
323
|
+
const tzm = parseInt(r[9], 10) | 0;
|
|
324
|
+
if (tzh < 0 || tzh > 23 || tzm < 0 || tzm > 59)
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return true;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Parses an ISO 8601 date-time string with optional timezone.
|
|
333
|
+
* Returns a Date object if valid, otherwise undefined.
|
|
334
|
+
*
|
|
335
|
+
* @param {string} str - The date-time string to parse
|
|
336
|
+
* @param {any} [def=undefined] - Default value to return if invalid
|
|
337
|
+
* @returns {Date|undefined} - The parsed Date or default value
|
|
338
|
+
*/
|
|
339
|
+
export function getDateTypeOfISODateTime(str, def = undefined) {
|
|
340
|
+
if (!isValidISODateTime(str))
|
|
341
|
+
return def;
|
|
342
|
+
|
|
343
|
+
// If no timezone specified, treat as local time by appending Z
|
|
344
|
+
// (ISO 8601 without timezone is local time, but for consistency we treat as UTC)
|
|
345
|
+
if (!/[Z+-]\d{2}:\d{2}$/i.test(str) && !str.endsWith('Z')) {
|
|
346
|
+
// Try parsing as-is (Date.parse handles both formats)
|
|
347
|
+
const date = new Date(Date.parse(str.replace(' ', 'T')));
|
|
348
|
+
return isNaN(date.getTime()) ? def : date;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
return new Date(Date.parse(str));
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Parses an ISO 8601 time string with optional timezone.
|
|
356
|
+
* Returns a Date object (with 1970-01-01 as date) if valid, otherwise undefined.
|
|
357
|
+
*
|
|
358
|
+
* @param {string} str - The time string to parse
|
|
359
|
+
* @param {any} [def=undefined] - Default value to return if invalid
|
|
360
|
+
* @returns {Date|undefined} - The parsed Date or default value
|
|
361
|
+
*/
|
|
362
|
+
export function getDateTypeOfISOTime(str, def = undefined) {
|
|
363
|
+
if (!isValidISOTime(str))
|
|
364
|
+
return def;
|
|
365
|
+
|
|
366
|
+
// Prepend a dummy date for parsing
|
|
367
|
+
const dateTimeStr = CONST_TIME_INSERTDATE + str;
|
|
368
|
+
const date = new Date(Date.parse(dateTimeStr));
|
|
369
|
+
return isNaN(date.getTime()) ? def : date;
|
|
370
|
+
}
|
|
371
|
+
//#endregion
|
package/src/float.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
//@ts-check
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
isNumberType,
|
|
5
|
+
} from './index.js';
|
|
6
|
+
|
|
7
|
+
export const FLOAT16_MAX = 65504.0;
|
|
8
|
+
export const FLOAT16_MIN = 0.00006103515625;
|
|
9
|
+
export const FLOAT16_EPS = 0.0009765625;
|
|
10
|
+
export const FLOAT16_EXBITS = 5;
|
|
11
|
+
export const FLOAT16_FRBITS = 10;
|
|
12
|
+
|
|
13
|
+
export function isValidFloat16(value) {
|
|
14
|
+
return isNumberType(value)
|
|
15
|
+
&& !Number.isNaN(value)
|
|
16
|
+
&& value >= -FLOAT16_MAX
|
|
17
|
+
&& value <= FLOAT16_MAX;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function getValidFloat16(value, defVal = NaN) {
|
|
21
|
+
if (!isNumberType(value) /* TODO: do we need this? */
|
|
22
|
+
|| Number.isNaN(value)) return defVal;
|
|
23
|
+
if (value < -FLOAT16_MAX) return -Infinity;
|
|
24
|
+
if (value > FLOAT16_MAX) return Infinity;
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function Float16_increment(value) {
|
|
29
|
+
const next = value + 2 ** (Math.log2(value) - 11);
|
|
30
|
+
return (next > FLOAT16_MAX)
|
|
31
|
+
? Infinity
|
|
32
|
+
: next;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function Float16_decrement(value) {
|
|
36
|
+
const next = value - 2 ** (Math.log2(value) - 11);
|
|
37
|
+
return (next < -FLOAT16_MAX)
|
|
38
|
+
? -Infinity
|
|
39
|
+
: next;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const FLOAT32_MAX = 3.4028234663852886e+38;
|
|
43
|
+
export const FLOAT32_MIN = 1.1754943508222875e-38;
|
|
44
|
+
export const FLOAT32_EPS = 1.1920928955078125e-7;
|
|
45
|
+
export const FLOAT32_EXBITS = 8;
|
|
46
|
+
export const FLOAT32_FRBITS = 23;
|
|
47
|
+
|
|
48
|
+
export function isValidFloat32(value) {
|
|
49
|
+
return isNumberType(value)
|
|
50
|
+
&& !Number.isNaN(value)
|
|
51
|
+
&& value >= -FLOAT32_MAX
|
|
52
|
+
&& value <= FLOAT32_MAX;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function getValidFloat32(value, defVal = NaN) {
|
|
56
|
+
if (!isNumberType(value) || Number.isNaN(value)) return defVal;
|
|
57
|
+
if (value < -FLOAT32_MAX) return -Infinity;
|
|
58
|
+
if (value > FLOAT32_MAX) return Infinity;
|
|
59
|
+
return value;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function Float32_increment(value) {
|
|
63
|
+
const next = value + 2 ** (Math.log2(value) - 24);
|
|
64
|
+
return (next > FLOAT32_MAX)
|
|
65
|
+
? Infinity
|
|
66
|
+
: next;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function Float32_decrement(value) {
|
|
70
|
+
const next = value - 2 ** (Math.log2(value) - 24);
|
|
71
|
+
return (next < -FLOAT32_MAX)
|
|
72
|
+
? -Infinity
|
|
73
|
+
: next;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export const FLOAT64_MAX = Number.MAX_VALUE;
|
|
77
|
+
export const FLOAT64_MIN = Number.MIN_VALUE;
|
|
78
|
+
export const FLOAT64_EPS = Number.EPSILON;
|
|
79
|
+
export const FLOAT64_EXBITS = 11;
|
|
80
|
+
export const FLOAT64_FRBITS = 52;
|
|
81
|
+
|
|
82
|
+
export function isValidFloat64(value) {
|
|
83
|
+
return isNumberType(value)
|
|
84
|
+
&& !Number.isNaN(value)
|
|
85
|
+
&& value >= -FLOAT64_MAX
|
|
86
|
+
&& value <= FLOAT64_MAX;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function getValidFloat64(value, defVal = NaN) {
|
|
90
|
+
return isNumberType(value)
|
|
91
|
+
? value
|
|
92
|
+
: defVal;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function Float64_increment(value) {
|
|
96
|
+
return value + 2 ** (Math.log2(value) - 53);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function Float64_decrement(value) {
|
|
100
|
+
return value - 2 ** (Math.log2(value) - 53);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export const FLOAT128_MAX = 0.0;
|
|
104
|
+
export const FLOAT128_MIN = 0.0;
|
|
105
|
+
export const FLOAT128_EPS = 0.0;
|
|
106
|
+
export const FLOAT128_EXBITS = 15;
|
|
107
|
+
export const FLOAT128_FRBITS = 112;
|
package/src/function.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
//@ts-check
|
|
2
|
+
import {
|
|
3
|
+
isFn,
|
|
4
|
+
} from './index.js';
|
|
5
|
+
|
|
6
|
+
// export * from './function-tools-xtra';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* trueThat
|
|
10
|
+
* acts as a dummy validator that always returns true
|
|
11
|
+
* @param {any} whatever any json data input
|
|
12
|
+
* @param {string | undefined} _path the current json path to the data
|
|
13
|
+
* @param {any | undefined} _root the root of the json data
|
|
14
|
+
* @param {string | string[] | undefined} _key a key or an array of keys
|
|
15
|
+
* @returns {boolean} returns always true
|
|
16
|
+
*/
|
|
17
|
+
// eslint-disable-next-line no-unused-vars
|
|
18
|
+
export function trueThat(whatever, _path = undefined, _root = undefined, _key = undefined) {
|
|
19
|
+
const that = true;
|
|
20
|
+
return whatever === true || that;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* falseThat
|
|
25
|
+
* acts as a dummy validator that always returns false
|
|
26
|
+
* @param {any} whatever any json data input
|
|
27
|
+
* @param {string | undefined} _path the current json path to the data
|
|
28
|
+
* @param {any | undefined} _root the root of the json data
|
|
29
|
+
* @param {string | string[] | undefined} _key a key or an array of keys
|
|
30
|
+
* @returns {boolean} returns always true
|
|
31
|
+
*/
|
|
32
|
+
// eslint-disable-next-line no-unused-vars
|
|
33
|
+
export function falseThat(whatever, _path = undefined, _root = undefined, _key = undefined) {
|
|
34
|
+
// eslint-disable-next-line no-constant-binary-expression
|
|
35
|
+
return false && whatever;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function fallbackFn(compiled, fallback = trueThat) {
|
|
39
|
+
if (isFn(compiled)) return compiled;
|
|
40
|
+
return isFn(fallback)
|
|
41
|
+
? fallback
|
|
42
|
+
: trueThat;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function addFunctionToArray(arr = [], fn) {
|
|
46
|
+
if (fn == null) return arr;
|
|
47
|
+
if (isFn(fn))
|
|
48
|
+
arr.push(fn);
|
|
49
|
+
else if (fn.constructor === Array) {
|
|
50
|
+
for (let i = 0; i < fn.length; ++i) {
|
|
51
|
+
if (isFn(fn[i]))
|
|
52
|
+
arr.push(fn[i]);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return arr;
|
|
56
|
+
}
|