@based/schema 0.0.16 → 1.0.2

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 (105) hide show
  1. package/dist/error.d.ts +18 -0
  2. package/dist/error.js +31 -0
  3. package/dist/error.js.map +1 -0
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.js +1 -1
  6. package/dist/index.js.map +1 -1
  7. package/dist/set/collections.js +14 -32
  8. package/dist/set/collections.js.map +1 -1
  9. package/dist/set/error.d.ts +1 -2
  10. package/dist/set/error.js +3 -8
  11. package/dist/set/error.js.map +1 -1
  12. package/dist/set/fields/array.d.ts +2 -0
  13. package/dist/set/fields/array.js +96 -0
  14. package/dist/set/fields/array.js.map +1 -0
  15. package/dist/set/fields/index.d.ts +3 -0
  16. package/dist/set/fields/index.js +72 -0
  17. package/dist/set/fields/index.js.map +1 -0
  18. package/dist/set/fields/number.d.ts +4 -0
  19. package/dist/set/fields/number.js +121 -0
  20. package/dist/set/fields/number.js.map +1 -0
  21. package/dist/set/fields/object.d.ts +3 -0
  22. package/dist/set/fields/object.js +33 -0
  23. package/dist/set/fields/object.js.map +1 -0
  24. package/dist/set/fields/references.d.ts +3 -0
  25. package/dist/set/fields/references.js +106 -0
  26. package/dist/set/fields/references.js.map +1 -0
  27. package/dist/set/fields/set.d.ts +2 -0
  28. package/dist/set/fields/set.js +63 -0
  29. package/dist/set/fields/set.js.map +1 -0
  30. package/dist/set/fields/string.d.ts +3 -0
  31. package/dist/set/fields/string.js +190 -0
  32. package/dist/set/fields/string.js.map +1 -0
  33. package/dist/set/index.d.ts +2 -5
  34. package/dist/set/index.js +101 -126
  35. package/dist/set/index.js.map +1 -1
  36. package/dist/set/isValidId.d.ts +2 -0
  37. package/dist/set/isValidId.js +21 -0
  38. package/dist/set/isValidId.js.map +1 -0
  39. package/dist/set/number.js +23 -36
  40. package/dist/set/number.js.map +1 -1
  41. package/dist/set/parseDefaultAndValue.js +1 -3
  42. package/dist/set/parseDefaultAndValue.js.map +1 -1
  43. package/dist/set/references.js +5 -12
  44. package/dist/set/references.js.map +1 -1
  45. package/dist/set/rest.js +4 -4
  46. package/dist/set/rest.js.map +1 -1
  47. package/dist/set/string.js +35 -35
  48. package/dist/set/string.js.map +1 -1
  49. package/dist/set/types.d.ts +0 -5
  50. package/dist/set/types.js +0 -2
  51. package/dist/types.d.ts +7 -1
  52. package/dist/types.js.map +1 -1
  53. package/dist/walker/args.d.ts +31 -0
  54. package/dist/walker/args.js +120 -0
  55. package/dist/walker/args.js.map +1 -0
  56. package/dist/walker/index.d.ts +6 -0
  57. package/dist/walker/index.js +40 -0
  58. package/dist/walker/index.js.map +1 -0
  59. package/dist/walker/parse.d.ts +2 -0
  60. package/dist/walker/parse.js +157 -0
  61. package/dist/walker/parse.js.map +1 -0
  62. package/dist/walker/types.d.ts +44 -0
  63. package/dist/walker/types.js +9 -0
  64. package/dist/walker/types.js.map +1 -0
  65. package/package.json +2 -2
  66. package/src/{set/error.ts → error.ts} +3 -1
  67. package/src/index.ts +2 -2
  68. package/src/set/fields/array.ts +111 -0
  69. package/src/set/fields/index.ts +69 -0
  70. package/src/set/fields/number.ts +134 -0
  71. package/src/set/fields/object.ts +30 -0
  72. package/src/set/fields/references.ts +114 -0
  73. package/src/set/fields/set.ts +63 -0
  74. package/src/set/fields/string.ts +199 -0
  75. package/src/set/index.ts +105 -187
  76. package/src/set/isValidId.ts +23 -0
  77. package/src/set/types.ts +0 -20
  78. package/src/types.ts +4 -2
  79. package/src/walker/args.ts +159 -0
  80. package/src/walker/index.ts +35 -0
  81. package/src/walker/parse.ts +193 -0
  82. package/src/walker/types.ts +75 -0
  83. package/test/number.ts +289 -543
  84. package/test/reference.ts +150 -198
  85. package/test/rest.ts +227 -0
  86. package/test/string.ts +139 -183
  87. package/test/utils/index.ts +23 -0
  88. package/test/walker.ts +558 -3
  89. package/dist/set2/index.d.ts +0 -0
  90. package/dist/set2/index.js +0 -71
  91. package/dist/set2/index.js.map +0 -1
  92. package/dist/walker.d.ts +0 -51
  93. package/dist/walker.js +0 -120
  94. package/dist/walker.js.map +0 -1
  95. package/src/set/collections.ts +0 -338
  96. package/src/set/number.ts +0 -167
  97. package/src/set/parseDefaultAndValue.ts +0 -54
  98. package/src/set/parsers.ts +0 -20
  99. package/src/set/references.ts +0 -113
  100. package/src/set/rest.ts +0 -135
  101. package/src/set/string.ts +0 -254
  102. package/src/set2/index.ts +0 -71
  103. package/src/walker.ts +0 -201
  104. package/test/setWalker.ts +0 -494
  105. package/test/text.ts +0 -171
