@based/schema 3.1.0 → 3.2.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.
Files changed (61) hide show
  1. package/README.md +1 -20
  2. package/dist/display/index.d.ts +2 -0
  3. package/dist/display/index.js +26 -0
  4. package/dist/display/number.d.ts +3 -0
  5. package/dist/display/number.js +89 -0
  6. package/dist/display/string.d.ts +3 -0
  7. package/dist/display/string.js +23 -0
  8. package/dist/display/timestamp.d.ts +3 -0
  9. package/dist/display/timestamp.js +127 -0
  10. package/dist/error.d.ts +19 -0
  11. package/dist/error.js +24 -0
  12. package/dist/index.d.ts +5 -0
  13. package/dist/index.js +22 -0
  14. package/dist/languages.d.ts +187 -0
  15. package/dist/languages.js +190 -0
  16. package/dist/set/fields/array.d.ts +2 -0
  17. package/dist/set/fields/array.js +123 -0
  18. package/dist/set/fields/index.d.ts +3 -0
  19. package/dist/set/fields/index.js +74 -0
  20. package/dist/set/fields/number.d.ts +4 -0
  21. package/dist/set/fields/number.js +129 -0
  22. package/dist/set/fields/object.d.ts +3 -0
  23. package/dist/set/fields/object.js +33 -0
  24. package/dist/set/fields/references.d.ts +3 -0
  25. package/dist/set/fields/references.js +128 -0
  26. package/dist/set/fields/set.d.ts +2 -0
  27. package/dist/set/fields/set.js +63 -0
  28. package/dist/set/fields/string.d.ts +3 -0
  29. package/dist/set/fields/string.js +284 -0
  30. package/dist/set/index.d.ts +3 -0
  31. package/dist/set/index.js +183 -0
  32. package/dist/set/isValidId.d.ts +2 -0
  33. package/dist/set/isValidId.js +21 -0
  34. package/dist/set/types.d.ts +0 -0
  35. package/dist/set/types.js +1 -0
  36. package/dist/src/compat/index.js +10 -2
  37. package/dist/src/compat/newToOld.d.ts +2 -2
  38. package/dist/src/compat/newToOld.js +173 -31
  39. package/dist/src/compat/oldToNew.d.ts +1 -1
  40. package/dist/src/compat/oldToNew.js +200 -25
  41. package/dist/src/generateQuery.d.ts +12 -0
  42. package/dist/src/generateQuery.js +75 -0
  43. package/dist/src/set/fields/references.js +40 -0
  44. package/dist/test/compat.js +25 -0
  45. package/dist/test/query.d.ts +1 -0
  46. package/dist/test/query.js +93 -0
  47. package/dist/types.d.ts +205 -0
  48. package/dist/types.js +27 -0
  49. package/dist/updateSchema.d.ts +2 -0
  50. package/dist/updateSchema.js +16 -0
  51. package/dist/validateSchema.d.ts +4 -0
  52. package/dist/validateSchema.js +41 -0
  53. package/dist/walker/args.d.ts +36 -0
  54. package/dist/walker/args.js +162 -0
  55. package/dist/walker/index.d.ts +6 -0
  56. package/dist/walker/index.js +49 -0
  57. package/dist/walker/parse.d.ts +3 -0
  58. package/dist/walker/parse.js +186 -0
  59. package/dist/walker/types.d.ts +45 -0
  60. package/dist/walker/types.js +10 -0
  61. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  const metaChecker = (field) => {
2
2
  return (field === 'validation' ||
3
- field === 'format' ||
3
+ // field === 'format' ||
4
4
  field === 'index' ||
5
5
  field === 'description' ||
6
6
  field === 'title' ||
@@ -30,47 +30,189 @@ const metaChecker = (field) => {
30
30
  field === 'maximum' ||
31
31
  field === 'exclusiveMaximum' ||
32
32
  field === 'exclusiveMinimum' ||
33
- field === '$delete');
33
+ field === '$delete' ||
34
+ field === 'display');
34
35
  };
