@travetto/schema 6.0.1 → 7.0.0-rc.1
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/README.md +30 -26
- package/__index__.ts +4 -2
- package/package.json +3 -3
- package/src/bind-util.ts +47 -44
- package/src/decorator/common.ts +32 -16
- package/src/decorator/field.ts +21 -184
- package/src/decorator/input.ts +207 -0
- package/src/decorator/method.ts +28 -0
- package/src/decorator/schema.ts +36 -29
- package/src/name.ts +2 -2
- package/src/service/changes.ts +27 -30
- package/src/service/registry-adapter.ts +340 -0
- package/src/service/registry-index.ts +230 -0
- package/src/service/types.ts +113 -63
- package/src/validate/types.ts +4 -0
- package/src/validate/validator.ts +70 -64
- package/support/transformer/util.ts +147 -61
- package/support/transformer.schema.ts +137 -49
- package/src/service/registry.ts +0 -501
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { Any, Class, ClassInstance, getClass } from '@travetto/runtime';
|
|
2
|
+
|
|
3
|
+
import { CommonRegExp } from '../validate/regexp.ts';
|
|
4
|
+
import { CONSTRUCTOR_PROPERTY, SchemaInputConfig } from '../service/types.ts';
|
|
5
|
+
import { SchemaRegistryIndex } from '../service/registry-index.ts';
|
|
6
|
+
|
|
7
|
+
type PropType<V> = (<T extends Partial<Record<K, V | Function>>, K extends string>(t: T, k: K, idx?: TypedPropertyDescriptor<Any> | number) => void);
|
|
8
|
+
|
|
9
|
+
function input<V>(...obj: Partial<SchemaInputConfig>[]): PropType<V> {
|
|
10
|
+
return (instanceOrCls: ClassInstance | Class, property: string | symbol, idx?: number | TypedPropertyDescriptor<Any>): void => {
|
|
11
|
+
const adapter = SchemaRegistryIndex.getForRegister(getClass(instanceOrCls));
|
|
12
|
+
const propertyKey = property ?? CONSTRUCTOR_PROPERTY;
|
|
13
|
+
if (typeof idx === 'number') {
|
|
14
|
+
adapter.registerParameter(propertyKey, idx, ...obj);
|
|
15
|
+
} else {
|
|
16
|
+
adapter.registerField(propertyKey, ...obj);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Registering an input
|
|
23
|
+
* @param type The type for the input
|
|
24
|
+
* @param config The input configuration
|
|
25
|
+
* @augments `@travetto/schema:Input`
|
|
26
|
+
* @kind decorator
|
|
27
|
+
*/
|
|
28
|
+
export function Input(type: Pick<SchemaInputConfig, 'type' | 'array'>, ...config: Partial<SchemaInputConfig>[]): PropType<unknown> {
|
|
29
|
+
return input(type, ...config);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Alias for the input
|
|
34
|
+
* @param aliases List of all aliases for a field
|
|
35
|
+
* @augments `@travetto/schema:Input`
|
|
36
|
+
* @kind decorator
|
|
37
|
+
*/
|
|
38
|
+
export function Alias(...aliases: string[]): PropType<unknown> { return input({ aliases }); }
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Mark an input as required
|
|
42
|
+
* @param active This determines if this field is required or not.
|
|
43
|
+
* @param message The error message when a the constraint fails.
|
|
44
|
+
* @augments `@travetto/schema:Input`
|
|
45
|
+
* @kind decorator
|
|
46
|
+
*/
|
|
47
|
+
export function Required(active = true, message?: string): PropType<unknown> { return input({ required: { active, message } }); }
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Define an input as a set of enumerated values
|
|
51
|
+
* @param values The list of values allowed for the enumeration
|
|
52
|
+
* @param message The error message to show when the constraint fails
|
|
53
|
+
* @augments `@travetto/schema:Input`
|
|
54
|
+
* @kind decorator
|
|
55
|
+
*/
|
|
56
|
+
export function Enum(values: string[], message?: string): PropType<string | number> {
|
|
57
|
+
message = message || `{path} is only allowed to be "${values.join('" or "')}"`;
|
|
58
|
+
return input({ enum: { values, message } });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Mark the input as indicating it's storing textual data
|
|
63
|
+
* @augments `@travetto/schema:Input`
|
|
64
|
+
* @kind decorator
|
|
65
|
+
*/
|
|
66
|
+
export function Text(): PropType<string | string[]> { return input({ specifiers: ['text'] }); }
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Mark the input to indicate it's for long form text
|
|
70
|
+
* @augments `@travetto/schema:Input`
|
|
71
|
+
* @kind decorator
|
|
72
|
+
*/
|
|
73
|
+
export function LongText(): PropType<string | string[]> { return input({ specifiers: ['text', 'long'] }); }
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Require the input to match a specific RegExp
|
|
77
|
+
* @param re The regular expression to match against
|
|
78
|
+
* @param message The message to show when the constraint fails
|
|
79
|
+
* @augments `@travetto/schema:Input`
|
|
80
|
+
* @kind decorator
|
|
81
|
+
*/
|
|
82
|
+
export function Match(re: RegExp, message?: string): PropType<string | string[]> { return input({ match: { re, message } }); }
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* The minimum length for the string or array
|
|
86
|
+
* @param n The minimum length
|
|
87
|
+
* @param message The message to show when the constraint fails
|
|
88
|
+
* @augments `@travetto/schema:Input`
|
|
89
|
+
* @kind decorator
|
|
90
|
+
*/
|
|
91
|
+
export function MinLength(n: number, message?: string): PropType<string | unknown[]> {
|
|
92
|
+
return input({ minlength: { n, message }, ...(n === 0 ? { required: { active: false } } : {}) });
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* The maximum length for the string or array
|
|
97
|
+
* @param n The maximum length
|
|
98
|
+
* @param message The message to show when the constraint fails
|
|
99
|
+
* @augments `@travetto/schema:Input`
|
|
100
|
+
* @kind decorator
|
|
101
|
+
*/
|
|
102
|
+
export function MaxLength(n: number, message?: string): PropType<string | unknown[]> { return input({ maxlength: { n, message } }); }
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* The minimum value
|
|
106
|
+
* @param n The minimum value
|
|
107
|
+
* @param message The message to show when the constraint fails
|
|
108
|
+
* @augments `@travetto/schema:Input`
|
|
109
|
+
* @kind decorator
|
|
110
|
+
*/
|
|
111
|
+
export function Min<T extends number | Date>(n: T, message?: string): PropType<Date | number> {
|
|
112
|
+
return input({ min: { n, message } });
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* The maximum value
|
|
117
|
+
* @param n The maximum value
|
|
118
|
+
* @param message The message to show when the constraint fails
|
|
119
|
+
* @augments `@travetto/schema:Input`
|
|
120
|
+
* @kind decorator
|
|
121
|
+
*/
|
|
122
|
+
export function Max<T extends number | Date>(n: T, message?: string): PropType<Date | number> {
|
|
123
|
+
return input({ max: { n, message } });
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Mark an input as an email
|
|
128
|
+
* @param message The message to show when the constraint fails
|
|
129
|
+
* @augments `@travetto/schema:Input`
|
|
130
|
+
* @kind decorator
|
|
131
|
+
*/
|
|
132
|
+
export function Email(message?: string): PropType<string | string[]> { return Match(CommonRegExp.email, message); }
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Mark an input as an telephone number
|
|
136
|
+
* @param message The message to show when the constraint fails
|
|
137
|
+
* @augments `@travetto/schema:Input`
|
|
138
|
+
* @kind decorator
|
|
139
|
+
*/
|
|
140
|
+
export function Telephone(message?: string): PropType<string | string[]> { return Match(CommonRegExp.telephone, message); }
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Mark an input as a url
|
|
144
|
+
* @param message The message to show when the constraint fails
|
|
145
|
+
* @augments `@travetto/schema:Input`
|
|
146
|
+
* @kind decorator
|
|
147
|
+
*/
|
|
148
|
+
export function Url(message?: string): PropType<string | string[]> { return Match(CommonRegExp.url, message); }
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Determine the numeric precision of the value
|
|
152
|
+
* @param digits The number of digits a number should have
|
|
153
|
+
* @param decimals The number of decimal digits to support
|
|
154
|
+
* @augments `@travetto/schema:Input`
|
|
155
|
+
* @kind decorator
|
|
156
|
+
*/
|
|
157
|
+
export function Precision(digits: number, decimals?: number): PropType<number> { return input({ precision: [digits, decimals] }); }
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Mark a number as an integer
|
|
161
|
+
* @augments `@travetto/schema:Input`
|
|
162
|
+
* @kind decorator
|
|
163
|
+
*/
|
|
164
|
+
export function Integer(): PropType<number> { return Precision(0); }
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Mark a number as a float
|
|
168
|
+
* @augments `@travetto/schema:Input`
|
|
169
|
+
* @kind decorator
|
|
170
|
+
*/
|
|
171
|
+
export function Float(): PropType<number> { return Precision(10, 7); }
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Mark a number as a long value
|
|
175
|
+
* @augments `@travetto/schema:Input`
|
|
176
|
+
* @kind decorator
|
|
177
|
+
*/
|
|
178
|
+
export function Long(): PropType<number> { return Precision(19, 0); }
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Mark a number as a currency
|
|
182
|
+
* @augments `@travetto/schema:Input`
|
|
183
|
+
* @kind decorator
|
|
184
|
+
*/
|
|
185
|
+
export function Currency(): PropType<number> { return Precision(13, 2); }
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Specifier for the input
|
|
189
|
+
* @param specifiers The specifiers for an input
|
|
190
|
+
* @augments `@travetto/schema:Input`
|
|
191
|
+
* @kind decorator
|
|
192
|
+
*/
|
|
193
|
+
export function Specifier(...specifiers: string[]): PropType<unknown> { return input({ specifiers }); }
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Sets the discriminator field via a property decorator
|
|
197
|
+
* @augments `@travetto/schema:Input`
|
|
198
|
+
* @kind decorator
|
|
199
|
+
*/
|
|
200
|
+
export function DiscriminatorField(): ((t: ClassInstance, k: string) => void) {
|
|
201
|
+
return (instance: ClassInstance, property: string): void => {
|
|
202
|
+
SchemaRegistryIndex.getForRegister(getClass(instance)).register({
|
|
203
|
+
discriminatedBase: true,
|
|
204
|
+
discriminatedField: property
|
|
205
|
+
});
|
|
206
|
+
};
|
|
207
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Any, castTo, ClassInstance, getClass } from '@travetto/runtime';
|
|
2
|
+
|
|
3
|
+
import { SchemaMethodConfig } from '../service/types';
|
|
4
|
+
import { SchemaRegistryIndex } from '../service/registry-index';
|
|
5
|
+
import { MethodValidatorFn } from '../validate/types';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Registering a method
|
|
9
|
+
* @param config The method configuration
|
|
10
|
+
* @augments `@travetto/schema:Method`
|
|
11
|
+
* @kind decorator
|
|
12
|
+
*/
|
|
13
|
+
export function Method(...config: Partial<SchemaMethodConfig>[]) {
|
|
14
|
+
return (instanceOrCls: ClassInstance, property: string | symbol): void => {
|
|
15
|
+
SchemaRegistryIndex.getForRegister(getClass(instanceOrCls)).registerMethod(property, ...config);
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Add a custom validator for a given method
|
|
21
|
+
*
|
|
22
|
+
* @param fn The validator function
|
|
23
|
+
* @augments `@travetto/schema:Method`
|
|
24
|
+
* @kind decorator
|
|
25
|
+
*/
|
|
26
|
+
export function MethodValidator<T extends (...args: Any[]) => Any>(fn: MethodValidatorFn<Parameters<T>>): MethodDecorator {
|
|
27
|
+
return Method({ validators: [castTo(fn)] });
|
|
28
|
+
}
|
package/src/decorator/schema.ts
CHANGED
|
@@ -1,22 +1,27 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { castTo, Class, DeepPartial } from '@travetto/runtime';
|
|
2
2
|
|
|
3
3
|
import { BindUtil } from '../bind-util.ts';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { SchemaClassConfig, ViewFieldsConfig } from '../service/types.ts';
|
|
5
|
+
import { ValidatorFn } from '../validate/types.ts';
|
|
6
|
+
import { SchemaRegistryIndex } from '../service/registry-index.ts';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Provides all the valid string type fields from a given type T
|
|
10
|
+
*/
|
|
11
|
+
type ValidStringField<T> = { [K in Extract<keyof T, string>]: T[K] extends string ? K : never }[Extract<keyof T, string>];
|
|
7
12
|
|
|
8
13
|
/**
|
|
9
14
|
* Register a class as a Schema
|
|
10
15
|
*
|
|
11
16
|
* @augments `@travetto/schema:Schema`
|
|
17
|
+
* @kind decorator
|
|
12
18
|
*/
|
|
13
|
-
export function Schema(cfg?: Partial<Pick<
|
|
14
|
-
return <T, U extends Class<T>>(
|
|
15
|
-
|
|
19
|
+
export function Schema(cfg?: Partial<Pick<SchemaClassConfig, 'validators' | 'methods'>>) {
|
|
20
|
+
return <T, U extends Class<T>>(cls: U): void => {
|
|
21
|
+
cls.from ??= function <V>(this: Class<V>, data: DeepPartial<V>, view?: string): V {
|
|
16
22
|
return BindUtil.bindSchema(this, data, { view });
|
|
17
23
|
};
|
|
18
|
-
|
|
19
|
-
return target;
|
|
24
|
+
SchemaRegistryIndex.getForRegister(cls).registerClass(cfg);
|
|
20
25
|
};
|
|
21
26
|
}
|
|
22
27
|
|
|
@@ -24,41 +29,43 @@ export function Schema(cfg?: Partial<Pick<ClassConfig, 'subTypeName' | 'subTypeF
|
|
|
24
29
|
* Add a custom validator, can be at the class level
|
|
25
30
|
*
|
|
26
31
|
* @param fn The validator function
|
|
32
|
+
* @kind decorator
|
|
27
33
|
*/
|
|
28
34
|
export const Validator = <T>(fn: ValidatorFn<T, string>) =>
|
|
29
|
-
(
|
|
30
|
-
|
|
35
|
+
(cls: Class<T>): void => {
|
|
36
|
+
SchemaRegistryIndex.getForRegister(cls).register({ validators: [castTo(fn)] });
|
|
31
37
|
};
|
|
32
38
|
|
|
33
39
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* @param
|
|
40
|
+
* Register a specific view for a class
|
|
41
|
+
* @param name The name of the view
|
|
42
|
+
* @param fields The specific fields to add as part of a view
|
|
43
|
+
* @kind decorator
|
|
37
44
|
*/
|
|
38
|
-
export function
|
|
39
|
-
return (
|
|
40
|
-
|
|
45
|
+
export function View<T>(name: string, fields: ViewFieldsConfig<Partial<T>>) {
|
|
46
|
+
return (cls: Class<Partial<T>>): void => {
|
|
47
|
+
SchemaRegistryIndex.getForRegister(cls).register({ views: { [name]: fields } });
|
|
41
48
|
};
|
|
42
49
|
}
|
|
43
50
|
|
|
44
51
|
/**
|
|
45
|
-
* Register a
|
|
46
|
-
* @param
|
|
47
|
-
* @
|
|
52
|
+
* Register a class as a discriminated class, by a specific type
|
|
53
|
+
* @param type The type to use for discrimination
|
|
54
|
+
* @kind decorator
|
|
48
55
|
*/
|
|
49
|
-
export function
|
|
50
|
-
return (
|
|
51
|
-
|
|
56
|
+
export function SubType<T>(type?: string) {
|
|
57
|
+
return (cls: Class<Partial<T>>): void => {
|
|
58
|
+
SchemaRegistryIndex.getForRegister(cls).register({ discriminatedType: type });
|
|
52
59
|
};
|
|
53
60
|
}
|
|
54
61
|
|
|
55
62
|
/**
|
|
56
|
-
* Register a class as a
|
|
57
|
-
* @param
|
|
58
|
-
* @
|
|
63
|
+
* Register a class as a discriminated class
|
|
64
|
+
* @param field The field to use for discrimination
|
|
65
|
+
* @kind decorator
|
|
59
66
|
*/
|
|
60
|
-
export function
|
|
61
|
-
return (
|
|
62
|
-
|
|
67
|
+
export function Discriminated<T>(field: ValidStringField<T>) {
|
|
68
|
+
return (cls: Class<Partial<T>>): void => {
|
|
69
|
+
SchemaRegistryIndex.getForRegister(cls).register({ discriminatedField: field, discriminatedBase: true });
|
|
63
70
|
};
|
|
64
71
|
}
|
package/src/name.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SchemaClassConfig } from './service/types.ts';
|
|
2
2
|
|
|
3
3
|
const ID_RE = /(\d{1,100})Δ$/;
|
|
4
4
|
|
|
@@ -14,7 +14,7 @@ export class SchemaNameResolver {
|
|
|
14
14
|
this.#digits = digits;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
getName(schema:
|
|
17
|
+
getName(schema: SchemaClassConfig): string {
|
|
18
18
|
const cls = schema.class;
|
|
19
19
|
const id = cls.Ⲑid;
|
|
20
20
|
if (ID_RE.test(cls.name)) {
|
package/src/service/changes.ts
CHANGED
|
@@ -3,27 +3,25 @@ import { EventEmitter } from 'node:events';
|
|
|
3
3
|
import { Class } from '@travetto/runtime';
|
|
4
4
|
import { ChangeEvent } from '@travetto/registry';
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
const id = (c: Class | string): string => typeof c === 'string' ? c : c.Ⲑid;
|
|
6
|
+
import { SchemaFieldConfig, SchemaClassConfig } from './types.ts';
|
|
9
7
|
|
|
10
8
|
interface FieldMapping {
|
|
11
|
-
path:
|
|
12
|
-
config:
|
|
9
|
+
path: SchemaFieldConfig[];
|
|
10
|
+
config: SchemaClassConfig;
|
|
13
11
|
}
|
|
14
12
|
|
|
15
13
|
export interface FieldChangeEvent {
|
|
16
14
|
cls: Class;
|
|
17
|
-
changes: ChangeEvent<
|
|
15
|
+
changes: ChangeEvent<SchemaFieldConfig>[];
|
|
18
16
|
}
|
|
19
17
|
|
|
20
18
|
interface SubSchemaChange {
|
|
21
|
-
path:
|
|
22
|
-
fields: ChangeEvent<
|
|
19
|
+
path: SchemaFieldConfig[];
|
|
20
|
+
fields: ChangeEvent<SchemaFieldConfig>[];
|
|
23
21
|
}
|
|
24
22
|
|
|
25
23
|
export interface SchemaChange {
|
|
26
|
-
config:
|
|
24
|
+
config: SchemaClassConfig;
|
|
27
25
|
subs: SubSchemaChange[];
|
|
28
26
|
}
|
|
29
27
|
|
|
@@ -33,7 +31,7 @@ export interface SchemaChangeEvent {
|
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
/**
|
|
36
|
-
* Schema change listener. Handles all changes that occur via the
|
|
34
|
+
* Schema change listener. Handles all changes that occur via the SchemaRegistryIndex
|
|
37
35
|
*/
|
|
38
36
|
class $SchemaChangeListener {
|
|
39
37
|
|
|
@@ -60,7 +58,7 @@ class $SchemaChangeListener {
|
|
|
60
58
|
* Clear dependency mappings for a given class
|
|
61
59
|
*/
|
|
62
60
|
clearSchemaDependency(cls: Class): void {
|
|
63
|
-
this.#mapping.delete(id
|
|
61
|
+
this.#mapping.delete(cls.Ⲑid);
|
|
64
62
|
}
|
|
65
63
|
|
|
66
64
|
/**
|
|
@@ -70,12 +68,12 @@ class $SchemaChangeListener {
|
|
|
70
68
|
* @param path The path within the object hierarchy to arrive at the class
|
|
71
69
|
* @param config The configuration or the class
|
|
72
70
|
*/
|
|
73
|
-
trackSchemaDependency(src: Class, parent: Class, path:
|
|
74
|
-
const idValue = id
|
|
71
|
+
trackSchemaDependency(src: Class, parent: Class, path: SchemaFieldConfig[], config: SchemaClassConfig): void {
|
|
72
|
+
const idValue = src.Ⲑid;
|
|
75
73
|
if (!this.#mapping.has(idValue)) {
|
|
76
74
|
this.#mapping.set(idValue, new Map());
|
|
77
75
|
}
|
|
78
|
-
this.#mapping.get(idValue)!.set(id
|
|
76
|
+
this.#mapping.get(idValue)!.set(parent.Ⲑid, { path, config });
|
|
79
77
|
}
|
|
80
78
|
|
|
81
79
|
/**
|
|
@@ -85,7 +83,7 @@ class $SchemaChangeListener {
|
|
|
85
83
|
*/
|
|
86
84
|
emitSchemaChanges({ cls, changes }: FieldChangeEvent): void {
|
|
87
85
|
const updates = new Map<string, SchemaChange>();
|
|
88
|
-
const clsId = id
|
|
86
|
+
const clsId = cls.Ⲑid;
|
|
89
87
|
|
|
90
88
|
if (this.#mapping.has(clsId)) {
|
|
91
89
|
const deps = this.#mapping.get(clsId)!;
|
|
@@ -108,25 +106,24 @@ class $SchemaChangeListener {
|
|
|
108
106
|
* @param prev The previous class config
|
|
109
107
|
* @param curr The current class config
|
|
110
108
|
*/
|
|
111
|
-
emitFieldChanges(
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
const currView = curr!.totalView;
|
|
109
|
+
emitFieldChanges(ev: ChangeEvent<SchemaClassConfig>): void {
|
|
110
|
+
const prev = 'prev' in ev ? ev.prev : undefined;
|
|
111
|
+
const curr = 'curr' in ev ? ev.curr : undefined;
|
|
115
112
|
|
|
116
|
-
const prevFields = new Set(
|
|
117
|
-
const currFields = new Set(
|
|
113
|
+
const prevFields = new Set(Object.keys(prev?.fields ?? {}));
|
|
114
|
+
const currFields = new Set(Object.keys(curr?.fields ?? {}));
|
|
118
115
|
|
|
119
|
-
const changes: ChangeEvent<
|
|
116
|
+
const changes: ChangeEvent<SchemaFieldConfig>[] = [];
|
|
120
117
|
|
|
121
118
|
for (const c of currFields) {
|
|
122
|
-
if (!prevFields.has(c)) {
|
|
123
|
-
changes.push({ curr:
|
|
119
|
+
if (!prevFields.has(c) && curr) {
|
|
120
|
+
changes.push({ curr: curr.fields[c], type: 'added' });
|
|
124
121
|
}
|
|
125
122
|
}
|
|
126
123
|
|
|
127
124
|
for (const c of prevFields) {
|
|
128
|
-
if (!currFields.has(c)) {
|
|
129
|
-
changes.push({ prev:
|
|
125
|
+
if (!currFields.has(c) && prev) {
|
|
126
|
+
changes.push({ prev: prev.fields[c], type: 'removing' });
|
|
130
127
|
}
|
|
131
128
|
}
|
|
132
129
|
|
|
@@ -134,14 +131,14 @@ class $SchemaChangeListener {
|
|
|
134
131
|
const compareTypes = (a: Class, b: Class): boolean => a.Ⲑid ? a.Ⲑid === b.Ⲑid : a === b;
|
|
135
132
|
|
|
136
133
|
for (const c of currFields) {
|
|
137
|
-
if (prevFields.has(c)) {
|
|
138
|
-
const prevSchema =
|
|
139
|
-
const currSchema =
|
|
134
|
+
if (prevFields.has(c) && prev && curr) {
|
|
135
|
+
const prevSchema = prev.fields[c];
|
|
136
|
+
const currSchema = curr.fields[c];
|
|
140
137
|
if (
|
|
141
138
|
JSON.stringify(prevSchema) !== JSON.stringify(currSchema) ||
|
|
142
139
|
!compareTypes(prevSchema.type, currSchema.type)
|
|
143
140
|
) {
|
|
144
|
-
changes.push({ prev:
|
|
141
|
+
changes.push({ prev: prev.fields[c], curr: curr.fields[c], type: 'changed' });
|
|
145
142
|
}
|
|
146
143
|
}
|
|
147
144
|
}
|