@based/schema 0.0.15 → 1.0.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.
Files changed (112) hide show
  1. package/dist/{set/error.d.ts → error.d.ts} +4 -2
  2. package/dist/{set/error.js → error.js} +2 -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/fields/array.d.ts +2 -0
  8. package/dist/set/fields/array.js +96 -0
  9. package/dist/set/fields/array.js.map +1 -0
  10. package/dist/set/fields/index.d.ts +3 -0
  11. package/dist/set/fields/index.js +72 -0
  12. package/dist/set/fields/index.js.map +1 -0
  13. package/dist/set/fields/number.d.ts +4 -0
  14. package/dist/set/fields/number.js +121 -0
  15. package/dist/set/fields/number.js.map +1 -0
  16. package/dist/set/fields/object.d.ts +3 -0
  17. package/dist/set/fields/object.js +33 -0
  18. package/dist/set/fields/object.js.map +1 -0
  19. package/dist/set/fields/references.d.ts +3 -0
  20. package/dist/set/fields/references.js +106 -0
  21. package/dist/set/fields/references.js.map +1 -0
  22. package/dist/set/fields/set.d.ts +2 -0
  23. package/dist/set/fields/set.js +63 -0
  24. package/dist/set/fields/set.js.map +1 -0
  25. package/dist/set/fields/string.d.ts +3 -0
  26. package/dist/set/fields/string.js +190 -0
  27. package/dist/set/fields/string.js.map +1 -0
  28. package/dist/set/index.d.ts +2 -5
  29. package/dist/set/index.js +98 -126
  30. package/dist/set/index.js.map +1 -1
  31. package/dist/set/isValidId.d.ts +2 -0
  32. package/dist/set/isValidId.js +21 -0
  33. package/dist/set/isValidId.js.map +1 -0
  34. package/dist/set/types.d.ts +0 -5
  35. package/dist/set/types.js +0 -2
  36. package/dist/types.d.ts +7 -1
  37. package/dist/types.js.map +1 -1
  38. package/dist/walker/args.d.ts +31 -0
  39. package/dist/walker/args.js +120 -0
  40. package/dist/walker/args.js.map +1 -0
  41. package/dist/walker/index.d.ts +6 -0
  42. package/dist/walker/index.js +40 -0
  43. package/dist/walker/index.js.map +1 -0
  44. package/dist/walker/parse.d.ts +2 -0
  45. package/dist/walker/parse.js +157 -0
  46. package/dist/walker/parse.js.map +1 -0
  47. package/dist/walker/types.d.ts +44 -0
  48. package/dist/walker/types.js +9 -0
  49. package/dist/walker/types.js.map +1 -0
  50. package/package.json +2 -2
  51. package/src/{set/error.ts → error.ts} +3 -1
  52. package/src/index.ts +2 -2
  53. package/src/set/fields/array.ts +111 -0
  54. package/src/set/fields/index.ts +69 -0
  55. package/src/set/fields/number.ts +134 -0
  56. package/src/set/fields/object.ts +30 -0
  57. package/src/set/fields/references.ts +114 -0
  58. package/src/set/fields/set.ts +63 -0
  59. package/src/set/fields/string.ts +199 -0
  60. package/src/set/index.ts +103 -188
  61. package/src/set/isValidId.ts +23 -0
  62. package/src/set/types.ts +0 -20
  63. package/src/types.ts +4 -2
  64. package/src/walker/args.ts +159 -0
  65. package/src/walker/index.ts +35 -0
  66. package/src/walker/parse.ts +193 -0
  67. package/src/walker/types.ts +75 -0
  68. package/test/number.ts +289 -543
  69. package/test/reference.ts +150 -198
  70. package/test/rest.ts +227 -0
  71. package/test/string.ts +139 -183
  72. package/test/utils/index.ts +23 -0
  73. package/test/walker.ts +579 -16
  74. package/dist/set/collections.d.ts +0 -5
  75. package/dist/set/collections.js +0 -229
  76. package/dist/set/collections.js.map +0 -1
  77. package/dist/set/error.js.map +0 -1
  78. package/dist/set/number.d.ts +0 -4
  79. package/dist/set/number.js +0 -124
  80. package/dist/set/number.js.map +0 -1
  81. package/dist/set/parseDefaultAndValue.d.ts +0 -3
  82. package/dist/set/parseDefaultAndValue.js +0 -35
  83. package/dist/set/parseDefaultAndValue.js.map +0 -1
  84. package/dist/set/parsers.d.ts +0 -3
  85. package/dist/set/parsers.js +0 -42
  86. package/dist/set/parsers.js.map +0 -1
  87. package/dist/set/references.d.ts +0 -3
  88. package/dist/set/references.js +0 -84
  89. package/dist/set/references.js.map +0 -1
  90. package/dist/set/rest.d.ts +0 -5
  91. package/dist/set/rest.js +0 -76
  92. package/dist/set/rest.js.map +0 -1
  93. package/dist/set/string.d.ts +0 -3
  94. package/dist/set/string.js +0 -173
  95. package/dist/set/string.js.map +0 -1
  96. package/dist/set2/index.d.ts +0 -0
  97. package/dist/set2/index.js +0 -71
  98. package/dist/set2/index.js.map +0 -1
  99. package/dist/walker.d.ts +0 -49
  100. package/dist/walker.js +0 -120
  101. package/dist/walker.js.map +0 -1
  102. package/src/set/collections.ts +0 -338
  103. package/src/set/number.ts +0 -167
  104. package/src/set/parseDefaultAndValue.ts +0 -54
  105. package/src/set/parsers.ts +0 -20
  106. package/src/set/references.ts +0 -113
  107. package/src/set/rest.ts +0 -135
  108. package/src/set/string.ts +0 -254
  109. package/src/set2/index.ts +0 -71
  110. package/src/walker.ts +0 -191
  111. package/test/setWalker.ts +0 -494
  112. package/test/text.ts +0 -171
package/src/set/index.ts CHANGED
@@ -1,197 +1,112 @@
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])
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: [],
99
69
  }
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'])
124
- }
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
  }
163
80
  }
164
- }
165
-
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)
81
+ if (value.type) {
82
+ if (type && value.type !== type) {
83
+ error(ParseError.incorrectNodeType, { target })
84
+ return
176
85
  }
86
+ type = value.type
177
87
  }
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)
88
+ const typeSchema = type === 'root' ? schema.root : schema.types[type]
89
+ if (!typeSchema) {
90
+ error(ParseError.incorrectNodeType, { target })
91
+ return
193
92
  }
194
- }
195
-
196
- return target
93
+ target.type = type
94
+ target.$language = value.$language
95
+ target.$id = value.$id
96
+ return { target, typeSchema }
97
+ },
98
+ error: (code, args) => {
99
+ args.target.errors.push({
100
+ code,
101
+ path: args.path ?? [],
102
+ })
103
+ },
104
+ collect: (args) => {
105
+ args.root.target.collected.push(args)
106
+ },
197
107
  }
108
+
109
+ export const setWalker = (
110
+ schema: BasedSchema,
111
+ value: any
112
+ ): 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'