@naturalcycles/nodejs-lib 15.34.0 → 15.36.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/stream/index.d.ts +1 -0
- package/dist/stream/index.js +1 -0
- package/dist/stream/writable/writableChunk.d.ts +15 -0
- package/dist/stream/writable/writableChunk.js +83 -0
- package/dist/validation/ajv/ajvSchema.d.ts +13 -7
- package/dist/validation/ajv/ajvSchema.js +31 -19
- package/package.json +1 -1
- package/src/stream/index.ts +1 -0
- package/src/stream/writable/writableChunk.ts +104 -0
- package/src/validation/ajv/ajvSchema.ts +43 -26
package/dist/stream/index.d.ts
CHANGED
|
@@ -26,5 +26,6 @@ export * from './transform/transformThrottle.js';
|
|
|
26
26
|
export * from './transform/worker/baseWorkerClass.js';
|
|
27
27
|
export * from './transform/worker/transformMultiThreaded.js';
|
|
28
28
|
export * from './transform/worker/transformMultiThreaded.model.js';
|
|
29
|
+
export * from './writable/writableChunk.js';
|
|
29
30
|
export * from './writable/writablePushToArray.js';
|
|
30
31
|
export * from './writable/writableVoid.js';
|
package/dist/stream/index.js
CHANGED
|
@@ -26,5 +26,6 @@ export * from './transform/transformThrottle.js';
|
|
|
26
26
|
export * from './transform/worker/baseWorkerClass.js';
|
|
27
27
|
export * from './transform/worker/transformMultiThreaded.js';
|
|
28
28
|
export * from './transform/worker/transformMultiThreaded.model.js';
|
|
29
|
+
export * from './writable/writableChunk.js';
|
|
29
30
|
export * from './writable/writablePushToArray.js';
|
|
30
31
|
export * from './writable/writableVoid.js';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Predicate } from '@naturalcycles/js-lib/types';
|
|
2
|
+
import { type TransformOptions, type TransformTyped, type WritableTyped } from '../index.js';
|
|
3
|
+
export interface WritableChunkOptions<T> extends TransformOptions {
|
|
4
|
+
splitPredicate: Predicate<T>;
|
|
5
|
+
transformFactories?: (() => TransformTyped<T, T>)[];
|
|
6
|
+
writableFactory: (splitIndex: number) => WritableTyped<T>;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Allows to split the output to multiple files by splitting into chunks
|
|
10
|
+
* based on `shouldSplitFn`.
|
|
11
|
+
* `transformFactories` are used to create a chain of transforms for each chunk.
|
|
12
|
+
* It was meant to be used with createGzip, which needs a proper start and end for each chunk
|
|
13
|
+
* for the output file to be a valid gzip file.
|
|
14
|
+
*/
|
|
15
|
+
export declare function writableChunk<T>(opt: WritableChunkOptions<T>): WritableTyped<T>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Writable } from 'node:stream';
|
|
2
|
+
import { _first, _last } from '@naturalcycles/js-lib/array';
|
|
3
|
+
import { createCommonLoggerAtLevel } from '@naturalcycles/js-lib/log';
|
|
4
|
+
import { _deepCopy } from '@naturalcycles/js-lib/object';
|
|
5
|
+
import { transformNoOp, } from '../index.js';
|
|
6
|
+
/**
|
|
7
|
+
* Allows to split the output to multiple files by splitting into chunks
|
|
8
|
+
* based on `shouldSplitFn`.
|
|
9
|
+
* `transformFactories` are used to create a chain of transforms for each chunk.
|
|
10
|
+
* It was meant to be used with createGzip, which needs a proper start and end for each chunk
|
|
11
|
+
* for the output file to be a valid gzip file.
|
|
12
|
+
*/
|
|
13
|
+
export function writableChunk(opt) {
|
|
14
|
+
const { highWaterMark, splitPredicate, transformFactories = [], writableFactory } = opt;
|
|
15
|
+
const logger = createCommonLoggerAtLevel(opt.logger, opt.logLevel);
|
|
16
|
+
let indexWritten = 0;
|
|
17
|
+
let currentSplitIndex = 0;
|
|
18
|
+
// We don't want to have an empty chain, so we add a no-op transform
|
|
19
|
+
if (transformFactories.length === 0) {
|
|
20
|
+
transformFactories.push((transformNoOp));
|
|
21
|
+
}
|
|
22
|
+
// Create the transforms as well as the Writable, and pipe them together
|
|
23
|
+
let currentWritable = writableFactory(currentSplitIndex);
|
|
24
|
+
let transforms = transformFactories.map(f => f());
|
|
25
|
+
generateTuples(transforms).forEach(([t1, t2]) => t1.pipe(t2));
|
|
26
|
+
_last(transforms).pipe(currentWritable);
|
|
27
|
+
// We keep track of all the pending writables, so we can await them in the final method
|
|
28
|
+
const writablesFinish = [awaitFinish(currentWritable)];
|
|
29
|
+
return new Writable({
|
|
30
|
+
objectMode: true,
|
|
31
|
+
highWaterMark,
|
|
32
|
+
write(chunk, _, cb) {
|
|
33
|
+
// pipe will take care of piping the data through the different streams correctly
|
|
34
|
+
transforms[0].write(chunk, cb);
|
|
35
|
+
if (splitPredicate(chunk, ++indexWritten)) {
|
|
36
|
+
logger.log(`writableChunk: splitting at index ${currentSplitIndex}`);
|
|
37
|
+
currentSplitIndex++;
|
|
38
|
+
transforms[0].end();
|
|
39
|
+
currentWritable = writableFactory(currentSplitIndex);
|
|
40
|
+
transforms = transformFactories.map(f => f());
|
|
41
|
+
generateTuples(transforms).forEach(([t1, t2]) => t1.pipe(t2));
|
|
42
|
+
_last(transforms).pipe(currentWritable);
|
|
43
|
+
writablesFinish.push(awaitFinish(currentWritable));
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
async final(cb) {
|
|
47
|
+
try {
|
|
48
|
+
transforms[0].end();
|
|
49
|
+
await Promise.all(writablesFinish);
|
|
50
|
+
logger.log('writableChunk: all writables are finished');
|
|
51
|
+
cb();
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
cb(err);
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* This is a helper function to create a promise which resolves when the stream emits a 'finish'
|
|
61
|
+
* event.
|
|
62
|
+
* This is used to await all the writables in the final method of the writableChunk
|
|
63
|
+
*/
|
|
64
|
+
async function awaitFinish(stream) {
|
|
65
|
+
return await new Promise(resolve => {
|
|
66
|
+
stream.on('finish', resolve);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Generates an array of [arr[i], arr[i+1]] tuples from the input array.
|
|
71
|
+
* The resulting array will have a length of `arr.length - 1`.
|
|
72
|
+
* ```ts
|
|
73
|
+
* generateTuples([1, 2, 3, 4]) // [[1, 2], [2, 3], [3, 4]]
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
function generateTuples(arr) {
|
|
77
|
+
const tuples = [];
|
|
78
|
+
const arrCopy = _deepCopy(arr);
|
|
79
|
+
for (let i = 1; i < arrCopy.length; i++) {
|
|
80
|
+
tuples.push([arrCopy[i - 1], arrCopy[i]]);
|
|
81
|
+
}
|
|
82
|
+
return tuples;
|
|
83
|
+
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { type ValidationFunction, type ValidationFunctionResult } from '@naturalcycles/js-lib';
|
|
2
2
|
import type { JsonSchema, JsonSchemaBuilder } from '@naturalcycles/js-lib/json-schema';
|
|
3
|
+
import type { AnyObject } from '@naturalcycles/js-lib/types';
|
|
3
4
|
import { ZodType } from '@naturalcycles/js-lib/zod';
|
|
4
5
|
import type { Ajv } from 'ajv';
|
|
5
6
|
import { AjvValidationError } from './ajvValidationError.js';
|
|
7
|
+
export type SchemaHandledByAjv<T> = JsonSchemaBuilder<T> | JsonSchema<T> | AjvSchema<T> | ZodType<T>;
|
|
6
8
|
export interface AjvValidationOptions {
|
|
7
9
|
/**
|
|
8
10
|
* Defaults to true,
|
|
@@ -63,11 +65,15 @@ export declare class AjvSchema<T = unknown> {
|
|
|
63
65
|
* Implementation note: JsonSchemaBuilder goes first in the union type, otherwise TypeScript fails to infer <T> type
|
|
64
66
|
* correctly for some reason.
|
|
65
67
|
*/
|
|
66
|
-
static create<T>(schema:
|
|
68
|
+
static create<T>(schema: SchemaHandledByAjv<T>, cfg?: Partial<AjvSchemaCfg>): AjvSchema<T>;
|
|
67
69
|
/**
|
|
68
|
-
* @
|
|
70
|
+
* @deprecated
|
|
71
|
+
*
|
|
72
|
+
* Use `AjvSchema.create`
|
|
69
73
|
*/
|
|
70
74
|
static createFromZod<T>(zodSchema: ZodType<T>, cfg?: Partial<AjvSchemaCfg>): AjvSchema<T>;
|
|
75
|
+
static isJsonSchemaBuilder<T>(schema: unknown): schema is JsonSchemaBuilder<T>;
|
|
76
|
+
static isZodSchema<T>(schema: unknown): schema is ZodType<T>;
|
|
71
77
|
readonly cfg: AjvSchemaCfg;
|
|
72
78
|
/**
|
|
73
79
|
* It returns the original object just for convenience.
|
|
@@ -81,12 +87,12 @@ export declare class AjvSchema<T = unknown> {
|
|
|
81
87
|
isValid(input: T, opt?: AjvValidationOptions): boolean;
|
|
82
88
|
getValidationResult(input: T, opt?: AjvValidationOptions): ValidationFunctionResult<T, AjvValidationError>;
|
|
83
89
|
getValidationFunction(): ValidationFunction<T, AjvValidationError>;
|
|
84
|
-
static
|
|
85
|
-
static
|
|
86
|
-
static
|
|
90
|
+
static isSchemaWithCachedAjvSchema<Base, T>(schema: Base): schema is WithCachedAjvSchema<Base, T>;
|
|
91
|
+
static cacheAjvSchema<Base extends AnyObject, T>(schema: Base, ajvSchema: AjvSchema<T>): WithCachedAjvSchema<Base, T>;
|
|
92
|
+
static requireCachedAjvSchema<Base, T>(schema: WithCachedAjvSchema<Base, T>): AjvSchema<T>;
|
|
87
93
|
private getAJVValidateFunction;
|
|
88
94
|
}
|
|
89
95
|
export declare const HIDDEN_AJV_SCHEMA: unique symbol;
|
|
90
|
-
export
|
|
96
|
+
export type WithCachedAjvSchema<Base, T> = Base & {
|
|
91
97
|
[HIDDEN_AJV_SCHEMA]: AjvSchema<T>;
|
|
92
|
-
}
|
|
98
|
+
};
|
|
@@ -46,24 +46,36 @@ export class AjvSchema {
|
|
|
46
46
|
static create(schema, cfg) {
|
|
47
47
|
if (schema instanceof AjvSchema)
|
|
48
48
|
return schema;
|
|
49
|
-
if (schema
|
|
50
|
-
return
|
|
49
|
+
if (AjvSchema.isSchemaWithCachedAjvSchema(schema)) {
|
|
50
|
+
return AjvSchema.requireCachedAjvSchema(schema);
|
|
51
51
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
let jsonSchema;
|
|
53
|
+
if (AjvSchema.isJsonSchemaBuilder(schema)) {
|
|
54
|
+
jsonSchema = schema.build();
|
|
55
|
+
}
|
|
56
|
+
else if (AjvSchema.isZodSchema(schema)) {
|
|
57
|
+
jsonSchema = z.toJSONSchema(schema, { target: 'draft-7' });
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
jsonSchema = schema;
|
|
61
|
+
}
|
|
62
|
+
const ajvSchema = new AjvSchema(jsonSchema, cfg);
|
|
63
|
+
AjvSchema.cacheAjvSchema(schema, ajvSchema);
|
|
64
|
+
return ajvSchema;
|
|
55
65
|
}
|
|
56
66
|
/**
|
|
57
|
-
* @
|
|
67
|
+
* @deprecated
|
|
68
|
+
*
|
|
69
|
+
* Use `AjvSchema.create`
|
|
58
70
|
*/
|
|
59
71
|
static createFromZod(zodSchema, cfg) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
return
|
|
72
|
+
return AjvSchema.create(zodSchema, cfg);
|
|
73
|
+
}
|
|
74
|
+
static isJsonSchemaBuilder(schema) {
|
|
75
|
+
return schema instanceof JsonSchemaAnyBuilder;
|
|
76
|
+
}
|
|
77
|
+
static isZodSchema(schema) {
|
|
78
|
+
return schema instanceof ZodType;
|
|
67
79
|
}
|
|
68
80
|
cfg;
|
|
69
81
|
/**
|
|
@@ -121,14 +133,14 @@ export class AjvSchema {
|
|
|
121
133
|
});
|
|
122
134
|
};
|
|
123
135
|
}
|
|
124
|
-
static
|
|
125
|
-
return !!schema[HIDDEN_AJV_SCHEMA];
|
|
136
|
+
static isSchemaWithCachedAjvSchema(schema) {
|
|
137
|
+
return !!schema?.[HIDDEN_AJV_SCHEMA];
|
|
126
138
|
}
|
|
127
|
-
static
|
|
128
|
-
return Object.assign(
|
|
139
|
+
static cacheAjvSchema(schema, ajvSchema) {
|
|
140
|
+
return Object.assign(schema, { [HIDDEN_AJV_SCHEMA]: ajvSchema });
|
|
129
141
|
}
|
|
130
|
-
static
|
|
131
|
-
return
|
|
142
|
+
static requireCachedAjvSchema(schema) {
|
|
143
|
+
return schema[HIDDEN_AJV_SCHEMA];
|
|
132
144
|
}
|
|
133
145
|
getAJVValidateFunction = _lazyValue(() => this.cfg.ajv.compile(this.schema));
|
|
134
146
|
}
|
package/package.json
CHANGED
package/src/stream/index.ts
CHANGED
|
@@ -26,5 +26,6 @@ export * from './transform/transformThrottle.js'
|
|
|
26
26
|
export * from './transform/worker/baseWorkerClass.js'
|
|
27
27
|
export * from './transform/worker/transformMultiThreaded.js'
|
|
28
28
|
export * from './transform/worker/transformMultiThreaded.model.js'
|
|
29
|
+
export * from './writable/writableChunk.js'
|
|
29
30
|
export * from './writable/writablePushToArray.js'
|
|
30
31
|
export * from './writable/writableVoid.js'
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { Writable } from 'node:stream'
|
|
2
|
+
import { _first, _last } from '@naturalcycles/js-lib/array'
|
|
3
|
+
import { createCommonLoggerAtLevel } from '@naturalcycles/js-lib/log'
|
|
4
|
+
import { _deepCopy } from '@naturalcycles/js-lib/object'
|
|
5
|
+
import type { Predicate } from '@naturalcycles/js-lib/types'
|
|
6
|
+
import {
|
|
7
|
+
transformNoOp,
|
|
8
|
+
type TransformOptions,
|
|
9
|
+
type TransformTyped,
|
|
10
|
+
type WritableTyped,
|
|
11
|
+
} from '../index.js'
|
|
12
|
+
|
|
13
|
+
export interface WritableChunkOptions<T> extends TransformOptions {
|
|
14
|
+
splitPredicate: Predicate<T>
|
|
15
|
+
transformFactories?: (() => TransformTyped<T, T>)[]
|
|
16
|
+
writableFactory: (splitIndex: number) => WritableTyped<T>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Allows to split the output to multiple files by splitting into chunks
|
|
21
|
+
* based on `shouldSplitFn`.
|
|
22
|
+
* `transformFactories` are used to create a chain of transforms for each chunk.
|
|
23
|
+
* It was meant to be used with createGzip, which needs a proper start and end for each chunk
|
|
24
|
+
* for the output file to be a valid gzip file.
|
|
25
|
+
*/
|
|
26
|
+
export function writableChunk<T>(opt: WritableChunkOptions<T>): WritableTyped<T> {
|
|
27
|
+
const { highWaterMark, splitPredicate, transformFactories = [], writableFactory } = opt
|
|
28
|
+
const logger = createCommonLoggerAtLevel(opt.logger, opt.logLevel)
|
|
29
|
+
|
|
30
|
+
let indexWritten = 0
|
|
31
|
+
let currentSplitIndex = 0
|
|
32
|
+
// We don't want to have an empty chain, so we add a no-op transform
|
|
33
|
+
if (transformFactories.length === 0) {
|
|
34
|
+
transformFactories.push(transformNoOp<T>)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Create the transforms as well as the Writable, and pipe them together
|
|
38
|
+
let currentWritable = writableFactory(currentSplitIndex)
|
|
39
|
+
let transforms = transformFactories.map(f => f())
|
|
40
|
+
generateTuples(transforms).forEach(([t1, t2]) => t1.pipe(t2))
|
|
41
|
+
_last(transforms).pipe(currentWritable)
|
|
42
|
+
|
|
43
|
+
// We keep track of all the pending writables, so we can await them in the final method
|
|
44
|
+
const writablesFinish: Promise<void>[] = [awaitFinish(currentWritable)]
|
|
45
|
+
|
|
46
|
+
return new Writable({
|
|
47
|
+
objectMode: true,
|
|
48
|
+
highWaterMark,
|
|
49
|
+
write(chunk: T, _, cb) {
|
|
50
|
+
// pipe will take care of piping the data through the different streams correctly
|
|
51
|
+
transforms[0]!.write(chunk, cb)
|
|
52
|
+
|
|
53
|
+
if (splitPredicate(chunk, ++indexWritten)) {
|
|
54
|
+
logger.log(`writableChunk: splitting at index ${currentSplitIndex}`)
|
|
55
|
+
currentSplitIndex++
|
|
56
|
+
transforms[0]!.end()
|
|
57
|
+
|
|
58
|
+
currentWritable = writableFactory(currentSplitIndex)
|
|
59
|
+
transforms = transformFactories.map(f => f())
|
|
60
|
+
generateTuples(transforms).forEach(([t1, t2]) => t1.pipe(t2))
|
|
61
|
+
_last(transforms).pipe(currentWritable)
|
|
62
|
+
|
|
63
|
+
writablesFinish.push(awaitFinish(currentWritable))
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
async final(cb) {
|
|
67
|
+
try {
|
|
68
|
+
transforms[0]!.end()
|
|
69
|
+
await Promise.all(writablesFinish)
|
|
70
|
+
logger.log('writableChunk: all writables are finished')
|
|
71
|
+
cb()
|
|
72
|
+
} catch (err) {
|
|
73
|
+
cb(err as Error)
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* This is a helper function to create a promise which resolves when the stream emits a 'finish'
|
|
81
|
+
* event.
|
|
82
|
+
* This is used to await all the writables in the final method of the writableChunk
|
|
83
|
+
*/
|
|
84
|
+
async function awaitFinish(stream: Writable): Promise<void> {
|
|
85
|
+
return await new Promise(resolve => {
|
|
86
|
+
stream.on('finish', resolve)
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Generates an array of [arr[i], arr[i+1]] tuples from the input array.
|
|
92
|
+
* The resulting array will have a length of `arr.length - 1`.
|
|
93
|
+
* ```ts
|
|
94
|
+
* generateTuples([1, 2, 3, 4]) // [[1, 2], [2, 3], [3, 4]]
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
function generateTuples<T>(arr: T[]): [T, T][] {
|
|
98
|
+
const tuples: [T, T][] = []
|
|
99
|
+
const arrCopy = _deepCopy(arr)
|
|
100
|
+
for (let i = 1; i < arrCopy.length; i++) {
|
|
101
|
+
tuples.push([arrCopy[i - 1]!, arrCopy[i]!])
|
|
102
|
+
}
|
|
103
|
+
return tuples
|
|
104
|
+
}
|
|
@@ -8,12 +8,15 @@ import type { JsonSchema, JsonSchemaBuilder } from '@naturalcycles/js-lib/json-s
|
|
|
8
8
|
import { JsonSchemaAnyBuilder } from '@naturalcycles/js-lib/json-schema'
|
|
9
9
|
import { _deepCopy, _filterNullishValues } from '@naturalcycles/js-lib/object'
|
|
10
10
|
import { _substringBefore } from '@naturalcycles/js-lib/string'
|
|
11
|
+
import type { AnyObject } from '@naturalcycles/js-lib/types'
|
|
11
12
|
import { z, ZodType } from '@naturalcycles/js-lib/zod'
|
|
12
13
|
import type { Ajv } from 'ajv'
|
|
13
14
|
import { _inspect } from '../../string/inspect.js'
|
|
14
15
|
import { AjvValidationError } from './ajvValidationError.js'
|
|
15
16
|
import { getAjv } from './getAjv.js'
|
|
16
17
|
|
|
18
|
+
export type SchemaHandledByAjv<T> = JsonSchemaBuilder<T> | JsonSchema<T> | AjvSchema<T> | ZodType<T>
|
|
19
|
+
|
|
17
20
|
export interface AjvValidationOptions {
|
|
18
21
|
/**
|
|
19
22
|
* Defaults to true,
|
|
@@ -104,32 +107,44 @@ export class AjvSchema<T = unknown> {
|
|
|
104
107
|
* Implementation note: JsonSchemaBuilder goes first in the union type, otherwise TypeScript fails to infer <T> type
|
|
105
108
|
* correctly for some reason.
|
|
106
109
|
*/
|
|
107
|
-
static create<T>(
|
|
108
|
-
schema: JsonSchemaBuilder<T> | JsonSchema<T> | AjvSchema<T> | ZodType<T>,
|
|
109
|
-
cfg?: Partial<AjvSchemaCfg>,
|
|
110
|
-
): AjvSchema<T> {
|
|
110
|
+
static create<T>(schema: SchemaHandledByAjv<T>, cfg?: Partial<AjvSchemaCfg>): AjvSchema<T> {
|
|
111
111
|
if (schema instanceof AjvSchema) return schema
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
|
|
113
|
+
if (AjvSchema.isSchemaWithCachedAjvSchema<typeof schema, T>(schema)) {
|
|
114
|
+
return AjvSchema.requireCachedAjvSchema<typeof schema, T>(schema)
|
|
114
115
|
}
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
|
|
117
|
+
let jsonSchema: JsonSchema<T>
|
|
118
|
+
|
|
119
|
+
if (AjvSchema.isJsonSchemaBuilder(schema)) {
|
|
120
|
+
jsonSchema = schema.build()
|
|
121
|
+
} else if (AjvSchema.isZodSchema(schema)) {
|
|
122
|
+
jsonSchema = z.toJSONSchema(schema, { target: 'draft-7' }) as JsonSchema<T>
|
|
123
|
+
} else {
|
|
124
|
+
jsonSchema = schema
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const ajvSchema = new AjvSchema<T>(jsonSchema, cfg)
|
|
128
|
+
AjvSchema.cacheAjvSchema(schema, ajvSchema)
|
|
129
|
+
|
|
130
|
+
return ajvSchema
|
|
117
131
|
}
|
|
118
132
|
|
|
119
133
|
/**
|
|
120
|
-
* @
|
|
134
|
+
* @deprecated
|
|
135
|
+
*
|
|
136
|
+
* Use `AjvSchema.create`
|
|
121
137
|
*/
|
|
122
138
|
static createFromZod<T>(zodSchema: ZodType<T>, cfg?: Partial<AjvSchemaCfg>): AjvSchema<T> {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const jsonSchema = z.toJSONSchema(zodSchema, { target: 'draft-7' })
|
|
128
|
-
const ajvSchema = new AjvSchema<T>(jsonSchema as JsonSchema<T>, cfg)
|
|
139
|
+
return AjvSchema.create(zodSchema, cfg)
|
|
140
|
+
}
|
|
129
141
|
|
|
130
|
-
|
|
142
|
+
static isJsonSchemaBuilder<T>(schema: unknown): schema is JsonSchemaBuilder<T> {
|
|
143
|
+
return schema instanceof JsonSchemaAnyBuilder
|
|
144
|
+
}
|
|
131
145
|
|
|
132
|
-
|
|
146
|
+
static isZodSchema<T>(schema: unknown): schema is ZodType<T> {
|
|
147
|
+
return schema instanceof ZodType
|
|
133
148
|
}
|
|
134
149
|
|
|
135
150
|
readonly cfg: AjvSchemaCfg
|
|
@@ -208,19 +223,21 @@ export class AjvSchema<T = unknown> {
|
|
|
208
223
|
}
|
|
209
224
|
}
|
|
210
225
|
|
|
211
|
-
static
|
|
212
|
-
|
|
226
|
+
static isSchemaWithCachedAjvSchema<Base, T>(
|
|
227
|
+
schema: Base,
|
|
228
|
+
): schema is WithCachedAjvSchema<Base, T> {
|
|
229
|
+
return !!(schema as any)?.[HIDDEN_AJV_SCHEMA]
|
|
213
230
|
}
|
|
214
231
|
|
|
215
|
-
static
|
|
216
|
-
|
|
232
|
+
static cacheAjvSchema<Base extends AnyObject, T>(
|
|
233
|
+
schema: Base,
|
|
217
234
|
ajvSchema: AjvSchema<T>,
|
|
218
|
-
):
|
|
219
|
-
return Object.assign(
|
|
235
|
+
): WithCachedAjvSchema<Base, T> {
|
|
236
|
+
return Object.assign(schema, { [HIDDEN_AJV_SCHEMA]: ajvSchema })
|
|
220
237
|
}
|
|
221
238
|
|
|
222
|
-
static
|
|
223
|
-
return
|
|
239
|
+
static requireCachedAjvSchema<Base, T>(schema: WithCachedAjvSchema<Base, T>): AjvSchema<T> {
|
|
240
|
+
return schema[HIDDEN_AJV_SCHEMA]
|
|
224
241
|
}
|
|
225
242
|
|
|
226
243
|
private getAJVValidateFunction = _lazyValue(() => this.cfg.ajv.compile<T>(this.schema))
|
|
@@ -230,6 +247,6 @@ const separator = '\n'
|
|
|
230
247
|
|
|
231
248
|
export const HIDDEN_AJV_SCHEMA = Symbol('HIDDEN_AJV_SCHEMA')
|
|
232
249
|
|
|
233
|
-
export
|
|
250
|
+
export type WithCachedAjvSchema<Base, T> = Base & {
|
|
234
251
|
[HIDDEN_AJV_SCHEMA]: AjvSchema<T>
|
|
235
252
|
}
|