@based/schema 2.7.0 → 2.7.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.
@@ -1,3 +1,3 @@
1
- import { BasedSchema } from '../types.js';
2
1
  import { BasedOldSchema } from './oldSchemaType.js';
3
- export declare const convertNewToOld: (schema: BasedSchema) => Partial<BasedOldSchema>;
2
+ import { BasedSchemaPartial } from '../types.js';
3
+ export declare const convertNewToOld: (schema: BasedSchemaPartial) => Partial<BasedOldSchema>;
@@ -67,7 +67,7 @@ const metaParser = (obj) => {
67
67
  }
68
68
  }
69
69
  }
70
- return Object.keys({ meta: tmp }.meta).length > 0 ? { meta: tmp } : null;
70
+ return Object.keys(tmp).length > 0 ? { meta: tmp } : null;
71
71
  };
72
72
  const migrateField = (field) => {
73
73
  if (field?.type === 'object') {
@@ -205,7 +205,13 @@ const convertRoot = (schema) => {
205
205
  export const convertNewToOld = (schema) => {
206
206
  const tmpSchema = migrateTypes(schema);
207
207
  tmpSchema.prefixToTypeMapping = schema.prefixToTypeMapping;
208
- tmpSchema.languages = [schema.language, ...schema?.translations];
208
+ tmpSchema.languages = [];
209
+ if (schema.language) {
210
+ tmpSchema.languages.push(schema.language);
211
+ }
212
+ if (schema.translations) {
213
+ tmpSchema.languages.push(...schema.translations);
214
+ }
209
215
  tmpSchema.rootType = convertRoot(schema);
210
216
  delete tmpSchema.root;
211
217
  return tmpSchema;
@@ -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;
@@ -4,7 +4,7 @@ import { basedSchemaDateFormats } from '../display/timestamp.js';
4
4
  import { ParseError } from '../error.js';
5
5
  import { basedSchemaFieldTypes, basedSchemaStringFormatValues, languages, } from '../types.js';
6
6
  import { validate } from './index.js';
7
- import { mustBeBidirectional, mustBeBoolean, mustBeNumber, mustBeString, mustBeStringArray, } from './utils.js';
7
+ import { mustBeArray, mustBeBidirectional, mustBeBoolean, mustBeNumber, mustBeString, mustBeStringArray, } from './utils.js';
8
8
  export const mustBeField = (value, path, newSchema, oldSchema, options) => {
9
9
  if (!(typeof value === 'object' && !Array.isArray(value))) {
10
10
  return [
@@ -14,7 +14,7 @@ export const mustBeField = (value, path, newSchema, oldSchema, options) => {
14
14
  },
15
15
  ];
16
16
  }
17
- const type = value.type;
17
+ const type = value.hasOwnProperty('enum') ? 'enum' : value.type;
18
18
  if ((options?.limitTo === 'primitives' &&
19
19
  ![
20
20
  'string',
@@ -75,6 +75,12 @@ export const mustBeField = (value, path, newSchema, oldSchema, options) => {
75
75
  case 'set':
76
76
  validator = basedSchemaFieldSetValidator;
77
77
  break;
78
+ case 'reference':
79
+ validator = basedSchemaFieldReferenceValidator;
80
+ break;
81
+ case 'references':
82
+ validator = basedSchemaFieldReferencesValidator;
83
+ break;
78
84
  default:
79
85
  validator = basedSchemaFieldSharedValidator;
80
86
  break;
@@ -214,7 +220,9 @@ export const basedSchemaStringValidator = {
214
220
  };
215
221
  export const basedSchemaFieldEnumValidator = {
216
222
  ...basedSchemaFieldSharedValidator,
217
- enum: {},
223
+ enum: {
224
+ validator: mustBeArray,
225
+ },
218
226
  };
219
227
  export const basedSchemaFieldCardinalityValidator = {
220
228
  ...basedSchemaFieldSharedValidator,
@@ -3,6 +3,10 @@ export declare const mustBeString: (value: string, path: string[]) => {
3
3
  code: ParseError;
4
4
  path: string[];
5
5
  }[];
6
+ export declare const mustBeArray: (value: string[], path: string[]) => {
7
+ code: ParseError;
8
+ path: string[];
9
+ }[];
6
10
  export declare const mustBeStringArray: (value: string[], path: string[]) => {
7
11
  code: ParseError;
8
12
  path: string[];
@@ -7,6 +7,14 @@ export const mustBeString = (value, path) => typeof value === 'string'
7
7
  path,
8
8
  },
9
9
  ];
10
+ export const mustBeArray = (value, path) => Array.isArray(value)
11
+ ? []
12
+ : [
13
+ {
14
+ code: ParseError.incorrectFormat,
15
+ path,
16
+ },
17
+ ];
10
18
  export const mustBeStringArray = (value, path) => Array.isArray(value) && value.every((i) => typeof i === 'string')
11
19
  ? []
12
20
  : [
@@ -1,5 +1,6 @@
1
1
  import test from 'ava';
2
2
  // TODO: maybe nice to use for validate import { newSchemas } from './data/newSchemas.js'
3
+ import { newSchemas } from './data/newSchemas.js';
3
4
  import { oldSchemas } from './data/oldSchemas.js';
4
5
  import { convertNewToOld, convertOldToNew, validateSchema, } from '../src/index.js';
5
6
  test('old schema compat mode', async (t) => {
@@ -12,4 +13,15 @@ test('old schema compat mode', async (t) => {
12
13
  t.deepEqual(oldSchema, convertNewToOld(newSchema), `Schema conversion oldSchemas index ${i}`);
13
14
  }
14
15
  });
16
+ test.failing('new schema compat mode', async (t) => {
17
+ for (let i = 0; i < newSchemas.length - 1; i++) {
18
+ // for (let i = 0; i < 1; i++) {
19
+ const newSchema = newSchemas[i];
20
+ const validation = await validateSchema(newSchema);
21
+ const oldSchema = convertNewToOld(newSchema);
22
+ console.dir(validation, { depth: null });
23
+ t.true(validation.valid);
24
+ t.deepEqual(newSchema, convertOldToNew(oldSchema), `Schema conversion newSchemas index ${i}`);
25
+ }
26
+ });
15
27
  //# sourceMappingURL=compat.js.map
@@ -1,2 +1,2 @@
1
- import { BasedSchema } from '../../src/types.js';
2
- export declare const newSchemas: BasedSchema[];
1
+ import { BasedSchemaPartial } from '../../src/types.js';
2
+ export declare const newSchemas: BasedSchemaPartial[];
@@ -1,4 +1,240 @@
1
+ const defaultFields = {
2
+ createdAt: {
3
+ readOnly: true,
4
+ type: 'timestamp',
5
+ },
6
+ updatedAt: {
7
+ readOnly: true,
8
+ type: 'timestamp',
9
+ },
10
+ };
11
+ const testSchema = {
12
+ language: 'en',
13
+ translations: ['pt', 'es'],
14
+ root: {
15
+ fields: {
16
+ currentSeason: {
17
+ type: 'reference',
18
+ title: 'Currently active season',
19
+ },
20
+ },
21
+ },
22
+ types: {
23
+ file: {
24
+ fields: {
25
+ ...defaultFields,
26
+ width: {
27
+ type: 'number',
28
+ },
29
+ height: {
30
+ type: 'number',
31
+ },
32
+ },
33
+ },
34
+ country: {
35
+ prefix: 'co',
36
+ title: 'Country',
37
+ description: 'This is the country',
38
+ fields: {
39
+ ...defaultFields,
40
+ name: {
41
+ type: 'string',
42
+ title: 'Country code',
43
+ },
44
+ title: {
45
+ type: 'text',
46
+ title: 'Translated country name',
47
+ },
48
+ circleImage: {
49
+ type: 'reference',
50
+ title: 'Circular flag image',
51
+ },
52
+ heartImage: {
53
+ type: 'reference',
54
+ title: 'Heart-shaped flag image',
55
+ },
56
+ },
57
+ },
58
+ season: {
59
+ prefix: 'se',
60
+ fields: {
61
+ ...defaultFields,
62
+ name: {
63
+ type: 'string',
64
+ title: 'Season name',
65
+ },
66
+ winner: {
67
+ type: 'reference',
68
+ allowedTypes: ['contestant'],
69
+ },
70
+ countries: {
71
+ type: 'references',
72
+ title: 'Participating countries',
73
+ },
74
+ },
75
+ },
76
+ episode: {
77
+ prefix: 'ep',
78
+ fields: {
79
+ ...defaultFields,
80
+ episodeType: {
81
+ type: 'string', // redemption, grandFinal, nationalFinal or nationalQualifier
82
+ title: 'Type of episode',
83
+ },
84
+ title: {
85
+ type: 'text',
86
+ title: 'Episode title',
87
+ },
88
+ image: {
89
+ type: 'reference',
90
+ allowedTypes: ['file'],
91
+ },
92
+ startTime: {
93
+ type: 'timestamp',
94
+ title: 'Start time',
95
+ },
96
+ endTime: {
97
+ type: 'timestamp',
98
+ title: 'End time',
99
+ },
100
+ producer: {
101
+ type: 'reference',
102
+ allowedTypes: ['broadcaster'],
103
+ },
104
+ distributors: {
105
+ type: 'references',
106
+ allowedTypes: ['broadcaster'],
107
+ },
108
+ },
109
+ },
110
+ votingWindow: {
111
+ prefix: 'vo',
112
+ fields: {
113
+ ...defaultFields,
114
+ startTime: {
115
+ type: 'timestamp',
116
+ },
117
+ closeTime: {
118
+ type: 'timestamp',
119
+ },
120
+ endTime: {
121
+ type: 'timestamp',
122
+ },
123
+ },
124
+ },
125
+ contestant: {
126
+ prefix: 'ct',
127
+ fields: {
128
+ ...defaultFields,
129
+ name: {
130
+ type: 'string',
131
+ },
132
+ song: {
133
+ type: 'string',
134
+ },
135
+ songUrl: {
136
+ type: 'string',
137
+ format: 'URL',
138
+ },
139
+ writer: {
140
+ type: 'string',
141
+ },
142
+ image: {
143
+ type: 'reference',
144
+ allowedTypes: ['file'],
145
+ },
146
+ content: {
147
+ type: 'text',
148
+ format: 'html',
149
+ },
150
+ },
151
+ },
152
+ broadcaster: {
153
+ prefix: 'br',
154
+ fields: {
155
+ ...defaultFields,
156
+ name: {
157
+ type: 'string',
158
+ },
159
+ email: {
160
+ type: 'string',
161
+ format: 'email',
162
+ },
163
+ image: {
164
+ type: 'reference',
165
+ allowedTypes: ['file'],
166
+ },
167
+ },
168
+ },
169
+ feed: {
170
+ prefix: 'fe',
171
+ fields: {
172
+ ...defaultFields,
173
+ title: {
174
+ type: 'text',
175
+ },
176
+ content: {
177
+ type: 'text',
178
+ format: 'html',
179
+ },
180
+ imageUrl: {
181
+ type: 'string',
182
+ format: 'URL',
183
+ },
184
+ videoUrl: {
185
+ type: 'string',
186
+ format: 'URL',
187
+ },
188
+ url: {
189
+ type: 'string',
190
+ format: 'URL',
191
+ },
192
+ },
193
+ },
194
+ user: {
195
+ prefix: 'us',
196
+ fields: {
197
+ ...defaultFields,
198
+ name: { type: 'string' },
199
+ language: { type: 'string' },
200
+ notify: { type: 'boolean' },
201
+ country: { type: 'string' },
202
+ customerId: {
203
+ // stripe customerId
204
+ type: 'string',
205
+ },
206
+ credits: {
207
+ type: 'record',
208
+ values: {
209
+ type: 'object',
210
+ properties: {
211
+ purchased: {
212
+ type: 'number',
213
+ },
214
+ earned: {
215
+ type: 'number',
216
+ },
217
+ },
218
+ },
219
+ },
220
+ voteHistory: {
221
+ type: 'record',
222
+ values: {
223
+ type: 'record',
224
+ values: {
225
+ type: 'record',
226
+ values: {
227
+ type: 'number',
228
+ },
229
+ },
230
+ },
231
+ },
232
+ },
233
+ },
234
+ },
235
+ };
1
236
  export const newSchemas = [
237
+ testSchema,
2
238
  {
3
239
  types: {
4
240
  thing: {
@@ -11,6 +247,10 @@ export const newSchemas = [
11
247
  bla: {
12
248
  prefix: 'bl',
13
249
  fields: {
250
+ createdAt: {
251
+ type: 'timestamp',
252
+ readOnly: true,
253
+ },
14
254
  enum: {
15
255
  enum: ['tony', 'jim'],
16
256
  },
@@ -109,6 +349,7 @@ export const newSchemas = [
109
349
  },
110
350
  $defs: {},
111
351
  language: 'en',
352
+ translations: [],
112
353
  root: {
113
354
  fields: {},
114
355
  },
@@ -363,4 +363,74 @@ test('arrays', async (t) => {
363
363
  ],
364
364
  });
365
365
  });
366
+ test('enum', async (t) => {
367
+ t.deepEqual(await validateSchema({
368
+ root: {
369
+ fields: {
370
+ enumField: {
371
+ enum: ['one', 'two'],
372
+ },
373
+ },
374
+ },
375
+ }), {
376
+ valid: true,
377
+ });
378
+ t.deepEqual(await validateSchema({
379
+ root: {
380
+ fields: {
381
+ enumField: {
382
+ enum: [1, 2],
383
+ },
384
+ },
385
+ },
386
+ }), {
387
+ valid: true,
388
+ });
389
+ t.deepEqual(await validateSchema({
390
+ root: {
391
+ fields: {
392
+ enumField: {
393
+ enum: [{ one: 'one' }, { two: 'two' }],
394
+ },
395
+ },
396
+ },
397
+ }), {
398
+ valid: true,
399
+ });
400
+ t.deepEqual(await validateSchema({
401
+ root: {
402
+ fields: {
403
+ enumField: {
404
+ // @ts-ignore
405
+ enum: 'invalidEnum',
406
+ },
407
+ },
408
+ },
409
+ }), {
410
+ errors: [
411
+ {
412
+ code: ParseError.incorrectFormat,
413
+ path: ['root', 'fields', 'enumField', 'enum'],
414
+ },
415
+ ],
416
+ });
417
+ t.deepEqual(await validateSchema({
418
+ root: {
419
+ fields: {
420
+ enumField: {
421
+ enum: ['one', 'two'],
422
+ // @ts-ignore
423
+ invalidProperty: 'invalid',
424
+ },
425
+ },
426
+ },
427
+ }), {
428
+ errors: [
429
+ {
430
+ code: ParseError.invalidProperty,
431
+ path: ['root', 'fields', 'enumField', 'invalidProperty'],
432
+ },
433
+ ],
434
+ });
435
+ });
366
436
  //# sourceMappingURL=fields.js.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ import test from 'ava';
2
+ import { newSchemas } from '../data/newSchemas.js';
3
+ import { validateSchema } from '../../src/index.js';
4
+ test('these schemas should work', async (t) => {
5
+ await Promise.all(newSchemas.map(async (validSchema) => {
6
+ const validation = await validateSchema(validSchema);
7
+ if (!validation.valid) {
8
+ console.dir(validation.errors, { depth: null });
9
+ }
10
+ t.true(validation.valid);
11
+ }));
12
+ });
13
+ //# sourceMappingURL=realWorld.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@based/schema",
3
- "version": "2.7.0",
3
+ "version": "2.7.1",
4
4
  "license": "MIT",
5
5
  "main": "dist/src/index.js",
6
6
  "files": [
@@ -26,7 +26,8 @@
26
26
  "ava": {
27
27
  "timeout": "2m",
28
28
  "files": [
29
- "./dist/test/*.js"
29
+ "./dist/test/*.js",
30
+ "./dist/test/validateSchema/*.js"
30
31
  ]
31
32
  },
32
33
  "devDependencies": {
@@ -35,6 +36,6 @@
35
36
  "ts-node": "10.9.1",
36
37
  "typescript": "^5.1.6",
37
38
  "rimraf": "^3.0.2",
38
- "ava": "5.3.1"
39
+ "ava": "6.1.1"
39
40
  }
40
41
  }
@@ -1,3 +0,0 @@
1
- import { BasedSchema } from '../types.js';
2
- import { BasedOldSchema } from './oldSchemaType.js';
3
- export declare const convertNewToOld222: (schema: BasedSchema) => Partial<BasedOldSchema>;
@@ -1,205 +0,0 @@
1
- const metaChecker = (field) => {
2
- return (field === 'validation' ||
3
- field === 'format' ||
4
- field === 'index' ||
5
- field === 'description' ||
6
- field === 'title' ||
7
- field === 'examples' ||
8
- field === 'ui' ||
9
- field === 'isRequired' ||
10
- field === 'title' ||
11
- field === 'description' ||
12
- field === 'index' ||
13
- field === 'readOnly' ||
14
- field === 'writeOnly' ||
15
- field === '$comment' ||
16
- field === 'examples' ||
17
- field === 'default' ||
18
- field === 'customValidator' ||
19
- field === 'value' ||
20
- field === 'path' ||
21
- field === 'target' ||
22
- field === 'minLength' ||
23
- field === 'maxLength' ||
24
- field === 'contentMediaEncoding' ||
25
- field === 'pattern' ||
26
- field === 'display' ||
27
- field === 'multiline' ||
28
- field === 'multipleOf' ||
29
- field === 'minimum' ||
30
- field === 'maximum' ||
31
- field === 'exclusiveMaximum' ||
32
- field === 'exclusiveMinimum' ||
33
- field === '$delete');
34
- };
35
- const excludedFields = (field) => {
36
- return field === 'language' || field === 'translations' || field === '$defs';
37
- };
38
- const DEFAULT_FIELDS = {
39
- id: { type: 'string' },
40
- createdAt: { type: 'timestamp' },
41
- updatedAt: { type: 'timestamp' },
42
- type: { type: 'string' },
43
- parents: { type: 'references' },
44
- children: { type: 'references' },
45
- ancestors: { type: 'references' },
46
- descendants: { type: 'references' },
47
- aliases: {
48
- type: 'set',
49
- items: { type: 'string' },
50
- },
51
- };
52
- const metaParser = (obj) => {
53
- const tmp = {};
54
- for (const i in obj) {
55
- if (metaChecker(i)) {
56
- if (i === 'title') {
57
- tmp.name = obj[i];
58
- }
59
- else {
60
- tmp[i] = obj[i];
61
- }
62
- }
63
- }
64
- return Object.keys({ meta: tmp }.meta).length > 0 ? { meta: tmp } : null;
65
- };
66
- const migrateField = (oldField) => {
67
- switch (oldField?.type) {
68
- case 'object':
69
- return {
70
- ...metaParser(oldField),
71
- type: 'object',
72
- properties: migrateFields(oldField.properties, true),
73
- };
74
- case 'json':
75
- return {
76
- ...oldField,
77
- ...metaParser(oldField),
78
- type: 'json',
79
- };
80
- case 'array':
81
- const values = migrateField(oldField.items);
82
- if (!values) {
83
- return null;
84
- }
85
- return {
86
- ...metaParser(oldField),
87
- type: 'array',
88
- items: values,
89
- };
90
- case 'set':
91
- return {
92
- ...metaParser(oldField),
93
- type: 'set',
94
- items: migrateField(oldField.items),
95
- };
96
- case 'record':
97
- return {
98
- ...metaParser(oldField),
99
- type: 'record',
100
- values: migrateField(oldField.values),
101
- };
102
- case 'reference':
103
- case 'references':
104
- return {
105
- ...metaParser(oldField),
106
- type: oldField.type,
107
- ...(oldField.bidirectional
108
- ? { bidirectional: oldField.bidirectional }
109
- : null),
110
- };
111
- case 'float':
112
- return {
113
- ...metaParser(oldField),
114
- type: 'number',
115
- };
116
- case 'int':
117
- return {
118
- ...metaParser(oldField),
119
- type: 'integer',
120
- };
121
- case 'digest':
122
- return {
123
- format: 'strongPassword',
124
- type: 'string',
125
- };
126
- case 'id':
127
- return {
128
- ...metaParser(oldField),
129
- type: 'string',
130
- };
131
- case 'url':
132
- return {
133
- ...metaParser(oldField),
134
- format: 'URL',
135
- type: 'string',
136
- };
137
- case 'email':
138
- return {
139
- ...metaParser(oldField),
140
- type: 'string',
141
- };
142
- case 'phone':
143
- return {
144
- format: 'mobilePhone',
145
- type: 'string',
146
- };
147
- case 'geo':
148
- return {
149
- format: 'latLong',
150
- type: 'string',
151
- };
152
- case 'type':
153
- return {
154
- ...metaParser(oldField),
155
- type: 'string',
156
- };
157
- default:
158
- return {
159
- ...metaParser(oldField),
160
- type: oldField.type,
161
- };
162
- }
163
- };
164
- const migrateFields = (oldFields, recursing = false) => {
165
- const result = {};
166
- if (oldFields) {
167
- for (const key in oldFields) {
168
- if (oldFields.hasOwnProperty(key)) {
169
- if (!recursing && Object.keys(DEFAULT_FIELDS).includes(key)) {
170
- continue;
171
- }
172
- const field = migrateField(oldFields[key]);
173
- if (!field) {
174
- continue;
175
- }
176
- result[key] = field;
177
- }
178
- }
179
- }
180
- return result;
181
- };
182
- const migrateTypes = (oldSchema) => {
183
- const result = {
184
- types: {},
185
- };
186
- for (const key in oldSchema.types) {
187
- if (oldSchema.types.hasOwnProperty(key)) {
188
- const type = oldSchema.types[key];
189
- result.types[key] = {
190
- ...metaParser(type),
191
- prefix: type.prefix,
192
- fields: migrateFields(type.fields),
193
- };
194
- }
195
- }
196
- return result;
197
- };
198
- export const convertNewToOld222 = (schema) => {
199
- const tmpSchema = migrateTypes(schema);
200
- tmpSchema.prefixToTypeMapping = schema.prefixToTypeMapping;
201
- tmpSchema.languages = [schema.language, ...schema?.translations];
202
- delete tmpSchema.root;
203
- return tmpSchema;
204
- };
205
- //# sourceMappingURL=Untitled-1.js.map