@based/schema 3.1.0 → 4.1.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/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/parse/assert.d.ts +7 -0
- package/dist/parse/assert.js +33 -0
- package/dist/parse/errors.d.ts +19 -0
- package/dist/parse/errors.js +19 -0
- package/dist/parse/index.d.ts +20 -0
- package/dist/parse/index.js +132 -0
- package/dist/parse/props.d.ts +7 -0
- package/dist/parse/props.js +290 -0
- package/dist/parse/utils.d.ts +3 -0
- package/dist/parse/utils.js +29 -0
- package/dist/parsePayload/index.d.ts +3 -0
- package/dist/parsePayload/index.js +2 -0
- package/dist/parseSchema/assert.d.ts +6 -0
- package/dist/parseSchema/assert.js +27 -0
- package/dist/parseSchema/errors.d.ts +19 -0
- package/dist/parseSchema/errors.js +19 -0
- package/dist/parseSchema/index.d.ts +20 -0
- package/dist/parseSchema/index.js +132 -0
- package/dist/parseSchema/props.d.ts +7 -0
- package/dist/parseSchema/props.js +256 -0
- package/dist/parseSchema/utils.d.ts +3 -0
- package/dist/parseSchema/utils.js +29 -0
- package/dist/src/compat/index.js +12 -4
- package/dist/src/set/fields/references.js +43 -30
- package/dist/src/types.d.ts +5 -13
- package/dist/src/types.js +14 -0
- package/dist/src/validateSchema/fieldValidators.js +4 -4
- package/dist/test/compat.js +26 -1
- package/dist/test/data/newSchemas.js +19 -21
- package/dist/test/reference.js +4 -2
- package/dist/test/walker.js +2 -2
- package/dist/types.d.ts +140 -0
- package/dist/types.js +5 -0
- package/package.json +14 -25
- package/README.md +0 -21
- package/dist/src/compat/newToOld.d.ts +0 -3
- package/dist/src/compat/newToOld.js +0 -76
- package/dist/src/compat/oldToNew.d.ts +0 -3
- package/dist/src/compat/oldToNew.js +0 -35
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { INVALID_VALUE, UNKNOWN_PROP } from './errors.js';
|
|
2
|
+
import { getPropType } from './utils.js';
|
|
3
|
+
import propParsers from './props.js';
|
|
4
|
+
import pc from 'picocolors';
|
|
5
|
+
import { expectBoolean, expectObject } from './assert.js';
|
|
6
|
+
export { getPropType };
|
|
7
|
+
export class Parser {
|
|
8
|
+
constructor(schema) {
|
|
9
|
+
this.schema = schema;
|
|
10
|
+
}
|
|
11
|
+
inQuery;
|
|
12
|
+
schema;
|
|
13
|
+
type;
|
|
14
|
+
parseType(type) {
|
|
15
|
+
expectObject(type);
|
|
16
|
+
this.parseProps(type.props, type);
|
|
17
|
+
}
|
|
18
|
+
parseTypes() {
|
|
19
|
+
const { types } = this.schema;
|
|
20
|
+
expectObject(types);
|
|
21
|
+
for (const type in types) {
|
|
22
|
+
this.parseType(types[type]);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
parseProps(props, schemaType = null) {
|
|
26
|
+
expectObject(props);
|
|
27
|
+
this.type = schemaType;
|
|
28
|
+
for (const key in props) {
|
|
29
|
+
const prop = props[key];
|
|
30
|
+
const type = getPropType(prop);
|
|
31
|
+
if (type in propParsers) {
|
|
32
|
+
propParsers[type](prop, this);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
throw Error(INVALID_VALUE);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
parseLocales() {
|
|
40
|
+
const { locales } = this.schema;
|
|
41
|
+
expectObject(locales);
|
|
42
|
+
for (const locale in locales) {
|
|
43
|
+
const opts = locales[locale];
|
|
44
|
+
expectObject(opts);
|
|
45
|
+
for (const key in opts) {
|
|
46
|
+
const val = opts[key];
|
|
47
|
+
if (key === 'required') {
|
|
48
|
+
expectBoolean(val);
|
|
49
|
+
}
|
|
50
|
+
else if (key === 'fallback') {
|
|
51
|
+
if (!Array.isArray(val) || !val.every((v) => typeof v === 'string')) {
|
|
52
|
+
throw Error(INVALID_VALUE);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
throw Error(UNKNOWN_PROP);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
parse() {
|
|
62
|
+
expectObject(this.schema);
|
|
63
|
+
for (const key in this.schema) {
|
|
64
|
+
if (key === 'types') {
|
|
65
|
+
this.parseTypes();
|
|
66
|
+
}
|
|
67
|
+
else if (key === 'props') {
|
|
68
|
+
this.parseProps(this.schema.props);
|
|
69
|
+
}
|
|
70
|
+
else if (key === 'locales') {
|
|
71
|
+
this.parseLocales();
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
throw Error(UNKNOWN_PROP);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export const print = (schema, path) => {
|
|
80
|
+
let obj = schema;
|
|
81
|
+
const depth = path.length - 1;
|
|
82
|
+
const lines = path.map((key, lvl) => {
|
|
83
|
+
const v = obj[key];
|
|
84
|
+
const padding = ' '.repeat(lvl);
|
|
85
|
+
const prefix = key === Object.keys(obj)[0] ? '' : `${padding}...\n`;
|
|
86
|
+
if (lvl === depth) {
|
|
87
|
+
const err = key in obj
|
|
88
|
+
? `${key}: ${typeof v === 'object' && v !== null && !Array.isArray(v) ? `{..}` : JSON.stringify(v)}`
|
|
89
|
+
: key;
|
|
90
|
+
return `${prefix}${'--'.repeat(lvl - 1)}> ${pc.red(err)}`;
|
|
91
|
+
}
|
|
92
|
+
obj = v;
|
|
93
|
+
return `${prefix}${padding}${key}: {`;
|
|
94
|
+
});
|
|
95
|
+
return lines.join('\n');
|
|
96
|
+
};
|
|
97
|
+
export const debug = (schema) => {
|
|
98
|
+
let curr;
|
|
99
|
+
const proxy = (obj, path = []) => {
|
|
100
|
+
const copy = {};
|
|
101
|
+
return new Proxy(obj, {
|
|
102
|
+
get(_, key) {
|
|
103
|
+
const v = obj[key];
|
|
104
|
+
curr = [...path, key];
|
|
105
|
+
if (typeof v !== 'object' || v === null) {
|
|
106
|
+
return v;
|
|
107
|
+
}
|
|
108
|
+
copy[key] ??= proxy(obj[key], curr);
|
|
109
|
+
return copy[key];
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
const parser = new Parser(proxy(schema));
|
|
114
|
+
try {
|
|
115
|
+
parser.parse();
|
|
116
|
+
}
|
|
117
|
+
catch (e) {
|
|
118
|
+
e.message += '\n\n' + print(schema, curr) + '\n';
|
|
119
|
+
e.cause = curr;
|
|
120
|
+
throw e;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
export const parseSchema = (schema) => {
|
|
124
|
+
try {
|
|
125
|
+
new Parser(schema).parse();
|
|
126
|
+
return { schema };
|
|
127
|
+
}
|
|
128
|
+
catch (e) {
|
|
129
|
+
debug(schema);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { SchemaAnyProp } from '../types.js';
|
|
2
|
+
import { Parser } from './index.js';
|
|
3
|
+
type PropsFns<PropType> = Record<string, (val: any, prop: PropType, ctx: Parser, key?: string) => void>;
|
|
4
|
+
declare function propParser<PropType extends SchemaAnyProp>(required: PropsFns<PropType>, optional: PropsFns<PropType>, allowShorthand?: number): (prop: any, ctx: Parser) => void;
|
|
5
|
+
declare const p: Record<string, ReturnType<typeof propParser>>;
|
|
6
|
+
export default p;
|
|
7
|
+
//# sourceMappingURL=props.d.ts.map
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { expectBoolean, expectFunction, expectObject, expectString, expectNumber, } from './assert.js';
|
|
2
|
+
import { EXPECTED_ARR, EXPECTED_DATE, EXPECTED_OBJ, EXPECTED_PRIMITIVE, EXPECTED_VALUE_IN_ENUM, INVALID_VALUE, MIN_MAX, OUT_OF_RANGE, TEXT_REQUIRES_LOCALES, TYPE_MISMATCH, UNKNOWN_PROP, } from './errors.js';
|
|
3
|
+
import { getPropType } from './utils.js';
|
|
4
|
+
const shared = {
|
|
5
|
+
type() { },
|
|
6
|
+
required(val) {
|
|
7
|
+
expectBoolean(val);
|
|
8
|
+
},
|
|
9
|
+
query(val) {
|
|
10
|
+
expectFunction(val);
|
|
11
|
+
},
|
|
12
|
+
path(val, prop, ctx) {
|
|
13
|
+
expectString(val);
|
|
14
|
+
const path = val.split('.');
|
|
15
|
+
let t = ctx.type;
|
|
16
|
+
for (const key of path) {
|
|
17
|
+
if ('items' in t) {
|
|
18
|
+
t = t.items;
|
|
19
|
+
}
|
|
20
|
+
if ('ref' in t) {
|
|
21
|
+
t = ctx.schema.types[t.ref];
|
|
22
|
+
}
|
|
23
|
+
t = t.props[key];
|
|
24
|
+
expectObject(t);
|
|
25
|
+
}
|
|
26
|
+
if (t.type !== getPropType(prop)) {
|
|
27
|
+
throw Error(TYPE_MISMATCH);
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
function propParser(required, optional, allowShorthand) {
|
|
32
|
+
return (prop, ctx) => {
|
|
33
|
+
if (typeof prop === 'string') {
|
|
34
|
+
// allow string
|
|
35
|
+
if (allowShorthand === 0) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
throw Error(EXPECTED_OBJ);
|
|
39
|
+
}
|
|
40
|
+
if (Array.isArray(prop)) {
|
|
41
|
+
// allow array
|
|
42
|
+
if (allowShorthand === 1) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
throw Error(EXPECTED_OBJ);
|
|
46
|
+
}
|
|
47
|
+
for (const key in required) {
|
|
48
|
+
required[key](prop[key], prop, ctx);
|
|
49
|
+
}
|
|
50
|
+
for (const key in prop) {
|
|
51
|
+
const val = prop[key];
|
|
52
|
+
if (key in optional) {
|
|
53
|
+
optional[key](val, prop, ctx);
|
|
54
|
+
}
|
|
55
|
+
else if (key in shared) {
|
|
56
|
+
shared[key](val, prop, ctx);
|
|
57
|
+
}
|
|
58
|
+
else if (!(key in required)) {
|
|
59
|
+
if (key[0] === '$' && 'ref' in prop) {
|
|
60
|
+
optional.edge(val, prop, ctx, key);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
throw Error(UNKNOWN_PROP);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const p = {};
|
|
70
|
+
p.boolean = propParser({}, {
|
|
71
|
+
default(val) {
|
|
72
|
+
expectBoolean(val);
|
|
73
|
+
},
|
|
74
|
+
}, 0);
|
|
75
|
+
p.enum = propParser({
|
|
76
|
+
enum(items) {
|
|
77
|
+
if (!Array.isArray(items)) {
|
|
78
|
+
throw Error(EXPECTED_ARR);
|
|
79
|
+
}
|
|
80
|
+
if (items.length > 255) {
|
|
81
|
+
throw Error('Max enum length (255) exceeded');
|
|
82
|
+
}
|
|
83
|
+
for (const item of items) {
|
|
84
|
+
if (typeof item === 'object') {
|
|
85
|
+
throw Error(EXPECTED_PRIMITIVE);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
}, {
|
|
90
|
+
default(val, prop) {
|
|
91
|
+
if (!prop.enum.includes(val)) {
|
|
92
|
+
throw Error(EXPECTED_VALUE_IN_ENUM);
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
}, 1);
|
|
96
|
+
p.number = propParser({
|
|
97
|
+
min(val) {
|
|
98
|
+
expectNumber(val);
|
|
99
|
+
},
|
|
100
|
+
max(val, prop) {
|
|
101
|
+
expectNumber(val);
|
|
102
|
+
if (prop.min > val) {
|
|
103
|
+
throw Error(MIN_MAX);
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
step(val) {
|
|
107
|
+
if (typeof val !== 'number' && val !== 'any') {
|
|
108
|
+
throw Error(INVALID_VALUE);
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
}, {
|
|
112
|
+
default(val, prop) {
|
|
113
|
+
expectNumber(val);
|
|
114
|
+
if (val > prop.max || val < prop.min) {
|
|
115
|
+
throw Error(OUT_OF_RANGE);
|
|
116
|
+
}
|
|
117
|
+
if (prop.step !== 'any') {
|
|
118
|
+
const min = typeof prop.min !== 'number' || prop.min === Infinity ? 0 : prop.min;
|
|
119
|
+
const v = val - min;
|
|
120
|
+
if (~~(v / prop.step) * prop.step !== v) {
|
|
121
|
+
throw Error(INVALID_VALUE);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
}, 0);
|
|
126
|
+
p.object = propParser({
|
|
127
|
+
props(val, prop, ctx) {
|
|
128
|
+
ctx.parseProps(val, ctx.type);
|
|
129
|
+
},
|
|
130
|
+
}, {
|
|
131
|
+
default(val) {
|
|
132
|
+
console.warn('TODO object default value');
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
p.reference = propParser({
|
|
136
|
+
ref(ref, _prop, { schema }) {
|
|
137
|
+
schema.types[ref].props;
|
|
138
|
+
},
|
|
139
|
+
prop(propKey, prop, { schema, type, inQuery }) {
|
|
140
|
+
const propAllowed = type && !inQuery;
|
|
141
|
+
if (propAllowed) {
|
|
142
|
+
expectString(propKey);
|
|
143
|
+
let targetProp = schema.types[prop.ref].props[propKey];
|
|
144
|
+
if ('items' in targetProp) {
|
|
145
|
+
targetProp = targetProp.items;
|
|
146
|
+
}
|
|
147
|
+
if ('ref' in targetProp && 'prop' in targetProp) {
|
|
148
|
+
let t = schema.types[targetProp.ref].props[targetProp.prop];
|
|
149
|
+
if ('items' in t) {
|
|
150
|
+
t = t.items;
|
|
151
|
+
}
|
|
152
|
+
if (t === prop) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
throw Error(INVALID_VALUE);
|
|
157
|
+
}
|
|
158
|
+
if (propKey !== undefined) {
|
|
159
|
+
throw Error('ref prop not supported on root or edge p');
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
}, {
|
|
163
|
+
default(val) {
|
|
164
|
+
expectString(val);
|
|
165
|
+
},
|
|
166
|
+
edge(val, prop, ctx, key) {
|
|
167
|
+
const edgeAllowed = ctx.type && !ctx.inQuery;
|
|
168
|
+
if (edgeAllowed) {
|
|
169
|
+
let t = ctx.schema.types[prop.ref].props[prop.prop];
|
|
170
|
+
t = t.items || t;
|
|
171
|
+
if (t[key]) {
|
|
172
|
+
throw Error('Edge can not be defined on both props');
|
|
173
|
+
}
|
|
174
|
+
const edgePropType = getPropType(val);
|
|
175
|
+
p[edgePropType](val, ctx);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
throw Error('ref edge not supported on root or edge p');
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
p.set = propParser({
|
|
182
|
+
items(items, prop, ctx) {
|
|
183
|
+
expectObject(items);
|
|
184
|
+
const itemsType = getPropType(items);
|
|
185
|
+
if (itemsType === 'string' ||
|
|
186
|
+
itemsType === 'number' ||
|
|
187
|
+
itemsType === 'timestamp' ||
|
|
188
|
+
itemsType === 'boolean') {
|
|
189
|
+
ctx.inQuery = 'query' in prop;
|
|
190
|
+
p[itemsType](items, ctx);
|
|
191
|
+
ctx.inQuery = false;
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
throw new Error(INVALID_VALUE);
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
}, {
|
|
198
|
+
default(val, prop) {
|
|
199
|
+
console.warn('TODO SET DEFAULT VALUE');
|
|
200
|
+
// if (typeof val === 'object') {
|
|
201
|
+
// throwErr(ERRORS.EXPECTED_PRIMITIVE, prop, 'default')
|
|
202
|
+
// }
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
p.references = propParser({
|
|
206
|
+
items(items, prop, ctx) {
|
|
207
|
+
expectObject(items);
|
|
208
|
+
const itemsType = getPropType(items);
|
|
209
|
+
if (itemsType === 'reference') {
|
|
210
|
+
ctx.inQuery = 'query' in prop;
|
|
211
|
+
p[itemsType](items, ctx);
|
|
212
|
+
ctx.inQuery = false;
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
throw new Error(INVALID_VALUE);
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
}, {
|
|
219
|
+
default(val, prop) {
|
|
220
|
+
console.warn('TODO SET DEFAULT VALUE');
|
|
221
|
+
// if (typeof val === 'object') {
|
|
222
|
+
// throwErr(ERRORS.EXPECTED_PRIMITIVE, prop, 'default')
|
|
223
|
+
// }
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
p.string = propParser({}, {
|
|
227
|
+
default(val) {
|
|
228
|
+
expectString(val);
|
|
229
|
+
},
|
|
230
|
+
}, 0);
|
|
231
|
+
p.text = propParser({
|
|
232
|
+
type(_val, _prop, { schema }) {
|
|
233
|
+
if (schema.locales) {
|
|
234
|
+
for (const _ in schema.locales) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
throw Error(TEXT_REQUIRES_LOCALES);
|
|
239
|
+
},
|
|
240
|
+
}, {
|
|
241
|
+
default(val, prop) {
|
|
242
|
+
console.warn('MAKE DEFAULT VALUE FOR TEXT');
|
|
243
|
+
// if (typeof val !== 'string') {
|
|
244
|
+
// throwErr(ERRORS.EXPECTED_STR, prop, 'default')
|
|
245
|
+
// }
|
|
246
|
+
},
|
|
247
|
+
}, 0);
|
|
248
|
+
p.timestamp = propParser({}, {
|
|
249
|
+
default(val) {
|
|
250
|
+
if (typeof val !== 'number' && !(val instanceof Date)) {
|
|
251
|
+
throw Error(EXPECTED_DATE);
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
}, 0);
|
|
255
|
+
export default p;
|
|
256
|
+
//# sourceMappingURL=props.js.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { INVALID_TYPE, MISSING_TYPE } from './errors.js';
|
|
2
|
+
export const getPropType = (prop) => {
|
|
3
|
+
if (typeof prop === 'string') {
|
|
4
|
+
return prop;
|
|
5
|
+
}
|
|
6
|
+
if ('type' in prop) {
|
|
7
|
+
if (typeof prop.type !== 'string') {
|
|
8
|
+
throw Error(INVALID_TYPE);
|
|
9
|
+
}
|
|
10
|
+
return prop.type;
|
|
11
|
+
}
|
|
12
|
+
if ('ref' in prop) {
|
|
13
|
+
return 'reference';
|
|
14
|
+
}
|
|
15
|
+
if ('items' in prop) {
|
|
16
|
+
if (getPropType(prop.items) === 'reference') {
|
|
17
|
+
return 'references';
|
|
18
|
+
}
|
|
19
|
+
return 'set';
|
|
20
|
+
}
|
|
21
|
+
if ('props' in prop) {
|
|
22
|
+
return 'object';
|
|
23
|
+
}
|
|
24
|
+
if ('enum' in prop || Array.isArray(prop)) {
|
|
25
|
+
return 'enum';
|
|
26
|
+
}
|
|
27
|
+
throw Error(MISSING_TYPE);
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=utils.js.map
|
package/dist/src/compat/index.js
CHANGED
|
@@ -21,7 +21,7 @@ const convertNewToOldMeta = (props) => {
|
|
|
21
21
|
if (i[0] !== '$') {
|
|
22
22
|
const v = props[i];
|
|
23
23
|
meta ??= {};
|
|
24
|
-
if (i === '
|
|
24
|
+
if (i === 'allowedType') {
|
|
25
25
|
meta.refTypes = v;
|
|
26
26
|
}
|
|
27
27
|
else if (i === 'display' && v === 'bytes') {
|
|
@@ -42,7 +42,7 @@ const convertOldToNewMeta = (props) => {
|
|
|
42
42
|
for (const i in props) {
|
|
43
43
|
const v = props[i];
|
|
44
44
|
if (i === 'refTypes') {
|
|
45
|
-
meta.
|
|
45
|
+
meta.allowedType = v; // TODO
|
|
46
46
|
}
|
|
47
47
|
else if (i === 'format' && v === 'bytes') {
|
|
48
48
|
meta.display = 'bytes';
|
|
@@ -58,7 +58,7 @@ const convertOldToNewMeta = (props) => {
|
|
|
58
58
|
};
|
|
59
59
|
const convertNewFieldToOldField = (newField) => {
|
|
60
60
|
// @ts-ignore
|
|
61
|
-
const { type, properties, values, items, ...props } = newField;
|
|
61
|
+
const { type, bidirectional, properties, values, items, ...props } = newField;
|
|
62
62
|
const meta = convertNewToOldMeta(props);
|
|
63
63
|
// @ts-ignore
|
|
64
64
|
const overwrite = newToOldType[type] || newToOldType[props.format];
|
|
@@ -70,6 +70,10 @@ const convertNewFieldToOldField = (newField) => {
|
|
|
70
70
|
if (meta) {
|
|
71
71
|
oldField.meta = meta;
|
|
72
72
|
}
|
|
73
|
+
if (bidirectional) {
|
|
74
|
+
// @ts-ignore
|
|
75
|
+
oldField.bidirectional = bidirectional;
|
|
76
|
+
}
|
|
73
77
|
if (properties) {
|
|
74
78
|
// @ts-ignore
|
|
75
79
|
oldField.properties = {};
|
|
@@ -133,7 +137,7 @@ export const convertNewToOld = (newSchema) => {
|
|
|
133
137
|
};
|
|
134
138
|
const convertOldFieldToNewField = (oldField) => {
|
|
135
139
|
// @ts-ignore
|
|
136
|
-
const { type, properties, values, items, meta = {} } = oldField;
|
|
140
|
+
const { type, bidirectional, properties, values, items, meta = {} } = oldField;
|
|
137
141
|
const overwrite = oldToNewType[type] || oldToNewType[meta.format];
|
|
138
142
|
const newField = overwrite
|
|
139
143
|
? {
|
|
@@ -144,6 +148,10 @@ const convertOldFieldToNewField = (oldField) => {
|
|
|
144
148
|
type,
|
|
145
149
|
...convertOldToNewMeta(meta),
|
|
146
150
|
};
|
|
151
|
+
if (bidirectional) {
|
|
152
|
+
// @ts-ignore
|
|
153
|
+
newField.bidirectional = bidirectional;
|
|
154
|
+
}
|
|
147
155
|
if (properties) {
|
|
148
156
|
// @ts-ignore
|
|
149
157
|
newField.properties = {};
|
|
@@ -22,36 +22,9 @@ async function parseOperator(args, key) {
|
|
|
22
22
|
return [n.value];
|
|
23
23
|
}
|
|
24
24
|
const typeIsAllowed = (args, type) => {
|
|
25
|
-
if ('
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (typeof t === 'string') {
|
|
29
|
-
if (t === type) {
|
|
30
|
-
return true;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
if (t.type && t.type === type) {
|
|
35
|
-
typeMatches = true;
|
|
36
|
-
if (t.$filter) {
|
|
37
|
-
// stage on requires validation in target
|
|
38
|
-
// TODO: ASYNC REQUIRED HOOK
|
|
39
|
-
// if(!(await args.target.referenceFilterCondition(value, t.$filter))){
|
|
40
|
-
// error(args, ParseError.referenceIsIncorrectType)
|
|
41
|
-
// return
|
|
42
|
-
// }
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
else if (!t.type && t.$filter) {
|
|
46
|
-
// if(!(await args.target.referenceFilterCondition))
|
|
47
|
-
// error(args, ParseError.referenceIsIncorrectType, )
|
|
48
|
-
// return
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
if (typeMatches === false) {
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
25
|
+
if ('allowedType' in args.fieldSchema) {
|
|
26
|
+
const t = args.fieldSchema.allowedType;
|
|
27
|
+
return typeof t === 'string' && t === type;
|
|
55
28
|
}
|
|
56
29
|
return true;
|
|
57
30
|
};
|
|
@@ -86,6 +59,36 @@ export const reference = async (args) => {
|
|
|
86
59
|
args.error(ParseError.referenceIsIncorrectType);
|
|
87
60
|
}
|
|
88
61
|
};
|
|
62
|
+
function parseSortableOp(args, value, op) {
|
|
63
|
+
if (typeof value[op] !== 'object') {
|
|
64
|
+
args.error(ParseError.incorrectFormat);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (!args.fieldSchema.sortable) {
|
|
68
|
+
args.error(ParseError.incorrectFieldType);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
switch (typeof value[op].$idx) {
|
|
72
|
+
case 'bigint':
|
|
73
|
+
break;
|
|
74
|
+
case 'number':
|
|
75
|
+
value[op].$idx = BigInt(value[op].$idx);
|
|
76
|
+
break;
|
|
77
|
+
default:
|
|
78
|
+
args.error(ParseError.incorrectFormat);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (Array.isArray(value[op].$value)) {
|
|
82
|
+
// NOP
|
|
83
|
+
}
|
|
84
|
+
else if (typeof value[op].$value === 'string') {
|
|
85
|
+
value[op].$value = [value[op].$value];
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
args.error(ParseError.incorrectFormat);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
89
92
|
export const references = async (args) => {
|
|
90
93
|
const { value } = args;
|
|
91
94
|
if (typeof value !== 'object' || value === null) {
|
|
@@ -113,6 +116,16 @@ export const references = async (args) => {
|
|
|
113
116
|
else if (key === '$remove') {
|
|
114
117
|
args.value.$remove = await parseOperator(args, key);
|
|
115
118
|
}
|
|
119
|
+
else if (key === '$assign') {
|
|
120
|
+
parseSortableOp(args, value, '$assign');
|
|
121
|
+
}
|
|
122
|
+
else if (key === '$insert') {
|
|
123
|
+
parseSortableOp(args, value, '$insert');
|
|
124
|
+
}
|
|
125
|
+
else if (key === '$move') {
|
|
126
|
+
parseSortableOp(args, value, '$move');
|
|
127
|
+
value.$move.$value.reverse();
|
|
128
|
+
}
|
|
116
129
|
else {
|
|
117
130
|
args.create({ key }).error(ParseError.fieldDoesNotExist);
|
|
118
131
|
}
|
package/dist/src/types.d.ts
CHANGED
|
@@ -5,11 +5,7 @@ import { ArgsClass, Path } from './walker/index.js';
|
|
|
5
5
|
import { StringFormat } from './display/string.js';
|
|
6
6
|
import { NumberFormat } from './display/number.js';
|
|
7
7
|
import { DateFormat } from './display/timestamp.js';
|
|
8
|
-
export
|
|
9
|
-
type?: string;
|
|
10
|
-
$filter: any | any[];
|
|
11
|
-
})[];
|
|
12
|
-
export declare const basedSchemaFieldTypes: readonly ["array", "object", "record", "set", "string", "boolean", "number", "json", "integer", "timestamp", "reference", "references", "text", "enum", "cardinality", "any"];
|
|
8
|
+
export declare const basedSchemaFieldTypes: readonly ["array", "object", "record", "set", "string", "boolean", "number", "json", "integer", "timestamp", "created", "updated", "reference", "references", "text", "enum", "cardinality", "any"];
|
|
13
9
|
export type BasedSchemaFieldType = (typeof basedSchemaFieldTypes)[number];
|
|
14
10
|
export declare const isCollection: (type: string) => boolean;
|
|
15
11
|
export type BasedSchemaPattern = string;
|
|
@@ -123,18 +119,14 @@ export type BasedSchemaFieldSet = {
|
|
|
123
119
|
export type BasedSchemaFieldEnumerable = BasedSchemaFieldText | BasedSchemaFieldObject | BasedSchemaFieldRecord | BasedSchemaFieldArray | BasedSchemaFieldSet;
|
|
124
120
|
export type BasedSchemaFieldReference = {
|
|
125
121
|
type: 'reference';
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
};
|
|
129
|
-
allowedTypes?: AllowedTypes;
|
|
122
|
+
allowedType: string;
|
|
123
|
+
inverseProperty?: string;
|
|
130
124
|
} & BasedSchemaFieldShared;
|
|
131
125
|
export type BasedSchemaFieldReferences = {
|
|
132
126
|
type: 'references';
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
};
|
|
127
|
+
allowedType: string;
|
|
128
|
+
inverseProperty?: string;
|
|
136
129
|
sortable?: boolean;
|
|
137
|
-
allowedTypes?: AllowedTypes;
|
|
138
130
|
} & BasedSchemaFieldShared;
|
|
139
131
|
export type BasedSchemaFields = {
|
|
140
132
|
string: BasedSchemaFieldString;
|
package/dist/src/types.js
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
import { languages as allLanguages } from './languages.js';
|
|
2
|
+
// Schema type
|
|
3
|
+
// inspiration from https://json-schema.org/understanding-json-schema/index.html
|
|
4
|
+
// but added a few extra types
|
|
5
|
+
// reference
|
|
6
|
+
// references
|
|
7
|
+
// set
|
|
8
|
+
// record
|
|
9
|
+
// https://json-schema.org/learn/examples/geographical-location.schema.json
|
|
10
|
+
// contentSchema can be used for JSON types as well
|
|
11
|
+
// contentSchema can be used for reference / refrences
|
|
12
|
+
// TODO parser / validator / parseOut / parseIn (parsIn after validator)
|
|
13
|
+
// for refs etc check https://json-schema.org/understanding-json-schema/structuring.html#defs
|
|
2
14
|
export const basedSchemaFieldTypes = [
|
|
3
15
|
'array',
|
|
4
16
|
'object',
|
|
@@ -10,6 +22,8 @@ export const basedSchemaFieldTypes = [
|
|
|
10
22
|
'json',
|
|
11
23
|
'integer',
|
|
12
24
|
'timestamp',
|
|
25
|
+
'created',
|
|
26
|
+
'updated',
|
|
13
27
|
'reference',
|
|
14
28
|
'references',
|
|
15
29
|
'text',
|
|
@@ -333,22 +333,22 @@ export const basedSchemaFieldSetValidator = {
|
|
|
333
333
|
};
|
|
334
334
|
export const basedSchemaFieldReferenceValidator = {
|
|
335
335
|
...basedSchemaFieldSharedValidator,
|
|
336
|
-
|
|
336
|
+
inverseProperty: {
|
|
337
337
|
validator: mustBeBidirectional,
|
|
338
338
|
optional: true,
|
|
339
339
|
},
|
|
340
|
-
|
|
340
|
+
allowedType: {
|
|
341
341
|
// TODO: validator
|
|
342
342
|
optional: true,
|
|
343
343
|
},
|
|
344
344
|
};
|
|
345
345
|
export const basedSchemaFieldReferencesValidator = {
|
|
346
346
|
...basedSchemaFieldSharedValidator,
|
|
347
|
-
|
|
347
|
+
inverseProperty: {
|
|
348
348
|
validator: mustBeBidirectional,
|
|
349
349
|
optional: true,
|
|
350
350
|
},
|
|
351
|
-
|
|
351
|
+
allowedType: {
|
|
352
352
|
// TODO: validator
|
|
353
353
|
optional: true,
|
|
354
354
|
},
|