yukichant 3.0.5 → 3.1.0-beta.3
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.
- package/__tests__/cli.js +20 -0
- package/__tests__/data.js +41 -0
- package/__tests__/index.js +42 -0
- package/__tests__/machine-encrypt.js +49 -0
- package/dic/base.dat.gz +0 -0
- package/dic/cc.dat.gz +0 -0
- package/dic/check.dat.gz +0 -0
- package/dic/tid.dat.gz +0 -0
- package/dic/tid_map.dat.gz +0 -0
- package/dic/tid_pos.dat.gz +0 -0
- package/dic/unk.dat.gz +0 -0
- package/dic/unk_char.dat.gz +0 -0
- package/dic/unk_compat.dat.gz +0 -0
- package/dic/unk_invoke.dat.gz +0 -0
- package/dic/unk_map.dat.gz +0 -0
- package/dic/unk_pos.dat.gz +0 -0
- package/package.json +4 -2
- package/raw_data/json_generator +49 -0
- package/raw_data/meisi_json_generator +53 -0
- package/raw_data/spell.txt +1011 -0
- package/raw_data/spell_NG_word.txt +4 -0
- package/src/cli.js +5 -1
- package/src/index.js +84 -9
- package/test_data/help_message.js +3 -0
- package/.github/workflows/app-test.yml +0 -57
- package/.github/workflows/npm-publish.yml +0 -36
package/__tests__/cli.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const chant_cmd = `./src/cli.js`
|
|
2
|
+
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import { execSync } from 'child_process';
|
|
5
|
+
import help_message from '../test_data/help_message';
|
|
6
|
+
|
|
7
|
+
describe('chant',()=>{
|
|
8
|
+
test('generate',async ()=>{
|
|
9
|
+
let result = execSync(`${chant_cmd}`)
|
|
10
|
+
expect(result.toString()).toEqual(expect.anything())
|
|
11
|
+
})
|
|
12
|
+
test('--help',async ()=>{
|
|
13
|
+
let result = execSync(`${chant_cmd} --help`)
|
|
14
|
+
expect(result.toString()).toEqual(help_message)
|
|
15
|
+
})
|
|
16
|
+
test('encode to decode',async ()=>{
|
|
17
|
+
let result = execSync(`echo -n unko | ${chant_cmd} | ${chant_cmd} -d`)
|
|
18
|
+
expect(result.toString()).toEqual('unko')
|
|
19
|
+
})
|
|
20
|
+
})
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/*
|
|
2
|
+
|
|
3
|
+
このテストではdata/*.jsonのバリューの重複がないことを検証する。
|
|
4
|
+
|
|
5
|
+
data/dousi.jsonとdata/meisi.jsonのバリュー(呪文)の文字列は重複してはならない。
|
|
6
|
+
後から要素を追加した際に、重複が発生すると正常にdecodeできなくなる懸念があるためである。
|
|
7
|
+
|
|
8
|
+
*/
|
|
9
|
+
import fs from 'fs'
|
|
10
|
+
const meisi = JSON.parse(fs.readFileSync('./data/meisi.json', 'utf8'));
|
|
11
|
+
const dousi = JSON.parse(fs.readFileSync('./data/dousi.json', 'utf8'));
|
|
12
|
+
|
|
13
|
+
describe('meisi', () => {
|
|
14
|
+
test('meisiの値に重複するものが存在しない', () => {
|
|
15
|
+
let valueCount = 0
|
|
16
|
+
let valueHash = {}
|
|
17
|
+
Object.entries(meisi).forEach(([k,v])=> {
|
|
18
|
+
valueCount += v.length
|
|
19
|
+
v.forEach(v2=> {
|
|
20
|
+
valueHash[v2] = true
|
|
21
|
+
})
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
expect(Object.keys(valueHash).length === valueCount).toBeTruthy()
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
describe('dousi', () => {
|
|
29
|
+
test('dousiの値に重複するものが存在しない', () => {
|
|
30
|
+
let valueCount = 0
|
|
31
|
+
let valueHash = {}
|
|
32
|
+
Object.entries(dousi).forEach(([k,v])=> {
|
|
33
|
+
valueCount += v.length
|
|
34
|
+
v.forEach(v2=> {
|
|
35
|
+
valueHash[v2] = true
|
|
36
|
+
})
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
expect(Object.keys(valueHash).length === valueCount).toBeTruthy()
|
|
40
|
+
})
|
|
41
|
+
})
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import chant from '../src/index'
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
const meisi = JSON.parse(fs.readFileSync('./data/meisi.json', 'utf8'));
|
|
4
|
+
const dousi = JSON.parse(fs.readFileSync('./data/dousi.json', 'utf8'));
|
|
5
|
+
|
|
6
|
+
describe('chant',()=>{
|
|
7
|
+
test('encode',()=>{
|
|
8
|
+
// encodeしたときに、encodeあとの文字がランダムにどれか選ばれるため
|
|
9
|
+
// 乱数を考慮して複数回テストを実行する。
|
|
10
|
+
for (let i=0; i<1000; i++) {
|
|
11
|
+
expect(chant.encode('unko\n'))
|
|
12
|
+
.toMatch(/^(回廊に|回廊へ)(凍結|凍土に)(冥へ|冥界|冥府の|冥府より)(借り。)(血塗ら。)$/)
|
|
13
|
+
}
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
test('decode',async ()=>{
|
|
17
|
+
expect(await chant.decode(chant.encode('こんにちは')))
|
|
18
|
+
.toBe('こんにちは')
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
test('decode 改行文字込',async ()=>{
|
|
22
|
+
expect(await chant.decode('回廊に凍結冥界借り。血塗ら。')).toBe('unko\n')
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
test('dumpされた文字が途中でもdecodeできるかの確認',async ()=>{
|
|
26
|
+
// chant.encode('')
|
|
27
|
+
expect(await chant.decode(chant.encode('💩💩').slice(0,-4)))
|
|
28
|
+
.toEqual(expect.stringContaining('💩'))
|
|
29
|
+
})
|
|
30
|
+
test('関係ない文字でもエラーが出ないことの確認',async ()=>{
|
|
31
|
+
// chant.encode('')
|
|
32
|
+
expect(()=> chant.decode('💩')).not.toThrow()
|
|
33
|
+
//下のテストは無理になった
|
|
34
|
+
//expect(chant.decode('💩')).toBe('')
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
test('decode 文字の間違いをある程度修正できるか',async ()=>{
|
|
38
|
+
// 回廊に凍結冥界借り。血塗ら。
|
|
39
|
+
// 回 結 塗
|
|
40
|
+
expect(await chant.decode('廻廊に凍吉冥界借り。血土ら。')).toBe('unko\n')
|
|
41
|
+
})
|
|
42
|
+
})
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import simpleEnigma from '../src/machine-encrypt.js'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
describe('simpleEnigma',()=>{
|
|
5
|
+
test('変換して元に戻せるかの確認',()=>{
|
|
6
|
+
|
|
7
|
+
let input = [1,2,3,4,5,6,7,8,9,10]
|
|
8
|
+
let encryptData = simpleEnigma.uint8ArrayEncrypt(input)
|
|
9
|
+
|
|
10
|
+
// toBeだとオブジェクト同士の参照が一致しているかまで調べてしまうためtoEqualを使う
|
|
11
|
+
// enigmaと同じ仕組みのため初期位置が同じencoderは,decoderになる
|
|
12
|
+
expect(simpleEnigma.uint8ArrayEncrypt(encryptData))
|
|
13
|
+
.toEqual(input)
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
test('連続したバイト列が偏り少なく出力される確認',()=>{
|
|
17
|
+
|
|
18
|
+
//すべて0の500このリスト
|
|
19
|
+
let continuSameNumber = Array.from({ length : 500 }).map(_=> 0)
|
|
20
|
+
let result = simpleEnigma.uint8ArrayEncrypt(continuSameNumber)
|
|
21
|
+
|
|
22
|
+
let result_count = Array.from({ length : 256 }).map(_=> 0)
|
|
23
|
+
|
|
24
|
+
result.forEach(v=>{
|
|
25
|
+
result_count[v] += 1
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
expect(Math.max(...result_count))
|
|
29
|
+
.toBeLessThan(15)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test('辞書にあるすべての単語を出力して問題ないかの確認',()=>{
|
|
33
|
+
// 辞書は名詞が256単語周期、動詞が 256*4単語周期になっている
|
|
34
|
+
// 257 * 4 回 同じデータを入れるとすべてのデータが取り出せる
|
|
35
|
+
let input = Array.from({ length : (257 * 4) }).map(_=> 0)
|
|
36
|
+
let encryptData = simpleEnigma.uint8ArrayEncrypt(input)
|
|
37
|
+
|
|
38
|
+
// enigmaと同じ仕組みのため初期位置が同じencoderは,decoderになる
|
|
39
|
+
expect(simpleEnigma.uint8ArrayEncrypt(encryptData))
|
|
40
|
+
.toEqual(input)
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test('大きなバイト列をエンコードできるか確認', () => {
|
|
44
|
+
let arr = Array.from((new Array(1000000)).keys()).map((_, i) => i % 256)
|
|
45
|
+
let decoded = simpleEnigma.uint8ArrayEncrypt(simpleEnigma.uint8ArrayEncrypt(arr))
|
|
46
|
+
|
|
47
|
+
expect(arr).toEqual(decoded)
|
|
48
|
+
})
|
|
49
|
+
})
|
package/dic/base.dat.gz
ADDED
|
Binary file
|
package/dic/cc.dat.gz
ADDED
|
Binary file
|
package/dic/check.dat.gz
ADDED
|
Binary file
|
package/dic/tid.dat.gz
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dic/unk.dat.gz
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yukichant",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "v3.1.0-beta.3",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": "amanoese/yukichant",
|
|
@@ -21,7 +21,9 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"commander": "^8.3.0",
|
|
24
|
-
"
|
|
24
|
+
"fastest-levenshtein": "^1.0.16",
|
|
25
|
+
"get-stdin": "^9.0.0",
|
|
26
|
+
"kuromoji": "^0.1.2"
|
|
25
27
|
},
|
|
26
28
|
"keywords": [
|
|
27
29
|
"cli",
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
set -eu
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR=$(cd $(dirname $0); pwd)
|
|
6
|
+
|
|
7
|
+
DOUSI_TEMP=`mktemp`
|
|
8
|
+
|
|
9
|
+
genarate_json(){
|
|
10
|
+
local TEMP=`mktemp`
|
|
11
|
+
|
|
12
|
+
## remove near distance words
|
|
13
|
+
cat "$1" |
|
|
14
|
+
grep -v -f ${SCRIPT_DIR}/spell_NG_word.txt |
|
|
15
|
+
xargs -L1 -I@ bash -c "mecab ${1}|cut -d, -f8| agrep -c -1 '@';echo @" 2>/dev/null |
|
|
16
|
+
xargs -L2 |
|
|
17
|
+
sort -nrs -k1,1 > "$TEMP"
|
|
18
|
+
|
|
19
|
+
## remove partial match
|
|
20
|
+
cat "$TEMP" |
|
|
21
|
+
cut -d' ' -f2-|
|
|
22
|
+
xargs -L1 -I@ bash -c "grep '@' '${TEMP}'|wc -l;echo @"|
|
|
23
|
+
xargs -L2 |
|
|
24
|
+
awk '$1==1{print $2}'|
|
|
25
|
+
|
|
26
|
+
## genarate json
|
|
27
|
+
head -256|
|
|
28
|
+
paste <((seq 32 255;seq 0 31)|xargs -L1 -I@ bash -c 'echo 0$(echo "obase=16;@"|bc)|grep -o "..$"') - |
|
|
29
|
+
sort -k1,1 |
|
|
30
|
+
sed -r 's/^(.*)\t/ \"\1\":/;s/:(.*)/: ["\1"],/'|
|
|
31
|
+
sed '1s/^/{\n/;256s/,/\n}/'
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
MEISI_TEMP=`${SCRIPT_DIR}/meisi_json_generator | sed -n 2p`
|
|
35
|
+
|
|
36
|
+
cat ${SCRIPT_DIR}/spell.txt |
|
|
37
|
+
base64 -d |
|
|
38
|
+
mecab |
|
|
39
|
+
tr '\t' ,|
|
|
40
|
+
awk -F, '$2~/動詞/&&$2!~/助動詞/{print $1}'|
|
|
41
|
+
sort -u |
|
|
42
|
+
sed -n '/../p'|
|
|
43
|
+
grep -P '\p{Han}' |
|
|
44
|
+
grep -v -f "$MEISI_TEMP" > "$DOUSI_TEMP"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
genarate_json $DOUSI_TEMP |
|
|
48
|
+
sed 's/"/。"/4' |
|
|
49
|
+
sed '/0A/s/\[.*]/["具現化せよ。", "踊れ。", "歌え。", "紡げ。"]/' > ${SCRIPT_DIR}/../data/dousi.json
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
set -eu
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR=$(cd $(dirname $0); pwd)
|
|
6
|
+
|
|
7
|
+
MEISI_TEMP=`mktemp`
|
|
8
|
+
|
|
9
|
+
## 名詞と副詞と連体化した単語を合わせたテキストの生成
|
|
10
|
+
cat ${SCRIPT_DIR}/spell.txt |
|
|
11
|
+
base64 -d |
|
|
12
|
+
mecab |
|
|
13
|
+
tr '\t' ,|
|
|
14
|
+
awk -F, '$2~/名詞/|| $1~/EOF/{print s;a=1;s=$1}a==2{a=0;s=""}a==1&&$2~/助詞/{a=0;if($3~/連体化/){a=2}s=s$1}'|
|
|
15
|
+
sort -u |
|
|
16
|
+
sed -n '/../p'|
|
|
17
|
+
grep -P '\p{Han}' > "$MEISI_TEMP"
|
|
18
|
+
|
|
19
|
+
## 部分一致指定舞う単語の排除
|
|
20
|
+
MEISI_UNIQ_TEMP=`mktemp`
|
|
21
|
+
cat "$MEISI_TEMP" |
|
|
22
|
+
xargs -L1 -I@ bash -c "echo \$(grep -c @ $MEISI_TEMP) @"|
|
|
23
|
+
awk '$1==1{print $2}'|
|
|
24
|
+
## NG単語の排除
|
|
25
|
+
grep -v -f $SCRIPT_DIR/spell_NG_word.txt |
|
|
26
|
+
cat > $MEISI_UNIQ_TEMP
|
|
27
|
+
|
|
28
|
+
## 同じ漢字で始まる単語をグルーピング
|
|
29
|
+
MEISI_RESULT_TEMP=`mktemp`
|
|
30
|
+
cat $MEISI_TEMP |
|
|
31
|
+
grep -oP '^\p{Han}'|
|
|
32
|
+
sort -u |
|
|
33
|
+
xargs -L1 -I@ bash -c "grep '^@' $MEISI_UNIQ_TEMP |xargs"|
|
|
34
|
+
sort -u|
|
|
35
|
+
awk '{print NF,$0}'|
|
|
36
|
+
sort -nr -k1,1|
|
|
37
|
+
head -257|
|
|
38
|
+
cut -d' ' -f2- > $MEISI_RESULT_TEMP
|
|
39
|
+
|
|
40
|
+
## genarate json
|
|
41
|
+
cat $MEISI_RESULT_TEMP|
|
|
42
|
+
head -257|
|
|
43
|
+
paste <((echo 10 227 {129..131}|tr ' ' \\n;seq 32 255|grep -v -e 129 -e 130 -e 131 -e 223;seq 0 31|grep -v 10;echo 223)| xargs -L1 -I@ bash -c 'echo 0$(echo "obase=16;@"|bc)|grep -o "..$"') - |
|
|
44
|
+
sort -k1,1 |
|
|
45
|
+
tee /dev/stderr |
|
|
46
|
+
sed 's/ /","/g' |
|
|
47
|
+
sed -r 's/^(.*)\t/ \"\1\":/;s/:(.*)/: ["\1"],/'|
|
|
48
|
+
sed '1s/^/{\n/;$s/,$/\n}/' > ${SCRIPT_DIR}/../data/meisi.json
|
|
49
|
+
|
|
50
|
+
## DEBUG用?
|
|
51
|
+
echo $MEISI_TEMP
|
|
52
|
+
echo $MEISI_UNIQ_TEMP
|
|
53
|
+
echo $MEISI_RESULT_TEMP
|