35
- const excludedFields = (field) => {
36
- return field === 'language' || field === 'translations' || field === '$defs';
36
+ const DEFAULT_FIELDS = {
37
+ // id: { type: 'string' },
38
+ // createdAt: { type: 'timestamp' },
39
+ // updatedAt: { type: 'timestamp' },
40
+ // type: { type: 'string' },
41
+ // parents: { type: 'references' },
42
+ // children: { type: 'references' },
43
+ // ancestors: { type: 'references' },
44
+ // descendants: { type: 'references' },
45
+ // aliases: {
46
+ // type: 'set',
47
+ // items: { type: 'string' },
48
+ // },
37
49
  };
38
- export const convertNewToOld = (schema) => {
39
- const tmpSchema = {};
40
- const walker = (target, source) => {
41
- for (const i in source) {
42
- if (source[i] && typeof source[i] === 'object' && i in target === false) {
43
- target[i] = source[i].length ? [] : {};
44
- walker(target[i], source[i]);
50
+ const metaParser = (obj) => {
51
+ const tmp = {};
52
+ for (const i in obj) {
53
+ if (metaChecker(i)) {
54
+ if (i === 'title') {
55
+ tmp.name = obj[i];
45
56
  }
46
- else if (!metaChecker(i)) {
47
- target[i] = source[i];
57
+ else if (obj[i] === 'bytes') {
58
+ tmp.format = obj[i];
48
59
  }
49
60
  else {
50
- target.meta = {};
51
- for (const i in source) {
52
- if (metaChecker(i) && typeof source[i] !== 'object') {
53
- if (i === 'title') {
54
- target.meta = { ...target.meta, name: source[i] };
55
- }
56
- else {
57
- target.meta = { ...target.meta, [i]: source[i] };
58
- }
59
- delete source[i];
60
- }
61
+ tmp[i] = obj[i];
62
+ }
63
+ }
64
+ }
65
+ return Object.keys(tmp).length > 0 ? { meta: tmp } : null;
66
+ };
67
+ const migrateField = (field) => {
68
+ if (field?.type === 'object') {
69
+ return {
70
+ ...metaParser(field),
71
+ type: 'object',
72
+ properties: migrateFields(field.properties, true),
73
+ };
74
+ }
75
+ else if (field?.type === 'json') {
76
+ return {
77
+ ...field,
78
+ ...metaParser(field),
79
+ type: 'json',
80
+ };
81
+ }
82
+ else if (field?.type === 'array') {
83
+ const values = migrateField(field.values);
84
+ if (!values) {
85
+ return null;
86
+ }
87
+ return {
88
+ ...metaParser(field),
89
+ type: 'array',
90
+ items: values,
91
+ };
92
+ }
93
+ else if (field?.type === 'set') {
94
+ return {
95
+ ...metaParser(field),
96
+ type: 'set',
97
+ items: migrateField(field.items),
98
+ };
99
+ }
100
+ else if (field?.type === 'record') {
101
+ return {
102
+ ...metaParser(field),
103
+ type: 'record',
104
+ values: migrateField(field.values),
105
+ };
106
+ }
107
+ else if (field?.type === 'reference' || field?.type === 'references') {
108
+ return {
109
+ ...metaParser(field),
110
+ type: field?.type,
111
+ ...(field.bidirectional ? { bidirectional: field.bidirectional } : null),
112
+ };
113
+ }
114
+ else if (field?.type === 'integer') {
115
+ return {
116
+ ...metaParser(field),
117
+ type: 'int',
118
+ };
119
+ }
120
+ else if (field?.format === 'strongPassword') {
121
+ return { ...metaParser(field), type: 'digest' };
122
+ }
123
+ else if (field?.format === 'basedId') {
124
+ return { ...metaParser(field), type: 'id' };
125
+ }
126
+ else if (field?.format === 'URL') {
127
+ return { ...metaParser(field), type: 'url' };
128
+ }
129
+ else if (field?.format === 'email') {
130
+ return {
131
+ ...metaParser(field),
132
+ type: 'email',
133
+ };
134
+ }
135
+ else if (field?.format === 'mobilePhone') {
136
+ return {
137
+ ...metaParser(field),
138
+ type: 'phone',
139
+ };
140
+ }
141
+ else if (field?.format === 'latLong') {
142
+ return {
143
+ ...metaParser(field),
144
+ type: 'geo',
145
+ };
146
+ }
147
+ else {
148
+ return { ...metaParser(field), type: field?.type };
149
+ }
150
+ };
151
+ const migrateFields = (oldFields, recursing = false) => {
152
+ const result = {};
153
+ if (oldFields) {
154
+ for (const key in oldFields) {
155
+ if (oldFields.hasOwnProperty(key)) {
156
+ if (!recursing && Object.keys(DEFAULT_FIELDS).includes(key)) {
157
+ continue;
61
158
  }
159
+ const field = migrateField(oldFields[key]);
160
+ if (!field) {
161
+ continue;
162
+ }
163
+ result[key] = field;
62
164
  }
63
165
  }
166
+ }
167
+ return result;
168
+ };
169
+ const migrateTypes = (oldSchema) => {
170
+ const result = {
171
+ types: {},
64
172
  };
65
- walker(tmpSchema, schema);
66
- if ((tmpSchema.meta = {}))
67
- delete tmpSchema.meta;
68
- for (const i in tmpSchema) {
69
- if (excludedFields(i)) {
70
- delete tmpSchema[i];
173
+ for (const key in oldSchema.types) {
174
+ if (oldSchema.types.hasOwnProperty(key)) {
175
+ const type = oldSchema.types[key];
176
+ result.types[key] = {
177
+ ...metaParser(type),
178
+ fields: migrateFields(type.fields),
179
+ };
180
+ if (type.prefix) {
181
+ result.types[key].prefix = type.prefix;
182
+ }
71
183
  }
72
184
  }
73
- tmpSchema.languages = [schema.language, ...schema?.translations];
185
+ return result;
186
+ };
187
+ const convertRoot = (schema) => {
188
+ const result = {
189
+ fields: {},
190
+ ...metaParser(schema.root),
191
+ ...(schema.root?.prefix ? { prefix: schema.root.prefix } : null),
192
+ };
193
+ for (const i in schema.root?.fields) {
194
+ const field = schema.root?.fields[i];
195
+ result.fields[i] = {
196
+ ...metaParser(field),
197
+ ...migrateField(field),
198
+ };
199
+ }
200
+ return result;
201
+ };
202
+ export const convertNewToOld = (schema) => {
203
+ const tmpSchema = migrateTypes(schema);
204
+ if (schema.prefixToTypeMapping) {
205
+ tmpSchema.prefixToTypeMapping = schema.prefixToTypeMapping;
206
+ }
207
+ tmpSchema.languages = [];
208
+ if (schema.language) {
209
+ tmpSchema.languages.push(schema.language);
210
+ }
211
+ if (schema.translations) {
212
+ tmpSchema.languages.push(...schema.translations);
213
+ }
214
+ tmpSchema.rootType = convertRoot(schema);
215
+ delete tmpSchema.root;
74
216
  return tmpSchema;
75
217
  };
76
218
  //# sourceMappingURL=newToOld.js.map
@@ -1,3 +1,3 @@
1
1
  import { BasedSchema } from '../types.js';
2
2
  import { BasedOldSchema } from './oldSchemaType.js';
3
- export declare const convertOldToNew: (oldSchema: BasedOldSchema) => BasedSchema;
3
+ export declare const convertOldToNew: (oldSchema: Partial<BasedOldSchema>) => BasedSchema;
@@ -1,35 +1,210 @@
1
- export const convertOldToNew = (oldSchema) => {
2
- const tempSchema = {};
3
- const walker = (source, target) => {
4
- for (const i in source) {
5
- if (i === 'languages' && source[i].length) {
6
- target.language = source[i][0];
7
- target.translations = source[i].filter((_, i) => i !== 0);
1
+ const DEFAULT_FIELDS = {
2
+ // id: { type: 'string' },
3
+ // createdAt: { type: 'timestamp' },
4
+ // updatedAt: { type: 'timestamp' },
5
+ // type: { type: 'string' },
6
+ // parents: { type: 'references' },
7
+ // children: { type: 'references' },
8
+ // ancestors: { type: 'references' },
9
+ // descendants: { type: 'references' },
10
+ // aliases: {
11
+ // type: 'set',
12
+ // items: { type: 'string' },
13
+ // },
14
+ };
15
+ const metaParser = (obj) => {
16
+ const metaObj = obj?.meta;
17
+ const tmp = {};
18
+ for (const i in metaObj) {
19
+ if (i === 'name') {
20
+ tmp.title = metaObj[i];
21
+ }
22
+ else if (i === 'validation' ||
23
+ i === 'progress' ||
24
+ i === 'format' ||
25
+ i === 'ui') {
26
+ if (metaObj[i] === 'url') {
27
+ // tmp.format = 'URL'
28
+ }
29
+ if ((metaObj[i] === 'bytes' && obj.type === 'number') ||
30
+ metaObj.type === 'float') {
31
+ tmp.display = 'bytes';
32
+ }
33
+ }
34
+ else {
35
+ tmp[i] = metaObj[i];
36
+ }
37
+ }
38
+ return tmp;
39
+ };
40
+ const migrateField = (oldField) => {
41
+ switch (oldField.type) {
42
+ case 'object':
43
+ return {
44
+ ...metaParser(oldField),
45
+ type: 'object',
46
+ properties: migrateFields(oldField.properties, true),
47
+ };
48
+ case 'json':
49
+ return {
50
+ ...oldField,
51
+ ...metaParser(oldField),
52
+ type: 'json',
53
+ };
54
+ case 'array':
55
+ const values = migrateField(oldField.items);
56
+ if (!values) {
57
+ return null;
8
58
  }
9
- else if (typeof source[i] === 'object' && i in target === false) {
10
- if (i === 'meta' &&
11
- !Object.keys(source[i]).includes('properties' || 'type')) {
12
- for (const j in source[i]) {
13
- if (j === 'name') {
14
- target.title = source[i][j];
15
- }
16
- else {
17
- target[j] = source[i][j];
18
- }
19
- }
59
+ return {
60
+ ...metaParser(oldField),
61
+ type: 'array',
62
+ values,
63
+ };
64
+ case 'set':
65
+ return {
66
+ ...metaParser(oldField),
67
+ type: 'set',
68
+ items: migrateField(oldField.items),
69
+ };
70
+ case 'record':
71
+ return {
72
+ ...metaParser(oldField),
73
+ type: 'record',
74
+ values: migrateField(oldField.values),
75
+ };
76
+ case 'reference':
77
+ case 'references':
78
+ return {
79
+ ...metaParser(oldField),
80
+ type: oldField.type,
81
+ ...(oldField.bidirectional
82
+ ? { bidirectional: oldField.bidirectional }
83
+ : null),
84
+ };
85
+ case 'float':
86
+ return {
87
+ ...metaParser(oldField),
88
+ type: 'number',
89
+ };
90
+ case 'int':
91
+ return {
92
+ ...metaParser(oldField),
93
+ type: 'integer',
94
+ };
95
+ case 'digest':
96
+ return {
97
+ ...metaParser(oldField),
98
+ format: 'strongPassword',
99
+ type: 'string',
100
+ };
101
+ case 'id':
102
+ return {
103
+ format: 'basedId',
104
+ ...metaParser(oldField),
105
+ type: 'string',
106
+ };
107
+ case 'url':
108
+ return {
109
+ ...metaParser(oldField),
110
+ format: 'URL',
111
+ type: 'string',
112
+ };
113
+ case 'email':
114
+ return {
115
+ format: 'email',
116
+ ...metaParser(oldField),
117
+ type: 'string',
118
+ };
119
+ case 'phone':
120
+ return {
121
+ ...metaParser(oldField),
122
+ format: 'mobilePhone',
123
+ type: 'string',
124
+ };
125
+ case 'geo':
126
+ return {
127
+ ...metaParser(oldField),
128
+ format: 'latLong',
129
+ type: 'string',
130
+ };
131
+ case 'type':
132
+ return {
133
+ ...metaParser(oldField),
134
+ type: 'string',
135
+ };
136
+ case 'number':
137
+ return {
138
+ ...metaParser(oldField),
139
+ type: 'number',
140
+ };
141
+ default:
142
+ return {
143
+ ...metaParser(oldField),
144
+ type: oldField.type,
145
+ };
146
+ }
147
+ };
148
+ const migrateFields = (oldFields, recursing = false) => {
149
+ const result = {};
150
+ if (oldFields) {
151
+ for (const key in oldFields) {
152
+ if (true) {
153
+ if (!recursing && Object.keys(DEFAULT_FIELDS).includes(key)) {
154
+ continue;
20
155
  }
21
- else {
22
- target[i] = source[i].length ? [] : {};
23
- walker(source[i], target[i]);
156
+ const field = migrateField(oldFields[key]);
157
+ if (!field) {
158
+ continue;
24
159
  }
160
+ result[key] = field;
25
161
  }
26
- else if (i !== 'meta') {
27
- target[i] = source[i];
28
- }
29
162
  }
163
+ }
164
+ return result;
165
+ };
166
+ const migrateTypes = (oldSchema) => {
167
+ const result = {
168
+ types: {},
169
+ };
170
+ for (const key in oldSchema.types) {
171
+ if (oldSchema.types.hasOwnProperty(key)) {
172
+ const type = oldSchema.types[key];
173
+ result.types[key] = {
174
+ ...metaParser(type),
175
+ prefix: type.prefix,
176
+ fields: migrateFields(type.fields),
177
+ };
178
+ }
179
+ }
180
+ return result;
181
+ };
182
+ const convertRoot = (oldSchema) => {
183
+ const result = {
184
+ fields: {},
185
+ ...metaParser(oldSchema.rootType?.meta),
186
+ ...(oldSchema.rootType?.prefix
187
+ ? { prefix: oldSchema.rootType.prefix }
188
+ : null),
30
189
  };
31
- walker(oldSchema, tempSchema);
190
+ for (const i in oldSchema.rootType?.fields) {
191
+ const field = oldSchema.rootType?.fields[i];
192
+ result.fields[i] = {
193
+ ...metaParser(field?.meta),
194
+ ...migrateField(field),
195
+ };
196
+ }
197
+ return result;
198
+ };
199
+ export const convertOldToNew = (oldSchema) => {
200
+ const tempSchema = migrateTypes(oldSchema);
32
201
  tempSchema.$defs = {};
202
+ tempSchema.language = oldSchema.languages[0];
203
+ tempSchema.prefixToTypeMapping = oldSchema.prefixToTypeMapping;
204
+ tempSchema.translations = oldSchema.languages.filter((_, i) => i !== 0);
205
+ tempSchema.root = convertRoot(oldSchema);
206
+ delete tempSchema.rootType;
207
+ delete tempSchema.sha;
33
208
  return tempSchema;
34
209
  };
35
210
  //# sourceMappingURL=oldToNew.js.map
@@ -0,0 +1,12 @@
1
+ import { BasedSchema, BasedSchemaField, BasedSchemaType } from './types.js';
2
+ type Query = Record<string, any>;
3
+ type Transformer = (Query: any, opts: {
4
+ type: string;
5
+ schema: BasedSchemaType;
6
+ depth: number;
7
+ }) => Query;
8
+ export declare const generateQueryForType: (type: string, schema: BasedSchema, depth?: number, transformer?: Transformer, query?: Query, nestedRefs?: Set<BasedSchemaField>) => Query;
9
+ export declare const generateQuery: (query: {
10
+ $id: string;
11
+ } & Query, schema: BasedSchema, depth?: number, transformer?: Transformer) => Query;
12
+ export {};
@@ -0,0 +1,75 @@
1
+ const parseSchemaField = (schemaField, schema, depth, transformer, nestedRefs, currentQuery) => {
2
+ if ('values' in schemaField) {
3
+ return parseSchemaField(schemaField.values, schema, depth, transformer, nestedRefs, currentQuery);
4
+ }
5
+ if ('items' in schemaField) {
6
+ return parseSchemaField(schemaField.items, schema, depth, transformer, nestedRefs, currentQuery);
7
+ }
8
+ if ('properties' in schemaField) {
9
+ currentQuery ??= {};
10
+ for (const i in schemaField.properties) {
11
+ const v = currentQuery[i];
12
+ if (v === true || v === false) {
13
+ continue;
14
+ }
15
+ currentQuery[i] = parseSchemaField(schemaField.properties[i], schema, depth, transformer, nestedRefs, currentQuery[i]);
16
+ }
17
+ return currentQuery;
18
+ }
19
+ if (schemaField.type === 'reference' || schemaField.type === 'references') {
20
+ const nestedDepth = depth - 1;
21
+ if (nestedDepth < 0) {
22
+ return true;
23
+ }
24
+ if (nestedRefs) {
25
+ if (nestedRefs.has(schemaField)) {
26
+ return true;
27
+ }
28
+ nestedRefs.add(schemaField);
29
+ }
30
+ const allowedTypes = schemaField.allowedTypes?.length
31
+ ? schemaField.allowedTypes
32
+ : Object.keys(schema.types);
33
+ for (const i of allowedTypes) {
34
+ currentQuery = generateQueryForType(typeof i === 'string' ? i : i.type, schema, nestedDepth, transformer, currentQuery, nestedRefs || new Set([schemaField]));
35
+ }
36
+ if (schemaField.type === 'references') {
37
+ currentQuery.$list = true;
38
+ }
39
+ return currentQuery;
40
+ }
41
+ return true;
42
+ };
43
+ export const generateQueryForType = (type, schema, depth = 0, transformer, query = {}, nestedRefs) => {
44
+ const schemaType = type === 'root' ? schema.root : schema.types[type];
45
+ if (!schemaType) {
46
+ throw new Error('unknown type');
47
+ }
48
+ query.id ??= true;
49
+ query.type ??= true;
50
+ query.createdAt ??= true;
51
+ query.updatedAt ??= true;
52
+ if (schemaType.fields) {
53
+ for (const key in schemaType.fields) {
54
+ const v = query[key];
55
+ if (v === true || v === false) {
56
+ continue;
57
+ }
58
+ const schemaField = schemaType.fields[key];
59
+ query[key] = parseSchemaField(schemaField, schema, depth, transformer, nestedRefs, query[key]);
60
+ }
61
+ }
62
+ return transformer
63
+ ? transformer(query, { type, depth, schema: schemaType })
64
+ : query;
65
+ };
66
+ export const generateQuery = (query, schema, depth, transformer) => {
67
+ const type = query.$id === 'root'
68
+ ? query.$id
69
+ : schema.prefixToTypeMapping[query.$id.substring(0, 2)];
70
+ if (!type) {
71
+ throw new Error('invalid type');
72
+ }
73
+ return generateQueryForType(type, schema, depth, transformer, query);
74
+ };
75
+ //# sourceMappingURL=generateQuery.js.map
@@ -86,6 +86,36 @@ export const reference = async (args) => {
86
86
  args.error(ParseError.referenceIsIncorrectType);
87
87
  }
88
88
  };
89
+ function parseSortableOp(args, value, op) {
90
+ if (typeof value[op] !== 'object') {
91
+ args.error(ParseError.incorrectFormat);
92
+ return;
93
+ }
94
+ if (!args.fieldSchema.sortable) {
95
+ args.error(ParseError.incorrectFieldType);
96
+ return;
97
+ }
98
+ switch (typeof value[op].$idx) {
99
+ case 'bigint':
100
+ break;
101
+ case 'number':
102
+ value[op].$idx = BigInt(value[op].$idx);
103
+ break;
104
+ default:
105
+ args.error(ParseError.incorrectFormat);
106
+ return;
107
+ }
108
+ if (Array.isArray(value[op].$value)) {
109
+ // NOP
110
+ }
111
+ else if (typeof value[op].$value === 'string') {
112
+ value[op].$value = [value[op].$value];
113
+ }
114
+ else {
115
+ args.error(ParseError.incorrectFormat);
116
+ return;
117
+ }
118
+ }
89
119
  export const references = async (args) => {
90
120
  const { value } = args;
91
121
  if (typeof value !== 'object' || value === null) {
@@ -113,6 +143,16 @@ export const references = async (args) => {
113
143
  else if (key === '$remove') {
114
144
  args.value.$remove = await parseOperator(args, key);
115
145
  }
146
+ else if (key === '$assign') {
147
+ parseSortableOp(args, value, '$assign');
148
+ }
149
+ else if (key === '$insert') {
150
+ parseSortableOp(args, value, '$insert');
151
+ }
152
+ else if (key === '$move') {
153
+ parseSortableOp(args, value, '$move');
154
+ value.$move.$value.reverse();
155
+ }
116
156
  else {
117
157
  args.create({ key }).error(ParseError.fieldDoesNotExist);
118
158
  }
@@ -50,6 +50,31 @@ test('refTypes', async (t) => {
50
50
  // @ts-ignore
51
51
  t.is(oldSchema.types.youzi.fields.image.meta.refTypes[0], 'youzi');
52
52
  });
53
+ test('bidirectional', async (t) => {
54
+ const newSchema = convertOldToNew({
55
+ types: {
56
+ youzi: {
57
+ fields: {
58
+ image: {
59
+ type: 'reference',
60
+ bidirectional: {
61
+ fromField: 'success',
62
+ },
63
+ meta: {
64
+ refTypes: ['youzi'],
65
+ },
66
+ },
67
+ },
68
+ },
69
+ },
70
+ });
71
+ console.log(newSchema.types.youzi.fields.image);
72
+ // @ts-ignore
73
+ t.is(newSchema.types.youzi.fields.image.bidirectional.fromField, 'success');
74
+ const oldSchema = convertNewToOld(newSchema);
75
+ // @ts-ignore
76
+ t.is(oldSchema.types.youzi.fields.image.bidirectional.fromField, 'success');
77
+ });
53
78
  test('old schema compat mode', async (t) => {
54
79
  for (let i = 0; i < oldSchemas.length - 1; i++) {
55
80
  const oldSchema = oldSchemas[i];
@@ -0,0 +1 @@
1
+ export {};