-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
157 lines (142 loc) · 4.39 KB
/
index.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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
'use strict'
const decode = require('cedict/decode')
const hsk = require('cedict/hsk')
const fetch = require('node-fetch')
const sublevel = require('sublevel')
const level = require('level-party')
const get = require('./lib/get')
let state = {
db: null,
hanziDB: null,
pinyinDB: null,
hskDB: null,
pinyins: {},
initializing: false,
afterInitialized: []
}
const loadData = url => {
if (url) {
return fetch(url)
.then(res => res.arrayBuffer())
.then(decode)
} else {
return Promise.resolve(require('cedict'))
}
}
const saveEntry = (db, entry) => new Promise((resolve, reject) => {
const data = {
traditional: entry.traditional,
definitions: [].concat(entry.definitions.map(def => {
def.pinyin = def.pinyin.toLowerCase()
return def
}))
}
if (entry.simplified) data.simplified = entry.simplified
if (entry.hsk > 0) data.hsk = entry.hsk
for (const def of data.definitions) {
state.pinyins[def.pinyin] = state.pinyins[def.pinyin] || {}
state.pinyins[def.pinyin][data.simplified || data.traditional] = data.hsk
}
db.put(data.traditional, data, err => {
if (err) reject(err)
else {
if (data.simplified) {
db.put(data.simplified, data, err => {
if (err) reject(err)
else resolve()
})
} else {
resolve()
}
}
})
})
const savePinyinEntry = (db, pinyin, data) => new Promise((resolve, reject) => {
const list = Object.keys(data).sort((a, b) => {
if (data[a]) {
if (data[b]) return data[a] - data[b]
return -1
} else return 1
})
db.put(pinyin, list, err => {
if (err) reject(err)
else resolve()
})
})
const saveHSKEntry = (db, lvl, list) => new Promise((resolve, reject) => {
db.put(lvl, list, err => {
if (err) reject(err)
else resolve()
})
})
const importData = data => {
return Promise.all(data.map(e => saveEntry(state.hanziDB, e)))
.then(() => {
return Promise.all(Object.keys(state.pinyins).map(pinyin => {
return savePinyinEntry(state.pinyinDB, pinyin, state.pinyins[pinyin])
}))
})
.then(() => Promise.all(hsk.map((list, i) => saveHSKEntry(state.hskDB, i + 1, list))))
.then(() => {
return new Promise((resolve, reject) => {
state.db.put('cedict_available', true, err => {
if (err) reject(err)
else resolve(data)
})
})
})
}
const checkCedictAvailable = db => new Promise((resolve, reject) => {
db.get('cedict_available', (err, value) => {
if (err) {
if (err.type === 'NotFoundError') resolve(false)
else reject(err)
}
else resolve(value)
})
})
const init = async (db = 'cedict_db', url) => {
state.initializing = true
if (state.db) {
if (!state.hanziDB) state.hanziDB = sublevel(state.db, 'hanzi')
if (!state.pinyinDB) state.pinyinDB = sublevel(state.db, 'pinyin')
if (!state.hskDB) state.hskDB = sublevel(state.db, 'hsk')
if (await checkCedictAvailable(state.db)) return state.db
} else {
if (typeof db === 'string') state.db = await level(db, { valueEncoding: 'json' })
else state.db = db
if (!state.hanziDB) state.hanziDB = sublevel(state.db, 'hanzi')
if (!state.pinyinDB) state.pinyinDB = sublevel(state.db, 'pinyin')
if (!state.hskDB) state.hskDB = sublevel(state.db, 'hsk')
if (await checkCedictAvailable(state.db)) return state.db
}
const data = await loadData(url)
await importData(data)
state.initializing = false
state.afterInitialized.forEach(cb => cb())
state.afterInitialized = []
return state.db
}
const createGet = async (getter, query) => {
if (state[getter.name]) return state[getter.name](query)
else {
if (!state.hanziDB || !state.pinyinDB || !state.hskDB) {
if (state.initializing) {
await new Promise((resolve, reject) => state.afterInitialized.push(resolve))
} else await init()
}
state[getter.name] = getter(state.hanziDB, state.pinyinDB, state.hskDB)
return state[getter.name](query)
}
}
module.exports = {
init,
get: query => createGet(get, query),
getByHanzi: query => createGet(get.byHanzi, query),
getByPinyin: query => createGet(get.byPinyin, query),
getByZhuyin: query => createGet(get.byZhuyin, query),
getByHSK: query => createGet(get.byHSK, query),
getIndexByPinyin: query => createGet(get.indexByPinyin, query),
getIndexByZhuyin: query => createGet(get.indexByZhuyin, query),
getIndexByHSK: query => createGet(get.indexByHSK, query)
}