-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgenerate-dictionary.ts
More file actions
129 lines (109 loc) · 3.34 KB
/
Copy pathgenerate-dictionary.ts
File metadata and controls
129 lines (109 loc) · 3.34 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
120
121
122
123
124
125
126
127
128
129
// Generates the /src/en-wiktionary.txt file from the Kaikki data file.
import { createReadStream, createWriteStream } from 'node:fs'
import fs from 'node:fs/promises'
import readline from 'node:readline'
import type { Entry } from './utilities/types'
import { downloadDictionaryDataIfNecessary } from './utilities/download'
import { isValid } from './utilities/validation'
function sanitizeWord(word: string, cSpellPrefixesAndSuffixes = false): string {
const cleanWord = word.replaceAll(/–|—/g, '-').trim()
if (cSpellPrefixesAndSuffixes) {
// Replace leading or trailing - with +
if (cleanWord.startsWith('-')) {
return `+${cleanWord.slice(1)}`
}
if (cleanWord.endsWith('-')) {
return `${cleanWord.slice(0, -1)}+`
}
return cleanWord
}
return cleanWord
}
async function readWords(
filePath: string,
includePrefixes = false,
includeSuffixes = false,
maxWords: number = Number.POSITIVE_INFINITY,
): Promise<{ invalid: string[]; valid: string[] }> {
const wordSet = new Set<string>()
const wordSetInvalid = new Set<string>()
const fileStream = createReadStream(filePath)
const rl = readline.createInterface({
crlfDelay: Infinity,
input: fileStream,
})
for await (const line of rl) {
// eslint-disable-next-line ts/no-unsafe-type-assertion
const entry = JSON.parse(line) as Entry
if (
isValid(entry, {
excludedCategories: [
'Misspellings',
'Censored spellings',
'English censored spellings',
'English filter-avoidance spellings',
'Filter-avoidance spellings',
'Intentional misspellings',
// 'Terms with non-redundant manual transliterations'
],
excludedPartsOfSpeech: [
'symbol',
'det',
...(includeSuffixes ? [] : ['suffix']),
...(includePrefixes ? [] : ['prefix']),
],
excludedTags: ['archaic', 'Shavian', 'alt-of', 'alternative'],
// Cspell:ignore curch curches curchies
excludedWords: ['curch', 'curches', 'curchies'],
limitCharacters: true,
minLength: 2,
})
) {
if (
(includeSuffixes && entry.pos === 'suffix') ||
(includePrefixes && entry.pos === 'prefix')
) {
wordSet.add(sanitizeWord(entry.word, true))
} else {
wordSet.add(sanitizeWord(entry.word))
}
if (wordSet.size >= maxWords) {
break
}
} else {
wordSetInvalid.add(entry.word)
}
}
return {
invalid: [...wordSetInvalid].sort(),
valid: [...wordSet].sort(),
}
}
async function writeWords(filePath: string, words: string[]) {
await fs.rm(filePath, { force: true })
const writeStream = createWriteStream(filePath, { flags: 'a' })
for (const word of words) {
if (!writeStream.write(`${word}\n`)) {
await new Promise<void>((resolve) => {
writeStream.once('drain', resolve)
})
}
}
writeStream.end()
}
async function main() {
const kaikkiDataFile = await downloadDictionaryDataIfNecessary()
// Read (streams)
const { invalid: invalidWords, valid: words } = await readWords(kaikkiDataFile, true, true)
// Write
// TODO header directives?
const wordsFile = './src/en-wiktionary.txt'
await writeWords(wordsFile, words)
console.log(`Wrote ${words.length} words to "${wordsFile}"`)
if (invalidWords.length > 0) {
const invalidWordsFile = './data/en-wiktionary-invalid.txt'
await writeWords(invalidWordsFile, invalidWords)
console.log(`Wrote ${invalidWords.length} invalid words to "${invalidWordsFile}"`)
}
}
await main()