-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmod.js
More file actions
119 lines (91 loc) · 3.12 KB
/
mod.js
File metadata and controls
119 lines (91 loc) · 3.12 KB
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
112
113
114
115
116
117
118
119
const assert = (pred, msg) => {
console.assert(pred, msg)
if (pred === false) throw Error(msg)
}
export const prefixToKey = (prefix) => {
let key = prefix.trim()
// todo: optimize -- use indices instead of slicing
while (true) {
if (key.startsWith("'")) return key
// todo: support other kinds of newlines
const nli = key.indexOf('\n')
if (nli === -1) break
key = key.slice(nli + 1).trimStart()
}
return key
}
export const toMap = (jevko) => {
const {subjevkos, tag, suffix} = jevko
if (subjevkos.length === 0) return Object.create(null)
// assert(suffix.trim() === '')
assert(tag === undefined, `Unexpected tag: ${tag}`)
const ret = Object.create(null)
for (const {prefix, jevko} of subjevkos) {
let key = prefixToKey(prefix)
// skip over commented-out entries
if (key.startsWith("-")) continue
if (key.startsWith("'")) {
// note: allow unclosed string literals
if (key.at(-1) === "'") key = key.slice(1, -1)
else key = key.slice(1)
}
if (key === '') throw Error('Empty key!')
if (key in ret) throw Error(`Duplicate key '${key}'!`)
ret[key] = jevko
}
return ret
}
export const mapAt = (map, key) => map[key]
export const toNumber = (jevko) => {
const {subjevkos, tag, suffix} = jevko
assert(subjevkos.length === 0, `Expected 0 subjevkos, got ${subjevkos.length}`)
assert(tag === undefined, `Unexpected tag: ${tag}`)
const trimmed = suffix.trim()
assert(trimmed !== '', `Unexpected blank suffix!`)
if (trimmed === 'NaN') return NaN
const num = Number(trimmed)
if (Number.isNaN(num) === false) return num
throw Error('NaN')
}
export const toList = (jevko) => {
const {subjevkos, tag, suffix} = jevko
if (subjevkos.length === 0) return []
// assert(suffix.trim() === '')
assert(tag === undefined, `Unexpected tag: ${tag}`)
const ret = []
for (const {prefix, jevko} of subjevkos) {
let key = prefixToKey(prefix)
// skip over commented-out entries
if (key.startsWith("-")) continue
if (key !== '') throw Error('Nonempty key!')
ret.push(jevko)
}
return ret
}
export const toBoolean = (jevko) => {
const {subjevkos, tag, suffix} = jevko
assert(subjevkos.length === 0, `Expected 0 subjevkos, got ${subjevkos.length}`)
assert(tag === undefined, `Unexpected tag: ${tag}`)
const trimmed = suffix.trim()
if (trimmed === 'true') return true
if (trimmed === 'false') return false
throw Error(`Not a boolean: ${trimmed}`)
}
export const toString = (jevko) => {
const {subjevkos, tag, suffix} = jevko
assert(subjevkos.length === 0, `Expected 0 subjevkos, got ${subjevkos.length}`)
assert(tag === undefined, `Unexpected tag: ${tag}`)
const trimmed = suffix.trim()
if (trimmed.startsWith("'")) {
// note: allow unclosed string literals
if (trimmed.at(-1) === "'") return trimmed.slice(1, -1)
return trimmed.slice(1)
}
return trimmed
}
export const asJson = (jevko) => {
const {subjevkos, tag, suffix} = jevko
assert(subjevkos.length === 0, `Expected 0 subjevkos, got ${subjevkos.length}`)
assert(tag === 'json', `Expected tag to be 'json', got '${tag}'`)
return JSON.parse(suffix)
}