diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..4fc266a --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,60 @@ +name: Build + +on: + workflow_dispatch: + push: + branches: [main, dev, dev-*] + pull_request: + branches: [main] + release: + types: [created] + +jobs: + build: + name: ${{ github.event_name == 'release' && 'Publish to NPM' || (github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.repository == 'nk2028/tshet-uinh-examples' && github.ref == 'refs/heads/main')) && 'Publish to Tencent Cloud COS' || 'Test' }} + runs-on: ubuntu-latest + steps: + - name: Checkout latest code + uses: actions/checkout@v4 + + # Build + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + - name: Build + run: python build.py > index.js + + # Test + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + registry-url: https://registry.npmjs.org/ + - name: Install Node.js dependencies + run: npm ci + - name: Lint + run: npm run lint + - name: Run tests + run: npm test + + # Publish to NPM + - if: github.event_name == 'release' + name: Publish to NPM + run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.npm_token }} + + # Publish to Tencent Cloud COS + - if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.repository == 'nk2028/tshet-uinh-examples' && github.ref == 'refs/heads/main') + name: Install coscmd + run: sudo pip install coscmd + - if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.repository == 'nk2028/tshet-uinh-examples' && github.ref == 'refs/heads/main') + name: Configure coscmd + env: + SECRET_ID: ${{ secrets.SecretId }} + SECRET_KEY: ${{ secrets.SecretKey }} + run: coscmd config -a $SECRET_ID -s $SECRET_KEY -b nk2028-1305783649 -r ap-guangzhou + - if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.repository == 'nk2028/tshet-uinh-examples' && github.ref == 'refs/heads/main') + name: Publish static files to COS + run: coscmd upload -rs --delete -f . /tshet-uinh-examples --ignore '*/.*,*/node_modules/*,./test/*,./build.py,./package.json,./package-lock.json' diff --git a/.github/workflows/publish-cos.yml b/.github/workflows/publish-cos.yml deleted file mode 100644 index 5ee500a..0000000 --- a/.github/workflows/publish-cos.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: Publish to Tencent Cloud COS - -on: - workflow_dispatch: - push: - branches: - - main - -jobs: - deploy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - # Build - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: '3.12' - - name: Build - run: python build.py > index.js - - # Test - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '22' - registry-url: https://registry.npmjs.org/ - - name: Install Node.js dependencies - run: npm ci - - name: Run tests - run: npm test - - # Publish - - name: Install coscmd - run: sudo pip install coscmd - - name: Configure coscmd - env: - SECRET_ID: ${{ secrets.SecretId }} - SECRET_KEY: ${{ secrets.SecretKey }} - run: coscmd config -a $SECRET_ID -s $SECRET_KEY -b nk2028-1305783649 -r ap-guangzhou - - name: Publish static files to COS - run: coscmd upload -rs --delete -f . /tshet-uinh-examples --ignore '*/.*,*/node_modules/*,./test/*,./build.py,./package.json,./package-lock.json' diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml deleted file mode 100644 index c8307e3..0000000 --- a/.github/workflows/publish-npm.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Publish to NPM - -on: - release: - types: [created] - -jobs: - publish-npm: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - # Build - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: '3.12' - - name: Build - run: python build.py > index.js - - # Test - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '22' - registry-url: https://registry.npmjs.org/ - - name: Install Node.js dependencies - run: npm ci - - name: Run tests - run: npm test - - # Publish - - name: Publish - run: npm publish - env: - NODE_AUTH_TOKEN: ${{secrets.npm_token}} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 34c42e5..0000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Test - -on: - push: - branches: - - main - - dev - - dev-* - pull_request: - branches: [main] - -jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - # Build - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: '3.12' - - name: Build - run: python build.py > index.js - - # Test - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '22' - registry-url: https://registry.npmjs.org/ - - name: Install Node.js dependencies - run: npm ci - - name: Run tests - run: npm test diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 9511341..a584819 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,3 +1,3 @@ { - "recommendations": ["esbenp.prettier-vscode", "ms-python.python"] + "recommendations": ["ms-python.python"] } diff --git a/ayaka_v8.js b/ayaka_v8.js index 5f52190..23a2d83 100644 --- a/ayaka_v8.js +++ b/ayaka_v8.js @@ -5,6 +5,11 @@ * @author Ayaka */ +/** @type { 音韻地位['屬於'] } */ +const is = (...x) => 音韻地位.屬於(...x); +/** @type { 音韻地位['判斷'] } */ +const when = (...x) => 音韻地位.判斷(...x); + // 1. 選項 if (!音韻地位) return [ @@ -21,7 +26,7 @@ if (!音韻地位) return [ description: ['true: 迥 ク𛅥ィ', 'false: 迥 クヱィ', '僅當開啓假名時生效'].join('\n'), }], - ['音變', [1, {value: null, text: '無'}, '現代日語'], { + ['音變', [1, { value: null, text: '無' }, '現代日語'], { description: [ "'無': 宙 チウ tiu;南 ダム dam;愁 スウ suu", "'現代日語': 宙 チュウ tyuu;南 ダン dan;愁 スウ suu", @@ -29,13 +34,13 @@ if (!音韻地位) return [ }], // 參考:尉遲治平. 日本悉曇家所傳古漢語調值. - ['聲調', [1, {value: null, text: '無'}, '四聲', '四聲(數字)', '四聲(調值)', '六聲(調值)', '六聲(符號)', '八聲', '八聲(數字)', '八聲(調值)']], + ['聲調', [1, { value: null, text: '無' }, '四聲', '四聲(數字)', '四聲(調值)', '六聲(調值)', '六聲(符號)', '八聲', '八聲(數字)', '八聲(調值)']], ]; // 2. 輔助函數 const 假名表 = { - a: 'ア', i: 'イ', u: 'ウ', e: 'エ', o: 'オ', + a: 'ア', i: 'イ', u: 'ウ', e: 'エ', o: 'オ', ka: 'カ', ki: 'キ', ku: 'ク', ke: 'ケ', ko: 'コ', ga: 'ガ', gi: 'ギ', gu: 'グ', ge: 'ゲ', go: 'ゴ', sa: 'サ', si: 'シ', su: 'ス', se: 'セ', so: 'ソ', @@ -58,15 +63,15 @@ const 拗音表 = { }; const 韻尾表 = { - '': '', i: 'イ', u: 'ウ', - m: 'ム', n: 'ン', ng: 'ゥ', // ng: 'ィ', - p: 'フ', t: 'ツ', k: 'ク', // k: 'キ', + '': '', 'i': 'イ', 'u': 'ウ', + 'm': 'ム', 'n': 'ン', 'ng': 'ゥ', // ng: 'ィ', + 'p': 'フ', 't': 'ツ', 'k': 'ク', // k: 'キ', }; function roma2kata(s) { const r = /^([kgsztdnpbmyrw]?w??[yw]?)([aiueo])([ptkmngiu]*)$/g; // 將音節分為韻頭、主要元音及韻尾 const match = r.exec(s); - if (match == null) { + if (match === null) { throw new Error('無法轉換為假名:' + s); } const { 1: 韻頭, 2: 主要元音, 3: 韻尾 } = match; @@ -84,7 +89,7 @@ function roma2kata(s) { function kata2hira(s) { const diff = 'ぁ'.charCodeAt(0) - 'ァ'.charCodeAt(0); - return [...s].map((c) => ({ + return [...s].map(c => ({ '𛅤': '𛅐', '𛅥': '𛅑', '𛅦': '𛅒', @@ -92,7 +97,7 @@ function kata2hira(s) { } function small2large(s) { - return [...s].map((c) => ({ + return [...s].map(c => ({ '𛅤': 'ヰ', '𛅥': 'ヱ', '𛅦': 'ヲ', @@ -101,11 +106,6 @@ function small2large(s) { // 3. 推導規則 -/** @type { 音韻地位["屬於"] } */ -const is = (...x) => 音韻地位.屬於(...x); -/** @type { 音韻地位["判斷"] } */ -const when = (...x) => 音韻地位.判斷(...x); - function 聲母規則() { return when([ // 脣音 @@ -336,7 +336,7 @@ function 韻母規則() { let 聲母 = 聲母規則(); let 韻母 = 韻母規則(); -if (is('入聲')) { +if (is`入聲`) { if (韻母.endsWith('m')) 韻母 = 韻母.slice(0, -1) + 'p'; else if (韻母.endsWith('n')) 韻母 = 韻母.slice(0, -1) + 't'; else if (韻母.endsWith('ng')) 韻母 = 韻母.slice(0, -2) + 'k'; @@ -364,7 +364,7 @@ function 聲調規則() { } if (選項.聲調 === '六聲(符號)') { - if (is('入聲 全濁')) { + if (is`入聲 全濁`) { if (韻母.endsWith('p')) 韻母 = 韻母.slice(0, -1) + 'b'; else if (韻母.endsWith('t')) 韻母 = 韻母.slice(0, -1) + 'd'; else if (韻母.endsWith('k')) 韻母 = 韻母.slice(0, -1) + 'g'; @@ -401,7 +401,7 @@ function 聲調規則() { let 聲調 = 聲調規則(); -if (韻母.startsWith('w') && (!is('牙喉音') || is('A類 或 以母'))) 韻母 = 韻母.slice(1); +if (韻母.startsWith('w') && is`非 牙喉音 或 A類 或 以母`) 韻母 = 韻母.slice(1); // 4. 音變規則 @@ -429,9 +429,9 @@ if (['平假名', '片假名'].includes(選項.書寫系統)) { if (選項.音變 === '現代日語') { if (聲母 === 'p') 聲母 = 'h'; // 甫 pu -> hu - if (韻母.endsWith('t')) 韻母 = 韻母 + 'u'; // 遏 at -> atu - else if (韻母.endsWith('ek')) 韻母 = 韻母 + 'i'; // 席 sek -> seki - else if (韻母.endsWith('k')) 韻母 = 韻母 + 'u'; // 澤 tak -> taku + if (韻母.endsWith('t')) 韻母 += 'u'; // 遏 at -> atu + else if (韻母.endsWith('ek')) 韻母 += 'i'; // 席 sek -> seki + else if (韻母.endsWith('k')) 韻母 += 'u'; // 澤 tak -> taku } if (選項.書寫系統 === '平文式羅馬字') { diff --git a/baxter.js b/baxter.js index 855be0e..b38add1 100644 --- a/baxter.js +++ b/baxter.js @@ -6,13 +6,16 @@ * @author Ayaka */ +/** @type { 音韻地位['屬於'] } */ +const is = (...x) => 音韻地位.屬於(...x); +/** @type { 音韻地位['判斷'] } */ +const when = (...x) => 音韻地位.判斷(...x); + if (!音韻地位) return [ // 版本可選 '1992' 或 '2014',預設值為 '2014' ['版本', [2, '1992', '2014']], ]; -const is = (...x) => 音韻地位.屬於(...x); - let 聲母 = { 幫: 'p', 滂: 'ph', 並: 'b', 明: 'm', 端: 't', 透: 'th', 定: 'd', 泥: 'n', 來: 'l', diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..99e2546 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,158 @@ +import stylisticJs from '@stylistic/eslint-plugin-js'; +import taggedIs from './rules/tagged-is.js'; + +export default [ + { + ignores: ['index.js'], + languageOptions: { + sourceType: 'script', + globals: { + TshetUinh: 'readonly', + 音韻地位: 'writable', + 字頭: 'writable', + 選項: 'readonly', + require: 'readonly', + }, + parserOptions: { + ecmaFeatures: { + globalReturn: true, + impliedStrict: true, + }, + }, + }, + plugins: { + '@stylistic/js': stylisticJs, + 'tagged-is': { + rules: { + 'tagged-is': taggedIs, + }, + }, + }, + rules: { + 'no-constant-binary-expression': 'error', + 'no-debugger': 'error', + 'no-dupe-class-members': 'error', + 'no-dupe-else-if': 'error', + 'no-dupe-keys': 'error', + 'no-duplicate-case': 'error', + 'no-self-assign': 'error', + 'no-self-compare': 'error', + 'no-setter-return': 'error', + 'no-undef': 'error', + 'no-unexpected-multiline': 'error', + 'no-unreachable': 'error', + 'no-unreachable-loop': 'error', + 'no-unused-private-class-members': 'error', + 'no-unused-vars': ['error', { varsIgnorePattern: '^(is|when)$' }], + 'no-useless-assignment': 'error', + 'no-useless-backreference': 'error', + 'default-case-last': 'error', + 'eqeqeq': 'error', + 'grouped-accessor-pairs': 'error', + 'logical-assignment-operators': 'error', + 'no-empty': ['error', { allowEmptyCatch: true }], + 'no-empty-function': 'error', + 'no-empty-static-block': 'error', + 'no-eval': 'error', + 'no-extend-native': 'error', + 'no-extra-bind': 'error', + 'no-extra-boolean-cast': 'error', + 'no-extra-label': 'error', + 'no-global-assign': 'error', + 'no-label-var': 'error', + 'no-new-func': 'error', + 'no-new-wrappers': 'error', + 'no-object-constructor': 'error', + 'no-sequences': 'error', + 'no-shadow': 'error', + 'no-shadow-restricted-names': 'error', + 'no-throw-literal': 'error', + 'no-undefined': 'error', + 'no-unneeded-ternary': 'error', + 'no-unused-expressions': 'error', + 'no-unused-labels': 'error', + 'no-useless-call': 'error', + 'no-useless-catch': 'error', + 'no-useless-computed-key': 'error', + 'no-useless-concat': 'error', + 'no-useless-constructor': 'error', + 'no-useless-escape': 'error', + 'no-useless-return': 'error', + 'no-var': 'error', + 'no-void': 'error', + 'object-shorthand': 'error', + 'operator-assignment': 'error', + 'prefer-arrow-callback': 'error', + 'prefer-exponentiation-operator': 'error', + 'prefer-numeric-literals': 'error', + 'prefer-object-has-own': 'error', + 'prefer-object-spread': 'error', + 'prefer-regex-literals': 'error', + 'prefer-rest-params': 'error', + 'prefer-spread': 'error', + 'strict': ['error', 'never'], + 'symbol-description': 'error', + + '@stylistic/js/array-bracket-spacing': 'error', + '@stylistic/js/arrow-parens': ['error', 'as-needed'], + '@stylistic/js/arrow-spacing': 'error', + '@stylistic/js/block-spacing': 'error', + '@stylistic/js/comma-spacing': 'error', + '@stylistic/js/comma-style': 'error', + '@stylistic/js/computed-property-spacing': 'error', + '@stylistic/js/dot-location': ['error', 'property'], + '@stylistic/js/eol-last': 'error', + '@stylistic/js/function-call-spacing': 'error', + '@stylistic/js/generator-star-spacing': ['error', 'after'], + '@stylistic/js/indent': ['error', 2, { SwitchCase: 1, ArrayExpression: 'off', ObjectExpression: 'off' }], + '@stylistic/js/key-spacing': 'error', + '@stylistic/js/keyword-spacing': 'error', + '@stylistic/js/new-parens': 'error', + '@stylistic/js/no-extra-semi': 'error', + '@stylistic/js/no-floating-decimal': 'error', + '@stylistic/js/no-multiple-empty-lines': ['error', { max: 1, maxBOF: 0, maxEOF: 0 }], + '@stylistic/js/no-tabs': 'error', + '@stylistic/js/no-trailing-spaces': 'error', + '@stylistic/js/no-whitespace-before-property': 'error', + '@stylistic/js/object-curly-spacing': ['error', 'always'], + '@stylistic/js/operator-linebreak': ['error', 'after'], + '@stylistic/js/padded-blocks': ['error', 'never'], + '@stylistic/js/quote-props': ['error', 'consistent'], + '@stylistic/js/quotes': ['error', 'single', { avoidEscape: true }], + '@stylistic/js/rest-spread-spacing': 'error', + '@stylistic/js/semi': 'error', + '@stylistic/js/semi-spacing': 'error', + '@stylistic/js/semi-style': 'error', + '@stylistic/js/space-before-blocks': 'error', + '@stylistic/js/space-before-function-paren': ['error', { anonymous: 'always', named: 'never', asyncArrow: 'always' }], + '@stylistic/js/space-in-parens': 'error', + '@stylistic/js/space-infix-ops': 'error', + '@stylistic/js/space-unary-ops': 'error', + '@stylistic/js/spaced-comment': 'error', + '@stylistic/js/switch-colon-spacing': 'error', + '@stylistic/js/template-curly-spacing': 'error', + '@stylistic/js/template-tag-spacing': 'error', + '@stylistic/js/yield-star-spacing': 'error', + + 'tagged-is/tagged-is': 'error', + }, + }, + { + files: ['eslint.config.js', '*/**/*.js'], + languageOptions: { + sourceType: 'module', + globals: { + TshetUinh: 'off', + 音韻地位: 'off', + 字頭: 'off', + 選項: 'off', + require: 'off', + console: 'readonly', + process: 'readonly', + }, + parserOptions: { + ecmaFeatures: {}, + }, + }, + }, +]; diff --git a/gwongzau.js b/gwongzau.js index fa2b4d5..9998c10 100644 --- a/gwongzau.js +++ b/gwongzau.js @@ -5,13 +5,13 @@ * @author Ayaka */ -if (!音韻地位) return []; - -/** @type { 音韻地位["屬於"] } */ +/** @type { 音韻地位['屬於'] } */ const is = (...x) => 音韻地位.屬於(...x); -/** @type { 音韻地位["判斷"] } */ +/** @type { 音韻地位['判斷'] } */ const when = (...x) => 音韻地位.判斷(...x); +if (!音韻地位) return []; + function 聲母規則() { return when([ ['幫滂並母 C類', 'f'], @@ -191,7 +191,7 @@ let 韻母 = 韻母規則(); let 聲調 = 聲調規則(); // ng 拼細音時為 j -const is細音 = ['eo', 'i', 'oe', 'u', 'yu'].some((x) => 韻母.startsWith(x)); +const is細音 = ['eo', 'i', 'oe', 'u', 'yu'].some(x => 韻母.startsWith(x)); if (聲母 === 'ng' && is細音) 聲母 = 'j'; // 三四等清調 h 拼 a 元音部分韻母時為 j/w @@ -200,10 +200,10 @@ if (聲母 === 'h' && ['au', 'an', 'am'].includes(韻母) && is`清音 三四等 } // 陰入分化 -if (is('入聲') && 聲調 === '3' && is短元音(韻母)) 聲調 = '1'; +if (is`入聲` && 聲調 === '3' && is短元音(韻母)) 聲調 = '1'; // 合口 -if (is('合口 或 模韻') && !['eo', 'oe', 'yu'].some((x) => 韻母.startsWith(x))) { +if (is`合口 或 模韻` && !['eo', 'oe', 'yu'].some(x => 韻母.startsWith(x))) { if ((聲母 === 'g' || 聲母 === 'k') && !韻母.startsWith('u')) 聲母 += 'w'; else if (聲母 === 'h' && !韻母.startsWith('i')) 聲母 = 'f'; else if (聲母 === 'j' || 聲母 === '') 聲母 = 'w'; @@ -213,9 +213,9 @@ if (is('合口 或 模韻') && !['eo', 'oe', 'yu'].some((x) => 韻母.startsWith if (韻母 === 'om') 韻母 = 'am'; // m 韻尾在聲母為脣音時為 n -if (is('脣音') && 韻母.endsWith('m')) 韻母 = 韻母.slice(0, -1) + 'n'; +if (is`脣音` && 韻母.endsWith('m')) 韻母 = 韻母.slice(0, -1) + 'n'; -if (is('入聲')) { +if (is`入聲`) { if (韻母.endsWith('m')) 韻母 = 韻母.slice(0, -1) + 'p'; else if (韻母.endsWith('n')) 韻母 = 韻母.slice(0, -1) + 't'; else if (韻母.endsWith('ng')) 韻母 = 韻母.slice(0, -2) + 'k'; diff --git a/karlgren.js b/karlgren.js index c31cfb6..865f5e1 100644 --- a/karlgren.js +++ b/karlgren.js @@ -35,7 +35,9 @@ * @author unt */ +/** @type { 音韻地位['屬於'] } */ const is = (...x) => 音韻地位.屬於(...x); +/** @type { 音韻地位['判斷'] } */ const when = (...x) => 音韻地位.判斷(...x); const 音標字典 = { diff --git a/langjin.js b/langjin.js index 3d9b077..821653b 100644 --- a/langjin.js +++ b/langjin.js @@ -14,7 +14,7 @@ const is = (...x) => 音韻地位.屬於(...x); const when = (...x) => 音韻地位.判斷(...x); if (!音韻地位) return [ - ['標調方式', [1, '數字', '附標']], + ['標調方式', [2, '數字', '附標']], ['書寫系統', [1, '拼音方案', '國際音標']], ]; diff --git a/mid_tang.js b/mid_tang.js index e07a6b7..7387d1d 100644 --- a/mid_tang.js +++ b/mid_tang.js @@ -10,11 +10,12 @@ * @author unt */ -const is = (x) => 音韻地位.屬於(x); +/** @type { 音韻地位['屬於'] } */ +const is = (...x) => 音韻地位.屬於(...x); +/** @type { 音韻地位['判斷'] } */ const when = (...x) => 音韻地位.判斷(...x); const is盛唐 = 選項.預置風格?.includes('盛唐') ?? false; -const is韻圖 = 選項.預置風格?.includes('韻圖') ?? true; const is慧琳 = 選項.預置風格?.includes('慧琳') ?? false; const 預置風格changed = 選項._last預置風格 && 選項._last預置風格 !== 選項.預置風格; diff --git a/mongol.js b/mongol.js index f65b2bc..f6e74b9 100644 --- a/mongol.js +++ b/mongol.js @@ -25,8 +25,11 @@ * @author unt */ -const is = (x) => 音韻地位.屬於(x); +/** @type { 音韻地位['屬於'] } */ +const is = (...x) => 音韻地位.屬於(...x); +/** @type { 音韻地位['判斷'] } */ const when = (...x) => 音韻地位.判斷(...x); + const 字母韻後綴 = 選項?.後綴 ?? '₂'; if (!音韻地位) return [...[ @@ -170,7 +173,7 @@ function get聲母() { else if (韻圖等 === '三' || use創新 && is創新的二四等併入三等 || is`江韻 舒聲`) 聲母字典 = { 曉: 'x', 匣: use創新 ? 'ʝ' : 'ɣ', // 匣三(雄小韻)併入四等 }; - if (聲母字典[音韻地位.母] === undefined) 聲母字典 = { + if (!(音韻地位.母 in 聲母字典)) 聲母字典 = { 幫: 'p', 滂: 'pʰ', 並: 'b', 明: 'm', 端: 't', 透: 'tʰ', 定: 'd', 泥: 'n', 來: 'l', diff --git a/msoeg_v8.js b/msoeg_v8.js index 4d7d8ba..714275e 100644 --- a/msoeg_v8.js +++ b/msoeg_v8.js @@ -5,14 +5,17 @@ * @author unt */ +/** @type { 音韻地位['屬於'] } */ const is = (...x) => 音韻地位.屬於(...x); +/** @type { 音韻地位['判斷'] } */ const when = (...x) => 音韻地位.判斷(...x); + let isIPA = 選項.音標體系 !== 'MPA'; let 音標體系changed = 選項._last音標體系 && 選項._last音標體系 !== 選項.音標體系; let mpaRevoked = false; // 用於在用戶選擇放棄使用 MPA 時刷新選項列表的內容 if (音標體系changed && 選項.音標體系 === 'MPA') { const message = '請注意 MPA 不是國際音標,其中諸多符號不可按國際音標理解,容易引起誤會。在公共場合使用 MPA 後果自負!\n\n確認使用 MPA?'; - if (!confirm(message)) { + if (!confirm(message)) { // eslint-disable-line no-undef isIPA = true; 音標體系changed = false; mpaRevoked = true; @@ -54,7 +57,7 @@ if (!音韻地位) return [ ['莊三韻母起始|\n知乎文章用 r 化元音\n韻鑒用 ɻ\n這裏默認用普通的三等起始(B 類或 C 類)', [1, '普通', 'r 化元音', 'ɻ'], { hidden: !選項.顯示高級選項 }], ['覺韻|\n知乎文章和韻鑒用低元音\n這裏默認用中元音,與江韻一致', - [1, '中元音', '低元音'], { hidden: !選項.顯示高級選項 }], // + [1, '中元音', '低元音'], { hidden: !選項.顯示高級選項 }], ['庚三清|\n知乎文章和韻鑒用低元音', [2, '中元音', '低元音'], { hidden: !選項.顯示高級選項 }], ['宕攝入聲附加|\n知乎文章和韻鑒用 ⁽ʷ⁾\n這裏默認省略', @@ -79,9 +82,9 @@ function get聲母_默認拼寫() { 影: 'ʔʶ', 曉: 'χ', 匣: 'ʁ', 精: 'tsʶ', 清: 'tsʶʰ', 從: 'dzʶ', 心: 'sʶ', }; - if (is('云母 開口 非 侵鹽韻')) return 'ɰ'; - if (is('以母 合口 或 以母 東鍾虞韻')) return 'ɥ'; - if (is('三等 或 來母 二等 非 庚韻')) return 普通聲母字典[音韻地位.母] || 小舌化聲母字典[音韻地位.母]; + if (is`云母 開口 非 侵鹽韻`) return 'ɰ'; + if (is`以母 合口 或 以母 東鍾虞韻`) return 'ɥ'; + if (is`三等 或 來母 二等 非 庚韻`) return 普通聲母字典[音韻地位.母] || 小舌化聲母字典[音韻地位.母]; return 小舌化聲母字典[音韻地位.母] || 普通聲母字典[音韻地位.母]; } @@ -145,30 +148,30 @@ function get韻母() { let 匹配行 = 推導韻到元音.find(e => e[0].includes(韻)); let 元音 = 匹配行[1]; - let 韻尾 = 韻尾列表[匹配行[0].indexOf(韻)].split('/')[+is('入聲')]; + let 韻尾 = 韻尾列表[匹配行[0].indexOf(韻)].split('/')[+is`入聲`]; if (韻 === '覺' && !韻尾.includes('ʷ')) { 韻尾 += 'ʷ'; } - if (is('宕攝 入聲') && !韻尾.includes('ʷ')) { + if (is`宕攝 入聲` && !韻尾.includes('ʷ')) { 韻尾 += 選項.宕攝入聲附加.replace('無', ''); } // 處理三等介音 - if (元音 === 'ɯ' && is('銳音 或 蒸韻 B類')) { + if (元音 === 'ɯ' && is`銳音 或 蒸韻 B類`) { // 銳音之蒸韻歸 A 類,唇音性蒸韻下面歸 B 類 元音 = 'i' + 元音; } - if (元音.includes('i') && is('B類 非 幽韻')) { + if (元音.includes('i') && is`B類 非 幽韻`) { // 幽韻知乎原文和韻鑒僅 A 類 // 其中,支宵侵的重紐三等開口歸 C 類 - 元音 = 元音.replace('i', is('支宵韻 或 侵韻 見影組 非 云母') ? 'ɯ' : 'ị'); + 元音 = 元音.replace('i', is`支宵韻 或 侵韻 見影組 非 云母` ? 'ɯ' : 'ị'); } - if (選項.莊三韻母起始 === '普通' && is('莊組 三等')) { + if (選項.莊三韻母起始 === '普通' && is`莊組 三等`) { // AB 類歸 B 類 元音 = 元音[0].replace('i', 'ị') + 元音.slice(1); - } else if (is('莊組 三等')) { + } else if (is`莊組 三等`) { 元音 = 元音[0] + '̣' + 元音.slice(1); - if (!is('支魚韻')) { + if (!is`支魚韻`) { // 介音變爲等同於二等的 ɨ̣(支魚的第一部分不是介音) 元音 = 元音[0].replace('ɯ', 'ɨ').replace('i', 'ɨ') + 元音.slice(1); } @@ -180,10 +183,10 @@ function get韻母() { // 處理開合介音 if (元音[0] === 'ɯ') { - if (is('合口') || is('幫組 非 支宵侵韻')) { + if (is`合口 或 幫組 非 支宵侵韻`) { 元音 = 元音.replace('ɯ', 'u'); } - } else if (is('合口 非 云以母 非 虞韻')) { + } else if (is`合口 非 云以母 非 虞韻`) { 元音 = 'ʷ' + 元音; 元音 = 元音.replace('ʷɻ', 'ɻʷ'); } diff --git a/n_song.js b/n_song.js index c5cda39..1f0b5e7 100644 --- a/n_song.js +++ b/n_song.js @@ -7,8 +7,11 @@ * @author unt */ +/** @type { 音韻地位['屬於'] } */ const is = (...x) => 音韻地位.屬於(...x); +/** @type { 音韻地位['判斷'] } */ const when = (...x) => 音韻地位.判斷(...x); + const is表層 = 選項.顯示形式 !== '底層'; if (!音韻地位) return [ @@ -147,7 +150,7 @@ function get韻基() { ['臻攝', is`入聲` ? 'ɨt' : 'ɨn'], // 五聲上(入) & 三聲下 ['果假攝', 'a'], // 一聲上(舒) - ['山攝', is`入聲` ? 'at' : 'an'],// 一聲上(入) & 三聲上 + ['山攝', is`入聲` ? 'at' : 'an'], // 一聲上(入) & 三聲上 ['遇攝', 'ɯ'], // 六聲下(僅舒聲) diff --git a/package-lock.json b/package-lock.json index c85aeb7..4e070af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,937 @@ "dependencies": { "tshet-uinh": "^0.15.1", "tshet-uinh-deriver-tools": "^0.2.0" + }, + "devDependencies": { + "@stylistic/eslint-plugin-js": "^2.11.0", + "eslint": "^9.15.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.0.tgz", + "integrity": "sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.0.tgz", + "integrity": "sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", + "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.15.0.tgz", + "integrity": "sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz", + "integrity": "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==", + "dev": true, + "dependencies": { + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@stylistic/eslint-plugin-js": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.11.0.tgz", + "integrity": "sha512-btchD0P3iij6cIk5RR5QMdEhtCCV0+L6cNheGhGCd//jaHILZMTi/EOqgEDAf1s4ZoViyExoToM+S2Iwa3U9DA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.15.0.tgz", + "integrity": "sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.15.0", + "@eslint/plugin-kit": "^0.2.3", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.5", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dev": true, + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "dev": true + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/tshet-uinh": { @@ -30,6 +961,63 @@ "peerDependencies": { "tshet-uinh": "^0.15.0" } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 52bd655..29558c3 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,8 @@ "type": "module", "main": "index.js", "scripts": { + "lint": "eslint .", + "lint:fix": "eslint --fix .", "test": "node test/main.js" }, "repository": { @@ -25,5 +27,9 @@ "dependencies": { "tshet-uinh": "^0.15.1", "tshet-uinh-deriver-tools": "^0.2.0" + }, + "devDependencies": { + "@stylistic/eslint-plugin-js": "^2.11.0", + "eslint": "^9.15.0" } } diff --git a/panwuyun.js b/panwuyun.js index 03bd263..b7a7327 100644 --- a/panwuyun.js +++ b/panwuyun.js @@ -9,8 +9,11 @@ * @author unt */ +/** @type { 音韻地位['屬於'] } */ const is = (...x) => 音韻地位.屬於(...x); +/** @type { 音韻地位['判斷'] } */ const when = (...x) => 音韻地位.判斷(...x); + const is2000 = Boolean(選項.版本?.includes('2000')); const is2013 = Boolean(選項.版本?.includes('2013')); const is2023 = 選項.版本?.includes('2023') ?? true; diff --git a/putonghua.js b/putonghua.js index 8c7c2cd..1e895da 100644 --- a/putonghua.js +++ b/putonghua.js @@ -2,13 +2,13 @@ * * @author graphemecluster * @author JwietPuj-Drin - * + * * 選項「清聲母入聲調分派層次」詳見平山久雄《中古汉语的清入声在北京话里的对应规律》 * http://ccj.pku.edu.cn/Article/DownLoad?id=271015083&&type=ArticleFile * 默認選擇為「皆派入陰平」,参考刘海阳在對「北京话的入声为什么会派入三个不同的声调?」的回答中披露的材料—— * 「古代清音入声字在北京話的声調,凡是沒有异讀的,就采用北京已經通行的讀法。凡是有异讀的,假若其中有一个是陰平調,原則上就采用陰平,例如:“息”ㄒㄧ(xī)“击”ㄐㄧ(jī)。否則逐字考慮,采用比較通行……」 * https://www.zhihu.com/question/30370012/answer/533234460 - * + * * 選項「常母平聲陰聲韻聲母和船母平聲聲母」詳見 unt 對「为何中古的dʑ ʑ和普通话读音的对应似乎是反的(即dʑ > ʂ、ʑ > ʈʂ)?」的回答 * https://www.zhihu.com/question/526195183/answer/2425807330 */ diff --git a/rules/tagged-is.js b/rules/tagged-is.js new file mode 100644 index 0000000..97fe9ca --- /dev/null +++ b/rules/tagged-is.js @@ -0,0 +1,36 @@ +export default { + meta: { + type: 'suggestion', + docs: { + description: 'Enforce using tagged template with the `is` function', + }, + fixable: 'code', + schema: [], + }, + create(context) { + return { + CallExpression(node) { + if (node.callee.name === 'is') { + const arg = node.arguments[0]; + if (arg && (arg.type === 'TemplateLiteral' || (arg.type === 'Literal' && typeof arg.value === 'string'))) { + context.report({ + node, + message: 'Use tagged template with the `is` function.', + fix(fixer) { + if (arg.type === 'TemplateLiteral') { + return fixer.replaceText(node, `is${context.getSourceCode().getText(arg)}`); + } + if (arg.type === 'Literal' && typeof arg.value === 'string') { + return fixer.replaceText(node, `is\`${ + arg.raw.slice(1, -1).replace(/\\('|")|`|\$\{/g, (match, escaped) => escaped || `\\${match}`) + }\``); + } + return null; + }, + }); + } + } + }, + }; + }, +}; diff --git a/test/.prettierrc b/test/.prettierrc deleted file mode 100644 index 0967ef4..0000000 --- a/test/.prettierrc +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/test/main.js b/test/main.js index 36be303..9a1a811 100644 --- a/test/main.js +++ b/test/main.js @@ -1,29 +1,29 @@ -import util from "node:util"; +import util from 'node:util'; -import { 音韻地位 } from "tshet-uinh"; -import * as TshetUinhExamples from "../index.js"; +import { 資料, 音韻地位 } from 'tshet-uinh'; +import * as TshetUinhExamples from '../index.js'; -const 地位 = 音韻地位.from描述("書開三宵上"); +const 地位 = 音韻地位.from描述('書開三宵上'); const testCases = [ - ["tupa", "sjiewq"], - ["baxter", "syewX"], - ["karlgren", "ɕi̯ɛu꞉"], - ["wangli", "꜂ɕĭɛu"], - ["panwuyun", "ɕiᴇu˧˥"], - ["unt", "ɕéw"], - ["msoeg_v8", "ɕiɛuʔ"], - ["mid_tang", "ɕɛ́w"], - ["n_song", "ɕjɛ́w"], - ["mongol", "ꡮꡠꡓ"], - ["zhongyuan", "ʂjɛw³"], - //["fanwan", "shiu2"], - ["putonghua", "shǎo"], - ["gwongzau", "siu2"], - ["zaonhe", "sɔ̄"], - ["langjin", "shǎo"], - ["ayaka_v8", "seu"], - ["yec_en_hua", "A"], + ['tupa', 'sjiewq'], + ['baxter', 'syewX'], + ['karlgren', 'ɕi̯ɛu꞉'], + ['wangli', '꜂ɕĭɛu'], + ['panwuyun', 'ɕiᴇu˧˥'], + ['unt', 'ɕéw'], + ['msoeg_v8', 'ɕiɛuʔ'], + ['mid_tang', 'ɕɛ́w'], + ['n_song', 'ɕjɛ́w'], + ['mongol', 'ꡮꡠꡓ'], + ['zhongyuan', 'ʂjɛw³'], + // ['fanwan', 'shiu2'], + ['putonghua', 'shǎo'], + ['gwongzau', 'siu2'], + ['zaonhe', 'sɔ̄'], + ['langjin', 'shǎo'], + ['ayaka_v8', 'seu'], + ['yec_en_hua', 'A'], ]; let passed = 0; @@ -32,7 +32,9 @@ for (const [schema, expected] of testCases) { console.log(`Testing: ${schema}`); total++; try { - const result = TshetUinhExamples[schema]()(地位); + const deriver = TshetUinhExamples[schema](); + Array.from(資料.iter音韻地位(), deriver); // Ensure no error is thrown from all 音韻地位 + const result = deriver(地位); if (result === expected) { passed += 1; } else { diff --git a/tupa.js b/tupa.js index fe83682..22e6e6a 100644 --- a/tupa.js +++ b/tupa.js @@ -5,11 +5,13 @@ * @author unt */ -if (!音韻地位) return []; - +/** @type { 音韻地位['屬於'] } */ const is = (...x) => 音韻地位.屬於(...x); +/** @type { 音韻地位['判斷'] } */ const when = (...x) => 音韻地位.判斷(...x); +if (!音韻地位) return []; + function get聲母() { return { 幫: 'p', 滂: 'ph', 並: 'b', 明: 'm', diff --git a/unt.js b/unt.js index ace50ce..a223ca9 100644 --- a/unt.js +++ b/unt.js @@ -14,7 +14,7 @@ * * - 2022:切韻擬音 L * https://zhuanlan.zhihu.com/p/545490174 - * + * * - 2023:切韻通俗擬音 * https://zhuanlan.zhihu.com/p/545490174 * @@ -23,7 +23,9 @@ * @author unt */ +/** @type { 音韻地位['屬於'] } */ const is = (...x) => 音韻地位.屬於(...x); +/** @type { 音韻地位['判斷'] } */ const when = (...x) => 音韻地位.判斷(...x); const is專業模式 = 選項.專業模式 ?? false; diff --git a/wangli.js b/wangli.js index d0b98c4..340bb58 100644 --- a/wangli.js +++ b/wangli.js @@ -21,7 +21,9 @@ * @author Mishiro */ +/** @type { 音韻地位['屬於'] } */ const is = (...x) => 音韻地位.屬於(...x); +/** @type { 音韻地位['判斷'] } */ const when = (...x) => 音韻地位.判斷(...x); const is史稿 = 選項.擬音版本?.includes('稿') ?? true; diff --git a/yec_en_hua.js b/yec_en_hua.js index c1f8cf2..d972853 100644 --- a/yec_en_hua.js +++ b/yec_en_hua.js @@ -6,7 +6,9 @@ * @author 笑也 (JavaScript: unt) */ +/** @type { 音韻地位['屬於'] } */ const is = (...x) => 音韻地位.屬於(...x); +/** @type { 音韻地位['判斷'] } */ const when = (...x) => 音韻地位.判斷(...x); if (!音韻地位) return [ diff --git a/zaonhe.js b/zaonhe.js index 3e10911..1531713 100644 --- a/zaonhe.js +++ b/zaonhe.js @@ -10,7 +10,9 @@ * @author Nyoeghau */ -const is = (x) => 音韻地位.屬於(x); +/** @type { 音韻地位['屬於'] } */ +const is = (...x) => 音韻地位.屬於(...x); +/** @type { 音韻地位['判斷'] } */ const when = (...x) => 音韻地位.判斷(...x); if (!音韻地位) @@ -413,10 +415,10 @@ function 顎化規則(音節) { function 主流層選擇規則(音們) { let 音們_非主流度們 = []; - 音們.forEach((音) => { - 音們_非主流度們.push({ 音: 音, 非主流度: (音.match(/▽/g) || []).length }); + 音們.forEach(音 => { + 音們_非主流度們.push({ 音, 非主流度: (音.match(/▽/g) || []).length }); }); - return 音們_非主流度們.reduce(function (prev, curr) { + return 音們_非主流度們.reduce((prev, curr) => { return prev.非主流度 < curr.非主流度 ? prev : curr; }).音; } diff --git a/zhongyuan.js b/zhongyuan.js index e7807e2..e19a04e 100644 --- a/zhongyuan.js +++ b/zhongyuan.js @@ -10,7 +10,9 @@ * @author unt */ +/** @type { 音韻地位['屬於'] } */ const is = (...x) => 音韻地位.屬於(...x); +/** @type { 音韻地位['判斷'] } */ const when = (...x) => 音韻地位.判斷(...x); if (!音韻地位) return [ @@ -259,7 +261,6 @@ function get韻母() { ]], ], '無韻基規則', true); - let 韻母 = 洪細 + 開合 + 韻基; 韻母 = 韻母.replace('wu', 'u'); 韻母 = 韻母.replace('jwɨj', 'wɨj');