@naturalcycles/js-lib 15.37.0 → 15.39.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/dist/enum.util.d.ts +2 -1
- package/dist/enum.util.js +29 -0
- package/dist/json-schema/jsonSchemaBuilder.d.ts +6 -18
- package/dist/json-schema/jsonSchemaBuilder.js +35 -31
- package/dist/json-schema/jsonSchemas.js +2 -2
- package/dist/nanoid.js +1 -1
- package/dist/number/createDeterministicRandom.js +1 -1
- package/dist/string/hash.util.js +2 -1
- package/dist/string/leven.js +2 -1
- package/dist/string/safeJsonStringify.js +9 -4
- package/package.json +1 -1
- package/src/enum.util.ts +33 -1
- package/src/json-schema/jsonSchemaBuilder.ts +59 -36
- package/src/json-schema/jsonSchemas.ts +2 -2
- package/src/nanoid.ts +1 -2
- package/src/number/createDeterministicRandom.ts +1 -2
- package/src/string/hash.util.ts +3 -1
- package/src/string/leven.ts +2 -1
- package/src/string/safeJsonStringify.ts +9 -4
package/dist/enum.util.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { NumberEnum, StringEnum } from './types.js';
|
|
1
|
+
import type { AnyObject, NumberEnum, StringEnum } from './types.js';
|
|
2
|
+
export declare function getEnumType(en: AnyObject): 'StringEnum' | 'NumberEnum' | undefined;
|
|
2
3
|
/**
|
|
3
4
|
* Returns all String keys of a number-enum.
|
|
4
5
|
*/
|
package/dist/enum.util.js
CHANGED
|
@@ -1,3 +1,32 @@
|
|
|
1
|
+
export function getEnumType(en) {
|
|
2
|
+
/*
|
|
3
|
+
* enum Foo { A = 1, B = 2 }
|
|
4
|
+
* becomes
|
|
5
|
+
* { "1": "A", "2": "B", "A": 1, "B": 2}
|
|
6
|
+
*
|
|
7
|
+
* enum Foo { A = "V1", B = "V2" }
|
|
8
|
+
* becomes
|
|
9
|
+
* { "V1": "A", "V2": "B", "A": "V1", "B": "V2"}
|
|
10
|
+
*/
|
|
11
|
+
const entries = Object.entries(en);
|
|
12
|
+
if (!entries.length)
|
|
13
|
+
return;
|
|
14
|
+
const [, value] = entries.pop();
|
|
15
|
+
let isNumberEnum = typeof value === 'number';
|
|
16
|
+
let isStringEnum = typeof value === 'string';
|
|
17
|
+
for (const [key, value] of entries) {
|
|
18
|
+
const isValueNumber = typeof value === 'number';
|
|
19
|
+
const isValueString = typeof value === 'string';
|
|
20
|
+
isStringEnum &&= isValueString;
|
|
21
|
+
isNumberEnum &&= isValueNumber || String(en[value]) === key;
|
|
22
|
+
if (!isStringEnum && !isNumberEnum)
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
if (isNumberEnum)
|
|
26
|
+
return 'NumberEnum';
|
|
27
|
+
if (isStringEnum)
|
|
28
|
+
return 'StringEnum';
|
|
29
|
+
}
|
|
1
30
|
/**
|
|
2
31
|
* Returns all String keys of a number-enum.
|
|
3
32
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AnyObject, type BaseDBEntity, type IsoDate, type IsoDateTime, type UnixTimestamp } from '../types.js';
|
|
1
|
+
import { type AnyObject, type BaseDBEntity, type IsoDate, type IsoDateTime, type NumberEnum, type StringEnum, type UnixTimestamp, type UnixTimestampMillis } from '../types.js';
|
|
2
2
|
import type { JsonSchema, JsonSchemaAllOf, JsonSchemaAny, JsonSchemaArray, JsonSchemaBoolean, JsonSchemaConst, JsonSchemaEnum, JsonSchemaNull, JsonSchemaNumber, JsonSchemaObject, JsonSchemaOneOf, JsonSchemaRef, JsonSchemaString, JsonSchemaTuple } from './jsonSchema.model.js';
|
|
3
3
|
export interface JsonSchemaBuilder<T = unknown> {
|
|
4
4
|
build: () => JsonSchema<T>;
|
|
@@ -12,24 +12,12 @@ export declare const j: {
|
|
|
12
12
|
const<T extends string | number | boolean | null>(value: T): JsonSchemaAnyBuilder<T, JsonSchemaConst<T>, false>;
|
|
13
13
|
null(): JsonSchemaAnyBuilder<null, JsonSchemaNull, false>;
|
|
14
14
|
ref<T = unknown>($ref: string): JsonSchemaAnyBuilder<T, JsonSchemaRef<T>, false>;
|
|
15
|
-
enum<T
|
|
15
|
+
enum<const T extends readonly (string | number | boolean | null)[] | StringEnum | NumberEnum>(input: T): JsonSchemaAnyBuilder<T extends readonly (infer U)[] ? U : T extends StringEnum ? T[keyof T] : T extends NumberEnum ? T[keyof T] : never, JsonSchemaEnum<any>, false>;
|
|
16
16
|
boolean(): JsonSchemaAnyBuilder<boolean, JsonSchemaBoolean, false>;
|
|
17
17
|
buffer(): JsonSchemaAnyBuilder<Buffer<ArrayBufferLike>, JsonSchemaAny<Buffer<ArrayBufferLike>>, false>;
|
|
18
18
|
number<T extends number = number>(): JsonSchemaNumberBuilder<T, false>;
|
|
19
19
|
integer<T extends number = number>(): JsonSchemaNumberBuilder<T, false>;
|
|
20
|
-
unixTimestamp(): JsonSchemaNumberBuilder<UnixTimestamp, false>;
|
|
21
|
-
unixTimestamp2000(): JsonSchemaNumberBuilder<UnixTimestamp, false>;
|
|
22
20
|
string<T extends string = string>(): JsonSchemaStringBuilder<T, false>;
|
|
23
|
-
jwt(): JsonSchemaStringBuilder<string, false>;
|
|
24
|
-
/**
|
|
25
|
-
* Accepts only the `YYYY-MM-DD` shape from all ISO 8601 variants.
|
|
26
|
-
*/
|
|
27
|
-
isoDate(): JsonSchemaStringBuilder<IsoDate, false>;
|
|
28
|
-
/**
|
|
29
|
-
* Accepts strings that start with the `YYYY-MM-DDTHH:MM:SS` shape
|
|
30
|
-
* and optionally end with either a `Z` or a `+/-hh:mm` timezone part.
|
|
31
|
-
*/
|
|
32
|
-
isoDateTime(): JsonSchemaStringBuilder<IsoDateTime, false>;
|
|
33
21
|
object: typeof object;
|
|
34
22
|
dbEntity<T extends AnyObject>(props: T): JsonSchemaObjectBuilder<BaseDBEntity & ({ [K in keyof T as T[K] extends JsonSchemaAnyBuilder<any, any, infer Opt extends boolean> ? Opt extends true ? never : K : never]: T[K] extends JsonSchemaAnyBuilder<infer U, any, any> ? U : never; } & { [K_1 in keyof T as T[K_1] extends JsonSchemaAnyBuilder<any, any, infer Opt extends boolean> ? Opt extends true ? K_1 : never : never]?: (T[K_1] extends JsonSchemaAnyBuilder<infer U, any, any> ? U : never) | undefined; } extends infer O ? { [K_2 in keyof O]: O[K_2]; } : never) extends infer O_1 ? { [K_3 in keyof O_1]: O_1[K_3]; } : never, false>;
|
|
35
23
|
rootObject<T extends AnyObject>(props: { [K in keyof T]: JsonSchemaAnyBuilder<T[K]>; }): JsonSchemaObjectBuilder<T, false>;
|
|
@@ -86,10 +74,10 @@ export declare class JsonSchemaNumberBuilder<T extends number = number, Opt exte
|
|
|
86
74
|
int64: () => this;
|
|
87
75
|
float: () => this;
|
|
88
76
|
double: () => this;
|
|
89
|
-
unixTimestamp: () =>
|
|
90
|
-
unixTimestamp2000: () =>
|
|
91
|
-
unixTimestampMillis: () =>
|
|
92
|
-
unixTimestampMillis2000: () =>
|
|
77
|
+
unixTimestamp: () => JsonSchemaNumberBuilder<UnixTimestamp>;
|
|
78
|
+
unixTimestamp2000: () => JsonSchemaNumberBuilder<UnixTimestamp>;
|
|
79
|
+
unixTimestampMillis: () => JsonSchemaNumberBuilder<UnixTimestampMillis>;
|
|
80
|
+
unixTimestampMillis2000: () => JsonSchemaNumberBuilder<UnixTimestampMillis>;
|
|
93
81
|
utcOffset: () => this;
|
|
94
82
|
utcOffsetHours: () => this;
|
|
95
83
|
branded<B extends number>(): JsonSchemaNumberBuilder<B>;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { _uniq } from '../array/array.util.js';
|
|
2
|
+
import { _numberEnumValues, _stringEnumValues, getEnumType } from '../enum.util.js';
|
|
3
|
+
import { _assert } from '../error/assert.js';
|
|
2
4
|
import { _deepCopy } from '../object/object.util.js';
|
|
3
5
|
import { _sortObject } from '../object/sortObject.js';
|
|
4
6
|
import { JWT_REGEX, } from '../types.js';
|
|
@@ -27,8 +29,24 @@ export const j = {
|
|
|
27
29
|
$ref,
|
|
28
30
|
});
|
|
29
31
|
},
|
|
30
|
-
enum(
|
|
31
|
-
|
|
32
|
+
enum(input) {
|
|
33
|
+
let enumValues;
|
|
34
|
+
if (Array.isArray(input)) {
|
|
35
|
+
enumValues = input;
|
|
36
|
+
}
|
|
37
|
+
else if (typeof input === 'object') {
|
|
38
|
+
const enumType = getEnumType(input);
|
|
39
|
+
if (enumType === 'NumberEnum') {
|
|
40
|
+
enumValues = _numberEnumValues(input);
|
|
41
|
+
}
|
|
42
|
+
else if (enumType === 'StringEnum') {
|
|
43
|
+
enumValues = _stringEnumValues(input);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
_assert(enumValues, 'Unsupported enum input');
|
|
47
|
+
return new JsonSchemaAnyBuilder({
|
|
48
|
+
enum: enumValues,
|
|
49
|
+
});
|
|
32
50
|
},
|
|
33
51
|
boolean() {
|
|
34
52
|
return new JsonSchemaAnyBuilder({
|
|
@@ -47,41 +65,18 @@ export const j = {
|
|
|
47
65
|
integer() {
|
|
48
66
|
return new JsonSchemaNumberBuilder().integer();
|
|
49
67
|
},
|
|
50
|
-
unixTimestamp() {
|
|
51
|
-
return new JsonSchemaNumberBuilder().unixTimestamp();
|
|
52
|
-
},
|
|
53
|
-
unixTimestamp2000() {
|
|
54
|
-
return new JsonSchemaNumberBuilder().unixTimestamp2000();
|
|
55
|
-
},
|
|
56
68
|
// string types
|
|
57
69
|
string() {
|
|
58
70
|
return new JsonSchemaStringBuilder();
|
|
59
71
|
},
|
|
60
|
-
jwt() {
|
|
61
|
-
return new JsonSchemaStringBuilder().jwt();
|
|
62
|
-
},
|
|
63
|
-
/**
|
|
64
|
-
* Accepts only the `YYYY-MM-DD` shape from all ISO 8601 variants.
|
|
65
|
-
*/
|
|
66
|
-
isoDate() {
|
|
67
|
-
return new JsonSchemaStringBuilder().isoDate();
|
|
68
|
-
},
|
|
69
|
-
/**
|
|
70
|
-
* Accepts strings that start with the `YYYY-MM-DDTHH:MM:SS` shape
|
|
71
|
-
* and optionally end with either a `Z` or a `+/-hh:mm` timezone part.
|
|
72
|
-
*/
|
|
73
|
-
isoDateTime() {
|
|
74
|
-
return new JsonSchemaStringBuilder().isoDateTime();
|
|
75
|
-
},
|
|
76
|
-
// email: () => new JsonSchemaStringBuilder().email(),
|
|
77
72
|
// complex types
|
|
78
73
|
object,
|
|
79
74
|
dbEntity(props) {
|
|
80
75
|
return j
|
|
81
76
|
.object({
|
|
82
77
|
id: j.string(),
|
|
83
|
-
created: j.unixTimestamp2000(),
|
|
84
|
-
updated: j.unixTimestamp2000(),
|
|
78
|
+
created: j.integer().unixTimestamp2000(),
|
|
79
|
+
updated: j.integer().unixTimestamp2000(),
|
|
85
80
|
})
|
|
86
81
|
.extend(j.object(props));
|
|
87
82
|
},
|
|
@@ -226,10 +221,19 @@ export class JsonSchemaNumberBuilder extends JsonSchemaAnyBuilder {
|
|
|
226
221
|
int64 = () => this.format('int64');
|
|
227
222
|
float = () => this.format('float');
|
|
228
223
|
double = () => this.format('double');
|
|
229
|
-
unixTimestamp = () => this.format('unixTimestamp').description('UnixTimestamp');
|
|
230
|
-
unixTimestamp2000 = () => this.
|
|
231
|
-
|
|
232
|
-
|
|
224
|
+
unixTimestamp = () => this.integer().branded().format('unixTimestamp').description('UnixTimestamp');
|
|
225
|
+
unixTimestamp2000 = () => this.integer()
|
|
226
|
+
.branded()
|
|
227
|
+
.format('unixTimestamp2000')
|
|
228
|
+
.description('UnixTimestamp2000');
|
|
229
|
+
unixTimestampMillis = () => this.integer()
|
|
230
|
+
.branded()
|
|
231
|
+
.format('unixTimestampMillis')
|
|
232
|
+
.description('UnixTimestampMillis');
|
|
233
|
+
unixTimestampMillis2000 = () => this.integer()
|
|
234
|
+
.branded()
|
|
235
|
+
.format('unixTimestampMillis2000')
|
|
236
|
+
.description('UnixTimestampMillis2000');
|
|
233
237
|
utcOffset = () => this.format('utcOffset');
|
|
234
238
|
utcOffsetHours = () => this.format('utcOffsetHours');
|
|
235
239
|
branded() {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { j } from './jsonSchemaBuilder.js';
|
|
2
2
|
export const baseDBEntityJsonSchema = j.object({
|
|
3
3
|
id: j.string(),
|
|
4
|
-
created: j.unixTimestamp2000(),
|
|
5
|
-
updated: j.unixTimestamp2000(),
|
|
4
|
+
created: j.integer().unixTimestamp2000(),
|
|
5
|
+
updated: j.integer().unixTimestamp2000(),
|
|
6
6
|
});
|
package/dist/nanoid.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
// All credit to nanoid authors: https://github.com/ai/nanoid
|
|
3
3
|
// Reason for vendoring: (still) cannot import esm, and Nanoid went ESM-only since 4.0
|
|
4
4
|
/// <reference lib="dom" preserve="true" />
|
|
5
|
-
/* eslint-disable no-bitwise */
|
|
6
5
|
// "0-9a-zA-Z-_", same as base64url alphabet
|
|
7
6
|
const urlAlphabet = 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict';
|
|
7
|
+
// oxlint-disable no-bitwise -- NanoID uses bit operations to build compact IDs
|
|
8
8
|
export function nanoidBrowser(length = 21) {
|
|
9
9
|
let id = '';
|
|
10
10
|
const bytes = globalThis.crypto.getRandomValues(new Uint8Array(length));
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/* eslint-disable no-bitwise */
|
|
2
1
|
/**
|
|
3
2
|
* Returns a "deterministic Math.random() function"
|
|
4
3
|
*
|
|
@@ -6,6 +5,7 @@
|
|
|
6
5
|
*/
|
|
7
6
|
export function _createDeterministicRandom(seed = 0x2f6e2b1) {
|
|
8
7
|
return () => {
|
|
8
|
+
// oxlint-disable no-bitwise
|
|
9
9
|
// Robert Jenkins’ 32 bit integer hash function
|
|
10
10
|
seed = (seed + 0x7ed55d16 + (seed << 12)) & 0xffffffff;
|
|
11
11
|
seed = (seed ^ 0xc761c23c ^ (seed >>> 19)) & 0xffffffff;
|
package/dist/string/hash.util.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// oxlint-disable no-bitwise -- hash implementations use bit-level operations for speed
|
|
1
2
|
const BASE62 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
2
3
|
// const BASE64 = BASE62 + '+/'
|
|
3
4
|
const BASE64URL = BASE62 + '-_';
|
|
@@ -48,7 +49,7 @@ export function hashCode(s) {
|
|
|
48
49
|
let i = 0;
|
|
49
50
|
const len = s.length;
|
|
50
51
|
while (i < len) {
|
|
51
|
-
// eslint-disable-next-line
|
|
52
|
+
// eslint-disable-next-line unicorn/prefer-math-trunc, unicorn/prefer-code-point
|
|
52
53
|
hash = ((hash << 5) - hash + s.charCodeAt(i++)) << 0;
|
|
53
54
|
}
|
|
54
55
|
return hash + 2147483647 + 1;
|
package/dist/string/leven.js
CHANGED
|
@@ -13,7 +13,6 @@ export function _safeJsonStringify(obj, replacer, spaces, cycleReplacer) {
|
|
|
13
13
|
return JSON.stringify(obj, serializer(replacer, cycleReplacer), spaces);
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
/* eslint-disable no-bitwise, no-implicit-coercion */
|
|
17
16
|
// oxlint-disable no-unused-expressions
|
|
18
17
|
function serializer(replacer, cycleReplacer) {
|
|
19
18
|
const stack = [];
|
|
@@ -26,9 +25,15 @@ function serializer(replacer, cycleReplacer) {
|
|
|
26
25
|
return function (key, value) {
|
|
27
26
|
if (stack.length > 0) {
|
|
28
27
|
const thisPos = stack.indexOf(this);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
if (thisPos !== -1) {
|
|
29
|
+
stack.splice(thisPos + 1);
|
|
30
|
+
keys.splice(thisPos, Infinity, key);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
stack.push(this);
|
|
34
|
+
keys.push(key);
|
|
35
|
+
}
|
|
36
|
+
if (stack.includes(value)) {
|
|
32
37
|
value = cycleReplacer.call(this, key, value);
|
|
33
38
|
}
|
|
34
39
|
}
|
package/package.json
CHANGED
package/src/enum.util.ts
CHANGED
|
@@ -1,4 +1,36 @@
|
|
|
1
|
-
import type { NumberEnum, StringEnum } from './types.js'
|
|
1
|
+
import type { AnyObject, NumberEnum, StringEnum } from './types.js'
|
|
2
|
+
|
|
3
|
+
export function getEnumType(en: AnyObject): 'StringEnum' | 'NumberEnum' | undefined {
|
|
4
|
+
/*
|
|
5
|
+
* enum Foo { A = 1, B = 2 }
|
|
6
|
+
* becomes
|
|
7
|
+
* { "1": "A", "2": "B", "A": 1, "B": 2}
|
|
8
|
+
*
|
|
9
|
+
* enum Foo { A = "V1", B = "V2" }
|
|
10
|
+
* becomes
|
|
11
|
+
* { "V1": "A", "V2": "B", "A": "V1", "B": "V2"}
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const entries = Object.entries(en)
|
|
15
|
+
if (!entries.length) return
|
|
16
|
+
|
|
17
|
+
const [, value] = entries.pop()!
|
|
18
|
+
|
|
19
|
+
let isNumberEnum = typeof value === 'number'
|
|
20
|
+
let isStringEnum = typeof value === 'string'
|
|
21
|
+
|
|
22
|
+
for (const [key, value] of entries) {
|
|
23
|
+
const isValueNumber = typeof value === 'number'
|
|
24
|
+
const isValueString = typeof value === 'string'
|
|
25
|
+
|
|
26
|
+
isStringEnum &&= isValueString
|
|
27
|
+
isNumberEnum &&= isValueNumber || String(en[value]) === key
|
|
28
|
+
if (!isStringEnum && !isNumberEnum) break
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (isNumberEnum) return 'NumberEnum'
|
|
32
|
+
if (isStringEnum) return 'StringEnum'
|
|
33
|
+
}
|
|
2
34
|
|
|
3
35
|
/**
|
|
4
36
|
* Returns all String keys of a number-enum.
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { _uniq } from '../array/array.util.js'
|
|
2
|
+
import { _numberEnumValues, _stringEnumValues, getEnumType } from '../enum.util.js'
|
|
3
|
+
import { _assert } from '../error/assert.js'
|
|
2
4
|
import { _deepCopy } from '../object/object.util.js'
|
|
3
5
|
import { _sortObject } from '../object/sortObject.js'
|
|
4
6
|
import {
|
|
@@ -7,8 +9,10 @@ import {
|
|
|
7
9
|
type IsoDate,
|
|
8
10
|
type IsoDateTime,
|
|
9
11
|
JWT_REGEX,
|
|
10
|
-
type
|
|
12
|
+
type NumberEnum,
|
|
13
|
+
type StringEnum,
|
|
11
14
|
type UnixTimestamp,
|
|
15
|
+
type UnixTimestampMillis,
|
|
12
16
|
} from '../types.js'
|
|
13
17
|
import { JSON_SCHEMA_ORDER } from './jsonSchema.cnst.js'
|
|
14
18
|
import type {
|
|
@@ -58,9 +62,39 @@ export const j = {
|
|
|
58
62
|
$ref,
|
|
59
63
|
})
|
|
60
64
|
},
|
|
61
|
-
|
|
62
|
-
|
|
65
|
+
|
|
66
|
+
enum<const T extends readonly (string | number | boolean | null)[] | StringEnum | NumberEnum>(
|
|
67
|
+
input: T,
|
|
68
|
+
) {
|
|
69
|
+
let enumValues: readonly (string | number | boolean | null)[] | undefined
|
|
70
|
+
|
|
71
|
+
if (Array.isArray(input)) {
|
|
72
|
+
enumValues = input
|
|
73
|
+
} else if (typeof input === 'object') {
|
|
74
|
+
const enumType = getEnumType(input)
|
|
75
|
+
if (enumType === 'NumberEnum') {
|
|
76
|
+
enumValues = _numberEnumValues(input as NumberEnum)
|
|
77
|
+
} else if (enumType === 'StringEnum') {
|
|
78
|
+
enumValues = _stringEnumValues(input as StringEnum)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
_assert(enumValues, 'Unsupported enum input')
|
|
83
|
+
|
|
84
|
+
return new JsonSchemaAnyBuilder<
|
|
85
|
+
T extends readonly (infer U)[]
|
|
86
|
+
? U
|
|
87
|
+
: T extends StringEnum
|
|
88
|
+
? T[keyof T]
|
|
89
|
+
: T extends NumberEnum
|
|
90
|
+
? T[keyof T]
|
|
91
|
+
: never,
|
|
92
|
+
JsonSchemaEnum<any>
|
|
93
|
+
>({
|
|
94
|
+
enum: enumValues as any[],
|
|
95
|
+
})
|
|
63
96
|
},
|
|
97
|
+
|
|
64
98
|
boolean() {
|
|
65
99
|
return new JsonSchemaAnyBuilder<boolean, JsonSchemaBoolean>({
|
|
66
100
|
type: 'boolean',
|
|
@@ -79,45 +113,20 @@ export const j = {
|
|
|
79
113
|
integer<T extends number = number>() {
|
|
80
114
|
return new JsonSchemaNumberBuilder<T>().integer()
|
|
81
115
|
},
|
|
82
|
-
unixTimestamp() {
|
|
83
|
-
return new JsonSchemaNumberBuilder<UnixTimestamp>().unixTimestamp()
|
|
84
|
-
},
|
|
85
|
-
unixTimestamp2000() {
|
|
86
|
-
return new JsonSchemaNumberBuilder<UnixTimestamp>().unixTimestamp2000()
|
|
87
|
-
},
|
|
88
116
|
|
|
89
117
|
// string types
|
|
90
118
|
string<T extends string = string>() {
|
|
91
119
|
return new JsonSchemaStringBuilder<T>()
|
|
92
120
|
},
|
|
93
|
-
jwt() {
|
|
94
|
-
return new JsonSchemaStringBuilder<JWTString>().jwt()
|
|
95
|
-
},
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Accepts only the `YYYY-MM-DD` shape from all ISO 8601 variants.
|
|
99
|
-
*/
|
|
100
|
-
isoDate() {
|
|
101
|
-
return new JsonSchemaStringBuilder<IsoDate>().isoDate()
|
|
102
|
-
},
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Accepts strings that start with the `YYYY-MM-DDTHH:MM:SS` shape
|
|
106
|
-
* and optionally end with either a `Z` or a `+/-hh:mm` timezone part.
|
|
107
|
-
*/
|
|
108
|
-
isoDateTime() {
|
|
109
|
-
return new JsonSchemaStringBuilder<IsoDateTime>().isoDateTime()
|
|
110
|
-
},
|
|
111
121
|
|
|
112
|
-
// email: () => new JsonSchemaStringBuilder().email(),
|
|
113
122
|
// complex types
|
|
114
123
|
object,
|
|
115
124
|
dbEntity<T extends AnyObject>(props: T) {
|
|
116
125
|
return j
|
|
117
126
|
.object<BaseDBEntity>({
|
|
118
127
|
id: j.string(),
|
|
119
|
-
created: j.unixTimestamp2000(),
|
|
120
|
-
updated: j.unixTimestamp2000(),
|
|
128
|
+
created: j.integer().unixTimestamp2000(),
|
|
129
|
+
updated: j.integer().unixTimestamp2000(),
|
|
121
130
|
})
|
|
122
131
|
.extend(j.object(props))
|
|
123
132
|
},
|
|
@@ -305,13 +314,27 @@ export class JsonSchemaNumberBuilder<
|
|
|
305
314
|
int64 = (): this => this.format('int64')
|
|
306
315
|
float = (): this => this.format('float')
|
|
307
316
|
double = (): this => this.format('double')
|
|
308
|
-
unixTimestamp = (): this => this.format('unixTimestamp').description('UnixTimestamp')
|
|
309
|
-
unixTimestamp2000 = (): this => this.format('unixTimestamp2000').description('UnixTimestamp2000')
|
|
310
|
-
unixTimestampMillis = (): this =>
|
|
311
|
-
this.format('unixTimestampMillis').description('UnixTimestampMillis')
|
|
312
317
|
|
|
313
|
-
|
|
314
|
-
this.format('
|
|
318
|
+
unixTimestamp = (): JsonSchemaNumberBuilder<UnixTimestamp> =>
|
|
319
|
+
this.integer().branded<UnixTimestamp>().format('unixTimestamp').description('UnixTimestamp')
|
|
320
|
+
|
|
321
|
+
unixTimestamp2000 = (): JsonSchemaNumberBuilder<UnixTimestamp> =>
|
|
322
|
+
this.integer()
|
|
323
|
+
.branded<UnixTimestamp>()
|
|
324
|
+
.format('unixTimestamp2000')
|
|
325
|
+
.description('UnixTimestamp2000')
|
|
326
|
+
|
|
327
|
+
unixTimestampMillis = (): JsonSchemaNumberBuilder<UnixTimestampMillis> =>
|
|
328
|
+
this.integer()
|
|
329
|
+
.branded<UnixTimestampMillis>()
|
|
330
|
+
.format('unixTimestampMillis')
|
|
331
|
+
.description('UnixTimestampMillis')
|
|
332
|
+
|
|
333
|
+
unixTimestampMillis2000 = (): JsonSchemaNumberBuilder<UnixTimestampMillis> =>
|
|
334
|
+
this.integer()
|
|
335
|
+
.branded<UnixTimestampMillis>()
|
|
336
|
+
.format('unixTimestampMillis2000')
|
|
337
|
+
.description('UnixTimestampMillis2000')
|
|
315
338
|
|
|
316
339
|
utcOffset = (): this => this.format('utcOffset')
|
|
317
340
|
utcOffsetHours = (): this => this.format('utcOffsetHours')
|
|
@@ -3,6 +3,6 @@ import { j } from './jsonSchemaBuilder.js'
|
|
|
3
3
|
|
|
4
4
|
export const baseDBEntityJsonSchema = j.object<BaseDBEntity>({
|
|
5
5
|
id: j.string(),
|
|
6
|
-
created: j.unixTimestamp2000(),
|
|
7
|
-
updated: j.unixTimestamp2000(),
|
|
6
|
+
created: j.integer().unixTimestamp2000(),
|
|
7
|
+
updated: j.integer().unixTimestamp2000(),
|
|
8
8
|
})
|
package/src/nanoid.ts
CHANGED
|
@@ -4,8 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
/// <reference lib="dom" preserve="true" />
|
|
6
6
|
|
|
7
|
-
/* eslint-disable no-bitwise */
|
|
8
|
-
|
|
9
7
|
// "0-9a-zA-Z-_", same as base64url alphabet
|
|
10
8
|
const urlAlphabet = 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict'
|
|
11
9
|
|
|
@@ -16,6 +14,7 @@ export type NanoidFunction = (length?: number) => string
|
|
|
16
14
|
|
|
17
15
|
type NanoidRandomFunction = (bytes: number) => Uint8Array
|
|
18
16
|
|
|
17
|
+
// oxlint-disable no-bitwise -- NanoID uses bit operations to build compact IDs
|
|
19
18
|
export function nanoidBrowser(length = 21): string {
|
|
20
19
|
let id = ''
|
|
21
20
|
const bytes = globalThis.crypto.getRandomValues(new Uint8Array(length))
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
/* eslint-disable no-bitwise */
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Function that returns a random number between 0 and 1.
|
|
5
3
|
* Exactly same signature as Math.random function.
|
|
@@ -13,6 +11,7 @@ export type RandomFunction = () => number
|
|
|
13
11
|
*/
|
|
14
12
|
export function _createDeterministicRandom(seed = 0x2f6e2b1): RandomFunction {
|
|
15
13
|
return () => {
|
|
14
|
+
// oxlint-disable no-bitwise
|
|
16
15
|
// Robert Jenkins’ 32 bit integer hash function
|
|
17
16
|
seed = (seed + 0x7ed55d16 + (seed << 12)) & 0xffffffff
|
|
18
17
|
seed = (seed ^ 0xc761c23c ^ (seed >>> 19)) & 0xffffffff
|
package/src/string/hash.util.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Integer } from '../types.js'
|
|
2
2
|
|
|
3
|
+
// oxlint-disable no-bitwise -- hash implementations use bit-level operations for speed
|
|
4
|
+
|
|
3
5
|
const BASE62 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
|
4
6
|
// const BASE64 = BASE62 + '+/'
|
|
5
7
|
const BASE64URL = BASE62 + '-_'
|
|
@@ -54,7 +56,7 @@ export function hashCode(s: string): Integer {
|
|
|
54
56
|
let i = 0
|
|
55
57
|
const len = s.length
|
|
56
58
|
while (i < len) {
|
|
57
|
-
// eslint-disable-next-line
|
|
59
|
+
// eslint-disable-next-line unicorn/prefer-math-trunc, unicorn/prefer-code-point
|
|
58
60
|
hash = ((hash << 5) - hash + s.charCodeAt(i++)) << 0
|
|
59
61
|
}
|
|
60
62
|
return hash + 2147483647 + 1
|
package/src/string/leven.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
const array: number[] = []
|
|
2
2
|
const characterCodeCache: number[] = []
|
|
3
3
|
|
|
4
|
-
/* eslint-disable unicorn/prefer-code-point
|
|
4
|
+
/* eslint-disable unicorn/prefer-code-point */
|
|
5
|
+
// oxlint-disable no-bitwise
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Modified version of: https://github.com/sindresorhus/leven/
|
|
@@ -20,7 +20,6 @@ export function _safeJsonStringify(
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
/* eslint-disable no-bitwise, no-implicit-coercion */
|
|
24
23
|
// oxlint-disable no-unused-expressions
|
|
25
24
|
function serializer(replacer?: Reviver, cycleReplacer?: Reviver): Reviver {
|
|
26
25
|
const stack: any[] = []
|
|
@@ -34,9 +33,15 @@ function serializer(replacer?: Reviver, cycleReplacer?: Reviver): Reviver {
|
|
|
34
33
|
return function (key, value) {
|
|
35
34
|
if (stack.length > 0) {
|
|
36
35
|
const thisPos = stack.indexOf(this)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
if (thisPos !== -1) {
|
|
37
|
+
stack.splice(thisPos + 1)
|
|
38
|
+
keys.splice(thisPos, Infinity, key)
|
|
39
|
+
} else {
|
|
40
|
+
stack.push(this)
|
|
41
|
+
keys.push(key)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (stack.includes(value)) {
|
|
40
45
|
value = cycleReplacer.call(this, key, value)
|
|
41
46
|
}
|
|
42
47
|
} else {
|