Update saferKorean: better code
This commit is contained in:
parent
4868ccd6b2
commit
b266595c4b
10 changed files with 1053 additions and 388 deletions
1
TODO.md
1
TODO.md
|
|
@ -1,2 +1,3 @@
|
|||
|
||||
UNUSED 지우기
|
||||
rust 쪽에서 highpass 필터와 eq 먹이기 (audacity 프로젝트 확인하기)
|
||||
|
|
|
|||
526
package-lock.json
generated
526
package-lock.json
generated
|
|
@ -9,6 +9,7 @@
|
|||
"@discordjs/voice": "^0.19.2",
|
||||
"@prisma/adapter-pg": "^7.3.0",
|
||||
"@prisma/client": "^7.8.0",
|
||||
"@qwreey-js/kotlin-scope-func": "^1.0.0",
|
||||
"@snazzah/davey": "^0.1.11",
|
||||
"discord.js": "^14.26.4",
|
||||
"dotenv": "^17.4.2",
|
||||
|
|
@ -27,6 +28,7 @@
|
|||
"@types/pg": "^8.20.0",
|
||||
"eslint": "^10.4.0",
|
||||
"prettier": "^3.8.3",
|
||||
"tsx": "^4.22.3",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.59.4"
|
||||
}
|
||||
|
|
@ -306,6 +308,448 @@
|
|||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz",
|
||||
"integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz",
|
||||
"integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz",
|
||||
"integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-x64": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz",
|
||||
"integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz",
|
||||
"integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz",
|
||||
"integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz",
|
||||
"integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz",
|
||||
"integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz",
|
||||
"integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz",
|
||||
"integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz",
|
||||
"integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz",
|
||||
"integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz",
|
||||
"integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz",
|
||||
"integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz",
|
||||
"integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz",
|
||||
"integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz",
|
||||
"integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-arm64": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz",
|
||||
"integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz",
|
||||
"integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-arm64": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz",
|
||||
"integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz",
|
||||
"integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openharmony-arm64": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz",
|
||||
"integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openharmony"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz",
|
||||
"integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz",
|
||||
"integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz",
|
||||
"integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-x64": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz",
|
||||
"integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint-community/eslint-utils": {
|
||||
"version": "4.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
|
||||
|
|
@ -901,6 +1345,12 @@
|
|||
"react-dom": "^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@qwreey-js/kotlin-scope-func": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@qwreey-js/kotlin-scope-func/-/kotlin-scope-func-1.0.0.tgz",
|
||||
"integrity": "sha512-TqrDgWwRr0XpRRq6bmhktsf7MbPKc9ZTVEzakDmP2mziB5+lS2M6uVbv6+Wug24BA2PEXnFstwn7zLW9oUmzOA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@radix-ui/primitive": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
|
||||
|
|
@ -2147,6 +2597,48 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz",
|
||||
"integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/aix-ppc64": "0.28.0",
|
||||
"@esbuild/android-arm": "0.28.0",
|
||||
"@esbuild/android-arm64": "0.28.0",
|
||||
"@esbuild/android-x64": "0.28.0",
|
||||
"@esbuild/darwin-arm64": "0.28.0",
|
||||
"@esbuild/darwin-x64": "0.28.0",
|
||||
"@esbuild/freebsd-arm64": "0.28.0",
|
||||
"@esbuild/freebsd-x64": "0.28.0",
|
||||
"@esbuild/linux-arm": "0.28.0",
|
||||
"@esbuild/linux-arm64": "0.28.0",
|
||||
"@esbuild/linux-ia32": "0.28.0",
|
||||
"@esbuild/linux-loong64": "0.28.0",
|
||||
"@esbuild/linux-mips64el": "0.28.0",
|
||||
"@esbuild/linux-ppc64": "0.28.0",
|
||||
"@esbuild/linux-riscv64": "0.28.0",
|
||||
"@esbuild/linux-s390x": "0.28.0",
|
||||
"@esbuild/linux-x64": "0.28.0",
|
||||
"@esbuild/netbsd-arm64": "0.28.0",
|
||||
"@esbuild/netbsd-x64": "0.28.0",
|
||||
"@esbuild/openbsd-arm64": "0.28.0",
|
||||
"@esbuild/openbsd-x64": "0.28.0",
|
||||
"@esbuild/openharmony-arm64": "0.28.0",
|
||||
"@esbuild/sunos-x64": "0.28.0",
|
||||
"@esbuild/win32-arm64": "0.28.0",
|
||||
"@esbuild/win32-ia32": "0.28.0",
|
||||
"@esbuild/win32-x64": "0.28.0"
|
||||
}
|
||||
},
|
||||
"node_modules/escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
|
|
@ -2667,6 +3159,21 @@
|
|||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/gauge": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz",
|
||||
|
|
@ -4174,6 +4681,25 @@
|
|||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/tsx": {
|
||||
"version": "4.22.3",
|
||||
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.3.tgz",
|
||||
"integrity": "sha512-mdoNxBC/cSQObGGVQ5Bpn5i+yv7j68gk3Nfm3wFjcJg3Z0Mix9jzAFfP12prmm5eVGmDKtp0yyArrs0Q+8gZHg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esbuild": "~0.28.0"
|
||||
},
|
||||
"bin": {
|
||||
"tsx": "dist/cli.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.3"
|
||||
}
|
||||
},
|
||||
"node_modules/type-check": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||
|
|
|
|||
|
|
@ -13,13 +13,14 @@
|
|||
"build:tsc": "./node_modules/typescript/bin/tsc",
|
||||
"build": "npm run build:prisma && npm run build:tsc",
|
||||
"start": "prisma migrate deploy && node --import=extensionless/register .",
|
||||
"dev": "npm run build && node --import=extensionless/register ."
|
||||
"dev": "tsx packages/index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@discordjs/opus": "^0.10.0",
|
||||
"@discordjs/voice": "^0.19.2",
|
||||
"@prisma/adapter-pg": "^7.3.0",
|
||||
"@prisma/client": "^7.8.0",
|
||||
"@qwreey-js/kotlin-scope-func": "^1.0.0",
|
||||
"@snazzah/davey": "^0.1.11",
|
||||
"discord.js": "^14.26.4",
|
||||
"dotenv": "^17.4.2",
|
||||
|
|
@ -38,7 +39,8 @@
|
|||
"@types/pg": "^8.20.0",
|
||||
"eslint": "^10.4.0",
|
||||
"prettier": "^3.8.3",
|
||||
"typescript-eslint": "^8.59.4",
|
||||
"typescript": "^5.9.3"
|
||||
"tsx": "^4.22.3",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.59.4"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,9 @@ export * from "./enums"
|
|||
* Type-safe database client for TypeScript
|
||||
* @example
|
||||
* ```
|
||||
* const prisma = new PrismaClient()
|
||||
* const prisma = new PrismaClient({
|
||||
* adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL })
|
||||
* })
|
||||
* // Fetch zero or more DiscordUserProfiles
|
||||
* const discordUserProfiles = await prisma.discordUserProfile.findMany()
|
||||
* ```
|
||||
|
|
|
|||
|
|
@ -17,18 +17,26 @@ import type * as Prisma from "./prismaNamespace"
|
|||
|
||||
const config: runtime.GetPrismaClientConfig = {
|
||||
"previewFeatures": [],
|
||||
"clientVersion": "7.3.0",
|
||||
"engineVersion": "9d6ad21cbbceab97458517b147a6a09ff43aa735",
|
||||
"clientVersion": "7.8.0",
|
||||
"engineVersion": "3c6e192761c0362d496ed980de936e2f3cebcd3a",
|
||||
"activeProvider": "postgresql",
|
||||
"inlineSchema": "generator client {\n provider = \"prisma-client\"\n output = \"../packages/db/generated/prisma\"\n specifying = [\"prismaSchemaFolder\"]\n}\n\ndatasource db {\n provider = \"postgresql\"\n}\n\nmodel DiscordUserProfile {\n id String @id @default(cuid())\n userId String @unique\n voice Voice @default(Papago)\n nya Boolean @default(false)\n canTypecast Boolean @default(false)\n userSupertonicStyle String @default(\"\")\n}\n\nmodel DiscordGuildProfile {\n id String @id @default(cuid())\n guildId String @unique\n readChannel String[] @default([])\n}\n\nenum Voice {\n TypeCast\n Papago\n Supertonic\n}\n",
|
||||
"runtimeDataModel": {
|
||||
"models": {},
|
||||
"enums": {},
|
||||
"types": {}
|
||||
},
|
||||
"parameterizationSchema": {
|
||||
"strings": [],
|
||||
"graph": ""
|
||||
}
|
||||
}
|
||||
|
||||
config.runtimeDataModel = JSON.parse("{\"models\":{\"DiscordUserProfile\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"voice\",\"kind\":\"enum\",\"type\":\"Voice\"},{\"name\":\"nya\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"canTypecast\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"userSupertonicStyle\",\"kind\":\"scalar\",\"type\":\"String\"}],\"dbName\":null},\"DiscordGuildProfile\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"guildId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"readChannel\",\"kind\":\"scalar\",\"type\":\"String\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}")
|
||||
config.parameterizationSchema = {
|
||||
strings: JSON.parse("[\"where\",\"DiscordUserProfile.findUnique\",\"DiscordUserProfile.findUniqueOrThrow\",\"orderBy\",\"cursor\",\"DiscordUserProfile.findFirst\",\"DiscordUserProfile.findFirstOrThrow\",\"DiscordUserProfile.findMany\",\"data\",\"DiscordUserProfile.createOne\",\"DiscordUserProfile.createMany\",\"DiscordUserProfile.createManyAndReturn\",\"DiscordUserProfile.updateOne\",\"DiscordUserProfile.updateMany\",\"DiscordUserProfile.updateManyAndReturn\",\"create\",\"update\",\"DiscordUserProfile.upsertOne\",\"DiscordUserProfile.deleteOne\",\"DiscordUserProfile.deleteMany\",\"having\",\"_count\",\"_min\",\"_max\",\"DiscordUserProfile.groupBy\",\"DiscordUserProfile.aggregate\",\"DiscordGuildProfile.findUnique\",\"DiscordGuildProfile.findUniqueOrThrow\",\"DiscordGuildProfile.findFirst\",\"DiscordGuildProfile.findFirstOrThrow\",\"DiscordGuildProfile.findMany\",\"DiscordGuildProfile.createOne\",\"DiscordGuildProfile.createMany\",\"DiscordGuildProfile.createManyAndReturn\",\"DiscordGuildProfile.updateOne\",\"DiscordGuildProfile.updateMany\",\"DiscordGuildProfile.updateManyAndReturn\",\"DiscordGuildProfile.upsertOne\",\"DiscordGuildProfile.deleteOne\",\"DiscordGuildProfile.deleteMany\",\"DiscordGuildProfile.groupBy\",\"DiscordGuildProfile.aggregate\",\"AND\",\"OR\",\"NOT\",\"id\",\"guildId\",\"readChannel\",\"equals\",\"has\",\"hasEvery\",\"hasSome\",\"in\",\"notIn\",\"lt\",\"lte\",\"gt\",\"gte\",\"contains\",\"startsWith\",\"endsWith\",\"not\",\"userId\",\"Voice\",\"voice\",\"nya\",\"canTypecast\",\"userSupertonicStyle\",\"set\",\"push\"]"),
|
||||
graph: "TxEgCSoAAEIAMCsAAAQAECwAAEIAMC0BAAAAAT4BAAAAAUAAAENAIkEgAEQAIUIgAEQAIUMBADoAIQEAAAABACABAAAAAQAgCSoAAEIAMCsAAAQAECwAAEIAMC0BADoAIT4BADoAIUAAAENAIkEgAEQAIUIgAEQAIUMBADoAIQADAAAABAAgAwAABQAwBAAAAQAgAwAAAAQAIAMAAAUAMAQAAAEAIAMAAAAEACADAAAFADAEAAABACAGLQEAAAABPgEAAAABQAAAAEACQSAAAAABQiAAAAABQwEAAAABAQgAAAkAIAYtAQAAAAE-AQAAAAFAAAAAQAJBIAAAAAFCIAAAAAFDAQAAAAEBCAAACwAwAQgAAAsAMAYtAQBIACE-AQBIACFAAABOQCJBIABPACFCIABPACFDAQBIACECAAAAAQAgCAAADgAgBi0BAEgAIT4BAEgAIUAAAE5AIkEgAE8AIUIgAE8AIUMBAEgAIQIAAAAEACAIAAAQACACAAAABAAgCAAAEAAgAwAAAAEAIA8AAAkAIBAAAA4AIAEAAAABACABAAAABAAgAxUAAEsAIBYAAE0AIBcAAEwAIAkqAAA7ADArAAAXABAsAAA7ADAtAQA0ACE-AQA0ACFAAAA8QCJBIAA9ACFCIAA9ACFDAQA0ACEDAAAABAAgAwAAFgAwFAAAFwAgAwAAAAQAIAMAAAUAMAQAAAEAIAYqAAA5ADArAAAdABAsAAA5ADAtAQAAAAEuAQAAAAEvAAA1ACABAAAAGgAgAQAAABoAIAYqAAA5ADArAAAdABAsAAA5ADAtAQA6ACEuAQA6ACEvAAA1ACAAAwAAAB0AIAMAAB4AMAQAABoAIAMAAAAdACADAAAeADAEAAAaACADAAAAHQAgAwAAHgAwBAAAGgAgAy0BAAAAAS4BAAAAAS8AAEoAIAEIAAAiACADLQEAAAABLgEAAAABLwAASgAgAQgAACQAMAEIAAAkADADLQEASAAhLgEASAAhLwAASQAgAgAAABoAIAgAACcAIAMtAQBIACEuAQBIACEvAABJACACAAAAHQAgCAAAKQAgAgAAAB0AIAgAACkAIAMAAAAaACAPAAAiACAQAAAnACABAAAAGgAgAQAAAB0AIAMVAABFACAWAABHACAXAABGACAGKgAAMwAwKwAAMAAQLAAAMwAwLQEANAAhLgEANAAhLwAANQAgAwAAAB0AIAMAAC8AMBQAADAAIAMAAAAdACADAAAeADAEAAAaACAGKgAAMwAwKwAAMAAQLAAAMwAwLQEANAAhLgEANAAhLwAANQAgDhUAADcAIBYAADgAIBcAADgAIDABAAAAATQBAAAABDUBAAAABDYBAAAAATcBAAAAATgBAAAAATkBAAAAAToBAAAAATsBAAAAATwBAAAAAT0BADYAIQQwAQAAAAUxAQAAAAEyAQAAAAQzAQAAAAQOFQAANwAgFgAAOAAgFwAAOAAgMAEAAAABNAEAAAAENQEAAAAENgEAAAABNwEAAAABOAEAAAABOQEAAAABOgEAAAABOwEAAAABPAEAAAABPQEANgAhCDACAAAAATQCAAAABDUCAAAABDYCAAAAATcCAAAAATgCAAAAATkCAAAAAT0CADcAIQswAQAAAAE0AQAAAAQ1AQAAAAQ2AQAAAAE3AQAAAAE4AQAAAAE5AQAAAAE6AQAAAAE7AQAAAAE8AQAAAAE9AQA4ACEGKgAAOQAwKwAAHQAQLAAAOQAwLQEAOgAhLgEAOgAhLwAANQAgCzABAAAAATQBAAAABDUBAAAABDYBAAAAATcBAAAAATgBAAAAATkBAAAAAToBAAAAATsBAAAAATwBAAAAAT0BADgAIQkqAAA7ADArAAAXABAsAAA7ADAtAQA0ACE-AQA0ACFAAAA8QCJBIAA9ACFCIAA9ACFDAQA0ACEHFQAANwAgFgAAQQAgFwAAQQAgMAAAAEACNAAAAEAINQAAAEAIPQAAQEAiBRUAADcAIBYAAD8AIBcAAD8AIDAgAAAAAT0gAD4AIQUVAAA3ACAWAAA_ACAXAAA_ACAwIAAAAAE9IAA-ACECMCAAAAABPSAAPwAhBxUAADcAIBYAAEEAIBcAAEEAIDAAAABAAjQAAABACDUAAABACD0AAEBAIgQwAAAAQAI0AAAAQAg1AAAAQAg9AABBQCIJKgAAQgAwKwAABAAQLAAAQgAwLQEAOgAhPgEAOgAhQAAAQ0AiQSAARAAhQiAARAAhQwEAOgAhBDAAAABAAjQAAABACDUAAABACD0AAEFAIgIwIAAAAAE9IAA_ACEAAAABRAEAAAABAkQBAAAABEUBAAAABQFEAQAAAAQAAAABRAAAAEACAUQgAAAAAQAAAAADFQAGFgAHFwAIAAAAAxUABhYABxcACAAAAAMVAA4WAA8XABAAAAADFQAOFgAPFwAQAQIBAgMBBQYBBgcBBwgBCQoBCgwCCw0DDA8BDRECDhIEERMBEhQBExUCGBgFGRkJGhsKGxwKHB8KHSAKHiEKHyMKICUCISYLIigKIyoCJCsMJSwKJi0KJy4CKDENKTIR"
|
||||
}
|
||||
|
||||
async function decodeBase64AsWasm(wasmBase64: string): Promise<WebAssembly.Module> {
|
||||
const { Buffer } = await import('node:buffer')
|
||||
|
|
@ -59,7 +67,9 @@ export interface PrismaClientConstructor {
|
|||
* Type-safe database client for TypeScript
|
||||
* @example
|
||||
* ```
|
||||
* const prisma = new PrismaClient()
|
||||
* const prisma = new PrismaClient({
|
||||
* adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL })
|
||||
* })
|
||||
* // Fetch zero or more DiscordUserProfiles
|
||||
* const discordUserProfiles = await prisma.discordUserProfile.findMany()
|
||||
* ```
|
||||
|
|
@ -81,7 +91,9 @@ export interface PrismaClientConstructor {
|
|||
* Type-safe database client for TypeScript
|
||||
* @example
|
||||
* ```
|
||||
* const prisma = new PrismaClient()
|
||||
* const prisma = new PrismaClient({
|
||||
* adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL })
|
||||
* })
|
||||
* // Fetch zero or more DiscordUserProfiles
|
||||
* const discordUserProfiles = await prisma.discordUserProfile.findMany()
|
||||
* ```
|
||||
|
|
@ -166,9 +178,9 @@ export interface PrismaClient<
|
|||
* ])
|
||||
* ```
|
||||
*
|
||||
* Read more in our [docs](https://www.prisma.io/docs/concepts/components/prisma-client/transactions).
|
||||
* Read more in our [docs](https://www.prisma.io/docs/orm/prisma-client/queries/transactions).
|
||||
*/
|
||||
$transaction<P extends Prisma.PrismaPromise<any>[]>(arg: [...P], options?: { isolationLevel?: Prisma.TransactionIsolationLevel }): runtime.Types.Utils.JsPromise<runtime.Types.Utils.UnwrapTuple<P>>
|
||||
$transaction<P extends Prisma.PrismaPromise<any>[]>(arg: [...P], options?: { maxWait?: number, timeout?: number, isolationLevel?: Prisma.TransactionIsolationLevel }): runtime.Types.Utils.JsPromise<runtime.Types.Utils.UnwrapTuple<P>>
|
||||
|
||||
$transaction<R>(fn: (prisma: Omit<PrismaClient, runtime.ITXClientDenyList>) => runtime.Types.Utils.JsPromise<R>, options?: { maxWait?: number, timeout?: number, isolationLevel?: Prisma.TransactionIsolationLevel }): runtime.Types.Utils.JsPromise<R>
|
||||
|
||||
|
|
|
|||
|
|
@ -80,12 +80,12 @@ export type PrismaVersion = {
|
|||
}
|
||||
|
||||
/**
|
||||
* Prisma Client JS version: 7.3.0
|
||||
* Query Engine version: 9d6ad21cbbceab97458517b147a6a09ff43aa735
|
||||
* Prisma Client JS version: 7.8.0
|
||||
* Query Engine version: 3c6e192761c0362d496ed980de936e2f3cebcd3a
|
||||
*/
|
||||
export const prismaVersion: PrismaVersion = {
|
||||
client: "7.3.0",
|
||||
engine: "9d6ad21cbbceab97458517b147a6a09ff43aa735"
|
||||
client: "7.8.0",
|
||||
engine: "3c6e192761c0362d496ed980de936e2f3cebcd3a"
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -776,6 +776,21 @@ export type PrismaClientOptions = ({
|
|||
* ```
|
||||
*/
|
||||
comments?: runtime.SqlCommenterPlugin[]
|
||||
/**
|
||||
* Optional maximum size for the query plan cache. If not provided, a default size will be used.
|
||||
* A value of `0` can be used to disable the cache entirely. A higher cache size can improve
|
||||
* performance for applications that execute a large number of unique queries, while a smaller
|
||||
* cache size can reduce memory usage.
|
||||
*
|
||||
* @example
|
||||
* ```
|
||||
* const prisma = new PrismaClient({
|
||||
* adapter,
|
||||
* queryPlanCacheMaxSize: 100,
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
queryPlanCacheMaxSize?: number
|
||||
}
|
||||
export type GlobalOmitConfig = {
|
||||
discordUserProfile?: Prisma.DiscordUserProfileOmit
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ export type DiscordGuildProfileGroupByOutputType = {
|
|||
_max: DiscordGuildProfileMaxAggregateOutputType | null
|
||||
}
|
||||
|
||||
type GetDiscordGuildProfileGroupByPayload<T extends DiscordGuildProfileGroupByArgs> = Prisma.PrismaPromise<
|
||||
export type GetDiscordGuildProfileGroupByPayload<T extends DiscordGuildProfileGroupByArgs> = Prisma.PrismaPromise<
|
||||
Array<
|
||||
Prisma.PickEnumerable<DiscordGuildProfileGroupByOutputType, T['by']> &
|
||||
{
|
||||
|
|
@ -909,6 +909,11 @@ export type DiscordGuildProfileFindManyArgs<ExtArgs extends runtime.Types.Extens
|
|||
* Skip the first `n` DiscordGuildProfiles.
|
||||
*/
|
||||
skip?: number
|
||||
/**
|
||||
* {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs}
|
||||
*
|
||||
* Filter by unique combinations of DiscordGuildProfiles.
|
||||
*/
|
||||
distinct?: Prisma.DiscordGuildProfileScalarFieldEnum | Prisma.DiscordGuildProfileScalarFieldEnum[]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ export type DiscordUserProfileGroupByOutputType = {
|
|||
_max: DiscordUserProfileMaxAggregateOutputType | null
|
||||
}
|
||||
|
||||
type GetDiscordUserProfileGroupByPayload<T extends DiscordUserProfileGroupByArgs> = Prisma.PrismaPromise<
|
||||
export type GetDiscordUserProfileGroupByPayload<T extends DiscordUserProfileGroupByArgs> = Prisma.PrismaPromise<
|
||||
Array<
|
||||
Prisma.PickEnumerable<DiscordUserProfileGroupByOutputType, T['by']> &
|
||||
{
|
||||
|
|
@ -994,6 +994,11 @@ export type DiscordUserProfileFindManyArgs<ExtArgs extends runtime.Types.Extensi
|
|||
* Skip the first `n` DiscordUserProfiles.
|
||||
*/
|
||||
skip?: number
|
||||
/**
|
||||
* {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs}
|
||||
*
|
||||
* Filter by unique combinations of DiscordUserProfiles.
|
||||
*/
|
||||
distinct?: Prisma.DiscordUserProfileScalarFieldEnum | Prisma.DiscordUserProfileScalarFieldEnum[]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
import { Routes } from "discord.js";
|
||||
import { DiscordBot } from "./bot";
|
||||
import { APPLICATION_ID, DISCORD_TOKEN } from "./env";
|
||||
import "@qwreey-js/kotlin-scope-func";
|
||||
|
||||
export const bot = new DiscordBot(DISCORD_TOKEN);
|
||||
|
||||
bot.client.once("clientReady", async (client) => {
|
||||
await bot.registerCommands();
|
||||
await bot.registerEvents();
|
||||
bot.registerEvents();
|
||||
|
||||
console.log(
|
||||
"registerCommands: \n| " +
|
||||
|
|
@ -20,4 +21,4 @@ bot.client.once("clientReady", async (client) => {
|
|||
);
|
||||
});
|
||||
|
||||
bot.client.login(DISCORD_TOKEN);
|
||||
await bot.client.login(DISCORD_TOKEN);
|
||||
|
|
|
|||
|
|
@ -4,41 +4,316 @@ import IntegerKorean from "./integerKorean.js";
|
|||
import PhoneNumberKorean from "./phoneNumberKorean.js";
|
||||
import EmojiDescriptions from "./emoji-descriptions.json" with { type: "json" };
|
||||
|
||||
export const IsolatedSymbolMap = {
|
||||
"?": "물음표",
|
||||
"!": "느낌표",
|
||||
"'": "쿼트",
|
||||
'"': "더블쿼트",
|
||||
};
|
||||
export const SymbolMap = {
|
||||
"%": "퍼센트",
|
||||
$: "달러",
|
||||
"^": "캐럿",
|
||||
"&": "엔드",
|
||||
"*": "스타",
|
||||
"#": "샵",
|
||||
"@": "엣",
|
||||
".": "쩜",
|
||||
"-": "마이너스",
|
||||
"+": "플러스",
|
||||
_: "언더바",
|
||||
"=": "이퀄",
|
||||
"/": "슬래쉬",
|
||||
"~": "물결표",
|
||||
"\\": "역슬래쉬",
|
||||
"♡": "하트 ",
|
||||
"|": "",
|
||||
">": "",
|
||||
"<": "",
|
||||
":": "콜론",
|
||||
";": "세미콜론",
|
||||
};
|
||||
export const VersionPostfix = {
|
||||
a: "알파",
|
||||
b: "베타",
|
||||
};
|
||||
// Process tailing dots
|
||||
export function processDots(input: string): string {
|
||||
return input
|
||||
.replace(/[.,]+$/, "")
|
||||
.replace(/[.,]{2,}/g, "")
|
||||
.replace(/[.,]\s/g, " ");
|
||||
}
|
||||
|
||||
export const LangPrefixes = {
|
||||
// Process korean letter, choseong shortens
|
||||
export function processKorean(input: string): string {
|
||||
input = input.replace(/[아ㅏ]{3,}/g, "아아아");
|
||||
|
||||
return input.replace(/[ㄱ-ㅎㄲㄸㅃㅆㅉ]+/g, (i) =>
|
||||
i
|
||||
.replace(processKorean.DoubleMixedChoseongMapRegex, (content: string) => {
|
||||
// ㅇㅋ => 오키, ㅇㄴ => 아니, ...
|
||||
const key = content.substring(
|
||||
0,
|
||||
2,
|
||||
) as keyof typeof processKorean.DoubleMixedChoseongMap;
|
||||
const length = Math.min(Math.floor(content.length / 2), 2);
|
||||
return processKorean.DoubleMixedChoseongMap[key].repeat(length);
|
||||
})
|
||||
.replace(processKorean.RepeatedChoseongMapRegex, (content: string) => {
|
||||
// process ㄴㄴ ㄱㄱ ㅋㅋ ㄷㄷ, ...
|
||||
const key = (content[0] ??
|
||||
"") as keyof typeof processKorean.RepeatedChoseongMap;
|
||||
const item = processKorean.RepeatedChoseongMap[key];
|
||||
|
||||
if (typeof item == "string") {
|
||||
return item;
|
||||
} else if (typeof item == "function") {
|
||||
return item(content);
|
||||
}
|
||||
return content;
|
||||
})
|
||||
.replace(
|
||||
/[ㄱ-ㅎㄲㄸㅃㅆㅉ]/g,
|
||||
(char: string) =>
|
||||
processKorean.ChoseongMap[
|
||||
char as keyof typeof processKorean.ChoseongMap
|
||||
] ?? char,
|
||||
),
|
||||
);
|
||||
}
|
||||
export namespace processKorean {
|
||||
export const DoubleMixedChoseongMap = {
|
||||
ㅎㅇ: "하이",
|
||||
ㅅㄹ: "싫어",
|
||||
ㄱㄷ: "기달",
|
||||
ㅈㅂ: "제발",
|
||||
ㅁㄹ: "몰라",
|
||||
ㅅㅂ: "시바",
|
||||
ㅇㄷ: "어디",
|
||||
ㄴㅈ: "노잼",
|
||||
ㅂㅂ: "바바",
|
||||
ㅂㅇ: "바이",
|
||||
ㅈㅅ: "죄송",
|
||||
ㅇㄴ: "아니",
|
||||
ㅃㄹ: "빨리",
|
||||
ㅇㅈ: "인정",
|
||||
ㄴㄴ: "노노",
|
||||
ㄱㅅ: "감사",
|
||||
ㅉㅉ: "쯧쯧",
|
||||
ㅈㄹ: "지랄",
|
||||
ㄹㅇ: "리얼",
|
||||
ㅇㅎ: "아하",
|
||||
ㅇㅋ: "오키",
|
||||
ㅊㅋ: "추카",
|
||||
ㄲㅈ: "꺼져",
|
||||
};
|
||||
export const DoubleMixedChoseongMapRegex = new RegExp(
|
||||
Object.keys(DoubleMixedChoseongMap)
|
||||
.map((k) => `(?:${k})+`)
|
||||
.join("|"),
|
||||
"g",
|
||||
);
|
||||
|
||||
export const RepeatedChoseongMap = {
|
||||
ㅌ: "틔틔",
|
||||
ㄷ: "덜덜",
|
||||
ㄴ: "노노",
|
||||
ㅇ: "응응",
|
||||
ㅊ: "추추",
|
||||
ㅠ: "유유",
|
||||
ㅜ: "우우",
|
||||
ㅋ: (content: string) => "크".repeat(content.length),
|
||||
ㅎ: (content: string) => "흐".repeat(content.length),
|
||||
ㄱ: (content: string) => {
|
||||
if (content.length == 2) {
|
||||
return "고고";
|
||||
} else if (content.length == 3) {
|
||||
return "고고고";
|
||||
}
|
||||
return content;
|
||||
},
|
||||
};
|
||||
export const RepeatedChoseongMapRegex = new RegExp(
|
||||
Object.keys(RepeatedChoseongMap)
|
||||
.map((k) => `${k}{2,}`)
|
||||
.join("|"),
|
||||
"g",
|
||||
);
|
||||
|
||||
// prettier-ignore
|
||||
export const ChoseongMap = {
|
||||
ㄱ: "기역", ㄴ: "니은", ㄷ: "디귿", ㄹ: "리을", ㅁ: "미음", ㅂ: "비읍",
|
||||
ㅅ: "시옷", ㅇ: "이응", ㅈ: "지읒", ㅊ: "치읓", ㅋ: "키읔", ㅌ: "티읕",
|
||||
ㅍ: "피읖", ㅎ: "히읗", ㄲ: "쌍기역", ㄸ: "쌍디귿", ㅃ: "쌍비읍",
|
||||
ㅆ: "쌍시옷", ㅉ: "쌍지읒",
|
||||
};
|
||||
}
|
||||
|
||||
// Process 10km 1,000 1.1, ... numbers
|
||||
export function processNumber(input: string): string {
|
||||
return input
|
||||
.replace(
|
||||
/(\+\d+[\s-]+)?([\d-]+)/g,
|
||||
(_, prefix: string | undefined, phone: string) => {
|
||||
const all = (prefix ?? "") + phone;
|
||||
if (!phone.includes("-")) return all;
|
||||
return PhoneNumberKorean.convert(all);
|
||||
},
|
||||
)
|
||||
.replace(
|
||||
/([\d,]+)(?:(?<prefix>[kKMmgGtTpPeEzZyY][iI]?)(?<unit>[bB])|(?<prefix>[m]?)(?<unit>[lL])|(?<prefix>[mck]?)(?<unit>m))(?<tail>[^a-zA-Z])/g,
|
||||
(_, num: string, ...last: any): string => {
|
||||
const group = last[last.length - 1] as {
|
||||
prefix: string;
|
||||
unit: string;
|
||||
tail: string;
|
||||
};
|
||||
const tail = group.tail;
|
||||
const unit = group.unit.toLocaleLowerCase();
|
||||
const numStr = IntegerKorean.convertFromString(num);
|
||||
let prefix = group.prefix;
|
||||
|
||||
if (unit == "b") {
|
||||
// 10kib => 십키비바이트
|
||||
prefix =
|
||||
processNumber.DatasizePrefix[
|
||||
prefix.toLowerCase() as keyof typeof processNumber.DatasizePrefix
|
||||
];
|
||||
return `${numStr} ${prefix}바이트 ${tail}`;
|
||||
}
|
||||
if (unit == "l") {
|
||||
// 10l => 십리터
|
||||
prefix =
|
||||
processNumber.LiterPrefix[
|
||||
prefix.toLowerCase() as keyof typeof processNumber.LiterPrefix
|
||||
];
|
||||
return `${numStr} ${prefix}리터 ${tail}`;
|
||||
}
|
||||
if (unit == "m") {
|
||||
// 10m => 십미터
|
||||
prefix =
|
||||
processNumber.MeterPrefix[
|
||||
prefix as keyof typeof processNumber.MeterPrefix
|
||||
];
|
||||
return `${numStr} ${prefix}미터 ${tail}`;
|
||||
}
|
||||
return `${num}${prefix}${unit}${tail}`;
|
||||
},
|
||||
)
|
||||
.replace(
|
||||
/([\d.,]+)\s*([개살시평명])/g,
|
||||
(_, num: string, postfix: string) => {
|
||||
// 10명 => 열명
|
||||
if (num.includes(".")) {
|
||||
return num + postfix;
|
||||
}
|
||||
const intNum = parseInt(num.replace(/,/g, ""));
|
||||
if (CallingNumberKorean.canConvert(intNum)) {
|
||||
return CallingNumberKorean.convert(intNum) + postfix;
|
||||
} else {
|
||||
return IntegerKorean.convertFromString(num) + postfix;
|
||||
}
|
||||
},
|
||||
)
|
||||
.replace(/[\d,]+/g, (num: string) => {
|
||||
// 1,000 원 => 천원
|
||||
if (!num.includes(",")) return num;
|
||||
return IntegerKorean.convertFromString(num);
|
||||
})
|
||||
.replace(
|
||||
/(v?)([\d.]+)([ab]?)/g,
|
||||
(_, suffix: string, num: string, postfix: string) => {
|
||||
const dotCount = [...num.matchAll(/\./g)].length;
|
||||
const hasNoSuffix = suffix == "";
|
||||
|
||||
if (hasNoSuffix && dotCount == 0) {
|
||||
// 일반 숫자는 인트로 읽음
|
||||
return IntegerKorean.convertFromString(num) + postfix;
|
||||
} else if (hasNoSuffix && dotCount == 1) {
|
||||
// 소수는 . 앞은 인트로, 뒤는 플로트로 읽음
|
||||
const [intPart, floatPart] = num.split(/\./);
|
||||
return (
|
||||
IntegerKorean.convertFromString(intPart ?? "") +
|
||||
"쩜" +
|
||||
FloatKorean.convert(floatPart ?? "") +
|
||||
postfix
|
||||
);
|
||||
} else if ((suffix == "v" || postfix.length) && dotCount > 1) {
|
||||
// 버전표기는 버전을 붙여서
|
||||
return (
|
||||
"버전" +
|
||||
FloatKorean.convert(num) +
|
||||
(processNumber.VersionPostfix[
|
||||
postfix as keyof typeof processNumber.VersionPostfix
|
||||
] ?? "")
|
||||
);
|
||||
} else {
|
||||
// 모든 경우에 속하지 않으면 영일이삼사 형태로 읽음
|
||||
// (예: 111.111.111.111 ip address)
|
||||
return FloatKorean.convert(num) + postfix;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
export namespace processNumber {
|
||||
// prettier-ignore
|
||||
export const DatasizePrefix = {
|
||||
k: "킬로", ki: "키비", m: "메가", mi: "메비",
|
||||
g: "기가", gi: "기비", t: "테라", ti: "테비",
|
||||
p: "페타", pi: "페비", e: "엑사", ei: "엑시",
|
||||
z: "제타", zi: "제비", y: "요타", yi: "요비",
|
||||
};
|
||||
// prettier-ignore
|
||||
export const LiterPrefix = { m: "밀리", "": "" };
|
||||
// prettier-ignore
|
||||
export const MeterPrefix = {
|
||||
m: "밀리", c: "센치", "": "", k: "킬로",
|
||||
};
|
||||
// prettier-ignore
|
||||
export const VersionPostfix = {
|
||||
a: "알파", b: "베타",
|
||||
};
|
||||
}
|
||||
|
||||
// Process unicode emojis and unicode symbols
|
||||
export function processEmoji(input: string): string {
|
||||
return input
|
||||
.replace(
|
||||
processEmoji.UnicodeSymbolsRegex,
|
||||
(content: string) =>
|
||||
processEmoji.UnicodeSymbols[
|
||||
content as keyof typeof processEmoji.UnicodeSymbols
|
||||
] ?? content,
|
||||
)
|
||||
.replace(/\p{Extended_Pictographic}/gu, (content: string) => {
|
||||
return (
|
||||
EmojiDescriptions[content as keyof typeof EmojiDescriptions] ?? content
|
||||
);
|
||||
})
|
||||
.replace(/\p{Emoji}/u, " 이모지 ");
|
||||
}
|
||||
export namespace processEmoji {
|
||||
export const UnicodeSymbols = {
|
||||
"㎢": "제곱킬로미터",
|
||||
"㎡": "제곱미터",
|
||||
"↑": "위쪽 화살표",
|
||||
"↓": "아래쪽 화살표",
|
||||
"←": "왼쪽 화살표",
|
||||
"→": "오른쪽 화살표",
|
||||
"↔": "좌우 화살표",
|
||||
"↖": "왼쪽 위 화살표",
|
||||
"↗": "오른쪽 위 화살표",
|
||||
"↘": "오른쪽 아래 화살표",
|
||||
"↙": "왼쪽 아래 화살표",
|
||||
"™": "티앰",
|
||||
};
|
||||
export const UnicodeSymbolsRegex = new RegExp(
|
||||
"[" + Object.keys(UnicodeSymbols).join() + "]",
|
||||
"gu",
|
||||
);
|
||||
}
|
||||
|
||||
// Process ```codeblock``` and https://link
|
||||
export function processMarkdown(input: string): string {
|
||||
return input
|
||||
.replace(/```([\s\S]*?)```/g, (_, content: string) => {
|
||||
// Process codeblock
|
||||
const code = content
|
||||
.substring(0, processMarkdown.LangPrefixMaxLength)
|
||||
.toLowerCase();
|
||||
let lang = "";
|
||||
for (const [key, value] of Object.entries(processMarkdown.LangPrefixes)) {
|
||||
if (code.startsWith(key + "\n")) {
|
||||
lang = value + " ";
|
||||
break;
|
||||
}
|
||||
}
|
||||
return lang + "코드블럭";
|
||||
})
|
||||
|
||||
.replace(/[hH][tT]{2}[pP][sS]?:\/\/(\S+)/g, (_, url: string) => {
|
||||
// Process link
|
||||
const mapped = processMarkdown.GIFMap[
|
||||
url as keyof typeof processMarkdown.GIFMap
|
||||
] as string | undefined;
|
||||
if (mapped) return mapped;
|
||||
|
||||
if (url.startsWith("tenor.com/view")) {
|
||||
return "움짤!";
|
||||
}
|
||||
return "링크";
|
||||
});
|
||||
}
|
||||
export namespace processMarkdown {
|
||||
export const LangPrefixes = {
|
||||
typescript: "타입스크립트",
|
||||
javascript: "자바스크립트",
|
||||
java: "자바",
|
||||
|
|
@ -108,66 +383,15 @@ export const LangPrefixes = {
|
|||
jsx: "리액트 자바스크립트",
|
||||
an: "에이엔",
|
||||
parlance: "팔렌스",
|
||||
};
|
||||
export const LangPrefixMaxLength = (() => {
|
||||
};
|
||||
export const LangPrefixMaxLength = (() => {
|
||||
let max = 0;
|
||||
for (const key in LangPrefixes) {
|
||||
max = Math.max(key.length, max);
|
||||
}
|
||||
return max;
|
||||
})();
|
||||
export const ChoseongMap = {
|
||||
ㄱ: "기역",
|
||||
ㄴ: "니은",
|
||||
ㄷ: "디귿",
|
||||
ㄹ: "리을",
|
||||
ㅁ: "미음",
|
||||
ㅂ: "비읍",
|
||||
ㅅ: "시옷",
|
||||
ㅇ: "이응",
|
||||
ㅈ: "지읒",
|
||||
ㅊ: "치읓",
|
||||
ㅋ: "키읔",
|
||||
ㅌ: "티읕",
|
||||
ㅍ: "피읖",
|
||||
ㅎ: "히읗",
|
||||
ㄲ: "쌍기역",
|
||||
ㄸ: "쌍디귿",
|
||||
ㅃ: "쌍비읍",
|
||||
ㅆ: "쌍시옷",
|
||||
ㅉ: "쌍지읒",
|
||||
};
|
||||
|
||||
export const SIPrefix = {
|
||||
k: "킬로",
|
||||
ki: "키비",
|
||||
m: "메가",
|
||||
mi: "메비",
|
||||
g: "기가",
|
||||
gi: "기비",
|
||||
t: "테라",
|
||||
ti: "테비",
|
||||
p: "페타",
|
||||
pi: "페비",
|
||||
e: "엑사",
|
||||
ei: "엑시",
|
||||
z: "제타",
|
||||
zi: "제비",
|
||||
y: "요타",
|
||||
yi: "요비",
|
||||
};
|
||||
export const LiterPrefix = {
|
||||
m: "밀리",
|
||||
"": "",
|
||||
};
|
||||
export const MeterPrefix = {
|
||||
m: "밀리",
|
||||
c: "센치",
|
||||
"": "",
|
||||
k: "킬로",
|
||||
};
|
||||
|
||||
export const GIFMap = {
|
||||
})();
|
||||
export const GIFMap = {
|
||||
"tenor.com/view/majo-no-tabitabi-the-journey-of-elaina-elaina-windy-hair-gif-19187698":
|
||||
"화난 일레이나",
|
||||
"tenor.com/view/majo-no-tabitabi-the-journey-of-elaina-elaina-sparkle-amazed-gif-18827847":
|
||||
|
|
@ -180,214 +404,86 @@ export const GIFMap = {
|
|||
"당황한 일레이나",
|
||||
"images-ext-1.discordapp.net/external/2R41WcvNJwYMD69UKls2cDa_hEL-rzCRCFvOi2DDOVo/https/media.tenor.com/sU3RCOixDbgAAAPo/majo-no-tabitabi-the-journey-of-elaina.mp4":
|
||||
"일레이나 손짓",
|
||||
};
|
||||
|
||||
export const UnicodeSymbols = {
|
||||
"㎢": "제곱킬로미터",
|
||||
"㎡": "제곱미터",
|
||||
"↑": "위쪽 화살표",
|
||||
"↓": "아래쪽 화살표",
|
||||
"←": "왼쪽 화살표",
|
||||
"→": "오른쪽 화살표",
|
||||
"↔": "좌우 화살표",
|
||||
"↖": "왼쪽 위 화살표",
|
||||
"↗": "오른쪽 위 화살표",
|
||||
"↘": "오른쪽 아래 화살표",
|
||||
"↙": "왼쪽 아래 화살표",
|
||||
};
|
||||
export const UnicodeSymbolsRegex = new RegExp(
|
||||
"[" + Object.keys(UnicodeSymbols).join() + "]",
|
||||
"gu",
|
||||
);
|
||||
|
||||
export function processDots(input: string): string {
|
||||
return input
|
||||
.replace(/[.,]+$/, "")
|
||||
.replace(/[.,]{2,}/g, "")
|
||||
.replace(/[.,]\s/g, " ");
|
||||
};
|
||||
}
|
||||
|
||||
export function saferKorean(input: string): string {
|
||||
return (
|
||||
processDots(input.normalize() + " ")
|
||||
// Process isolated symbols
|
||||
// Process %$*&... symbols to readable korean
|
||||
export function processSymbol(input: string): string {
|
||||
return input
|
||||
.replace(
|
||||
processSymbol.SymbolMapRegExp,
|
||||
(t) => processSymbol.SymbolMap[t as keyof typeof processSymbol.SymbolMap],
|
||||
)
|
||||
.replace(/([?!]+)/g, (_, content: string): string => content[0] ?? "")
|
||||
.replace(/[ \t\f\r]+/g, " ");
|
||||
}
|
||||
export namespace processSymbol {
|
||||
export const SymbolMap = {
|
||||
"%": "퍼센트",
|
||||
$: "달러",
|
||||
"^": "캐럿",
|
||||
"&": "엔드",
|
||||
"*": "스타",
|
||||
"#": "샵",
|
||||
"@": "엣",
|
||||
".": "쩜",
|
||||
"-": "마이너스",
|
||||
"+": "플러스",
|
||||
_: "언더바",
|
||||
"=": "이퀄",
|
||||
"/": "슬래쉬",
|
||||
"~": "물결표",
|
||||
"\\": "역슬래쉬",
|
||||
"♡": "하트 ",
|
||||
"|": "",
|
||||
">": "",
|
||||
"<": "",
|
||||
":": "콜론",
|
||||
";": "세미콜론",
|
||||
};
|
||||
export const SymbolMapRegExp = new RegExp(
|
||||
"[" +
|
||||
Object.keys(SymbolMap)
|
||||
.map((i) => "\\" + i)
|
||||
.join() +
|
||||
"]",
|
||||
"g",
|
||||
);
|
||||
}
|
||||
|
||||
// Process isolated symbols
|
||||
export function processIsolatedSymbol(input: string): string {
|
||||
return input
|
||||
.replace(/^[?!'"]+ $/, (total) =>
|
||||
[...total]
|
||||
.map(
|
||||
(element) =>
|
||||
IsolatedSymbolMap[element as keyof typeof IsolatedSymbolMap],
|
||||
processIsolatedSymbol.IsolatedSymbolMap[
|
||||
element as keyof typeof processIsolatedSymbol.IsolatedSymbolMap
|
||||
],
|
||||
)
|
||||
.join(""),
|
||||
)
|
||||
.replace(/\s\|\|\s/g, " 오얼 ")
|
||||
.replace(/\s&&\s/g, " 엔드 ")
|
||||
|
||||
// Process codeblock
|
||||
.replace(/```([\s\S]*?)```/g, (_, content: string) => {
|
||||
const code = content.substring(0, LangPrefixMaxLength).toLowerCase();
|
||||
let lang = "";
|
||||
for (const [key, value] of Object.entries(LangPrefixes)) {
|
||||
if (code.startsWith(key + "\n")) {
|
||||
lang = value + " ";
|
||||
break;
|
||||
}
|
||||
}
|
||||
return lang + "코드블럭";
|
||||
})
|
||||
|
||||
// Process link
|
||||
.replace(/[hH][tT]{2}[pP][sS]?:\/\/(\S+)/g, (_, url: string) => {
|
||||
const mapped = GIFMap[url as keyof typeof GIFMap] as string | undefined;
|
||||
if (mapped) return mapped;
|
||||
|
||||
if (url.startsWith("tenor.com/view")) {
|
||||
return "움짤!";
|
||||
}
|
||||
return "링크";
|
||||
})
|
||||
|
||||
// Process koreans
|
||||
.replace(/[아ㅏ]{3,}/g, "아아아")
|
||||
.replace(/ㄹㅇ/g, (content: string) => {
|
||||
return "리얼".repeat(Math.min(Math.floor(content.length / 2), 2));
|
||||
})
|
||||
.replace(/(ㅇㄴ)+/g, (content: string) => {
|
||||
return "아니".repeat(Math.min(Math.floor(content.length / 2), 2));
|
||||
})
|
||||
.replace(/(ㅇㅎ)+/g, (content: string) => {
|
||||
return "아하".repeat(Math.min(Math.floor(content.length / 2), 2));
|
||||
})
|
||||
.replace(/(ㅇㅋ)+/g, (content: string) => {
|
||||
return "오키".repeat(Math.min(Math.floor(content.length / 2), 2));
|
||||
})
|
||||
.replace(/(ㅊㅋ)+/g, (content: string) => {
|
||||
return "추카".repeat(Math.min(Math.floor(content.length / 2), 2));
|
||||
})
|
||||
.replace(/ㄱ+/g, (content: string) => {
|
||||
if (content.length == 2) {
|
||||
return "고고";
|
||||
} else if (content.length == 3) {
|
||||
return "고고고";
|
||||
}
|
||||
return content;
|
||||
})
|
||||
.replace(/ㅋ{2,}/g, (content) => "크".repeat(content.length))
|
||||
.replace(/ㅌ{2,}/g, "틔틔")
|
||||
.replace(/ㄷ{2,}/g, "덜덜")
|
||||
.replace(/ㄴ{2,}/g, "노노")
|
||||
.replace(/ㅇ{2,}/g, "응응")
|
||||
.replace(/ㅊ{2,}/g, "추추")
|
||||
.replace(/ㅠ{2,}/g, "유유")
|
||||
.replace(/ㅜ{2,}/g, "우우")
|
||||
.replace(
|
||||
/[ㄱ-ㅎㄲㄸㅃㅆㅉ]/g,
|
||||
(char: string) => ChoseongMap[char as keyof typeof ChoseongMap],
|
||||
)
|
||||
|
||||
// Process number, unit
|
||||
.replace(
|
||||
/(\+\d+[\s-]+)?([\d-]+)/g,
|
||||
(_, prefix: string | undefined, phone: string) => {
|
||||
const all = (prefix ?? "") + phone;
|
||||
if (!phone.includes("-")) return all;
|
||||
return PhoneNumberKorean.convert(all);
|
||||
},
|
||||
)
|
||||
.replace(
|
||||
/([\d,]+)([kKMmgGtTpPeEzZyY][iI]?)[bB]/g,
|
||||
(_, num: string, mod: string) => {
|
||||
// 10kib => 십키비바이트
|
||||
num = IntegerKorean.convertFromString(num);
|
||||
mod = SIPrefix[mod.toLowerCase() as keyof typeof SIPrefix];
|
||||
return `${num} ${mod}바이트 `;
|
||||
},
|
||||
)
|
||||
.replace(/([\d,]+)([m]?)[lL]\s/g, (_, num: string, mod: string) => {
|
||||
// 10l => 십리터
|
||||
num = IntegerKorean.convertFromString(num);
|
||||
mod = LiterPrefix[mod as keyof typeof LiterPrefix];
|
||||
return `${num} ${mod}리터 `;
|
||||
})
|
||||
.replace(/([\d,]+)([mck]?)m\s/g, (_, num: string, mod: string) => {
|
||||
// 10m => 십미터
|
||||
num = IntegerKorean.convertFromString(num);
|
||||
mod = MeterPrefix[mod as keyof typeof MeterPrefix];
|
||||
return `${num} ${mod}미터 `;
|
||||
})
|
||||
.replace(
|
||||
/([\d.]+)\s*([개살시평명])/g,
|
||||
(_, num: string, postfix: string) => {
|
||||
// 10명 => 열명
|
||||
if (num.includes(".")) {
|
||||
return num + postfix;
|
||||
}
|
||||
const intNum = parseInt(num);
|
||||
if (CallingNumberKorean.canConvert(intNum)) {
|
||||
return CallingNumberKorean.convert(intNum) + postfix;
|
||||
} else {
|
||||
return IntegerKorean.convertFromString(num) + postfix;
|
||||
}
|
||||
},
|
||||
)
|
||||
.replace(/[\d,]+/g, (num: string) => {
|
||||
// 1,000 원 => 천원
|
||||
if (!num.includes(",")) return num;
|
||||
return IntegerKorean.convertFromString(num);
|
||||
})
|
||||
.replace(
|
||||
/(v?)([\d.]+)([ab]?)/g,
|
||||
(_, suffix: string, num: string, postfix: string) => {
|
||||
const dotCount = [...num.matchAll(/\./g)].length;
|
||||
const hasNoSuffix = suffix == "";
|
||||
|
||||
if (hasNoSuffix && dotCount == 0) {
|
||||
// 일반 숫자는 인트로 읽음
|
||||
return IntegerKorean.convertFromString(num) + postfix;
|
||||
} else if (hasNoSuffix && dotCount == 1) {
|
||||
// 소수는 . 앞은 인트로, 뒤는 플로트로 읽음
|
||||
const [intPart, floatPart] = num.split(/\./);
|
||||
return (
|
||||
IntegerKorean.convertFromString(intPart ?? "") +
|
||||
"쩜" +
|
||||
FloatKorean.convert(floatPart ?? "") +
|
||||
postfix
|
||||
);
|
||||
} else if ((suffix == "v" || postfix.length) && dotCount > 1) {
|
||||
// 버전표기는 버전을 붙여서
|
||||
return (
|
||||
"버전" +
|
||||
FloatKorean.convert(num) +
|
||||
(VersionPostfix[postfix as keyof typeof VersionPostfix] ?? "")
|
||||
);
|
||||
} else {
|
||||
// 모든 경우에 속하지 않으면 영일이삼사 형태로 읽음
|
||||
// (예: 111.111.111.111 ip address)
|
||||
return FloatKorean.convert(num) + postfix;
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
// Process symbol
|
||||
.replace(
|
||||
/[%^&*#@.\-+_=/\\♡$|:;><]/g,
|
||||
(t) => SymbolMap[t as keyof typeof SymbolMap],
|
||||
)
|
||||
.replace(/([?!]+)/g, (_, content: string): string => content[0] ?? "")
|
||||
.replace(/[ \t\f\r]+/g, " ")
|
||||
|
||||
// Process emoji
|
||||
.replace(
|
||||
UnicodeSymbolsRegex,
|
||||
(content: string) =>
|
||||
UnicodeSymbols[content as keyof typeof UnicodeSymbols] ?? content,
|
||||
)
|
||||
.replace(/\p{Extended_Pictographic}/gu, (content: string) => {
|
||||
return (
|
||||
EmojiDescriptions[content as keyof typeof EmojiDescriptions] ??
|
||||
content
|
||||
);
|
||||
})
|
||||
.replace(/\p{Emoji}/u, " 이모지 ")
|
||||
.trim()
|
||||
);
|
||||
.replace(/\s&&\s/g, " 엔드 ");
|
||||
}
|
||||
export namespace processIsolatedSymbol {
|
||||
export const IsolatedSymbolMap = {
|
||||
"?": "물음표",
|
||||
"!": "느낌표",
|
||||
"'": "쿼트",
|
||||
'"': "더블쿼트",
|
||||
};
|
||||
}
|
||||
|
||||
export function saferKorean(input: string): string {
|
||||
return (input.normalize() + " ")
|
||||
.let((i) => processDots(i))
|
||||
.let((i) => processIsolatedSymbol(i))
|
||||
.let((i) => processMarkdown(i))
|
||||
.let((i) => processKorean(i))
|
||||
.let((i) => processNumber(i))
|
||||
.let((i) => processSymbol(i))
|
||||
.let((i) => processEmoji(i))
|
||||
.trim();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue