@based/schema 5.0.4-alpha.1 → 5.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.
@@ -1,13 +1,86 @@
1
1
  import { convertToTimestamp } from '@based/utils';
2
- import { ALIAS, BINARY, JSON, BOOLEAN, CARDINALITY, TIMESTAMP, INT16, INT32, INT8, UINT8, UINT16, UINT32, NUMBER, ENUM, ID, MICRO_BUFFER, REFERENCE, REFERENCES, STRING, TEXT, ALIASES, VECTOR, COLVEC, WEAK_REFERENCE, WEAK_REFERENCES, NULL, OBJECT, } from './types.js';
3
- import { MAX_ID, MIN_ID } from '../types.js';
2
+ import { ALIAS, BINARY, JSON, BOOLEAN, CARDINALITY, TIMESTAMP, INT16, INT32, INT8, UINT8, UINT16, UINT32, NUMBER, ENUM, ID, MICRO_BUFFER, REFERENCE, REFERENCES, STRING, TEXT, ALIASES, VECTOR, COLVEC, NULL, OBJECT, TYPE_INDEX_MAP, } from './types.js';
3
+ import { MAX_ID, MIN_ID, } from '../types.js';
4
+ import v from 'validator';
5
+ import { getPropType } from '../parse/index.js';
4
6
  const EPSILON = 1e-9; // Small tolerance for floating point comparisons
7
+ const validators = {
8
+ email: v.isEmail,
9
+ URL: v.isURL,
10
+ MACAddress: v.isMACAddress,
11
+ IP: v.isIP,
12
+ IPRange: v.isIPRange,
13
+ FQDN: v.isFQDN,
14
+ IBAN: v.isIBAN,
15
+ BIC: v.isBIC,
16
+ alpha: v.isAlpha,
17
+ alphaLocales: v.isAlphaLocales,
18
+ alphanumeric: v.isAlphanumeric,
19
+ alphanumericLocales: v.isAlphanumericLocales,
20
+ passportNumber: v.isPassportNumber,
21
+ port: v.isPort,
22
+ lowercase: v.isLowercase,
23
+ uppercase: v.isUppercase,
24
+ ascii: v.isAscii,
25
+ semVer: v.isSemVer,
26
+ surrogatePair: v.isSurrogatePair,
27
+ IMEI: v.isIMEI,
28
+ hexadecimal: v.isHexadecimal,
29
+ octal: v.isOctal,
30
+ hexColor: v.isHexColor,
31
+ rgbColor: v.isRgbColor,
32
+ HSL: v.isHSL,
33
+ ISRC: v.isISRC,
34
+ MD5: v.isMD5,
35
+ JWT: v.isJWT,
36
+ UUID: v.isUUID,
37
+ luhnNumber: v.isLuhnNumber,
38
+ creditCard: v.isCreditCard,
39
+ identityCard: v.isIdentityCard,
40
+ EAN: v.isEAN,
41
+ ISIN: v.isISIN,
42
+ ISBN: v.isISBN,
43
+ ISSN: v.isISSN,
44
+ mobilePhone: v.isMobilePhone,
45
+ mobilePhoneLocales: v.isMobilePhoneLocales,
46
+ postalCode: v.isPostalCode,
47
+ postalCodeLocales: v.isPostalCodeLocales,
48
+ ethereumAddress: v.isEthereumAddress,
49
+ currency: v.isCurrency,
50
+ btcAddress: v.isBtcAddress,
51
+ ISO6391: v.isISO6391,
52
+ ISO8601: v.isISO8601,
53
+ RFC3339: v.isRFC3339,
54
+ ISO31661Alpha2: v.isISO31661Alpha2,
55
+ ISO31661Alpha3: v.isISO31661Alpha3,
56
+ ISO4217: v.isISO4217,
57
+ base32: v.isBase32,
58
+ base58: v.isBase58,
59
+ base64: v.isBase64,
60
+ dataURI: v.isDataURI,
61
+ magnetURI: v.isMagnetURI,
62
+ mimeType: v.isMimeType,
63
+ latLong: v.isLatLong,
64
+ slug: v.isSlug,
65
+ password: v.isStrongPassword,
66
+ taxID: v.isTaxID,
67
+ licensePlate: v.isLicensePlate,
68
+ VAT: v.isVAT,
69
+ code: () => true,
70
+ javascript: () => true,
71
+ typescript: () => true,
72
+ python: () => true,
73
+ rust: () => true,
74
+ css: () => true,
75
+ html: () => true,
76
+ json: () => true,
77
+ markdown: () => true,
78
+ clike: () => true,
79
+ };
5
80
  export const VALIDATION_MAP = {
6
81
  [NULL]: () => true,
7
82
  [OBJECT]: () => true,
8
83
  [COLVEC]: () => true,
9
- [WEAK_REFERENCE]: () => true,
10
- [WEAK_REFERENCES]: () => true,
11
84
  [ALIAS]: (value) => {
12
85
  if (typeof value !== 'string') {
13
86
  return false;
@@ -31,7 +104,9 @@ export const VALIDATION_MAP = {
31
104
  (val instanceof Uint8Array && val.byteLength === 8));
32
105
  },
33
106
  [TIMESTAMP]: (value, t) => {
34
- if (typeof value !== 'number' || value % t.step !== 0) {
107
+ if (typeof value !== 'number' ||
108
+ (t.step && value % t.step !== 0) ||
109
+ isNaN(value)) {
35
110
  return false;
36
111
  }
37
112
  if (t.min !== undefined) {
@@ -57,7 +132,9 @@ export const VALIDATION_MAP = {
57
132
  return true;
58
133
  },
59
134
  [INT16]: (value, t) => {
60
- if (typeof value !== 'number' || value % t.step !== 0) {
135
+ if (typeof value !== 'number' ||
136
+ (t.step && value % t.step !== 0) ||
137
+ isNaN(value)) {
61
138
  return false;
62
139
  }
63
140
  if (value > 32767 || value < -32768) {
@@ -72,7 +149,9 @@ export const VALIDATION_MAP = {
72
149
  return true;
73
150
  },
74
151
  [INT32]: (value, t) => {
75
- if (typeof value !== 'number' || value % t.step !== 0) {
152
+ if (typeof value !== 'number' ||
153
+ (t.step && value % t.step !== 0) ||
154
+ isNaN(value)) {
76
155
  return false;
77
156
  }
78
157
  if (value > 2147483647 || value < -2147483648) {
@@ -88,7 +167,9 @@ export const VALIDATION_MAP = {
88
167
  },
89
168
  [INT8]: (value, t) => {
90
169
  // use % for steps size
91
- if (typeof value !== 'number' || value % t.step !== 0) {
170
+ if (typeof value !== 'number' ||
171
+ (t.step && value % t.step !== 0) ||
172
+ isNaN(value)) {
92
173
  return false;
93
174
  }
94
175
  if (value > 127 || value < -128) {
@@ -103,7 +184,9 @@ export const VALIDATION_MAP = {
103
184
  return true;
104
185
  },
105
186
  [UINT8]: (value, t) => {
106
- if (typeof value !== 'number' || value % t.step !== 0) {
187
+ if (typeof value !== 'number' ||
188
+ (t.step && value % t.step !== 0) ||
189
+ isNaN(value)) {
107
190
  return false;
108
191
  }
109
192
  if (value > 255 || value < 0) {
@@ -118,7 +201,9 @@ export const VALIDATION_MAP = {
118
201
  return true;
119
202
  },
120
203
  [UINT16]: (value, t) => {
121
- if (typeof value !== 'number' || value % t.step !== 0) {
204
+ if (typeof value !== 'number' ||
205
+ (t.step && value % t.step !== 0) ||
206
+ isNaN(value)) {
122
207
  return false;
123
208
  }
124
209
  if (value > 65535 || value < 0) {
@@ -133,7 +218,9 @@ export const VALIDATION_MAP = {
133
218
  return true;
134
219
  },
135
220
  [UINT32]: (value, t) => {
136
- if (typeof value !== 'number' || value % t.step !== 0) {
221
+ if (typeof value !== 'number' ||
222
+ (t.step && value % t.step !== 0) ||
223
+ isNaN(value)) {
137
224
  return false;
138
225
  }
139
226
  if (value > 4294967295 || value < 0) {
@@ -165,11 +252,11 @@ export const VALIDATION_MAP = {
165
252
  }
166
253
  return true;
167
254
  },
168
- [ENUM]: (value, prop) => {
255
+ [ENUM]: (value, t) => {
169
256
  if (value === null) {
170
257
  return true;
171
258
  }
172
- const arr = prop.enum;
259
+ const arr = t.enum;
173
260
  for (let i = 0; i < arr.length; i++) {
174
261
  if (value === arr[i]) {
175
262
  return true;
@@ -211,18 +298,22 @@ export const VALIDATION_MAP = {
211
298
  }
212
299
  return true;
213
300
  },
214
- [STRING]: (value, t) => {
215
- // add max etc all here - make a ref to the original SCHEMA on DEF
216
- if (typeof value !== 'string' && !(value instanceof Uint8Array)) {
301
+ [STRING]: (v, t) => {
302
+ if (v instanceof Uint8Array) {
303
+ return !!v[1];
304
+ }
305
+ if (typeof v !== 'string') {
217
306
  return false;
218
307
  }
219
- return true;
220
- },
221
- [TEXT]: (value, t) => {
222
- // add max etc all here - make a ref to the original SCHEMA on DEF
223
- if (typeof value !== 'string' && !(value instanceof Uint8Array)) {
308
+ if (t.max !== undefined && v.length > t.max) {
309
+ return false;
310
+ }
311
+ if (t.min !== undefined && v.length < t.min) {
224
312
  return false;
225
313
  }
314
+ if (t.format !== undefined && t.format in validators) {
315
+ return validators[t.format](v);
316
+ }
226
317
  return true;
227
318
  },
228
319
  [ALIASES]: (value) => {
@@ -244,7 +335,9 @@ export const VALIDATION_MAP = {
244
335
  }
245
336
  return true;
246
337
  },
338
+ [TEXT]: null,
247
339
  };
340
+ VALIDATION_MAP[TEXT] = VALIDATION_MAP[STRING];
248
341
  export const defaultValidation = () => true;
249
342
  export const isValidId = (id) => {
250
343
  if (typeof id != 'number' || id < MIN_ID || id > MAX_ID) {
@@ -258,4 +351,64 @@ export const isValidString = (v) => {
258
351
  ArrayBuffer.isView(v);
259
352
  return isVal;
260
353
  };
354
+ const validateObj = (value, props, errors, path, required) => {
355
+ if (!props) {
356
+ errors.push({ path, value, error: 'Unexpected property' });
357
+ return;
358
+ }
359
+ if (value === null || typeof value !== 'object') {
360
+ if (required) {
361
+ errors.push({ path, value, error: 'Missing required value' });
362
+ return;
363
+ }
364
+ }
365
+ else {
366
+ for (const key in value) {
367
+ if (!(key in props)) {
368
+ errors.push({
369
+ path: [...path, key],
370
+ value: value[key],
371
+ error: 'Unexpected property',
372
+ });
373
+ }
374
+ }
375
+ }
376
+ for (const key in props) {
377
+ const val = value?.[key];
378
+ const prop = props[key];
379
+ if ('props' in prop) {
380
+ validateObj(val, prop.props, errors, [...path, key], prop.required);
381
+ }
382
+ else if (val !== undefined) {
383
+ const test = getValidator(prop);
384
+ const msg = test(val, prop);
385
+ if (msg !== true) {
386
+ errors.push({
387
+ path: [...path, key],
388
+ value: val,
389
+ error: typeof msg === 'string' ? msg : 'Invalid value',
390
+ });
391
+ }
392
+ }
393
+ }
394
+ };
395
+ export const getValidator = (prop) => {
396
+ const validator = VALIDATION_MAP[TYPE_INDEX_MAP[getPropType(prop)]] ?? defaultValidation;
397
+ const custom = prop.validation;
398
+ if (custom) {
399
+ return (a, b) => {
400
+ const msg = custom(a, b);
401
+ return msg === true ? validator(a, b) : msg;
402
+ };
403
+ }
404
+ return validator;
405
+ };
406
+ export function validate(schema, type, payload) {
407
+ const errors = [];
408
+ validateObj(payload, schema?.types?.[type]?.props, errors, [], true);
409
+ return {
410
+ valid: !errors.length,
411
+ errors,
412
+ };
413
+ }
261
414
  //# sourceMappingURL=validation.js.map
package/dist/infer.d.ts CHANGED
@@ -66,7 +66,7 @@ type InferSchemaTypes<T> = {
66
66
  type InferSchema<T extends Schema> = T extends {
67
67
  types: infer Types;
68
68
  } ? Types extends Record<string, any> ? InferSchemaTypes<Types> : never : never;
69
- export type Infer<T> = InferSchema<T>;
69
+ export type Infer<T extends Schema> = InferSchema<T>;
70
70
  export declare const infer: <T extends {
71
71
  types: Record<string, any>;
72
72
  }>(schema: T) => InferSchema<T>;
@@ -1,15 +1,12 @@
1
1
  import { convertToTimestamp } from '@based/utils';
2
2
  import { NUMBER, TYPE_INDEX_MAP } from '../def/types.js';
3
- import { VALIDATION_MAP } from '../def/validation.js';
4
- import { stringFormats, dateDisplays, numberDisplays, } from '../types.js';
3
+ import { getValidator } from '../def/validation.js';
4
+ import { stringFormats, } from '../types.js';
5
5
  import { expectBoolean, expectFunction, expectNumber, expectObject, expectString, } from './assert.js';
6
6
  import { EXPECTED_ARR, EXPECTED_OBJ, EXPECTED_PRIMITIVE, INVALID_VALUE, MIN_MAX, MISSING_TYPE, TEXT_REQUIRES_LOCALES, TYPE_MISMATCH, UNKNOWN_PROP, NOT_ALLOWED_IN_ITEMS, } from './errors.js';
7
7
  import { getPropType } from './utils.js';
8
- import { DEFAULT_MAP } from '../def/defaultMap.js';
9
8
  import { parseMinMaxStep } from '../def/utils.js';
10
9
  let stringFormatsSet;
11
- let numberDisplaysSet;
12
- let dateDisplaysSet;
13
10
  const STUB = {};
14
11
  const shared = {
15
12
  type() { },
@@ -49,15 +46,18 @@ const shared = {
49
46
  description(val) {
50
47
  expectString(val);
51
48
  },
52
- readOnly(val) {
53
- expectBoolean(val);
54
- },
55
49
  examples(val) {
56
50
  expectString(val);
57
51
  },
58
52
  validation(val) {
59
53
  expectFunction(val);
60
54
  },
55
+ hooks(val, prop, ctx) {
56
+ expectObject(val);
57
+ for (const key in val) {
58
+ expectFunction(val[key]);
59
+ }
60
+ },
61
61
  };
62
62
  function propParser(required, optional, allowShorthand) {
63
63
  return (prop, ctx) => {
@@ -118,35 +118,25 @@ export const isDefault = (val, prop, ctx) => {
118
118
  if (prop.type === 'timestamp') {
119
119
  val = convertToTimestamp(val);
120
120
  }
121
- const validation = prop.validation || VALIDATION_MAP[typeIndex];
122
- const propDef = {
123
- typeIndex,
124
- __isPropDef: true,
125
- start: 0,
126
- path: [],
127
- prop: 0,
128
- len: 0,
129
- separate: false,
130
- enum: prop.enum,
131
- validation,
132
- default: DEFAULT_MAP[typeIndex],
121
+ const validation = getValidator(prop);
122
+ const tmpProp = Object.assign({}, prop, {
133
123
  step: parseMinMaxStep((prop.step ?? typeIndex === NUMBER) ? 0 : 1),
134
124
  max: parseMinMaxStep(prop.max),
135
125
  min: parseMinMaxStep(prop.min),
136
- };
126
+ });
137
127
  if (prop.type === 'text') {
138
128
  if (typeof val === 'object') {
139
129
  for (const key in val) {
140
130
  if (!ctx.schema.locales || !(key in ctx.schema.locales)) {
141
131
  throw new Error(`Incorrect default for type "text" lang "${key}"`);
142
132
  }
143
- if (!validation(val[key], propDef)) {
133
+ if (!validation(val[key], tmpProp)) {
144
134
  throw new Error(`Incorrect default for type "text" lang "${key}"`);
145
135
  }
146
136
  }
147
137
  }
148
138
  else {
149
- if (!validation(val, propDef)) {
139
+ if (!validation(val, tmpProp)) {
150
140
  throw new Error(`Incorrect default for type "text"`);
151
141
  }
152
142
  val = {};
@@ -156,7 +146,7 @@ export const isDefault = (val, prop, ctx) => {
156
146
  }
157
147
  return val;
158
148
  }
159
- if (!validation(val, propDef)) {
149
+ if (!validation(val, tmpProp)) {
160
150
  throw new Error(`Incorrect default for type "${prop.type ?? 'enum'}"`);
161
151
  }
162
152
  if ('enum' in prop) {
@@ -184,7 +174,6 @@ p.vector = propParser({
184
174
  if (![
185
175
  'number',
186
176
  'int8',
187
- ,
188
177
  'uint8',
189
178
  'int16',
190
179
  'uint16',
@@ -242,21 +231,16 @@ p.enum = propParser({
242
231
  },
243
232
  }, 1);
244
233
  const numberOpts = {
245
- display(val) {
246
- expectString(val);
247
- numberDisplaysSet ??= new Set(numberDisplays);
248
- numberDisplaysSet.has(val);
249
- },
250
- min(val) {
234
+ min(val, prop, ctx, key) {
251
235
  expectNumber(val);
252
236
  },
253
- max(val, prop) {
237
+ max(val, prop, ctx, key) {
254
238
  expectNumber(val);
255
239
  if (prop.min > val) {
256
240
  throw Error(MIN_MAX);
257
241
  }
258
242
  },
259
- step(val) {
243
+ step(val, prop, ctx, key) {
260
244
  if (typeof val !== 'number' && val !== 'any') {
261
245
  throw Error(INVALID_VALUE);
262
246
  }
@@ -277,32 +261,6 @@ p.object = propParser({
277
261
  ctx.parseProps(val, ctx.type);
278
262
  },
279
263
  }, {});
280
- p.set = propParser({
281
- items(items, prop, ctx) {
282
- expectObject(items);
283
- const itemsType = getPropType(items);
284
- if (itemsType === 'string' ||
285
- itemsType === 'number' ||
286
- itemsType === 'timestamp' ||
287
- itemsType === 'boolean') {
288
- ctx.inQuery = 'query' in prop;
289
- ctx.isItems = true;
290
- p[itemsType](items, ctx);
291
- ctx.inQuery = false;
292
- ctx.isItems = false;
293
- }
294
- else {
295
- throw new Error(INVALID_VALUE);
296
- }
297
- },
298
- }, {
299
- default(val, prop) {
300
- console.warn('TODO SET DEFAULT VALUE');
301
- // if (typeof val === 'object') {
302
- // throwErr(ERRORS.EXPECTED_PRIMITIVE, prop, 'default')
303
- // }
304
- },
305
- });
306
264
  p.references = propParser({
307
265
  items(items, prop, ctx) {
308
266
  expectObject(items);
@@ -377,11 +335,6 @@ p.text = propParser({
377
335
  },
378
336
  }, 0);
379
337
  p.timestamp = propParser(STUB, {
380
- display(val) {
381
- expectString(val);
382
- dateDisplaysSet ??= new Set(dateDisplays);
383
- dateDisplaysSet.has(val);
384
- },
385
338
  min(val) {
386
339
  if (typeof val !== 'string' && typeof val !== 'number') {
387
340
  throw Error(INVALID_VALUE);
@@ -436,7 +389,6 @@ p.reference = propParser({
436
389
  for (let i = 3; i < lvl; i += 2) {
437
390
  prop += prop ? `.${path[i]}` : path[i];
438
391
  }
439
- targetProp.readOnly = true;
440
392
  targetProp.items = {
441
393
  ref,
442
394
  prop,
@@ -474,13 +426,15 @@ p.reference = propParser({
474
426
  if (edgeAllowed) {
475
427
  let t = ctx.schema.types[prop.ref].props[prop.prop];
476
428
  t = t.items || t;
477
- if (t[key] && t !== prop) {
478
- throw Error('Edge can not be defined on both props');
479
- }
480
- const edgePropType = getPropType(val);
429
+ // if (t[key] && t !== prop) {
430
+ // throw Error('Edge can not be defined on both props')
431
+ // }
432
+ // @ts-ignore
433
+ const edgePropType = getPropType(val, prop, key);
481
434
  const inType = ctx.type;
482
435
  ctx.type = null;
483
436
  p[edgePropType](val, ctx);
437
+ t[key] = prop[key];
484
438
  ctx.type = inType;
485
439
  return;
486
440
  }
@@ -15,11 +15,15 @@ export const getPropType = (prop, props, key) => {
15
15
  if ('ref' in prop) {
16
16
  return 'reference';
17
17
  }
18
- if ('items' in prop) {
19
- if (getPropType(prop.items) === 'reference') {
20
- return 'references';
21
- }
22
- return 'set';
18
+ if ('items' in prop && getPropType(prop.items) === 'reference') {
19
+ Object.keys(prop.items)
20
+ .filter((v) => v[0] === '$')
21
+ .forEach((v) => {
22
+ if (typeof prop.items[v] === 'string') {
23
+ prop.items[v] = { type: prop.items[v] };
24
+ }
25
+ });
26
+ return 'references';
23
27
  }
24
28
  if ('props' in prop) {
25
29
  return 'object';
package/dist/types.d.ts CHANGED
@@ -1,11 +1,6 @@
1
1
  import type { LangName } from './lang.js';
2
2
  import type { Validation } from './def/validation.js';
3
- type Role = 'title' | 'source' | 'media' | string;
4
- export declare const numberDisplays: readonly ["short", "human", "ratio", "bytes", "euro", "dollar", "pound", "meter"];
5
- export declare const dateDisplays: readonly ["date", "date-time", "date-time-text", "date-time-human", "date-time-human-short", "time", "time-precise"];
6
- export declare const stringFormats: readonly ["alpha", "alphaLocales", "alphanumeric", "alphanumericLocales", "ascii", "base32", "base58", "base64", "BIC", "btcAddress", "clike", "code", "creditCard", "css", "currency", "dataURI", "EAN", "email", "ethereumAddress", "FQDN", "hexadecimal", "hexColor", "HSL", "html", "IBAN", "identityCard", "IMEI", "IP", "IPRange", "ISBN", "ISIN", "ISO31661Alpha2", "ISO31661Alpha3", "ISO4217", "ISO6391", "ISO8601", "ISRC", "ISSN", "javascript", "json", "JWT", "latLong", "licensePlate", "lowercase", "luhnNumber", "MACAddress", "magnetURI", "markdown", "MD5", "mimeType", "mobilePhone", "mobilePhoneLocales", "octal", "password", "passportNumber", "port", "postalCode", "postalCodeLocales", "python", "RFC3339", "rgbColor", "rust", "semVer", "slug", "surrogatePair", "taxID", "typescript", "uppercase", "URL", "UUID", "VAT", "multiline"];
7
- type DateDisplay = (typeof dateDisplays)[number];
8
- type NumberDisplay = (typeof numberDisplays)[number] | `round-${number}`;
3
+ export declare const stringFormats: readonly ["alpha", "alphaLocales", "alphanumeric", "alphanumericLocales", "ascii", "base32", "base58", "base64", "BIC", "btcAddress", "clike", "code", "creditCard", "css", "currency", "dataURI", "EAN", "email", "ethereumAddress", "FQDN", "hexadecimal", "hexColor", "HSL", "html", "IBAN", "identityCard", "IMEI", "IP", "IPRange", "ISBN", "ISIN", "ISO31661Alpha2", "ISO31661Alpha3", "ISO4217", "ISO6391", "ISO8601", "ISRC", "ISSN", "javascript", "json", "JWT", "latLong", "licensePlate", "lowercase", "luhnNumber", "MACAddress", "magnetURI", "markdown", "MD5", "mimeType", "mobilePhone", "mobilePhoneLocales", "octal", "password", "passportNumber", "port", "postalCode", "postalCodeLocales", "python", "RFC3339", "rgbColor", "rust", "semVer", "slug", "surrogatePair", "taxID", "typescript", "uppercase", "URL", "UUID", "VAT"];
9
4
  type StringFormat = (typeof stringFormats)[number];
10
5
  type MimeString = 'text/html' | 'text/plain' | 'text/markdown' | 'image/png' | 'image/jpeg' | 'video/mp4' | 'video/quicktime' | 'image/*' | 'video/*' | 'audio/*' | '*/*' | `${string}/${string}`;
11
6
  type Mime = MimeString | MimeString[];
@@ -21,12 +16,9 @@ type Prop<V extends PropValues> = {
21
16
  required?: boolean;
22
17
  title?: string | Record<string, string>;
23
18
  description?: string | Record<string, string>;
24
- path?: string;
25
- query?: QueryFn;
26
- role?: Role;
27
- readOnly?: boolean;
28
19
  examples?: string[];
29
20
  validation?: Validation;
21
+ hooks?: SchemaPropHooks;
30
22
  } & V;
31
23
  type EnumItem = string | number | boolean;
32
24
  type NeverInItems = {
@@ -54,11 +46,7 @@ export type SchemaNumber = Prop<{
54
46
  default?: number;
55
47
  min?: number;
56
48
  max?: number;
57
- step?: number | 'any';
58
- display?: NumberDisplay;
59
- history?: {
60
- interval: 'year' | 'month' | 'week' | 'day' | 'hour' | 'minute' | 'second';
61
- };
49
+ step?: number;
62
50
  }>;
63
51
  export type SchemaString = Prop<{
64
52
  type: 'string';
@@ -120,14 +108,13 @@ export type SchemaColvec = Prop<{
120
108
  */
121
109
  baseType?: SchemaVectorBaseType;
122
110
  }>;
123
- export type SchemaTimestamp = Prop<{
111
+ export type SchemaTimestamp<isStrict = false> = Prop<{
124
112
  type: 'timestamp';
125
113
  default?: number | Date | string;
126
114
  on?: 'create' | 'update';
127
- display?: DateDisplay;
128
115
  min?: number | string;
129
116
  max?: number | string;
130
- step?: number | 'any' | string;
117
+ step?: isStrict extends true ? number : number | string;
131
118
  }>;
132
119
  export type SchemaReferenceOneWay = Prop<{
133
120
  type?: 'reference';
@@ -143,9 +130,9 @@ export type SchemaReference = Prop<{
143
130
  dependent?: boolean;
144
131
  mime?: Mime;
145
132
  }> & Record<`$${string}`, SchemaPropOneWay>;
146
- export type SchemaObject = Prop<{
133
+ export type SchemaObject<isStrict = false> = Prop<{
147
134
  type?: 'object';
148
- props: SchemaProps;
135
+ props: SchemaProps<isStrict>;
149
136
  }>;
150
137
  export type SchemaObjectOneWay = Prop<{
151
138
  type?: 'object';
@@ -166,15 +153,7 @@ export type SchemaAlias = Omit<SchemaString, 'type'> & {
166
153
  type: 'alias';
167
154
  };
168
155
  export type SchemaPropShorthand = 'timestamp' | 'binary' | 'boolean' | 'string' | 'alias' | 'text' | 'json' | 'cardinality' | NumberType | EnumItem[];
169
- type SetItems<isStrict = false> = SchemaTimestamp | SchemaBoolean | SchemaNumber | SchemaString | SchemaEnum | (isStrict extends true ? never : 'timestamp' | 'binary' | 'boolean' | 'string' | NumberType | EnumItem[]);
170
- export type SchemaSet<ItemsType extends SetItems = SetItems> = Prop<{
171
- type?: 'set';
172
- default?: ItemsType extends {
173
- default: any;
174
- } ? ItemsType['default'][] : undefined;
175
- items: ItemsType & NeverInItems;
176
- }>;
177
- type NonRefSchemaProps<isStrict = false> = SchemaTimestamp | SchemaBoolean | SchemaNumber | SchemaString | SchemaAlias | SchemaText | SchemaEnum | SchemaJson | SchemaBinary | SchemaCardinality | SchemaVector | SchemaColvec | (isStrict extends true ? SchemaSet<SetItems<true>> : SchemaPropShorthand | SchemaSet);
156
+ type NonRefSchemaProps<isStrict = false> = SchemaTimestamp<isStrict> | SchemaBoolean | SchemaNumber | SchemaString | SchemaAlias | SchemaText | SchemaEnum | SchemaJson | SchemaBinary | SchemaCardinality | SchemaVector | SchemaColvec | (isStrict extends true ? never : SchemaPropShorthand);
178
157
  export type SchemaProp<isStrict = false> = SchemaReferencesWithQuery | SchemaReferenceWithQuery | NonRefSchemaProps<isStrict> | SchemaReferences | SchemaReference | SchemaObject | SchemaBinary;
179
158
  export type SchemaPropOneWay<isStrict = false> = SchemaReferencesOneWay | SchemaReferenceOneWay | SchemaObjectOneWay | NonRefSchemaProps<isStrict>;
180
159
  export type SchemaAnyProp = SchemaPropOneWay | SchemaProp;
@@ -196,10 +175,24 @@ export type SchemaHooks = {
196
175
  groupBy?: (query: BasedDbQuery, field: string) => void;
197
176
  aggregate?: (query: BasedDbQuery, fields: Set<string>) => void;
198
177
  };
178
+ export type SchemaPropHooks = {
179
+ create?: (value: any, payload: Record<string, any>) => any;
180
+ update?: (value: any, payload: Record<string, any>) => any;
181
+ read?: (value: any, result: Record<string, any>) => any;
182
+ aggregate?: (query: BasedDbQuery, fields: Set<string>) => void;
183
+ search?: (query: BasedDbQuery, fields: Set<string>) => void;
184
+ groupBy?: (query: BasedDbQuery, field: string) => void;
185
+ filter?: (query: BasedDbQuery, field: string, operator: Operator, value: any) => void;
186
+ include?: (query: BasedDbQuery, fields: Map<string, {
187
+ field: string;
188
+ opts?: any;
189
+ }>) => void;
190
+ };
199
191
  type GenericSchemaType<isStrict = false> = {
200
192
  hooks?: SchemaHooks;
201
193
  id?: number;
202
194
  blockCapacity?: number;
195
+ capped?: number;
203
196
  insertOnly?: boolean;
204
197
  partial?: boolean;
205
198
  props: SchemaProps<isStrict>;
@@ -246,7 +239,6 @@ export type SchemaPropTypeMap = {
246
239
  enum: SchemaEnum;
247
240
  text: SchemaText;
248
241
  json: SchemaJson;
249
- set: SchemaSet;
250
242
  binary: SchemaBinary;
251
243
  cardinality: SchemaCardinality;
252
244
  vector: SchemaVector;
package/dist/types.js CHANGED
@@ -1,23 +1,4 @@
1
1
  import { getPropType } from './parse/utils.js';
2
- export const numberDisplays = [
3
- 'short',
4
- 'human',
5
- 'ratio',
6
- 'bytes',
7
- 'euro',
8
- 'dollar',
9
- 'pound',
10
- 'meter',
11
- ];
12
- export const dateDisplays = [
13
- 'date',
14
- 'date-time',
15
- 'date-time-text',
16
- 'date-time-human',
17
- 'date-time-human-short',
18
- 'time',
19
- 'time-precise',
20
- ];
21
2
  export const stringFormats = [
22
3
  'alpha',
23
4
  'alphaLocales',
@@ -90,8 +71,6 @@ export const stringFormats = [
90
71
  'URL',
91
72
  'UUID',
92
73
  'VAT',
93
- // TODO: for discussion
94
- 'multiline',
95
74
  ];
96
75
  export const isPropType = (type, prop) => {
97
76
  return getPropType(prop) === type;