package/src/set/index.ts CHANGED
@@ -1,197 +1,115 @@
1
- import {
2
- BasedSchemaField,
3
- BasedSchemaType,
4
- BasedSetHandlers,
5
- BasedSchema,
6
- BasedSetTarget,
7
- BasedSchemaCollectProps,
8
- BasedSetOptionalHandlers,
9
- } from '../types'
10
- import { error, ParseError } from './error'
11
- import parsers from './parsers'
12
- import { SetOptional } from 'type-fest'
13
-
14
- export const fieldWalker = async (
15
- path: (string | number)[],
16
- value: any,
17
- fieldSchema: BasedSchemaField,
18
- typeSchema: BasedSchemaType,
19
- target: BasedSetTarget,
20
- handlers: BasedSetHandlers,
21
- noCollect?: boolean
22
- ): Promise<void> => {
23
- if ('$ref' in fieldSchema) {
24
- // TODO: when we have this it has to get it from the schema and redo the parsing with the correct fieldSchema
25
- return
26
- }
27
- const valueType = typeof value
28
-
29
- const valueIsObject = value && valueType === 'object'
30
- if (valueIsObject && value.$delete === true) {
31
- if (!noCollect) {
32
- handlers.collect({ path, value, typeSchema, fieldSchema, target })
33
- }
34
- return
35
- }
36
-
37
- const typeDef = fieldSchema.type ?? ('enum' in fieldSchema ? 'enum' : '')
38
-
39
- if (!typeDef) {
40
- error(handlers, ParseError.fieldDoesNotExist, path)
41
- }
42
-
43
- if ('customValidator' in fieldSchema) {
44
- const customValidator = fieldSchema.customValidator
45
- if (!(await customValidator(value, path, target))) {
46
- error(handlers, ParseError.incorrectFormat, path)
47
- }
48
- }
49
-
50
- const parse = parsers[typeDef]
51
-
52
- await parse(path, value, fieldSchema, typeSchema, target, handlers, noCollect)
53
-
54
- return
55
- }
56
-
57
- export const setWalker = async (
58
- schema: BasedSchema,
59
- value: { [key: string]: any },
60
- inHandlers: BasedSetOptionalHandlers
61
- ): Promise<BasedSetTarget> => {
62
- let errors: {
63
- message: string
64
- code: ParseError
65
- }[]
66
-
67
- const collect: BasedSchemaCollectProps[] = []
68
-
69
- const x = { ...inHandlers }
70
-
71
- if (!('collectErrors' in x)) {
72
- errors = []
73
- x.collectErrors = (info) => {
74
- errors.push(info)
75
- }
76
- }
77
-
78
- let prevCollect: any
79
-
80
- if (!('collect' in x)) {
81
- x.collect = (info) => {
82
- collect.push(info)
83
- }
84
- } else {
85
- prevCollect = x.collect
86
- x.collect = (info) => {
87
- collect.push(info)
88
- }
89
- }
90
-
91
- const handlers: BasedSetHandlers = <BasedSetHandlers>x
92
-
93
- let type: string
94
-
95
- if (value.$id) {
96
- type = schema.prefixToTypeMapping[value.$id.slice(0, 2)]
97
- if (!type) {
98
- error(handlers, ParseError.incorrectNodeType, [value.$id])
99
- }
100
- }
101
-
102
- if (value.type) {
103
- if (type && value.type !== type) {
104
- error(handlers, ParseError.incorrectNodeType, [value.$id, value.type])
105
- }
106
- type = value.type
107
- }
108
-
109
- const schemaType = schema.types[type]
110
-
111
- if (!schemaType) {
112
- error(handlers, ParseError.incorrectNodeType, [type])
113
- }
114
-
115
- const target: BasedSetTarget = {
116
- type,
117
- schema,
118
- required: [],
119
- }
120
-
121
- if (value.$language) {
122
- if (!schema.languages.includes(value.$language)) {
123
- error(handlers, ParseError.languageNotSupported, ['$language'])
1
+ import { ParseError } from '../error'
2
+ import { BasedSchema, BasedSetTarget } from '../types'
3
+ import { walk, Opts } from '../walker'
4
+ import { fields } from './fields'
5
+ import { isValidId } from './isValidId'
6
+
7
+ const opts: Opts<BasedSetTarget> = {
8
+ parsers: {
9
+ keys: {
10
+ $id: async (args) => {
11
+ if (!isValidId(args.schema, args.value)) {
12
+ args.error(ParseError.incorrectFormat)
13
+ return
14
+ }
15
+ },
16
+ $language: async (args) => {
17
+ if (!args.schema.languages.includes(args.value)) {
18
+ args.error(ParseError.languageNotSupported)
19
+ return
20
+ }
21
+ },
22
+ $value: async (args) => {
23
+ const type = args.fieldSchema?.type
24
+ if (type === 'text') {
25
+ return
26
+ }
27
+ args.stop()
28
+ if (args.prev.value.$default) {
29
+ args.error(ParseError.valueAndDefault)
30
+ return
31
+ }
32
+ return { path: args.path.slice(0, -1) }
33
+ },
34
+ $default: async (args) => {
35
+ const type = args.fieldSchema?.type
36
+ if (type === 'number' || type === 'integer' || type === 'text') {
37
+ // default can exist with $incr and $decr
38
+ return
39
+ }
40
+ args.prev.stop()
41
+ const newArgs = args.create({
42
+ path: args.path.slice(0, -1),
43
+ skipCollection: true,
44
+ })
45
+ await newArgs.parse()
46
+ for (const key in args.prev.value) {
47
+ if (key !== '$default') {
48
+ args.prev.create({ key }).error(ParseError.fieldDoesNotExist)
49
+ }
50
+ }
51
+ newArgs.skipCollection = false
52
+ newArgs.value = { $default: newArgs.value }
53
+ newArgs.collect()
54
+ },
55
+ },
56
+ fields,
57
+ catch: async (args) => {
58
+ args.error(ParseError.fieldDoesNotExist)
59
+ },
60
+ },
61
+ init: async (value, schema, error) => {
62
+ let type: string
63
+ const target: BasedSetTarget = {
64
+ type,
65
+ schema,
66
+ required: [],
67
+ collected: [],
68
+ errors: [],
124
69
  }
125
- target.$language = value.$language
126
- }
127
-
128
- if (value.$id) {
129
- target.$id = value.$id
130
- } else if (value.$alias) {
131
- target.$alias = value.$alias
132
- }
133
-
134
- const q: Promise<void>[] = []
135
-
136
- for (const key in value) {
137
- if (key[0] !== '$' && key !== 'type') {
138
- const fieldSchema = schemaType.fields[key]
139
- if (!fieldSchema) {
140
- error(handlers, ParseError.fieldDoesNotExist, [key])
70
+ if (value.$id) {
71
+ if (value.$id === 'root') {
72
+ type = 'root'
141
73
  } else {
142
- q.push(
143
- fieldWalker(
144
- [key],
145
- value[key],
146
- fieldSchema,
147
- schemaType,
148
- target,
149
- handlers
150
- )
151
- )
74
+ type = schema.prefixToTypeMapping[value.$id.slice(0, 2)]
152
75
  }
153
- }
154
- }
155
-
156
- await Promise.all(q)
157
-
158
- if (schemaType.required) {
159
- for (const req of schemaType.required) {
160
- if (!(req in value)) {
161
- target.required.push([req])
76
+ if (!type) {
77
+ error(ParseError.incorrectFieldType, { target })
78
+ return
162
79
  }
80
+ } else if (value.$alias) {
81
+ target.$alias = value.$alias
163
82
  }
164
- }
165
83
 
166
- if (target.required?.length) {
167
- const requireDefined = await Promise.all(
168
- target.required.map(async (req) => {
169
- return handlers.checkRequiredFields(req)
170
- })
171
- )
172
- for (let i = 0; i < requireDefined.length; i++) {
173
- if (!requireDefined[i]) {
174
- const r = target.required[i]
175
- error(handlers, ParseError.requiredFieldNotDefined, r)
84
+ if (value.type) {
85
+ if (type && value.type !== type) {
86
+ error(ParseError.incorrectNodeType, { target })
87
+ return
176
88
  }
89
+ type = value.type
177
90
  }
178
- }
179
-
180
- if (errors?.length) {
181
- const err = new Error(
182
- 'Errors in in set' +
183
- errors.reduce((str, info) => {
184
- return str + `\n - ${info.message}`
185
- }, '')
186
- )
187
- throw err
188
- }
189
-
190
- if (prevCollect) {
191
- for (const x of collect) {
192
- prevCollect(x)
91
+ const typeSchema = type === 'root' ? schema.root : schema.types[type]
92
+ if (!typeSchema) {
93
+ error(ParseError.incorrectNodeType, { target })
94
+ return
193
95
  }
194
- }
195
-
196
- return target
96
+ target.type = type
97
+ target.$language = value.$language
98
+ target.$id = value.$id
99
+ return { target, typeSchema }
100
+ },
101
+ error: (code, args) => {
102
+ args.target.errors.push({
103
+ code,
104
+ path: args.path ?? [],
105
+ })
106
+ },
107
+ collect: (args) => {
108
+ args.root.target.collected.push(args)
109
+ },
197
110
  }
111
+
112
+ export const setWalker = (
113
+ schema: BasedSchema,
114
+ value: any
115
+ ): Promise<BasedSetTarget> => walk<BasedSetTarget>(schema, opts, value)
@@ -0,0 +1,23 @@
1
+ import { BasedSchema } from '../types'
2
+
3
+ export const isValidId = (schema: BasedSchema, id: any): boolean => {
4
+ if (typeof id !== 'string') {
5
+ return false
6
+ }
7
+
8
+ if (id === 'root') {
9
+ return true
10
+ }
11
+
12
+ if (id.length > 10) {
13
+ return false
14
+ }
15
+
16
+ const prefix = id.slice(0, 2)
17
+
18
+ if (!schema.prefixToTypeMapping[prefix]) {
19
+ return false
20
+ }
21
+
22
+ return true
23
+ }
package/src/set/types.ts CHANGED
@@ -1,20 +0,0 @@
1
- import {
2
- BasedSchemaType,
3
- BasedSetHandlers,
4
- BasedSetTarget,
5
- BasedSchemaFields,
6
- } from '../types'
7
-
8
- export type Parser<K extends keyof BasedSchemaFields> = (
9
- path: (string | number)[],
10
- value: any,
11
- fieldSchema: BasedSchemaFields[K],
12
- typeSchema: BasedSchemaType,
13
- target: BasedSetTarget,
14
- handlers: BasedSetHandlers,
15
- noCollect?: boolean
16
- ) => Promise<void | boolean>
17
-
18
- export type Parsers = {
19
- [Key in keyof BasedSchemaFields]: Parser<Key>
20
- }
package/src/types.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { Language } from './languages'
2
2
  import type { PartialDeep, SetOptional } from 'type-fest'
3
- import { ParseError } from './set/error'
3
+ import { ParseError } from './error'
4
+ import { ArgsClass, Path } from './walker'
4
5
 
5
6
  // Schema type
6
7
  // inspiration from https://json-schema.org/understanding-json-schema/index.html
@@ -65,7 +66,6 @@ export type BasedSchemaFieldShared = {
65
66
  hooks?:
66
67
  | { interval?: number; hook: string }
67
68
  | { interval?: number; hook: string }[]
68
-
69
69
  type?: BasedSchemaFieldType
70
70
  $id?: string
71
71
  $schema?: string
@@ -345,6 +345,8 @@ export type BasedSetTarget = {
345
345
  schema: BasedSchema
346
346
  $language?: BasedSchemaLanguage
347
347
  required: (number | string)[][]
348
+ collected: ArgsClass<BasedSetTarget>[]
349
+ errors: { code: ParseError; path: Path }[]
348
350
  }
349
351
 
350
352
  export type BasedSchemaCollectProps = {
@@ -0,0 +1,159 @@
1
+ import { BasedSchema } from '../types'
2
+ import { BasedSchemaType, BasedSchemaFields } from '../types'
3
+ import { ArgsOpts, Path, Opts, Stopped, ErrorHandler, Collect } from './types'
4
+ import { parse } from './parse'
5
+ import { ParseError } from '../error'
6
+
7
+ export class ArgsClass<
8
+ T,
9
+ K extends keyof BasedSchemaFields = keyof BasedSchemaFields
10
+ > {
11
+ errors: any[]
12
+
13
+ prev: ArgsClass<T, K>
14
+
15
+ root: ArgsClass<T, K> // getter
16
+
17
+ // only on root
18
+ _opts: Opts<T>
19
+
20
+ _target: T
21
+
22
+ _schema: BasedSchema
23
+
24
+ parseTopLevel?: boolean
25
+
26
+ _collectOverride: Collect<T>
27
+
28
+ fieldSchema?: BasedSchemaFields[K]
29
+
30
+ typeSchema?: BasedSchemaType
31
+
32
+ path: Path
33
+
34
+ skipCollection: boolean
35
+
36
+ value: any
37
+
38
+ stopped: Stopped | void
39
+
40
+ fromBackTrack: any[]
41
+
42
+ collectedCommands: any[]
43
+
44
+ constructor(opts: ArgsOpts<T, K>, prev?: ArgsClass<T, K>) {
45
+ this.fromBackTrack = []
46
+ this.collectedCommands = []
47
+ if (opts.prev) {
48
+ prev = opts.prev
49
+ }
50
+ if (opts.parseTopLevel) {
51
+ this.parseTopLevel = opts.parseTopLevel
52
+ }
53
+ if (prev) {
54
+ this.prev = prev
55
+ this.root = prev.root
56
+ this.fieldSchema = prev.fieldSchema
57
+ }
58
+ if (opts.path) {
59
+ this.path = opts.path
60
+ } else if (prev && opts.key !== undefined) {
61
+ this.path = [...prev.path, opts.key]
62
+ } else if (opts && prev) {
63
+ this.path = prev.path
64
+ } else {
65
+ this.path = []
66
+ }
67
+ this.value = opts.value
68
+ if (opts.fieldSchema) {
69
+ // @ts-ignore K is too loose
70
+ this.fieldSchema = opts.fieldSchema
71
+ }
72
+ if (opts.typeSchema) {
73
+ this.typeSchema = opts.typeSchema
74
+ }
75
+ if (opts.target) {
76
+ this._target = opts.target
77
+ }
78
+ if (opts.collect) {
79
+ this._collectOverride = opts.collect
80
+ }
81
+ if (opts.skipCollection) {
82
+ this.skipCollection = opts.skipCollection
83
+ }
84
+ }
85
+
86
+ get schema(): BasedSchema {
87
+ if (this._schema) {
88
+ return this.schema
89
+ }
90
+ return this.root._schema
91
+ }
92
+
93
+ get key(): (number | string) | void {
94
+ return this.path[this.path.length - 1]
95
+ }
96
+
97
+ get target(): T {
98
+ if (this._target) {
99
+ return this._target
100
+ }
101
+ let p = this.prev
102
+ while (p) {
103
+ if (p._target) {
104
+ return p._target
105
+ }
106
+ p = p.prev
107
+ }
108
+ }
109
+
110
+ stop(onllyStopFieldSchemaParser?: boolean) {
111
+ const target = this
112
+ if (onllyStopFieldSchemaParser) {
113
+ target.stopped = Stopped.onlyStopFieldParser
114
+ } else {
115
+ target.stopped = Stopped.stopAll
116
+ }
117
+ }
118
+
119
+ create(opts?: ArgsOpts<T>): ArgsClass<T> {
120
+ const newArgs = new ArgsClass(opts, this)
121
+ if (this._collectOverride) {
122
+ newArgs._collectOverride = this._collectOverride
123
+ }
124
+ if (!('value' in opts)) {
125
+ newArgs.value = this.value
126
+ }
127
+ return newArgs
128
+ }
129
+
130
+ async parse(opts?: ArgsOpts<T>): Promise<ArgsClass<T> | void> {
131
+ if (!opts) {
132
+ return parse(this)
133
+ } else {
134
+ const newArgs = new ArgsClass(opts, this)
135
+ if (this._collectOverride) {
136
+ newArgs._collectOverride = this._collectOverride
137
+ }
138
+ return newArgs.parse()
139
+ }
140
+ }
141
+
142
+ collect(value?: any) {
143
+ if (this.skipCollection) {
144
+ return
145
+ }
146
+ const collectArgs =
147
+ value !== undefined ? new ArgsClass({ value }, this) : this
148
+
149
+ if (this._collectOverride) {
150
+ this.collectedCommands.push(this._collectOverride(collectArgs))
151
+ } else {
152
+ this.collectedCommands.push(this.root._opts.collect(collectArgs))
153
+ }
154
+ }
155
+
156
+ error(code: ParseError): void {
157
+ this.root._opts.error(code, this)
158
+ }
159
+ }
@@ -0,0 +1,35 @@
1
+ import { BasedSchema } from '../types'
2
+ import { ArgsClass } from './args'
3
+ import { Opts } from './types'
4
+
5
+ export const walk = async <T>(
6
+ schema: BasedSchema,
7
+ opts: Opts<T>,
8
+ value: any
9
+ ): Promise<T> => {
10
+ if (!('collect' in opts)) {
11
+ opts.collect = () => {}
12
+ }
13
+
14
+ if (!('error' in opts)) {
15
+ opts.error = () => {}
16
+ }
17
+
18
+ const argsOpts = await opts.init(value, schema, opts.error)
19
+
20
+ if (!argsOpts.value) {
21
+ argsOpts.value = value
22
+ }
23
+
24
+ const args = new ArgsClass(argsOpts)
25
+ args.root = args
26
+ args._opts = opts
27
+ args._schema = schema
28
+ await args.parse()
29
+
30
+ return args.target
31
+ }
32
+
33
+ export { ArgsClass }
34
+
35
+ export * from './types'