-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjevkoBySchemaToValue.js
111 lines (103 loc) · 3.58 KB
/
jevkoBySchemaToValue.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
export const jevkoBySchemaToValue = (jevko, schema) => {
const {type} = schema
if (type === 'string') return toString(jevko, schema)
if (type === 'float64') return toNumber(jevko, schema)
if (type === 'boolean') return toBoolean(jevko, schema)
if (type === 'null') return toNull(jevko, schema)
if (type === 'array') return toArray(jevko, schema)
if (type === 'tuple') return toTuple(jevko, schema)
if (type === 'object') return toObject(jevko, schema)
if (type === 'first match') return toFirstMatch(jevko, schema)
throw Error(`Unknown schema type ${type}`)
}
const toString = (jevko, schema) => {
const {subjevkos, suffix} = jevko
if (subjevkos.length > 0) throw Error('nonempty subjevkos in string')
return suffix
}
const toNumber = (jevko, schema) => {
const {subjevkos, suffix} = jevko
if (subjevkos.length > 0) throw Error('nonempty subjevkos in string')
const trimmed = suffix.trim()
if (trimmed === 'NaN') return NaN
const num = Number(trimmed)
if (Number.isNaN(num) || trimmed === '') throw Error('nan')
return num
}
const toBoolean = (jevko, schema) => {
const {subjevkos, suffix} = jevko
if (subjevkos.length > 0) throw Error('nonempty subjevkos in string')
if (suffix === 'true') return true
if (suffix === 'false') return false
throw Error('not a boolean')
}
const toNull = (jevko, schema) => {
const {subjevkos, suffix} = jevko
if (subjevkos.length > 0) throw Error('nonempty subjevkos in string')
if (suffix === 'null' || suffix === '') return null
throw Error('not a null')
}
const toArray = (jevko, schema) => {
const {subjevkos, suffix} = jevko
if (suffix.trim() !== '') throw Error('suffix !== ""')
const ret = []
const {itemSchema} = schema
for (const {prefix, jevko} of subjevkos) {
if (prefix.trim() !== '') throw Error('nonempty prefix')
ret.push(jevkoBySchemaToValue(jevko, itemSchema))
}
return ret
}
const toTuple = (jevko, schema) => {
const {subjevkos, suffix} = jevko
if (suffix.trim() !== '') throw Error('suffix !== ""')
const ret = []
const {itemSchemas, isSealed} = schema
if (itemSchemas.length > subjevkos.length) throw Error('bad tuple')
if (isSealed && itemSchemas.length !== subjevkos.length) throw Error('also bad tuple')
for (let i = 0; i < itemSchemas.length; ++i) {
const {prefix, jevko} = subjevkos[i]
if (prefix.trim() !== '') throw Error('nonempty prefix')
ret.push(jevkoBySchemaToValue(jevko, itemSchemas[i]))
}
return ret
}
const toObject = (jevko, schema) => {
const {subjevkos, suffix} = jevko
if (suffix.trim() !== '') throw Error('suffix !== ""')
const keyJevkos = Object.create(null)
const ret = Object.create(null)
// if (subjevkos.length === 0) {
// // todo: if schema allows
// return ret
// }
const {optional = [], isSealed = true, props} = schema
const keys = Object.keys(props)
for (const {prefix, jevko} of subjevkos) {
const key = prefix.trim()
if (key === '') throw Error('empty key')
if (key in keyJevkos) throw Error('duplicate key')
if (isSealed && keys.includes(key) === false) throw Error('unknown key')
keyJevkos[key] = jevko
}
for (const key of keys) {
if (key in keyJevkos === false) {
if (optional.includes(key) === false) throw Error('key required')
continue
}
ret[key] = jevkoBySchemaToValue(keyJevkos[key], props[key])
}
return ret
}
const toFirstMatch = (jevko, schema) => {
const {alternatives} = schema
for (const alt of alternatives) {
try {
const x = jevkoBySchemaToValue(jevko, alt)
return x
} catch (e) {
continue
}
}
throw Error('union: invalid jevko')
}