diff --git a/.gitignore b/.gitignore
index 0f55829..e113703 100644
--- a/.gitignore
+++ b/.gitignore
@@ -129,3 +129,4 @@ dist
.yarn/install-state.gz
.pnp.*
+.idea
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
deleted file mode 100644
index b58b603..0000000
--- a/.idea/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Editor-based HTTP Client requests
-/httpRequests/
diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml
deleted file mode 100644
index d23208f..0000000
--- a/.idea/jsLibraryMappings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index 13ac5f6..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/ts-module-template.iml b/.idea/ts-module-template.iml
deleted file mode 100644
index 2cd19fb..0000000
--- a/.idea/ts-module-template.iml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 35eb1dd..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/README.md b/README.md
index 60f72b8..abe36df 100644
--- a/README.md
+++ b/README.md
@@ -1,25 +1,7 @@
-# ๐งฉ typescript-module
+# ๐ค Hangul
-TypeScript๋ฅผ ์ฌ์ฉํ ๋ชจ๋์ ์ฝ๊ฒ ๋ง๋ค๊ธฐ ์ํ ํ
ํ๋ฆฟ ๋ ํฌ์งํ ๋ฆฌ.
+```js
+require('hangul');
-- Bot App: [`๋ฉ์ ์ ๋ดR`](https://github.com/MessengerBotTeam/msgbot-old-release/releases/tag/0.7.36a) (0.7.36a ๋ฒ์ ์ด์)
-- CI/CD: [`GitHub Actions`](https://github.com/features/actions)
-- Module Bundler: [`Rollup`](https://rollupjs.org/)
-- Test: [`Vitest`](https://vitest.dev/)
-- Execute: [`TSX`](https://tsx.is/)
-- Runtime: [`Node.js`](https://nodejs.org/en)
-
-## ๐ features
-- `npm run build:all-in-one`: `src` ํด๋์ ๋ชจ๋ ์์ค๋ฅผ ํ๋์ `.js`, `.d.ts` ํ์ผ๋ก ๋ง๋ค์ด `dist/all`์ ๋น๋
-- `npm run build:no-all-in-one`: `src` ํด๋์ ๊ฐ ํ์ผ๋ค์ ํ์ผ ๊ตฌ์กฐ๋ฅผ ์ ์งํ ์ฑ `.js`, `.d.ts` ํ์ผ๋ก ๋ณํํด `dist/preserve`์ ๋น๋
-- `package.json`์ `version` ํค๊ฐ ๋ณ๊ฒฝ๋ ์ฑ๋ก ํธ์ฌํ๋ฉด ์๋์ผ๋ก ํด๋น ๋ฒ์ ์ผ๋ก ๋ฆด๋ฆฌ์ฆ ์์ฑ. (`v1.0.0-alpha` ์ฒ๋ผ ์ฐ๋ฉด prerelease๋ก ์ค์ ๋จ)
-
-> [!NOTE]
-> `package.json` ์์ `directories` ํค๋ฅผ ์์ ํ์ฌ ๋น๋ ํ๊ฒ ๋ณ๊ฒฝ ๊ฐ๋ฅ
-
-## โ
prepare
-1. ๋ ํฌ์งํ ๋ฆฌ ์ค์ ์์ `GitHub Actions` ๊ฐ ์ ์ ํ ๊ถํ์ ๊ฐ์ง๊ณ ์๋์ง ํ์ธํ์ธ์.
- - `Settings > Actions > General` ๋ก ์ด๋ํฉ๋๋ค.
- - `Workflow permissions` ์์ `Read and write permissions` ๋ฅผ ์ ํํ๊ณ ์ ์ฅํฉ๋๋ค.
-2. `package.json` ํ์ผ์ ์ด์ด `name`, `version`, `description`, `author`, `license` ๋ฑ์ ํ๋๋ฅผ ์ ์ ํ ์์ ํฉ๋๋ค.
-3. `npm install` ๋ช
๋ น์ด๋ฅผ ์คํํ์ฌ ์์กด์ฑ ํจํค์ง๋ฅผ ์ค์นํฉ๋๋ค.
+console.log('๋ญ'.์ด๊ฐ + ' ๊ผฌ๊ผฌ๋ ์ธ๊ณ , ์ค๋ฆฌ'.๊ฐ + ' ๊ฝฅ๊ฝฅ ์ด๋ค.');
+```
diff --git a/examples/index.js b/examples/index.js
index d31e478..3b9ac4f 100644
--- a/examples/index.js
+++ b/examples/index.js
@@ -1 +1,5 @@
-// example code
\ No newline at end of file
+import '../src';
+import { disassemble } from 'hangul';
+
+"์๋
ํ์ธ์".isHangul();
+disassemble("์๋
ํ์ธ์");
diff --git a/package-lock.json b/package-lock.json
index edcc276..d3e6312 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,11 +1,11 @@
{
- "name": "ts-module-template",
+ "name": "hangul",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
- "name": "ts-module-template",
+ "name": "hangul",
"version": "1.0.0",
"license": "MIT",
"devDependencies": {
diff --git a/package.json b/package.json
index 50039e3..cafeb5b 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
- "name": "ts-module-template",
- "version": "1.0.0",
- "description": "template for typescript module",
+ "name": "hangul",
+ "version": "0.1.0-beta",
+ "description": "hangul helper module",
"main": "src/index.ts",
"directories": {
"example": "./examples",
diff --git a/src/hangul.ts b/src/hangul.ts
new file mode 100644
index 0000000..6192ac9
--- /dev/null
+++ b/src/hangul.ts
@@ -0,0 +1,22 @@
+export function _isHangul(text: string): boolean {
+ return text.length > 0 && [...text].every(ch => '๊ฐ' <= ch && ch <= 'ํฃ');
+}
+
+export function isHangul(text: string): boolean {
+ return /^[๊ฐ-ํฃ]+$/.test(text);
+}
+
+// export function disassemble(text: string): string[];
+// export function disassembleGroups(text: string): string[][];
+// export function assemble(letters: string[]): string;
+
+// export function to์์ฌ์๋ฆฌ(letter: string): string;
+// export function to๊ฑฐ์ผ์๋ฆฌ(letter: string): string;
+// export function to๋์๋ฆฌ(letter: string): string;
+
+// export function canBe์ด์ฑ(letter: string): boolean;
+// export function canBe์ค์ฑ(letter: string): boolean;
+// export function canBe์ข
์ฑ(letter: string): boolean;
+
+// export function has๋ฐ์นจ();
+// ...
\ No newline at end of file
diff --git a/src/index.ts b/src/index.ts
index f01c1c2..a481391 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,8 +1 @@
-const bot = BotManager.getCurrentBot();
-
-bot.addListener(Event.MESSAGE, msg => {
- if (msg.content === '/ping')
- msg.reply('pong!');
- else if (msg.content === '/hello')
- msg.reply(`Hello, ${msg.author.name}!`);
-});
\ No newline at end of file
+export * from './josa';
\ No newline at end of file
diff --git a/src/josa.test.ts b/src/josa.test.ts
new file mode 100644
index 0000000..56573d6
--- /dev/null
+++ b/src/josa.test.ts
@@ -0,0 +1,233 @@
+import { describe, test, expect } from 'vitest';
+
+import { get์กฐ์ฌ, apply์กฐ์ฌ } from './josa';
+import './josa';
+
+describe('josa', () => {
+ test('์ฃผ๊ฒฉ์กฐ์ฌ', () => {
+ expect(apply์กฐ์ฌ('์ดํธ', '์ด/๊ฐ')).toBe('์ดํธ๊ฐ');
+ expect('์ดํธ'.์ด๊ฐ).toBe('์ดํธ๊ฐ');
+ expect('์ดํธ'.์ด).toBe('์ดํธ๊ฐ');
+ expect('์ดํธ'.๊ฐ).toBe('์ดํธ๊ฐ');
+ expect(apply์กฐ์ฌ('์นซ์', '์ด/๊ฐ')).toBe('์นซ์์ด');
+ expect('์นซ์'.์ด๊ฐ).toBe('์นซ์์ด');
+ expect('์นซ์'.์ด).toBe('์นซ์์ด');
+ expect('์นซ์'.๊ฐ).toBe('์นซ์์ด');
+ });
+ test('๋ชฉ์ ๊ฒฉ์กฐ์ฌ', () => {
+ expect(apply์กฐ์ฌ('์ดํธ', '์/๋ฅผ')).toBe('์ดํธ๋ฅผ');
+ expect('์ดํธ'.์๋ฅผ).toBe('์ดํธ๋ฅผ');
+ expect('์ดํธ'.์).toBe('์ดํธ๋ฅผ');
+ expect('์ดํธ'.๋ฅผ).toBe('์ดํธ๋ฅผ');
+ expect(apply์กฐ์ฌ('์นซ์', '์/๋ฅผ')).toBe('์นซ์์');
+ expect('์นซ์'.์๋ฅผ).toBe('์นซ์์');
+ expect('์นซ์'.์).toBe('์นซ์์');
+ expect('์นซ์'.๋ฅผ).toBe('์นซ์์');
+ });
+ test('๋์กฐ์ ๋ณด์กฐ์ฌ', () => {
+ expect(apply์กฐ์ฌ('์ดํธ', '์/๋')).toBe('์ดํธ๋');
+ expect('์ดํธ'.์๋).toBe('์ดํธ๋');
+ expect('์ดํธ'.์).toBe('์ดํธ๋');
+ expect('์ดํธ'.๋).toBe('์ดํธ๋');
+ expect(apply์กฐ์ฌ('์นซ์', '์/๋')).toBe('์นซ์์');
+ expect('์นซ์'.์๋).toBe('์นซ์์');
+ expect('์นซ์'.์).toBe('์นซ์์');
+ expect('์นซ์'.๋).toBe('์นซ์์');
+ });
+ test('๋ฐฉํฅ์ ๊ฒฉ์กฐ์ฌ', () => {
+ expect(apply์กฐ์ฌ('๋ฐ๊นฅ', '์ผ๋ก/๋ก')).toBe('๋ฐ๊นฅ์ผ๋ก');
+ expect('๋ฐ๊นฅ'.์ผ๋ก).toBe('๋ฐ๊นฅ์ผ๋ก');
+ expect('๋ฐ๊นฅ'.๋ก).toBe('๋ฐ๊นฅ์ผ๋ก');
+ expect(apply์กฐ์ฌ('๋ด๋ถ', '์ผ๋ก/๋ก')).toBe('๋ด๋ถ๋ก');
+ expect('๋ด๋ถ'.์ผ๋ก).toBe('๋ด๋ถ๋ก');
+ expect('๋ด๋ถ'.๋ก).toBe('๋ด๋ถ๋ก');
+ });
+ test('๋ฐฉํฅ์ ๊ฒฉ์กฐ์ฌ ใน ๋ฐ์นจ ์์ธ ์ฒ๋ฆฌ', () => {
+ expect(apply์กฐ์ฌ('์ง๋ฆ๊ธธ', '์ผ๋ก/๋ก')).toBe('์ง๋ฆ๊ธธ๋ก');
+ expect('์ง๋ฆ๊ธธ'.์ผ๋ก).toBe('์ง๋ฆ๊ธธ๋ก');
+ expect('์ง๋ฆ๊ธธ'.๋ก).toBe('์ง๋ฆ๊ธธ๋ก');
+ });
+ test('๋น๊ต์ ๊ฒฉ์กฐ์ฌ', () => {
+ expect(apply์กฐ์ฌ('์ดํธ', '์/๊ณผ')).toBe('์ดํธ์');
+ expect('์ดํธ'.์๊ณผ).toBe('์ดํธ์');
+ expect('์ดํธ'.์).toBe('์ดํธ์');
+ expect('์ดํธ'.๊ณผ).toBe('์ดํธ์');
+ expect(apply์กฐ์ฌ('์นซ์', '์/๊ณผ')).toBe('์นซ์๊ณผ');
+ expect('์นซ์'.์๊ณผ).toBe('์นซ์๊ณผ');
+ expect('์นซ์'.์).toBe('์นซ์๊ณผ');
+ expect('์นซ์'.๊ณผ).toBe('์นซ์๊ณผ');
+ });
+ test('์ ํ์ ๋ณด์กฐ์ฌ', () => {
+ expect(apply์กฐ์ฌ('์ดํธ', '์ด๋/๋')).toBe('์ดํธ๋');
+ expect('์ดํธ'.์ด๋).toBe('์ดํธ๋');
+ expect('์ดํธ'.๋).toBe('์ดํธ๋');
+ expect(apply์กฐ์ฌ('์นซ์', '์ด๋/๋')).toBe('์นซ์์ด๋');
+ expect('์นซ์'.์ด๋).toBe('์นซ์์ด๋');
+ expect('์นซ์'.๋).toBe('์นซ์์ด๋');
+ });
+ test('ํ์ ์ ๋ณด์กฐ์ฌ', () => {
+ expect(apply์กฐ์ฌ('์ดํธ', '์ด๋/๋')).toBe('์ดํธ๋');
+ expect('์ดํธ'.์ด๋).toBe('์ดํธ๋');
+ expect('์ดํธ'.๋).toBe('์ดํธ๋');
+ expect(apply์กฐ์ฌ('์นซ์', '์ด๋/๋')).toBe('์นซ์์ด๋');
+ expect('์นซ์'.์ด๋).toBe('์นซ์์ด๋');
+ expect('์นซ์'.๋).toBe('์นซ์์ด๋');
+ });
+ test('ํธ๊ฒฉ์กฐ์ฌ', () => {
+ expect(apply์กฐ์ฌ('์ฒ ์', '์/์ผ')).toBe('์ฒ ์์ผ');
+ expect('์ฒ ์'.์์ผ).toBe('์ฒ ์์ผ');
+ expect('์ฒ ์'.์).toBe('์ฒ ์์ผ');
+ expect('์ฒ ์'.์ผ).toBe('์ฒ ์์ผ');
+ expect(apply์กฐ์ฌ('๊ธธ๋', '์/์ผ')).toBe('๊ธธ๋์');
+ expect('๊ธธ๋'.์์ผ).toBe('๊ธธ๋์');
+ expect('๊ธธ๋'.์).toBe('๊ธธ๋์');
+ expect('๊ธธ๋'.์ผ).toBe('๊ธธ๋์');
+ });
+ test('์ ์์กฐ์ฌ', () => {
+ expect(apply์กฐ์ฌ('๊ณ ๊ธฐ', '์ด๋/๋')).toBe('๊ณ ๊ธฐ๋');
+ expect('๊ณ ๊ธฐ'.์ด๋).toBe('๊ณ ๊ธฐ๋');
+ expect('๊ณ ๊ธฐ'.๋).toBe('๊ณ ๊ธฐ๋');
+ expect(apply์กฐ์ฌ('๊ณผ์ผ', '์ด๋/๋')).toBe('๊ณผ์ผ์ด๋');
+ expect('๊ณผ์ผ'.์ด๋).toBe('๊ณผ์ผ์ด๋');
+ expect('๊ณผ์ผ'.๋).toBe('๊ณผ์ผ์ด๋');
+ });
+ test('์ฃผ์ ์ ๋ณด์กฐ์ฌ', () => {
+ expect(apply์กฐ์ฌ('์์ฌ', '์ด๋ผ/๋ผ')).toBe('์์ฌ๋ผ');
+ expect('์์ฌ'.์ด๋ผ).toBe('์์ฌ๋ผ');
+ expect('์์ฌ'.๋ผ).toBe('์์ฌ๋ผ');
+ expect(apply์กฐ์ฌ('์ ์๋', '์ด๋ผ/๋ผ')).toBe('์ ์๋์ด๋ผ');
+ expect('์ ์๋'.์ด๋ผ).toBe('์ ์๋์ด๋ผ');
+ expect('์ ์๋'.๋ผ).toBe('์ ์๋์ด๋ผ');
+ });
+ test('์์ ๊ฒฉ์กฐ์ฌ์ ์ข
๊ฒฐ์ด๋ฏธ', () => {
+ expect(apply์กฐ์ฌ('์ฌ๊ณผ', '์ด์์/์์')).toBe('์ฌ๊ณผ์์');
+ expect('์ฌ๊ณผ'.์ด์์).toBe('์ฌ๊ณผ์์');
+ expect('์ฌ๊ณผ'.์์).toBe('์ฌ๊ณผ์์');
+ expect(apply์กฐ์ฌ('์ฑ
', '์ด์์/์์')).toBe('์ฑ
์ด์์');
+ expect('์ฑ
'.์ด์์).toBe('์ฑ
์ด์์');
+ expect('์ฑ
'.์์).toBe('์ฑ
์ด์์');
+ });
+ test('์์ ๊ฒฉ์กฐ์ฌ์ ์ข
๊ฒฐ์ด๋ฏธ, "์ด" ๋ก ๋๋๋ ๋จ์ด ์์ธ ์ฒ๋ฆฌ', () => {
+ expect(apply์กฐ์ฌ('๋๋ฐ์ด', '์ด์์/์์')).toBe('๋๋ฐ์ด์์');
+ expect('๋๋ฐ์ด'.์ด์์).toBe('๋๋ฐ์ด์์');
+ expect('๋๋ฐ์ด'.์์).toBe('๋๋ฐ์ด์์');
+ });
+ test('์ง์๋ ์ ๋ถ ๋๋ ์๊ฒฉ์ ๋ํ๋ด๋ ์๊ฒฉ์กฐ์ฌ', () => {
+ expect(apply์กฐ์ฌ('ํ์', '์ผ๋ก์/๋ก์')).toBe('ํ์์ผ๋ก์');
+ expect('ํ์'.์ผ๋ก์).toBe('ํ์์ผ๋ก์');
+ expect('ํ์'.๋ก์).toBe('ํ์์ผ๋ก์');
+ expect(apply์กฐ์ฌ('๋ถ๋ชจ', '์ผ๋ก์/๋ก์')).toBe('๋ถ๋ชจ๋ก์');
+ expect('๋ถ๋ชจ'.์ผ๋ก์).toBe('๋ถ๋ชจ๋ก์');
+ expect('๋ถ๋ชจ'.๋ก์).toBe('๋ถ๋ชจ๋ก์');
+ });
+ test('์ง์๋ ์ ๋ถ ๋๋ ์๊ฒฉ์ ๋ํ๋ด๋ ์๊ฒฉ์กฐ์ฌ ใน ๋ฐ์นจ ์์ธ ์ฒ๋ฆฌ', () => {
+ expect(apply์กฐ์ฌ('๋ผ์ด๋ฒ', '์ผ๋ก์/๋ก์')).toBe('๋ผ์ด๋ฒ๋ก์');
+ expect('๋ผ์ด๋ฒ'.์ผ๋ก์).toBe('๋ผ์ด๋ฒ๋ก์');
+ expect('๋ผ์ด๋ฒ'.๋ก์).toBe('๋ผ์ด๋ฒ๋ก์');
+ });
+ test('์๋จ์ ์๋ฏธ๋ฅผ ๋ํ๋ด๋ ๋๊ตฌ๊ฒฉ์กฐ์ฌ', () => {
+ expect(apply์กฐ์ฌ('ํ ํฐ', '์ผ๋ก์จ/๋ก์จ')).toBe('ํ ํฐ์ผ๋ก์จ');
+ expect('ํ ํฐ'.์ผ๋ก์จ).toBe('ํ ํฐ์ผ๋ก์จ');
+ expect('ํ ํฐ'.๋ก์จ).toBe('ํ ํฐ์ผ๋ก์จ');
+ expect(apply์กฐ์ฌ('ํจ์', '์ผ๋ก์จ/๋ก์จ')).toBe('ํจ์๋ก์จ');
+ expect('ํจ์'.์ผ๋ก์จ).toBe('ํจ์๋ก์จ');
+ expect('ํจ์'.๋ก์จ).toBe('ํจ์๋ก์จ');
+ });
+ test('์๋จ์ ์๋ฏธ๋ฅผ ๋ํ๋ด๋ ๋๊ตฌ๊ฒฉ์กฐ์ฌ ใน ๋ฐ์นจ ์์ธ ์ฒ๋ฆฌ', () => {
+ expect(apply์กฐ์ฌ('๊ฑด๋ฌผ', '์ผ๋ก์จ/๋ก์จ')).toBe('๊ฑด๋ฌผ๋ก์จ');
+ expect('๊ฑด๋ฌผ'.์ผ๋ก์จ).toBe('๊ฑด๋ฌผ๋ก์จ');
+ expect('๊ฑด๋ฌผ'.๋ก์จ).toBe('๊ฑด๋ฌผ๋ก์จ');
+ });
+ test('์ด๋ค ํ๋์ ์ถ๋ฐ์ ์ด๋ ๋น๋กฏ๋๋ ๋์์์ ๋ํ๋ด๋ ๊ฒฉ ์กฐ์ฌ', () => {
+ expect(apply์กฐ์ฌ('์ญ์ผ๋', '์ผ๋ก๋ถํฐ/๋ก๋ถํฐ')).toBe('์ญ์ผ๋์ผ๋ก๋ถํฐ');
+ expect('์ญ์ผ๋'.์ผ๋ก๋ถํฐ).toBe('์ญ์ผ๋์ผ๋ก๋ถํฐ');
+ expect('์ญ์ผ๋'.๋ก๋ถํฐ).toBe('์ญ์ผ๋์ผ๋ก๋ถํฐ');
+ expect(apply์กฐ์ฌ('์ ๊ธฐ', '์ผ๋ก๋ถํฐ/๋ก๋ถํฐ')).toBe('์ ๊ธฐ๋ก๋ถํฐ');
+ expect('์ ๊ธฐ'.์ผ๋ก๋ถํฐ).toBe('์ ๊ธฐ๋ก๋ถํฐ');
+ expect('์ ๊ธฐ'.๋ก๋ถํฐ).toBe('์ ๊ธฐ๋ก๋ถํฐ');
+ });
+ test('์ด๋ค ํ๋์ ์ถ๋ฐ์ ์ด๋ ๋น๋กฏ๋๋ ๋์์์ ๋ํ๋ด๋ ๊ฒฉ ์กฐ์ฌ ใน ๋ฐ์นจ ์์ธ ์ฒ๋ฆฌ', () => {
+ expect(apply์กฐ์ฌ('๋๊ตด', '์ผ๋ก๋ถํฐ/๋ก๋ถํฐ')).toBe('๋๊ตด๋ก๋ถํฐ');
+ expect('๋๊ตด'.์ผ๋ก๋ถํฐ).toBe('๋๊ตด๋ก๋ถํฐ');
+ expect('๋๊ตด'.๋ก๋ถํฐ).toBe('๋๊ตด๋ก๋ถํฐ');
+ });
+ test('๋จ์ด๊ฐ ๋น ๋ฌธ์์ด์ผ ๊ฒฝ์ฐ ๋น ๋ฌธ์์ด์ ๋ฐํํ๋ค.', () => {
+ expect(apply์กฐ์ฌ('', '์ด/๊ฐ')).toBe('');
+ expect(''.์ด๊ฐ).toBe('');
+ expect(''.์ด).toBe('');
+ expect(''.๊ฐ).toBe('');
+ });
+});
+
+describe('josa.pick', () => {
+ test('์ฒซ ๋ฒ์งธ ๋งค๊ฐ๋ณ์๊ฐ ๋น ๋ฌธ์์ด์ด๋ผ๋ฉด ์ต์
์ค ์ฒซ ๋ฒ์งธ ๊ฐ์ ๋ฐํํ๋ค.', () => {
+ expect(get์กฐ์ฌ('', '์ด/๊ฐ')).toBe('์ด');
+ });
+ test('์ฃผ๊ฒฉ์กฐ์ฌ', () => {
+ expect(get์กฐ์ฌ('์ดํธ', '์ด/๊ฐ')).toBe('๊ฐ');
+ expect(get์กฐ์ฌ('์นซ์', '์ด/๊ฐ')).toBe('์ด');
+ });
+ test('๋ชฉ์ ๊ฒฉ์กฐ์ฌ', () => {
+ expect(get์กฐ์ฌ('์ดํธ', '์/๋ฅผ')).toBe('๋ฅผ');
+ expect(get์กฐ์ฌ('์นซ์', '์/๋ฅผ')).toBe('์');
+ });
+ test('๋์กฐ์ ๋ณด์กฐ์ฌ', () => {
+ expect(get์กฐ์ฌ('์ดํธ', '์/๋')).toBe('๋');
+ expect(get์กฐ์ฌ('์นซ์', '์/๋')).toBe('์');
+ });
+ test('๋ฐฉํฅ์ ๊ฒฉ์กฐ์ฌ', () => {
+ expect(get์กฐ์ฌ('๋ฐ๊นฅ', '์ผ๋ก/๋ก')).toBe('์ผ๋ก');
+ expect(get์กฐ์ฌ('๋ด๋ถ', '์ผ๋ก/๋ก')).toBe('๋ก');
+ });
+ test('๋ฐฉํฅ์ ๊ฒฉ์กฐ์ฌ ใน ๋ฐ์นจ ์์ธ ์ฒ๋ฆฌ', () => {
+ expect(get์กฐ์ฌ('์ง๋ฆ๊ธธ', '์ผ๋ก/๋ก')).toBe('๋ก');
+ });
+ test('๋น๊ต์ ๊ฒฉ์กฐ์ฌ', () => {
+ expect(get์กฐ์ฌ('์ดํธ', '์/๊ณผ')).toBe('์');
+ expect(get์กฐ์ฌ('์นซ์', '์/๊ณผ')).toBe('๊ณผ');
+ });
+ test('์ ํ์ ๋ณด์กฐ์ฌ', () => {
+ expect(get์กฐ์ฌ('์ดํธ', '์ด๋/๋')).toBe('๋');
+ expect(get์กฐ์ฌ('์นซ์', '์ด๋/๋')).toBe('์ด๋');
+ });
+ test('ํ์ ์ ๋ณด์กฐ์ฌ', () => {
+ expect(get์กฐ์ฌ('์ดํธ', '์ด๋/๋')).toBe('๋');
+ expect(get์กฐ์ฌ('์นซ์', '์ด๋/๋')).toBe('์ด๋');
+ });
+ test('ํธ๊ฒฉ์กฐ์ฌ', () => {
+ expect(get์กฐ์ฌ('์ฒ ์', '์/์ผ')).toBe('์ผ');
+ expect(get์กฐ์ฌ('๊ธธ๋', '์/์ผ')).toBe('์');
+ });
+ test('์ ์์กฐ์ฌ', () => {
+ expect(get์กฐ์ฌ('๊ณ ๊ธฐ', '์ด๋/๋')).toBe('๋');
+ expect(get์กฐ์ฌ('๊ณผ์ผ', '์ด๋/๋')).toBe('์ด๋');
+ });
+ test('์์ ๊ฒฉ์กฐ์ฌ์ ์ข
๊ฒฐ์ด๋ฏธ', () => {
+ expect(get์กฐ์ฌ('์ฌ๊ณผ', '์ด์์/์์')).toBe('์์');
+ expect(get์กฐ์ฌ('์ฑ
', '์ด์์/์์')).toBe('์ด์์');
+ });
+ test('์์ ๊ฒฉ์กฐ์ฌ์ ์ข
๊ฒฐ์ด๋ฏธ, "์ด" ๋ก ๋๋๋ ๋จ์ด ์์ธ ์ฒ๋ฆฌ', () => {
+ expect(get์กฐ์ฌ('๋๋ฐ์ด', '์ด์์/์์')).toBe('์์');
+ });
+ test('์ง์๋ ์ ๋ถ ๋๋ ์๊ฒฉ์ ๋ํ๋ด๋ ์๊ฒฉ์กฐ์ฌ', () => {
+ expect(get์กฐ์ฌ('ํ์', '์ผ๋ก์/๋ก์')).toBe('์ผ๋ก์');
+ expect(get์กฐ์ฌ('๋ถ๋ชจ', '์ผ๋ก์/๋ก์')).toBe('๋ก์');
+ });
+ test('์ง์๋ ์ ๋ถ ๋๋ ์๊ฒฉ์ ๋ํ๋ด๋ ์๊ฒฉ์กฐ์ฌ ใน ๋ฐ์นจ ์์ธ ์ฒ๋ฆฌ', () => {
+ expect(get์กฐ์ฌ('๋ผ์ด๋ฒ', '์ผ๋ก์/๋ก์')).toBe('๋ก์');
+ });
+ test('์๋จ์ ์๋ฏธ๋ฅผ ๋ํ๋ด๋ ๋๊ตฌ๊ฒฉ์กฐ์ฌ', () => {
+ expect(get์กฐ์ฌ('ํ ํฐ', '์ผ๋ก์จ/๋ก์จ')).toBe('์ผ๋ก์จ');
+ expect(get์กฐ์ฌ('ํจ์', '์ผ๋ก์จ/๋ก์จ')).toBe('๋ก์จ');
+ });
+ test('์๋จ์ ์๋ฏธ๋ฅผ ๋ํ๋ด๋ ๋๊ตฌ๊ฒฉ์กฐ์ฌ ใน ๋ฐ์นจ ์์ธ ์ฒ๋ฆฌ', () => {
+ expect(get์กฐ์ฌ('๊ฑด๋ฌผ', '์ผ๋ก์จ/๋ก์จ')).toBe('๋ก์จ');
+ });
+ test('์ด๋ค ํ๋์ ์ถ๋ฐ์ ์ด๋ ๋น๋กฏ๋๋ ๋์์์ ๋ํ๋ด๋ ๊ฒฉ ์กฐ์ฌ', () => {
+ expect(get์กฐ์ฌ('์ญ์ผ๋', '์ผ๋ก๋ถํฐ/๋ก๋ถํฐ')).toBe('์ผ๋ก๋ถํฐ');
+ expect(get์กฐ์ฌ('์ ๊ธฐ', '์ผ๋ก๋ถํฐ/๋ก๋ถํฐ')).toBe('๋ก๋ถํฐ');
+ });
+ test('์ด๋ค ํ๋์ ์ถ๋ฐ์ ์ด๋ ๋น๋กฏ๋๋ ๋์์์ ๋ํ๋ด๋ ๊ฒฉ ์กฐ์ฌ ใน ๋ฐ์นจ ์์ธ ์ฒ๋ฆฌ', () => {
+ expect(get์กฐ์ฌ('๋๊ตด', '์ผ๋ก๋ถํฐ/๋ก๋ถํฐ')).toBe('๋ก๋ถํฐ');
+ });
+});
\ No newline at end of file
diff --git a/src/josa.ts b/src/josa.ts
new file mode 100644
index 0000000..9eb57a8
--- /dev/null
+++ b/src/josa.ts
@@ -0,0 +1,117 @@
+type Josa =
+ | '์ด/๊ฐ'
+ | '์/๋ฅผ'
+ | '์/๋'
+ | '์ผ๋ก/๋ก'
+ | '์/๊ณผ'
+ | '์ด๋/๋'
+ | '์ด๋/๋'
+ | '์/์ผ'
+ | '์ด๋/๋'
+ | '์ด์์/์์'
+ | '์ผ๋ก์/๋ก์'
+ | '์ผ๋ก์จ/๋ก์จ'
+ | '์ผ๋ก๋ถํฐ/๋ก๋ถํฐ'
+ | '์ด๋ผ/๋ผ';
+
+const ๋กjosa: Josa[] = ['์ผ๋ก/๋ก', '์ผ๋ก์/๋ก์', '์ผ๋ก์จ/๋ก์จ', '์ผ๋ก๋ถํฐ/๋ก๋ถํฐ'];
+
+export function has๋ฐ์นจ(text: string) {
+ return (text.charCodeAt(text.length - 1) - '๊ฐ'.charCodeAt(0)) % 28 > 0;
+}
+
+export function get์ข
์ฑ(text: string): string | null {
+ const unicode = text.charCodeAt(text.length - 1) - '๊ฐ'.charCodeAt(0);
+ const ์ข
์ฑ = unicode % 28;
+ return ์ข
์ฑ > 0 ? String.fromCharCode(0x11a7 + ์ข
์ฑ) : null;
+}
+
+export function get์กฐ์ฌ(text: string, josa: Josa): string {
+ let [josa1, josa2] = josa.split('/');
+
+ if (text.length === 0)
+ return josa1;
+
+ if (josa === '์/๊ณผ' || (has๋ฐ์นจ(text) && ๋กjosa.includes(josa) && get์ข
์ฑ(text) === 'แฏ'))
+ return has๋ฐ์นจ(text) ? josa2 : josa1;
+
+ if (josa === '์ด์์/์์' && text[text.length - 1] === '์ด')
+ return josa2;
+
+ return has๋ฐ์นจ(text) ? josa1 : josa2;
+}
+
+// TODO: ์กฐ์ฌ ๋ค์ ๊ณต๋ฐฑ ์๋ ์ฝ์
?
+// console.log('๋ญ'.์ด๊ฐ + ' ๊ผฌ๊ผฌ๋ ์ธ๊ณ , ์ค๋ฆฌ'.๊ฐ + ' ๊ฝฅ๊ฝฅ ์ด๋ค.'); ์ฌ๊ธฐ์ ๊ณต๋ฐฑ ๋๋ฌธ์ ์๋ป์ง์ง ์ ใ
ํค์, ์ด์ฐจํผ ์กฐ์ฌ ๋ค์ ๊ณต๋ฐฑ์ ๋ฌด์กฐ๊ฑด ์ฌํ
๋ฐ
+
+export function apply์กฐ์ฌ(text: string, josa: Josa) {
+ if (text.length === 0)
+ return text;
+
+ return text + get์กฐ์ฌ(text, josa);
+}
+
+function add์กฐ์ฌMethod(josa: Josa) {
+ const [josa1, josa2] = josa.split('/');
+
+ const keys = [josa1, josa2];
+ if (!josa1.includes(josa2))
+ keys.push(josa1 + josa2);
+
+ keys.forEach(key => Object.defineProperty(String.prototype, key, {
+ get() { return apply์กฐ์ฌ(this, josa); }
+ }));
+}
+
+add์กฐ์ฌMethod('์ด/๊ฐ');
+add์กฐ์ฌMethod('์/๋ฅผ');
+add์กฐ์ฌMethod('์/๋');
+add์กฐ์ฌMethod('์ผ๋ก/๋ก');
+add์กฐ์ฌMethod('์/๊ณผ');
+add์กฐ์ฌMethod('์ด๋/๋');
+add์กฐ์ฌMethod('์ด๋/๋');
+add์กฐ์ฌMethod('์/์ผ');
+add์กฐ์ฌMethod('์ด๋/๋');
+add์กฐ์ฌMethod('์ด์์/์์');
+add์กฐ์ฌMethod('์ผ๋ก์/๋ก์');
+add์กฐ์ฌMethod('์ผ๋ก์จ/๋ก์จ');
+add์กฐ์ฌMethod('์ผ๋ก๋ถํฐ/๋ก๋ถํฐ');
+add์กฐ์ฌMethod('์ด๋ผ/๋ผ');
+
+declare global {
+ interface String {
+ ์ด: string;
+ ๊ฐ: string;
+ ์ด๊ฐ: string;
+ ์: string;
+ ๋ฅผ: string;
+ ์๋ฅผ: string;
+ ์: string;
+ ๋: string;
+ ์๋: string;
+ ์ผ๋ก: string;
+ ๋ก: string;
+ ์: string;
+ ๊ณผ: string;
+ ์๊ณผ: string;
+ ์ด๋: string;
+ ๋: string;
+ ์ด๋: string;
+ ๋: string;
+ ์: string;
+ ์ผ: string;
+ ์์ผ: string;
+ ์ด๋: string;
+ ๋: string;
+ ์ด์์: string;
+ ์์: string;
+ ์ผ๋ก์: string;
+ ๋ก์: string;
+ ์ผ๋ก์จ: string;
+ ๋ก์จ: string;
+ ์ผ๋ก๋ถํฐ: string;
+ ๋ก๋ถํฐ: string;
+ ์ด๋ผ: string;
+ ๋ผ: string;
+ }
+}
\ No newline at end of file
diff --git a/tests/generate_hangul.ts b/tests/generate_hangul.ts
new file mode 100644
index 0000000..a370f01
--- /dev/null
+++ b/tests/generate_hangul.ts
@@ -0,0 +1,11 @@
+function randomInt(min: number, max: number) {
+ return Math.floor(Math.random() * (max - min + 1)) + min;
+}
+
+function makeAnyHangulText(): string {
+ const len = randomInt(1, 100);
+ return Array(len).fill(0).map(() => String.fromCharCode(randomInt('๊ฐ'.charCodeAt(0), 'ํฃ'.charCodeAt(0)))).join('');
+}
+
+const hangulTexts = Array(1000).fill(0).map(() => makeAnyHangulText());
+console.log(hangulTexts);
diff --git a/tests/ishangul_bench.ts b/tests/ishangul_bench.ts
new file mode 100644
index 0000000..95d1ca4
--- /dev/null
+++ b/tests/ishangul_bench.ts
@@ -0,0 +1,24 @@
+import { _isHangul, isHangul } from "../src/hangul";
+
+function randomInt(min: number, max: number) {
+ return Math.floor(Math.random() * (max - min + 1)) + min;
+}
+
+function makeAnyHangulText(): string {
+ const len = randomInt(1, 100);
+ return Array(len).fill(0).map(() => String.fromCharCode(randomInt('๊ฐ'.charCodeAt(0), 'ํฃ'.charCodeAt(0)))).join('');
+}
+
+const hangulTexts = Array(1000).fill(0).map(() => makeAnyHangulText());
+
+console.time('isHangul');
+for (const text of hangulTexts) {
+ _isHangul(text);
+}
+console.timeEnd('isHangul'); // 5.654ms
+
+console.time('isHangul2');
+for (const text of hangulTexts) {
+ isHangul(text);
+}
+console.timeEnd('isHangul2'); // 0.612ms
\ No newline at end of file