@x0k/json-schema-merge 1.0.4 → 1.0.6
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/lib/json-schema/merge/merge.d.ts.map +1 -1
- package/dist/lib/json-schema/merge/merge.js +41 -1
- package/dist/lib/json-schema/merge/merge.js.map +1 -1
- package/package.json +7 -2
- package/src/index.ts +1 -0
- package/src/lib/array.ts +172 -0
- package/src/lib/function.ts +3 -0
- package/src/lib/json-schema/compare/compare.ts +343 -0
- package/src/lib/json-schema/compare/index.ts +1 -0
- package/src/lib/json-schema/index.ts +5 -0
- package/src/lib/json-schema/json-schema.ts +113 -0
- package/src/lib/json-schema/merge/all-of-merge.ts +44 -0
- package/src/lib/json-schema/merge/index.ts +3 -0
- package/src/lib/json-schema/merge/merge.ts +922 -0
- package/src/lib/json-schema/merge/patterns.ts +7 -0
- package/src/lib/json-schema/transform.ts +99 -0
- package/src/lib/json-schema/traverse.ts +61 -0
- package/src/lib/math.ts +3 -0
- package/src/lib/memoize.ts +24 -0
- package/src/lib/object.ts +16 -0
- package/src/lib/ord.ts +16 -0
- package/src/lib/traverser.ts +4 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
JSONSchema7 as Schema,
|
|
3
|
+
JSONSchema7Definition as SchemaDefinition,
|
|
4
|
+
} from "json-schema";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
SUB_SCHEMAS,
|
|
8
|
+
RECORDS_OF_SUB_SCHEMAS,
|
|
9
|
+
ARRAYS_OF_SUB_SCHEMAS,
|
|
10
|
+
isSchemaObject,
|
|
11
|
+
type AnySubSchemaKey,
|
|
12
|
+
type TransformedSchemaDefinition,
|
|
13
|
+
type TransformedSchema,
|
|
14
|
+
} from "./json-schema.ts";
|
|
15
|
+
import type {
|
|
16
|
+
ArraySchemaTraverserContext,
|
|
17
|
+
RecordSchemaTraverserContext,
|
|
18
|
+
SchemaTraverserContext,
|
|
19
|
+
SubSchemaTraverserContext,
|
|
20
|
+
} from "./traverse.ts";
|
|
21
|
+
|
|
22
|
+
export function transformSchemaDefinition<R>(
|
|
23
|
+
schema: SchemaDefinition,
|
|
24
|
+
transform: (
|
|
25
|
+
shallowCopy: TransformedSchemaDefinition<R, Schema>,
|
|
26
|
+
ctx: SchemaTraverserContext<AnySubSchemaKey>
|
|
27
|
+
) => R,
|
|
28
|
+
ctx: SchemaTraverserContext<AnySubSchemaKey> = { type: "root", path: [] }
|
|
29
|
+
): R {
|
|
30
|
+
if (!isSchemaObject(schema)) {
|
|
31
|
+
return transform(schema, ctx);
|
|
32
|
+
}
|
|
33
|
+
const shallowCopy = {
|
|
34
|
+
...schema,
|
|
35
|
+
} as TransformedSchema<R, Schema>;
|
|
36
|
+
for (const key of ARRAYS_OF_SUB_SCHEMAS) {
|
|
37
|
+
const array = schema[key];
|
|
38
|
+
if (array === undefined || !Array.isArray(array)) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const c: ArraySchemaTraverserContext<AnySubSchemaKey> = {
|
|
42
|
+
type: "array",
|
|
43
|
+
parent: schema,
|
|
44
|
+
key,
|
|
45
|
+
index: 0,
|
|
46
|
+
path: ctx.path.concat(key, 0),
|
|
47
|
+
};
|
|
48
|
+
shallowCopy[key] = array.map((item, index) => {
|
|
49
|
+
c.index = index;
|
|
50
|
+
c.path[c.path.length - 1] = index;
|
|
51
|
+
return transformSchemaDefinition(item, transform, c);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
const map = new Map<string, R | string[]>();
|
|
55
|
+
for (const key of RECORDS_OF_SUB_SCHEMAS) {
|
|
56
|
+
const record = schema[key];
|
|
57
|
+
if (record === undefined) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const c: RecordSchemaTraverserContext<AnySubSchemaKey> = {
|
|
61
|
+
type: "record",
|
|
62
|
+
parent: schema,
|
|
63
|
+
key,
|
|
64
|
+
property: "",
|
|
65
|
+
path: ctx.path.concat(key, ""),
|
|
66
|
+
};
|
|
67
|
+
const keys = Object.keys(record);
|
|
68
|
+
const keysLen = keys.length;
|
|
69
|
+
for (let i = 0; i < keysLen; i++) {
|
|
70
|
+
const property = keys[i]!;
|
|
71
|
+
const value = record[property]!;
|
|
72
|
+
if (Array.isArray(value)) {
|
|
73
|
+
map.set(property, value);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
c.property = property;
|
|
77
|
+
c.path[c.path.length - 1] = property;
|
|
78
|
+
map.set(property, transformSchemaDefinition(value, transform, c));
|
|
79
|
+
}
|
|
80
|
+
shallowCopy[key] = Object.fromEntries(map) as Record<string, R>;
|
|
81
|
+
map.clear();
|
|
82
|
+
}
|
|
83
|
+
const c: SubSchemaTraverserContext<AnySubSchemaKey> = {
|
|
84
|
+
type: "sub",
|
|
85
|
+
parent: schema,
|
|
86
|
+
key: "items",
|
|
87
|
+
path: ctx.path.concat(""),
|
|
88
|
+
};
|
|
89
|
+
for (const key of SUB_SCHEMAS) {
|
|
90
|
+
const value = schema[key];
|
|
91
|
+
if (value === undefined || Array.isArray(value)) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
c.key = key;
|
|
95
|
+
c.path[c.path.length - 1] = key;
|
|
96
|
+
shallowCopy[key] = transformSchemaDefinition(value, transform, c);
|
|
97
|
+
}
|
|
98
|
+
return transform(shallowCopy, ctx);
|
|
99
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
JSONSchema7 as Schema,
|
|
3
|
+
JSONSchema7Definition as SchemaDefinition,
|
|
4
|
+
} from "json-schema";
|
|
5
|
+
|
|
6
|
+
import type { Visitor } from "../traverser.ts";
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
AnySubSchemaKey,
|
|
10
|
+
SubSchemaKey,
|
|
11
|
+
SubSchemasArrayKey,
|
|
12
|
+
SubSchemasRecordKey,
|
|
13
|
+
} from "./json-schema.ts";
|
|
14
|
+
|
|
15
|
+
export type SchemaTraverserContextType = "array" | "record" | "sub" | "root";
|
|
16
|
+
|
|
17
|
+
export interface AbstractSchemaTraverserContext<
|
|
18
|
+
T extends SchemaTraverserContextType,
|
|
19
|
+
K extends AnySubSchemaKey,
|
|
20
|
+
> {
|
|
21
|
+
type: T;
|
|
22
|
+
path: SubSchemasArrayKey extends K ? Array<string | number> : string[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface ArraySchemaTraverserContext<
|
|
26
|
+
K extends AnySubSchemaKey,
|
|
27
|
+
> extends AbstractSchemaTraverserContext<"array", K> {
|
|
28
|
+
parent: Schema;
|
|
29
|
+
key: SubSchemasArrayKey & K;
|
|
30
|
+
index: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface RecordSchemaTraverserContext<
|
|
34
|
+
K extends AnySubSchemaKey,
|
|
35
|
+
> extends AbstractSchemaTraverserContext<"record", K> {
|
|
36
|
+
parent: Schema;
|
|
37
|
+
key: SubSchemasRecordKey & K;
|
|
38
|
+
property: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface SubSchemaTraverserContext<
|
|
42
|
+
K extends AnySubSchemaKey,
|
|
43
|
+
> extends AbstractSchemaTraverserContext<"sub", K> {
|
|
44
|
+
parent: Schema;
|
|
45
|
+
key: SubSchemaKey & K;
|
|
46
|
+
}
|
|
47
|
+
export interface RootSchemaTraverserContext<
|
|
48
|
+
K extends AnySubSchemaKey,
|
|
49
|
+
> extends AbstractSchemaTraverserContext<"root", K> {}
|
|
50
|
+
|
|
51
|
+
export type SchemaTraverserContext<K extends AnySubSchemaKey> =
|
|
52
|
+
| ArraySchemaTraverserContext<K>
|
|
53
|
+
| RecordSchemaTraverserContext<K>
|
|
54
|
+
| SubSchemaTraverserContext<K>
|
|
55
|
+
| RootSchemaTraverserContext<K>;
|
|
56
|
+
|
|
57
|
+
export type SchemaDefinitionVisitor<K extends AnySubSchemaKey, R> = Visitor<
|
|
58
|
+
SchemaDefinition,
|
|
59
|
+
SchemaTraverserContext<K>,
|
|
60
|
+
R
|
|
61
|
+
>;
|
package/src/lib/math.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface MapLike<K, V> {
|
|
2
|
+
has(key: K): boolean;
|
|
3
|
+
get(key: K): V | undefined;
|
|
4
|
+
set(key: K, value: V): void;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function memoize<Arg, Return>(
|
|
8
|
+
cache: MapLike<Arg, Return>,
|
|
9
|
+
func: (arg: Arg) => Return
|
|
10
|
+
): (arg: Arg) => Return {
|
|
11
|
+
return (arg: Arg) => {
|
|
12
|
+
if (cache.has(arg)) {
|
|
13
|
+
return cache.get(arg)!;
|
|
14
|
+
}
|
|
15
|
+
const ret = func(arg);
|
|
16
|
+
cache.set(arg, ret);
|
|
17
|
+
return ret;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const weakMemoize = memoize as <Arg extends object, Return>(
|
|
22
|
+
cache: WeakMap<Arg, Return>,
|
|
23
|
+
fn: (arg: Arg) => Return
|
|
24
|
+
) => (arg: Arg) => Return;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function isObject(value: unknown): value is object {
|
|
2
|
+
return value !== null && typeof value === "object";
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
const objProto = Object.prototype;
|
|
6
|
+
|
|
7
|
+
export function isRecordEmpty<R extends Record<string, any>>(
|
|
8
|
+
rec: R | Record<string, never>
|
|
9
|
+
): rec is Record<string, never> {
|
|
10
|
+
for (const key in rec) {
|
|
11
|
+
if (objProto.hasOwnProperty.call(rec, key)) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return true;
|
|
16
|
+
}
|
package/src/lib/ord.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type Comparator<T> = (a: T, b: T) => number;
|
|
2
|
+
|
|
3
|
+
export interface ComparableTypes {
|
|
4
|
+
number: number;
|
|
5
|
+
string: string;
|
|
6
|
+
boolean: boolean;
|
|
7
|
+
bigint: bigint;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type Comparable = ComparableTypes[keyof ComparableTypes];
|
|
11
|
+
|
|
12
|
+
export function ascComparator<T extends Comparable>(a: T, b: T) {
|
|
13
|
+
if (a < b) return -1;
|
|
14
|
+
if (a > b) return 1;
|
|
15
|
+
return 0;
|
|
16
|
+
}
|