├── .editorconfig
├── .github
└── workflows
│ ├── build.yml
│ └── create_release.yml
├── .gitignore
├── .npmignore
├── .prettierrc.js
├── .tool-versions
├── LICENSE.txt
├── README.md
├── demo
└── index.html
├── eslint.config.mjs
├── package-lock.json
├── package.json
├── rollup.config.js
├── src
├── cli.ts
├── config.ts
├── lib
│ ├── cacheRegexes.ts
│ ├── dict.ts
│ ├── dictionaries
│ │ ├── convert.ts
│ │ ├── dictionary.ts
│ │ └── jisDai2.ts
│ ├── kan2num.ts
│ ├── normalizeHelpers.ts
│ ├── patchAddr.ts
│ ├── utils.ts
│ └── zen2han.ts
├── main-node.ts
├── main.ts
├── normalize.ts
└── types.ts
├── test
├── addresses
│ ├── addresses.csv
│ ├── addresses.test.ts
│ ├── build-test-data.ts
│ └── list.txt
├── helpers.ts
├── integration
│ ├── browser.test.ts
│ ├── browser
│ │ ├── index-esm.html
│ │ └── index-umd.html
│ ├── node-cjs
│ │ ├── index.js
│ │ ├── package-lock.json
│ │ └── package.json
│ ├── node-esm
│ │ ├── index.js
│ │ ├── package-lock.json
│ │ └── package.json
│ ├── node.test.ts
│ ├── webpack-ts
│ │ ├── .gitignore
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── src
│ │ │ └── index.ts
│ │ ├── tsconfig.json
│ │ └── webpack.config.js
│ └── webpack.test.ts
├── main
│ ├── filesystem-api.test.ts
│ ├── main.test.ts
│ └── metadata.test.ts
└── run.ts
└── tsconfig.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 |
4 | name: build
5 |
6 | on:
7 | push:
8 | branches:
9 | - master
10 | tags: ['*']
11 | pull_request:
12 | branches:
13 | - master
14 |
15 | jobs:
16 | build:
17 | name: "ビルド・リント"
18 | runs-on: ubuntu-latest
19 | steps:
20 | - uses: actions/checkout@v4
21 | - name: Use Node.js
22 | uses: actions/setup-node@v4
23 | with:
24 | node-version: '22.x'
25 | cache: 'npm'
26 | - run: npm ci
27 | - run: npm run lint
28 | - run: npm run build
29 |
30 | - uses: actions/upload-artifact@v4
31 | with:
32 | name: dist
33 | path: dist
34 |
35 | - uses: actions/upload-pages-artifact@v3
36 | if: github.ref == 'refs/heads/master'
37 | with:
38 | path: demo
39 |
40 | deploy-pages:
41 | name: "GitHub Pages へのデプロイ"
42 | runs-on: ubuntu-latest
43 | needs:
44 | - build
45 | permissions:
46 | pages: write # to deploy to Pages
47 | id-token: write # to verify the deployment originates from an appropriate source
48 | environment:
49 | name: github-pages
50 | url: ${{ steps.deployment.outputs.page_url }}
51 | if: github.ref == 'refs/heads/master'
52 | steps:
53 | - uses: actions/deploy-pages@v4
54 | id: deployment
55 |
56 | test:
57 | name: "テスト"
58 | needs:
59 | - build
60 |
61 | runs-on: ${{ matrix.os }}
62 |
63 | strategy:
64 | matrix:
65 | os: [ubuntu-latest, windows-latest]
66 | node-version: [18.x, 20.x, 22.x]
67 |
68 | steps:
69 | - uses: actions/checkout@v4
70 | - name: Use Node.js ${{ matrix.node-version }}
71 | uses: actions/setup-node@v4
72 | with:
73 | node-version: ${{ matrix.node-version }}
74 | cache: 'npm'
75 |
76 | - uses: actions/download-artifact@v4
77 | with:
78 | name: dist
79 | path: dist
80 |
81 | - run: npm ci
82 | - run: npm test
83 |
84 | # 結合テストはビルドされたものが必要
85 | # また、Node.js 18.x では結合テストをスキップする
86 | - name: 結合テスト
87 | if: matrix.node-version != '18.x'
88 | run: npm run test:integration
89 |
90 | # アドレステストは時間かかるし、環境依存が無いので、matrixにいれる必要無い
91 | test-addresses:
92 | name: "詳細住所テスト"
93 | needs:
94 | - build
95 | runs-on: ubuntu-latest
96 | steps:
97 | - uses: actions/checkout@v4
98 | - name: Use Node.js
99 | uses: actions/setup-node@v4
100 | with:
101 | node-version: '22.x'
102 | cache: 'npm'
103 | - run: npm ci
104 | - run: npm run build
105 | - run: npm run test:addresses
106 |
107 | publish:
108 | name: 'npm 公開'
109 | runs-on: ubuntu-latest
110 | needs:
111 | - test
112 | if: startsWith(github.ref, 'refs/tags/v')
113 | steps:
114 | - uses: actions/checkout@v4
115 | # Setup .npmrc file to publish to npm
116 | - uses: actions/setup-node@v4
117 | with:
118 | node-version: '22.x'
119 | registry-url: 'https://registry.npmjs.org'
120 | scope: '@geolonia'
121 | cache: 'npm'
122 | - run: npm ci
123 | - run: npm run build
124 | - run: npm publish --access=public
125 | env:
126 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
127 |
--------------------------------------------------------------------------------
/.github/workflows/create_release.yml:
--------------------------------------------------------------------------------
1 | name: Auto Release
2 |
3 | permissions:
4 | contents: write
5 | on:
6 | push:
7 | tags:
8 | - 'v*.*.*'
9 |
10 | jobs:
11 | release:
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - name: Checkout repository
16 | uses: actions/checkout@v3
17 |
18 | - name: Create GitHub release
19 | uses: softprops/action-gh-release@v1
20 | with:
21 | name: ${{ github.event.inputs.tag }}
22 | tag_name: ${{ github.event.inputs.tag }}
23 | generate_release_notes: true
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | **/node_modules
6 | /.pnp
7 | .pnp.js
8 |
9 | # testing
10 | /coverage
11 |
12 | # production
13 | /build
14 | /demo/main-esm.mjs*
15 |
16 | # misc
17 | .DS_Store
18 | .env.local
19 | .env.development.local
20 | .env.test.local
21 | .env.production.local
22 |
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | /cache
28 | /dist
29 |
30 | // Use npm
31 | yarn.lock
32 |
33 | test/japanese-addresses-master
34 |
35 | test/integration/browser/main-esm.mjs
36 | test/integration/browser/main-umd.cjs
37 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | /cache
2 | /.github
3 | /src/addresses/test.*
4 | /test
5 |
--------------------------------------------------------------------------------
/.prettierrc.js:
--------------------------------------------------------------------------------
1 | export default {
2 | semi: false,
3 | trailingComma: 'all',
4 | singleQuote: true,
5 | tabWidth: 2,
6 | }
7 |
--------------------------------------------------------------------------------
/.tool-versions:
--------------------------------------------------------------------------------
1 | nodejs 22.9.0
2 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright 2020 Geolonia Inc.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # @geolonia/normalize-japanese-addresses
2 |
3 | [](https://github.com/geolonia/normalize-japanese-addresses/actions/workflows/build.yml)
4 |
5 | オープンソースの住所正規化ライブラリです。
6 |
7 | 経産省の [IMI コンポーネントツール](https://info.gbiz.go.jp/tools/imi_tools/)のジオコーディングの仕組みからインスピレーションをうけて開発しました。
8 |
9 | ## デモ
10 |
11 | [https://geolonia.github.io/normalize-japanese-addresses/](https://geolonia.github.io/normalize-japanese-addresses/)
12 |
13 | ## インストール
14 |
15 | ライブラリは npm レジストリで `@geolonia/normalize-japanese-addresses` として配布されています。
16 | npm コマンドなどを使ってインストールして下さい。
17 |
18 | ```shell
19 | $ npm install @geolonia/normalize-japanese-addresses -S
20 | ```
21 |
22 | ## 使い方
23 |
24 | ### `normalize(address: string, option: Option)`
25 |
26 | 住所を正規化します。
27 |
28 | ```javascript
29 | import { normalize } from '@geolonia/normalize-japanese-addresses';
30 | // ESMを利用しない場合は下記
31 | // const { normalize } = require('@geolonia/normalize-japanese-addresses');
32 |
33 | normalize('北海道札幌市西区24-2-2-3-3').then(result => {
34 | console.log(result);
35 | // {
36 | // "pref": "北海道", // 都道府県名
37 | // "city": "札幌市西区", // 市区町村名
38 | // "town": "二十四軒二条二丁目", // 大字・丁目名
39 | // "addr": "3-3", // 街区符号・住居符号または地番
40 | // "level": 8, // 正規化レベル
41 | // "point": {
42 | // "lat": 43.074206115, // 緯度
43 | // "lng": 141.315540696, // 軽度
44 | // "level": 8 // 位置情報データレベル
45 | // },
46 | // "other": "" // 正規化できなかった文字列
47 | // }
48 | })
49 | ```
50 |
51 | 住所の正規化結果として戻されるオブジェクトには、`level` プロパティが含まれます。`level` には、住所文字列のどこまでを判別できたかを以下の数値で格納しています。
52 |
53 | * `0` - 都道府県も判別できなかった。
54 | * `1` - 都道府県まで判別できた。
55 | * `2` - 市区町村まで判別できた。
56 | * `3` - 大字・丁目まで判別できた。
57 | * `8` - 住居表示住所の街区符号・住居符号または地番住所の地番まで判別できた。
58 |
59 | `point` に位置情報データ (EPSG:4326) が入っています。位置情報の精度を表す `level` プロパティを参照してください。住所正規化レベルと位置情報データのレベルが異なる場合は主には、住居表示または地番情報(レベル8)は存在しましたが、位置情報データが存在しなかった場合。この場合は、大字・丁目の代表点の位置情報データを返却します。
60 |
61 | 位置情報データのレベルは下記となります。
62 |
63 | * `1` - 都道府県庁所在地
64 | * `2` - 市区町村役所(役場)所在地
65 | * `3` - 大字・丁目の代表点
66 | * `8` - 住居表示住所の場合はフロンテージ位置多い。地番住所の場合は地番の中央点。
67 |
68 | レベルの上限を設定することも可能です。例えば都道府県名のみを正規化したい場合、`level` オプションで指定することで処理を速くすることができます。
69 |
70 | ```javascript
71 | const { normalize } = require('@geolonia/normalize-japanese-addresses')
72 | normalize('北海道札幌市西区24-2-2-3-3', { level: 1 }).then(result => {
73 | console.log(result);
74 | // {
75 | // "pref": "北海道",
76 | // "other": "札幌市西区24-2-2-3-3",
77 | // "level": 1,
78 | // "point": {
79 | // "lat": 43.0639406375,
80 | // "lng": 141.347906782,
81 | // "level": 1
82 | // }
83 | // }
84 | })
85 | ```
86 |
87 | ### グローバルオプション
88 |
89 | 以下のパラメーターを変更することでライブラリの動作全体に関わる設定が変更できます。
90 |
91 |
92 | #### `config.japaneseAddressesApi: string`
93 |
94 | 住所データを配信する Web API のエンドポイントを指定します。デフォルトは `https://japanese-addresses-v2.geoloniamaps.com/api/ja` です。この API から配信されるデータのディレクトリ構成は [Geolonia 住所データ](https://github.com/geolonia/japanese-addresses-v2/) を参考にしてください。
95 |
96 | NodeJS環境のみ、このオプションに対して `file://` 形式の URL を指定することで、ローカルファイルとして保存したファイルを参照することができます。
97 |
98 | ## 正規化の内容
99 |
100 | * `XXX郡` などの郡の名前が省略されている住所に対しては、それを補完します。
101 | * 住所に含まれるアルファベットと数字を半角に統一します。
102 | * 京都の通り名を削除します。
103 | * 新字体と旧字体のゆらぎを吸収して、国交省の位置参照情報に記載されている地名にあわせます。
104 | * `ヶケが`、`ヵカか力`、`之ノの`、`ッツっつ` などのゆらぎを吸収して、国交省の位置参照情報に記載されている地名にあわせます。
105 | * `釜`と`竈`、`埠頭`と`ふ頭`などの漢字のゆらぎを吸収します。
106 | * 町丁目レベルに記載されている数字は、国交省の位置参照情報にあわせて、すべて漢数字に変換します。
107 | * 番地や号レベルに記載されている数字はアラビア数字に変換し、`番地` などの文字列は `-` に変換します。
108 | * 住所の末尾に建物名がある場合は、なるべくなにもしないでそのまま返す仕様になっていますが、できればあらかじめ分離していただいたほうがいいかもしれません。
109 |
110 | 参考:
111 |
112 | * [ゆらぎを処理している文字列に関しては、ソースコードを御覧ください。](https://github.com/geolonia/normalize-japanese-addresses/blob/master/src/lib/dict.ts)
113 | * [変換前、変換後の住所の例はテストコードを御覧ください。](https://github.com/geolonia/normalize-japanese-addresses/blob/master/test/main/main.test.ts)
114 |
115 |
116 | ## 開発者向け情報
117 |
118 | まず、以下のコマンドで環境を用意してください。
119 |
120 | ```shell
121 | $ git clone git@github.com:geolonia/normalize-japanese-addresses.git
122 | $ cd normalize-japanese-addresses
123 | $ npm install
124 | ```
125 |
126 | 次に、以下を実行してコンパイルをおこないます。
127 |
128 | ```shell
129 | $ npm run build
130 | ```
131 |
132 | dist フォルダ以下に main-node.js など必要なファイルが生成されるので、
133 |
134 | ```javascript
135 | // sample.js
136 | import { normalize } from './dist/main-node-esm.mjs';
137 | // ESMを利用しない場合は下記
138 | // const { normalize } = require('./dist/main-node-cjs.cjs');
139 |
140 | normalize('北海道札幌市西区24-2-2-3-3', { level: 3 }).then(result => {
141 | console.log(result);
142 | // {
143 | // "pref": "北海道",
144 | // "city": "札幌市西区",
145 | // "town": "二十四軒二条二丁目",
146 | // "other": "3-3",
147 | // "level": 3,
148 | // "point": {
149 | // "lat": 43.074273,
150 | // "lng": 141.315099,
151 | // "level": 3
152 | // }
153 | // }
154 | })
155 | ```
156 |
157 | という内容で sample.js を用意したら、
158 |
159 | ```shell
160 | $ node sample.js
161 | ```
162 |
163 | でサンプルファイルを実行することができます。
164 |
165 | ## NodeJS バージョン対応方針について
166 |
167 | `normalize-japanese-addresses` は現在、 NodeJS 18.x, 20.x, 22.x を対象としてテストを実施し、動作を確認しております。ビルド時は「開発環境」の NodeJS バージョンを利用ください。
168 |
169 | NodeJS 以外のブラウザの環境は、最新ブラウザを前提とした対応となります。fetchが利用可能な環境であれば動く可能性が高い。テストは最新の Chrome を使って実施しております。
170 |
171 | 開発環境は、 `.tool-versions` にかかれているバージョンを利用してください。
172 |
173 | 準拠としては [Node.js Releases](https://nodejs.org/en/about/previous-releases) を参照してください。基本的に動作環境は Maintenance, Active LTS をターゲットとし、開発環境は最新の Active LTS を利用しますが、更新のタイミング等でずれることがあります。
174 |
175 | ## 注意
176 |
177 | * この正規化エンジンは、住所の「名寄せ」を目的としており、たとえば京都の「通り名」は削除します。
178 | * 郵便や宅急便などに使用される住所としては、問題ないと考えています。
179 | * 正規化に利用するデータは、 [`japanese-addresses-v2`](https://github.com/geolonia/japanese-addresses-v2) で作成されます。元データに関してはそのレポジトリを御覧ください。
180 | * 住居表示が未整備の地域については全体的に苦手です。
181 |
182 | ### 貢献方法
183 |
184 | [プルリクエスト](https://github.com/geolonia/normalize-japanese-addresses/pulls) や [Issue](https://github.com/geolonia/normalize-japanese-addresses/issues) はいつでも歓迎します。
185 |
186 | ## ライセンス、利用規約
187 |
188 | - ソースコードのライセンスは MIT ライセンスです。
189 | - ご利用に際しましては、できればソーシャルでのシェア、[Geolonia](https://geolonia.com/) へのリンクの設置などをしていただけると、開発者たちのモチベーションが上がると思います。
190 |
191 | 住所の正規化を工夫すれば精度があがりそうなので、そのあたりのアイディアを募集しています。
192 |
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | @geolonia/normalize-japanese-addresses
7 |
8 |
9 |
10 |
11 |
12 |
住所正規化デモ
13 |
14 |
15 |
16 |
17 |
20 |
21 |
22 |
23 |
218 |
219 |
--------------------------------------------------------------------------------
/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import tsdoc from 'eslint-plugin-tsdoc'
2 | import tsParser from '@typescript-eslint/parser'
3 | import path from 'node:path'
4 | import { fileURLToPath } from 'node:url'
5 | import js from '@eslint/js'
6 | import { FlatCompat } from '@eslint/eslintrc'
7 |
8 | const __filename = fileURLToPath(import.meta.url)
9 | const __dirname = path.dirname(__filename)
10 | const compat = new FlatCompat({
11 | baseDirectory: __dirname,
12 | recommendedConfig: js.configs.recommended,
13 | allConfig: js.configs.all,
14 | })
15 |
16 | export default [
17 | {
18 | ignores: ['node_modules/', 'dist'],
19 | },
20 | ...compat.extends(
21 | 'plugin:@typescript-eslint/recommended',
22 | 'plugin:prettier/recommended',
23 | ),
24 | {
25 | plugins: {
26 | tsdoc,
27 | },
28 |
29 | languageOptions: {
30 | parser: tsParser,
31 | ecmaVersion: 2020,
32 | sourceType: 'module',
33 | },
34 |
35 | rules: {
36 | '@typescript-eslint/explicit-module-boundary-types': 0,
37 | '@typescript-eslint/ban-ts-comment': 0,
38 | '@typescript-eslint/no-var-requires': 0,
39 | 'tsdoc/syntax': 'error',
40 | },
41 | },
42 | ]
43 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@geolonia/normalize-japanese-addresses",
3 | "version": "3.1.3",
4 | "description": "日本の住所を正規化するライブラリ",
5 | "type": "module",
6 | "main": "./dist/main-node-cjs.cjs",
7 | "types": "./dist/main-node.d.ts",
8 | "exports": {
9 | "node": {
10 | "import": "./dist/main-node-esm.mjs",
11 | "types": "./dist/main-node.d.ts",
12 | "require": "./dist/main-node-cjs.cjs"
13 | },
14 | "import": "./dist/main-esm.mjs",
15 | "types": "./dist/main.d.ts",
16 | "default": "./dist/main-umd.cjs"
17 | },
18 | "scripts": {
19 | "cli": "tsx ./src/cli.ts",
20 | "test": "npm run test:main",
21 | "test:main": "tsx ./test/run.ts main",
22 | "test:addresses": "tsx ./test/run.ts addresses",
23 | "test:generate-test-data": "tsx test/addresses/build-test-data.ts > test/addresses/addresses.csv",
24 | "test:integration": "tsx ./test/run.ts integration",
25 | "lint": "eslint \"src/**/*.ts\" \"test/**/*.test.ts\" --fix",
26 | "build": "npm run clean && rollup -c rollup.config.js && shx cp ./dist/main-esm.mjs* ./demo/",
27 | "clean": "shx rm -rf dist"
28 | },
29 | "engines": {
30 | "node": ">=18"
31 | },
32 | "author": "Geolonia, Inc.",
33 | "license": "MIT",
34 | "devDependencies": {
35 | "@rollup/plugin-commonjs": "^28.0.1",
36 | "@rollup/plugin-node-resolve": "^15.3.0",
37 | "@rollup/plugin-replace": "^6.0.1",
38 | "@rollup/plugin-terser": "^0.4.4",
39 | "@rollup/plugin-typescript": "^12.1.1",
40 | "@types/node": "^22",
41 | "@types/papaparse": "^5.3.14",
42 | "@typescript-eslint/eslint-plugin": "^8.7.0",
43 | "@typescript-eslint/parser": "^8.7.0",
44 | "eslint": "^9.11.1",
45 | "eslint-config-prettier": "^9.1.0",
46 | "eslint-plugin-prettier": "^5.2.1",
47 | "eslint-plugin-tsdoc": "^0.3.0",
48 | "glob": "^11.0.0",
49 | "jest-matcher-deep-close-to": "^3.0.2",
50 | "prettier": "^3.3.3",
51 | "puppeteer": "^23.6.0",
52 | "rollup": "^4.24.0",
53 | "rollup-plugin-delete": "^2.1.0",
54 | "rollup-plugin-dts": "^6.1.1",
55 | "shx": "^0.3.4",
56 | "tsx": "^4.19.1",
57 | "typescript": "^5.6.2"
58 | },
59 | "dependencies": {
60 | "@geolonia/japanese-addresses-v2": "0.0.5",
61 | "@geolonia/japanese-numeral": "^1.0.2",
62 | "lru-cache": "^11.0.1",
63 | "papaparse": "^5.4.1",
64 | "undici": "^6.19.8"
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import fs from 'node:fs'
2 | import path from 'node:path'
3 |
4 | import typescript from '@rollup/plugin-typescript'
5 | import { dts } from 'rollup-plugin-dts'
6 | import del from 'rollup-plugin-delete'
7 | import resolve from '@rollup/plugin-node-resolve'
8 | import commonjs from '@rollup/plugin-commonjs'
9 | import terser from '@rollup/plugin-terser'
10 | import replace from '@rollup/plugin-replace'
11 |
12 | const packageJson = JSON.parse(
13 | fs.readFileSync(path.join(import.meta.dirname, 'package.json'), 'utf-8'),
14 | )
15 |
16 | const replacePlugin = replace({
17 | preventAssignment: true,
18 | values: {
19 | __VERSION__: `'${packageJson.version}'`,
20 | },
21 | })
22 |
23 | export default [
24 | {
25 | input: 'src/main.ts',
26 | output: {
27 | file: './dist/main-umd.cjs',
28 | name: 'normalize',
29 | format: 'umd',
30 | sourcemap: true,
31 | },
32 | plugins: [
33 | typescript(),
34 | replacePlugin,
35 | resolve({ browser: true }),
36 | commonjs(),
37 | terser(),
38 | ],
39 | },
40 | {
41 | input: 'src/main.ts',
42 | output: {
43 | file: './dist/main-esm.mjs',
44 | name: 'normalize',
45 | format: 'esm',
46 | sourcemap: true,
47 | },
48 | plugins: [
49 | typescript(),
50 | replacePlugin,
51 | resolve({ browser: true }),
52 | commonjs(),
53 | terser(),
54 | ],
55 | },
56 | {
57 | input: 'src/main-node.ts',
58 | external: [
59 | '@geolonia/japanese-numeral',
60 | '@geolonia/japanese-addresses-v2',
61 | 'papaparse',
62 | 'undici',
63 | 'lru-cache',
64 | 'node:fs',
65 | ],
66 | output: {
67 | file: './dist/main-node-esm.mjs',
68 | format: 'esm',
69 | sourcemap: true,
70 | },
71 | plugins: [typescript(), replacePlugin],
72 | },
73 | {
74 | input: 'src/main-node.ts',
75 | external: [
76 | '@geolonia/japanese-numeral',
77 | '@geolonia/japanese-addresses-v2',
78 | 'papaparse',
79 | 'undici',
80 | 'lru-cache',
81 | 'node:fs',
82 | ],
83 | output: {
84 | file: './dist/main-node-cjs.cjs',
85 | format: 'cjs',
86 | sourcemap: true,
87 | },
88 | plugins: [typescript(), replacePlugin],
89 | },
90 | {
91 | input: 'dist/main.d.ts',
92 | output: [
93 | {
94 | file: './dist/main.d.ts',
95 | format: 'es',
96 | },
97 | ],
98 | plugins: [dts()],
99 | },
100 | {
101 | input: 'dist/main-node.d.ts',
102 | output: [
103 | {
104 | file: './dist/main-node.d.ts',
105 | format: 'es',
106 | },
107 | ],
108 | plugins: [
109 | dts(),
110 | del({
111 | targets: ['dist/**/*.d.ts', '!dist/main.d.ts', '!dist/main-node.d.ts'],
112 | hook: 'buildEnd',
113 | }),
114 | ],
115 | },
116 | ]
117 |
--------------------------------------------------------------------------------
/src/cli.ts:
--------------------------------------------------------------------------------
1 | import { normalize } from './main-node'
2 |
3 | async function main(args: string[]) {
4 | let options = {}
5 | if (args.length > 1) {
6 | options = JSON.parse(args[1])
7 | }
8 | const result = await normalize(args[0], options)
9 | console.log(JSON.stringify(result, null, 2))
10 | }
11 |
12 | main(process.argv.slice(2))
13 | .then(() => {
14 | process.exit(0)
15 | })
16 | .catch((e) => {
17 | console.error(e)
18 | process.exit(1)
19 | })
20 |
--------------------------------------------------------------------------------
/src/config.ts:
--------------------------------------------------------------------------------
1 | import { Config } from './normalize'
2 |
3 | // export const defaultEndpoint = 'http://localhost:8080/api/ja'
4 | export const defaultEndpoint =
5 | 'https://japanese-addresses-v2.geoloniamaps.com/api/ja'
6 |
7 | export const currentConfig: Config = {
8 | japaneseAddressesApi: defaultEndpoint,
9 | cacheSize: 1_000,
10 | }
11 |
12 | export type FetchOptions = {
13 | offset?: number
14 | length?: number
15 | }
16 |
17 | export type FetchResponseLike = {
18 | json: () => Promise
19 | text: () => Promise
20 | ok: boolean
21 | }
22 |
23 | export type FetchLike = (
24 | input: string,
25 | options?: FetchOptions,
26 | ) => Promise
27 |
28 | /**
29 | * @internal
30 | */
31 | export const __internals: { fetch: FetchLike } = {
32 | // default fetch
33 | fetch: (input: string, options) => {
34 | const o = options || {}
35 | let url = new URL(
36 | `${currentConfig.japaneseAddressesApi}${input}`,
37 | ).toString()
38 | if (currentConfig.geoloniaApiKey) {
39 | url += `?geolonia-api-key=${currentConfig.geoloniaApiKey}`
40 | }
41 | const headers: HeadersInit = {}
42 | if (typeof o.length !== 'undefined' && typeof o.offset !== 'undefined') {
43 | headers['Range'] = `bytes=${o.offset}-${o.offset + o.length - 1}`
44 | }
45 | let globalFetch: typeof fetch
46 | if (typeof fetch !== 'undefined') {
47 | globalFetch = fetch
48 | } else if (typeof window !== 'undefined') {
49 | globalFetch = window.fetch
50 | } else {
51 | throw new Error('fetch is not available in this environment')
52 | }
53 | return globalFetch(url, {
54 | headers,
55 | })
56 | },
57 | }
58 |
--------------------------------------------------------------------------------
/src/lib/cacheRegexes.ts:
--------------------------------------------------------------------------------
1 | import { toRegexPattern } from './dict'
2 | import { kan2num } from './kan2num'
3 | import Papaparse from 'papaparse'
4 | import { LRUCache } from 'lru-cache'
5 | import { currentConfig, __internals } from '../config'
6 | import { findKanjiNumbers, kanji2number } from '@geolonia/japanese-numeral'
7 | import {
8 | cityName,
9 | LngLat,
10 | MachiAzaApi,
11 | machiAzaName,
12 | PrefectureApi,
13 | prefectureName,
14 | SingleChiban,
15 | SingleCity,
16 | SingleMachiAza,
17 | SinglePrefecture,
18 | SingleRsdt,
19 | } from '@geolonia/japanese-addresses-v2'
20 |
21 | export type PrefectureList = PrefectureApi
22 | // interface SingleTown {
23 | // town: string
24 | // originalTown?: string
25 | // koaza: string
26 | // lat: string
27 | // lng: string
28 | // }
29 | type SingleTown = SingleMachiAza
30 | export type TownList = MachiAzaApi
31 | interface SingleAddr {
32 | addr: string
33 | lat: string | null
34 | lng: string | null
35 | }
36 | export type AddrList = SingleAddr[]
37 |
38 | const cache = new LRUCache({
39 | max: currentConfig.cacheSize,
40 | })
41 |
42 | // eslint-disable-next-line @typescript-eslint/no-empty-object-type
43 | async function fetchFromCache(
44 | key: string,
45 | fetcher: () => Promise,
46 | ): Promise {
47 | let data = cache.get(key) as T | undefined
48 | if (typeof data !== 'undefined') {
49 | return data
50 | }
51 | data = await fetcher()
52 | cache.set(key, data)
53 | return data
54 | }
55 |
56 | let cachedPrefecturePatterns: [SinglePrefecture, string][] | undefined =
57 | undefined
58 | const cachedCityPatterns: Map = new Map()
59 | let cachedPrefectures: PrefectureList | undefined = undefined
60 | const cachedTowns: { [key: string]: TownList } = {}
61 | let cachedSameNamedPrefectureCityRegexPatterns: [string, string][] | undefined =
62 | undefined
63 |
64 | export const getPrefectures = async () => {
65 | if (typeof cachedPrefectures !== 'undefined') {
66 | return cachedPrefectures
67 | }
68 |
69 | const prefsResp = await __internals.fetch('.json', {}) // ja.json
70 | const data = (await prefsResp.json()) as PrefectureApi
71 | return cachePrefectures(data)
72 | }
73 |
74 | export const cachePrefectures = (data: PrefectureList) => {
75 | return (cachedPrefectures = data)
76 | }
77 |
78 | export const getPrefectureRegexPatterns = (api: PrefectureApi) => {
79 | if (cachedPrefecturePatterns) {
80 | return cachedPrefecturePatterns
81 | }
82 |
83 | const data = api.data
84 | cachedPrefecturePatterns = data.map<[SinglePrefecture, string]>((pref) => {
85 | const _pref = pref.pref.replace(/(都|道|府|県)$/, '') // `東京` の様に末尾の `都府県` が抜けた住所に対応
86 | const pattern = `^${_pref}(都|道|府|県)?`
87 | return [pref, pattern]
88 | })
89 |
90 | return cachedPrefecturePatterns
91 | }
92 |
93 | export const getCityRegexPatterns = (pref: SinglePrefecture) => {
94 | const cachedResult = cachedCityPatterns.get(pref.code)
95 | if (typeof cachedResult !== 'undefined') {
96 | return cachedResult
97 | }
98 |
99 | const cities = pref.cities
100 | // 少ない文字数の地名に対してミスマッチしないように文字の長さ順にソート
101 | cities.sort((a, b) => {
102 | return cityName(a).length - cityName(b).length
103 | })
104 |
105 | const patterns = cities.map<[SingleCity, string]>((city) => {
106 | const name = cityName(city)
107 | let pattern = `^${toRegexPattern(name)}`
108 | if (name.match(/(町|村)$/)) {
109 | pattern = `^${toRegexPattern(name).replace(/(.+?)郡/, '($1郡)?')}` // 郡が省略されてるかも
110 | }
111 | return [city, pattern]
112 | })
113 |
114 | cachedCityPatterns.set(pref.code, patterns)
115 | return patterns
116 | }
117 |
118 | export const getTowns = async (
119 | prefObj: SinglePrefecture,
120 | cityObj: SingleCity,
121 | apiVersion: number,
122 | ) => {
123 | const pref = prefectureName(prefObj)
124 | const city = cityName(cityObj)
125 |
126 | const cacheKey = `${pref}-${city}`
127 | const cachedTown = cachedTowns[cacheKey]
128 | if (typeof cachedTown !== 'undefined') {
129 | return cachedTown
130 | }
131 |
132 | const townsResp = await __internals.fetch(
133 | ['', encodeURI(pref), encodeURI(city) + `.json?v=${apiVersion}`].join('/'),
134 | {},
135 | )
136 | const towns = (await townsResp.json()) as MachiAzaApi
137 | return (cachedTowns[cacheKey] = towns)
138 | }
139 |
140 | type MetadataRow = { start: number; length: number }
141 |
142 | async function fetchSubresource(
143 | kind: '地番' | '住居表示',
144 | pref: SinglePrefecture,
145 | city: SingleCity,
146 | row: MetadataRow,
147 | apiVersion: number,
148 | ) {
149 | const prefN = prefectureName(pref)
150 | const cityN = cityName(city)
151 | const resp = await __internals.fetch(
152 | [
153 | '',
154 | encodeURI(prefN),
155 | encodeURI(`${cityN}-${kind}.txt?v=${apiVersion}`),
156 | ].join('/'),
157 | {
158 | offset: row.start,
159 | length: row.length,
160 | },
161 | )
162 | return resp.text()
163 | }
164 |
165 | type RsdtDataRow = {
166 | blk_num: string
167 | rsdt_num: string
168 | rsdt_num2: string
169 | lng: string
170 | lat: string
171 | }
172 | type ChibanDataRow = {
173 | prc_num1: string
174 | prc_num2: string
175 | prc_num3: string
176 | lng: string
177 | lat: string
178 | }
179 | function parseSubresource(
180 | data: string,
181 | ): T[] {
182 | const firstLineEnd = data.indexOf('\n')
183 | // const firstLine = data.slice(0, firstLineEnd)
184 | const rest = data.slice(firstLineEnd + 1)
185 | const lines = Papaparse.parse(rest, {
186 | header: true,
187 | }).data
188 | const out: T[] = []
189 | for (const line of lines) {
190 | const point: LngLat | undefined =
191 | line.lng && line.lat
192 | ? [parseFloat(line.lng), parseFloat(line.lat)]
193 | : undefined
194 | if ('blk_num' in line) {
195 | out.push({
196 | blk_num: line.blk_num,
197 | rsdt_num: line.rsdt_num,
198 | rsdt_num2: line.rsdt_num2,
199 | point: point,
200 | } as T)
201 | } else if ('prc_num1' in line) {
202 | out.push({
203 | prc_num1: line.prc_num1,
204 | prc_num2: line.prc_num2,
205 | prc_num3: line.prc_num3,
206 | point: point,
207 | } as T)
208 | }
209 | }
210 | return out
211 | }
212 |
213 | export const getRsdt = async (
214 | pref: SinglePrefecture,
215 | city: SingleCity,
216 | town: SingleTown,
217 | apiVersion: number,
218 | ) => {
219 | const row = town.csv_ranges?.住居表示
220 | if (!row) {
221 | return []
222 | }
223 |
224 | const parsed = await fetchFromCache(
225 | `住居表示-${pref.code}-${city.code}-${machiAzaName(town)}`,
226 | async () => {
227 | const data = await fetchSubresource(
228 | '住居表示',
229 | pref,
230 | city,
231 | row,
232 | apiVersion,
233 | )
234 | const parsed = parseSubresource(data)
235 | parsed.sort((a, b) => {
236 | const aStr = [a.blk_num, a.rsdt_num, a.rsdt_num2]
237 | .filter((a) => !!a)
238 | .join('-')
239 | const bStr = [b.blk_num, b.rsdt_num, b.rsdt_num2]
240 | .filter((a) => !!a)
241 | .join('-')
242 | return bStr.length - aStr.length
243 | })
244 | return parsed
245 | },
246 | )
247 | return parsed
248 | }
249 |
250 | export const getChiban = async (
251 | pref: SinglePrefecture,
252 | city: SingleCity,
253 | town: SingleTown,
254 | apiVersion: number,
255 | ) => {
256 | const row = town.csv_ranges?.地番
257 | if (!row) {
258 | return []
259 | }
260 |
261 | const parsed = await fetchFromCache(
262 | `地番-${pref.code}-${city.code}-${machiAzaName(town)}`,
263 | async () => {
264 | const data = await fetchSubresource('地番', pref, city, row, apiVersion)
265 | const parsed = parseSubresource(data)
266 | parsed.sort((a, b) => {
267 | const aStr = [a.prc_num1, a.prc_num2, a.prc_num3]
268 | .filter((a) => !!a)
269 | .join('-')
270 | const bStr = [b.prc_num1, b.prc_num2, b.prc_num3]
271 | .filter((a) => !!a)
272 | .join('-')
273 | return bStr.length - aStr.length
274 | })
275 | return parsed
276 | },
277 | )
278 |
279 | return parsed
280 | }
281 |
282 | // 十六町 のように漢数字と町が連結しているか
283 | const isKanjiNumberFollewedByCho = (targetTownName: string) => {
284 | const xCho = targetTownName.match(/.町/g)
285 | if (!xCho) return false
286 | const kanjiNumbers = findKanjiNumbers(xCho[0])
287 | return kanjiNumbers.length > 0
288 | }
289 |
290 | export const getTownRegexPatterns = async (
291 | pref: SinglePrefecture,
292 | city: SingleCity,
293 | apiVersion: number,
294 | ) =>
295 | fetchFromCache<[SingleTown, string][]>(
296 | `${pref.code}-${city.code}`,
297 | async () => {
298 | const api = await getTowns(pref, city, apiVersion)
299 | const pre_towns = api.data
300 | const townSet = new Set(pre_towns.map((town) => machiAzaName(town)))
301 | const towns: (
302 | | SingleMachiAza
303 | | (SingleMachiAza & { originalTown: SingleMachiAza })
304 | )[] = []
305 |
306 | const isKyoto = city.city === '京都市'
307 |
308 | // 町丁目に「○○町」が含まれるケースへの対応
309 | // 通常は「○○町」のうち「町」の省略を許容し同義語として扱うが、まれに自治体内に「○○町」と「○○」が共存しているケースがある。
310 | // この場合は町の省略は許容せず、入力された住所は書き分けられているものとして正規化を行う。
311 | // 更に、「愛知県名古屋市瑞穂区十六町1丁目」漢数字を含むケースだと丁目や番地・号の正規化が不可能になる。このようなケースも除外。
312 | for (const town of pre_towns) {
313 | towns.push(town)
314 |
315 | const originalTown = machiAzaName(town)
316 | if (originalTown.indexOf('町') === -1) continue
317 | const townAbbr = originalTown.replace(/(?!^町)町/g, '') // NOTE: 冒頭の「町」は明らかに省略するべきではないので、除外
318 | if (
319 | !isKyoto && // 京都は通り名削除の処理があるため、意図しないマッチになるケースがある。これを除く
320 | !townSet.has(townAbbr) &&
321 | !townSet.has(`大字${townAbbr}`) && // 大字は省略されるため、大字〇〇と〇〇町がコンフリクトする。このケースを除外
322 | !isKanjiNumberFollewedByCho(originalTown)
323 | ) {
324 | // エイリアスとして町なしのパターンを登録
325 | towns.push({
326 | machiaza_id: town.machiaza_id,
327 | point: town.point,
328 | oaza_cho: townAbbr,
329 | originalTown: town,
330 | })
331 | }
332 | }
333 |
334 | // 少ない文字数の地名に対してミスマッチしないように文字の長さ順にソート
335 | towns.sort((a, b) => {
336 | let aLen = machiAzaName(a).length
337 | let bLen = machiAzaName(b).length
338 |
339 | // 大字で始まる場合、優先度を低く設定する。
340 | // 大字XX と XXYY が存在するケースもあるので、 XXYY を先にマッチしたい
341 | if (machiAzaName(a).startsWith('大字')) aLen -= 2
342 | if (machiAzaName(b).startsWith('大字')) bLen -= 2
343 |
344 | return bLen - aLen
345 | })
346 |
347 | const patterns = towns.map<[SingleMachiAza, string]>((town) => {
348 | const pattern = toRegexPattern(
349 | machiAzaName(town)
350 | // 横棒を含む場合(流通センター、など)に対応
351 | .replace(/[--﹣−‐⁃‑‒–—﹘―⎯⏤ーー─━]/g, '[--﹣−‐⁃‑‒–—﹘―⎯⏤ーー─━]')
352 | .replace(/大?字/g, '(大?字)?')
353 | // 以下住所マスターの町丁目に含まれる数字を正規表現に変換する
354 | // ABRデータには大文字の数字が含まれている(第1地割、など)ので、数字も一致するようにする
355 | .replace(
356 | /([壱一二三四五六七八九十]+|[1234567890]+)(丁目?|番(町|丁)|条|軒|線|(の|ノ)町|地割|号)/g,
357 | (match: string) => {
358 | const patterns = []
359 |
360 | patterns.push(
361 | match
362 | .toString()
363 | .replace(
364 | /(丁目?|番(町|丁)|条|軒|線|(の|ノ)町|地割|号)/,
365 | '',
366 | ),
367 | ) // 漢数字
368 |
369 | if (match.match(/^壱/)) {
370 | patterns.push('一')
371 | patterns.push('1')
372 | patterns.push('1')
373 | } else {
374 | const num = match
375 | .replace(/([一二三四五六七八九十]+)/g, (match) => {
376 | return kan2num(match)
377 | })
378 | .replace(/([1234567890]+)/g, (match) => {
379 | return kanji2number(match).toString()
380 | })
381 | .replace(/(丁目?|番(町|丁)|条|軒|線|(の|ノ)町|地割|号)/, '')
382 |
383 | patterns.push(num.toString()) // 半角アラビア数字
384 | }
385 |
386 | // 以下の正規表現は、上のよく似た正規表現とは違うことに注意!
387 | const _pattern = `(${patterns.join(
388 | '|',
389 | )})((丁|町)目?|番(町|丁)|条|軒|線|の町?|地割|号|[--﹣−‐⁃‑‒–—﹘―⎯⏤ーー─━])`
390 | // if (city === '下閉伊郡普代村' && town.machiaza_id === '0022000') {
391 | // console.log(_pattern)
392 | // }
393 | return _pattern // デバッグのときにめんどくさいので変数に入れる。
394 | },
395 | ),
396 | )
397 | return ['originalTown' in town ? town.originalTown : town, pattern]
398 | })
399 |
400 | // X丁目の丁目なしの数字だけ許容するため、最後に数字だけ追加していく
401 | for (const town of towns) {
402 | const chomeMatch = machiAzaName(town).match(
403 | /([^一二三四五六七八九十]+)([一二三四五六七八九十]+)(丁目?)/,
404 | )
405 | if (!chomeMatch) {
406 | continue
407 | }
408 | const chomeNamePart = chomeMatch[1]
409 | const chomeNum = chomeMatch[2]
410 | const pattern = toRegexPattern(
411 | `^${chomeNamePart}(${chomeNum}|${kan2num(chomeNum)})`,
412 | )
413 | patterns.push([town, pattern])
414 | }
415 |
416 | return patterns
417 | },
418 | )
419 |
420 | export const getSameNamedPrefectureCityRegexPatterns = (
421 | prefApi: PrefectureApi,
422 | ) => {
423 | if (typeof cachedSameNamedPrefectureCityRegexPatterns !== 'undefined') {
424 | return cachedSameNamedPrefectureCityRegexPatterns
425 | }
426 |
427 | const prefList = prefApi.data
428 | const _prefs = prefList.map((pref) => {
429 | return pref.pref.replace(/[都|道|府|県]$/, '')
430 | })
431 |
432 | cachedSameNamedPrefectureCityRegexPatterns = []
433 | for (const pref of prefList) {
434 | for (const city of pref.cities) {
435 | const cityN = cityName(city)
436 |
437 | // 「福島県石川郡石川町」のように、市の名前が別の都道府県名から始まっているケースも考慮する。
438 | for (let j = 0; j < _prefs.length; j++) {
439 | if (cityN.indexOf(_prefs[j]) === 0) {
440 | cachedSameNamedPrefectureCityRegexPatterns.push([
441 | `${pref.pref}${cityN}`,
442 | `^${cityN}`,
443 | ])
444 | }
445 | }
446 | }
447 | }
448 |
449 | return cachedSameNamedPrefectureCityRegexPatterns
450 | }
451 |
--------------------------------------------------------------------------------
/src/lib/dict.ts:
--------------------------------------------------------------------------------
1 | import { convert } from './dictionaries/convert'
2 |
3 | export const toRegexPattern = (string: string) => {
4 | let _str = string
5 |
6 | // 以下なるべく文字数が多いものほど上にすること
7 | _str = _str
8 | .replace(/三栄町|四谷三栄町/g, '(三栄町|四谷三栄町)')
9 | .replace(/鬮野川|くじ野川|くじの川/g, '(鬮野川|くじ野川|くじの川)')
10 | .replace(/柿碕町|柿さき町/g, '(柿碕町|柿さき町)')
11 | .replace(/通り|とおり/g, '(通り|とおり)')
12 | .replace(/埠頭|ふ頭/g, '(埠頭|ふ頭)')
13 | .replace(/番町|番丁/g, '(番町|番丁)')
14 | .replace(/大冝|大宜/g, '(大冝|大宜)')
15 | .replace(/穝|さい/g, '(穝|さい)')
16 | .replace(/杁|えぶり/g, '(杁|えぶり)')
17 | .replace(/薭|稗|ひえ|ヒエ/g, '(薭|稗|ひえ|ヒエ)')
18 | .replace(/[之ノの]/g, '[之ノの]')
19 | .replace(/[ヶケが]/g, '[ヶケが]')
20 | .replace(/[ヵカか力]/g, '[ヵカか力]')
21 | .replace(/[ッツっつ]/g, '[ッツっつ]')
22 | .replace(/[ニ二]/g, '[ニ二]')
23 | .replace(/[ハ八]/g, '[ハ八]')
24 | .replace(/塚|塚/g, '(塚|塚)')
25 | .replace(/釜|竈/g, '(釜|竈)')
26 | .replace(/條|条/g, '(條|条)')
27 | .replace(/狛|拍/g, '(狛|拍)')
28 | .replace(/藪|薮/g, '(藪|薮)')
29 | .replace(/渕|淵/g, '(渕|淵)')
30 | .replace(/エ|ヱ|え/g, '(エ|ヱ|え)')
31 | .replace(/曾|曽/g, '(曾|曽)')
32 | .replace(/舟|船/g, '(舟|船)')
33 | .replace(/莵|菟/g, '(莵|菟)')
34 | .replace(/市|巿/g, '(市|巿)')
35 | .replace(/崎|﨑/g, '(崎|﨑)')
36 |
37 | _str = convert(_str)
38 |
39 | return _str
40 | }
41 |
--------------------------------------------------------------------------------
/src/lib/dictionaries/convert.ts:
--------------------------------------------------------------------------------
1 | import { dictionary } from './dictionary'
2 |
3 | type PatternMap = { [key: string]: string }
4 | const patternMap = dictionary.reduce((acc: PatternMap, dictionary) => {
5 | const pattern = `(${dictionary.src}|${dictionary.dst})`
6 | // { 亞: '(亞|亜)', 亜: '(亞|亜)', 圍: '(圍|囲)', 囲: '(圍|囲)', ...}
7 | return { ...acc, [dictionary.src]: pattern, [dictionary.dst]: pattern }
8 | }, {})
9 |
10 | const regexp = new RegExp(
11 | Array.from(new Set(Object.values(patternMap))).join('|'),
12 | 'g',
13 | )
14 |
15 | export const convert = (regexText: string) =>
16 | regexText.replace(regexp, (match) => patternMap[match])
17 |
--------------------------------------------------------------------------------
/src/lib/dictionaries/dictionary.ts:
--------------------------------------------------------------------------------
1 | import { jisDai2Dictionary } from './jisDai2'
2 |
3 | export type Dictionary = { src: string; dst: string }
4 |
5 | export const dictionary = [
6 | jisDai2Dictionary,
7 | // Add more dictionary here
8 | // exmapleDictionary,
9 | ].flat()
10 |
--------------------------------------------------------------------------------
/src/lib/dictionaries/jisDai2.ts:
--------------------------------------------------------------------------------
1 | import { Dictionary } from './dictionary'
2 |
3 | // JIS 第2水準 => 第1水準 及び 旧字体 => 新字体
4 | export const jisDai2Dictionary: Dictionary[] = [
5 | { src: '亞', dst: '亜' },
6 | { src: '圍', dst: '囲' },
7 | { src: '壹', dst: '壱' },
8 | { src: '榮', dst: '栄' },
9 | { src: '驛', dst: '駅' },
10 | { src: '應', dst: '応' },
11 | { src: '櫻', dst: '桜' },
12 | { src: '假', dst: '仮' },
13 | { src: '會', dst: '会' },
14 | { src: '懷', dst: '懐' },
15 | { src: '覺', dst: '覚' },
16 | { src: '樂', dst: '楽' },
17 | { src: '陷', dst: '陥' },
18 | { src: '歡', dst: '歓' },
19 | { src: '氣', dst: '気' },
20 | { src: '戲', dst: '戯' },
21 | { src: '據', dst: '拠' },
22 | { src: '挾', dst: '挟' },
23 | { src: '區', dst: '区' },
24 | { src: '徑', dst: '径' },
25 | { src: '溪', dst: '渓' },
26 | { src: '輕', dst: '軽' },
27 | { src: '藝', dst: '芸' },
28 | { src: '儉', dst: '倹' },
29 | { src: '圈', dst: '圏' },
30 | { src: '權', dst: '権' },
31 | { src: '嚴', dst: '厳' },
32 | { src: '恆', dst: '恒' },
33 | { src: '國', dst: '国' },
34 | { src: '齋', dst: '斎' },
35 | { src: '雜', dst: '雑' },
36 | { src: '蠶', dst: '蚕' },
37 | { src: '殘', dst: '残' },
38 | { src: '兒', dst: '児' },
39 | { src: '實', dst: '実' },
40 | { src: '釋', dst: '釈' },
41 | { src: '從', dst: '従' },
42 | { src: '縱', dst: '縦' },
43 | { src: '敍', dst: '叙' },
44 | { src: '燒', dst: '焼' },
45 | { src: '條', dst: '条' },
46 | { src: '剩', dst: '剰' },
47 | { src: '壤', dst: '壌' },
48 | { src: '釀', dst: '醸' },
49 | { src: '眞', dst: '真' },
50 | { src: '盡', dst: '尽' },
51 | { src: '醉', dst: '酔' },
52 | { src: '髓', dst: '髄' },
53 | { src: '聲', dst: '声' },
54 | { src: '竊', dst: '窃' },
55 | { src: '淺', dst: '浅' },
56 | { src: '錢', dst: '銭' },
57 | { src: '禪', dst: '禅' },
58 | { src: '爭', dst: '争' },
59 | { src: '插', dst: '挿' },
60 | { src: '騷', dst: '騒' },
61 | { src: '屬', dst: '属' },
62 | { src: '對', dst: '対' },
63 | { src: '滯', dst: '滞' },
64 | { src: '擇', dst: '択' },
65 | { src: '單', dst: '単' },
66 | { src: '斷', dst: '断' },
67 | { src: '癡', dst: '痴' },
68 | { src: '鑄', dst: '鋳' },
69 | { src: '敕', dst: '勅' },
70 | { src: '鐵', dst: '鉄' },
71 | { src: '傳', dst: '伝' },
72 | { src: '黨', dst: '党' },
73 | { src: '鬪', dst: '闘' },
74 | { src: '屆', dst: '届' },
75 | { src: '腦', dst: '脳' },
76 | { src: '廢', dst: '廃' },
77 | { src: '發', dst: '発' },
78 | { src: '蠻', dst: '蛮' },
79 | { src: '拂', dst: '払' },
80 | { src: '邊', dst: '辺' },
81 | { src: '瓣', dst: '弁' },
82 | { src: '寶', dst: '宝' },
83 | { src: '沒', dst: '没' },
84 | { src: '滿', dst: '満' },
85 | { src: '藥', dst: '薬' },
86 | { src: '餘', dst: '余' },
87 | { src: '樣', dst: '様' },
88 | { src: '亂', dst: '乱' },
89 | { src: '兩', dst: '両' },
90 | { src: '禮', dst: '礼' },
91 | { src: '靈', dst: '霊' },
92 | { src: '爐', dst: '炉' },
93 | { src: '灣', dst: '湾' },
94 | { src: '惡', dst: '悪' },
95 | { src: '醫', dst: '医' },
96 | { src: '飮', dst: '飲' },
97 | { src: '營', dst: '営' },
98 | { src: '圓', dst: '円' },
99 | { src: '歐', dst: '欧' },
100 | { src: '奧', dst: '奥' },
101 | { src: '價', dst: '価' },
102 | { src: '繪', dst: '絵' },
103 | { src: '擴', dst: '拡' },
104 | { src: '學', dst: '学' },
105 | { src: '罐', dst: '缶' },
106 | { src: '勸', dst: '勧' },
107 | { src: '觀', dst: '観' },
108 | { src: '歸', dst: '帰' },
109 | { src: '犧', dst: '犠' },
110 | { src: '擧', dst: '挙' },
111 | { src: '狹', dst: '狭' },
112 | { src: '驅', dst: '駆' },
113 | { src: '莖', dst: '茎' },
114 | { src: '經', dst: '経' },
115 | { src: '繼', dst: '継' },
116 | { src: '缺', dst: '欠' },
117 | { src: '劍', dst: '剣' },
118 | { src: '檢', dst: '検' },
119 | { src: '顯', dst: '顕' },
120 | { src: '廣', dst: '広' },
121 | { src: '鑛', dst: '鉱' },
122 | { src: '碎', dst: '砕' },
123 | { src: '劑', dst: '剤' },
124 | { src: '參', dst: '参' },
125 | { src: '慘', dst: '惨' },
126 | { src: '絲', dst: '糸' },
127 | { src: '辭', dst: '辞' },
128 | { src: '舍', dst: '舎' },
129 | { src: '壽', dst: '寿' },
130 | { src: '澁', dst: '渋' },
131 | { src: '肅', dst: '粛' },
132 | { src: '將', dst: '将' },
133 | { src: '證', dst: '証' },
134 | { src: '乘', dst: '乗' },
135 | { src: '疊', dst: '畳' },
136 | { src: '孃', dst: '嬢' },
137 | { src: '觸', dst: '触' },
138 | { src: '寢', dst: '寝' },
139 | { src: '圖', dst: '図' },
140 | { src: '穗', dst: '穂' },
141 | { src: '樞', dst: '枢' },
142 | { src: '齊', dst: '斉' },
143 | { src: '攝', dst: '摂' },
144 | { src: '戰', dst: '戦' },
145 | { src: '潛', dst: '潜' },
146 | { src: '雙', dst: '双' },
147 | { src: '莊', dst: '荘' },
148 | { src: '裝', dst: '装' },
149 | { src: '藏', dst: '蔵' },
150 | { src: '續', dst: '続' },
151 | { src: '體', dst: '体' },
152 | { src: '臺', dst: '台' },
153 | { src: '澤', dst: '沢' },
154 | { src: '膽', dst: '胆' },
155 | { src: '彈', dst: '弾' },
156 | { src: '蟲', dst: '虫' },
157 | { src: '廳', dst: '庁' },
158 | { src: '鎭', dst: '鎮' },
159 | { src: '點', dst: '点' },
160 | { src: '燈', dst: '灯' },
161 | { src: '盜', dst: '盗' },
162 | { src: '獨', dst: '独' },
163 | { src: '貳', dst: '弐' },
164 | { src: '霸', dst: '覇' },
165 | { src: '賣', dst: '売' },
166 | { src: '髮', dst: '髪' },
167 | { src: '祕', dst: '秘' },
168 | { src: '佛', dst: '仏' },
169 | { src: '變', dst: '変' },
170 | { src: '辯', dst: '弁' },
171 | { src: '豐', dst: '豊' },
172 | { src: '飜', dst: '翻' },
173 | { src: '默', dst: '黙' },
174 | { src: '與', dst: '与' },
175 | { src: '譽', dst: '誉' },
176 | { src: '謠', dst: '謡' },
177 | { src: '覽', dst: '覧' },
178 | { src: '獵', dst: '猟' },
179 | { src: '勵', dst: '励' },
180 | { src: '齡', dst: '齢' },
181 | { src: '勞', dst: '労' },
182 | { src: '壓', dst: '圧' },
183 | { src: '爲', dst: '為' },
184 | { src: '隱', dst: '隠' },
185 | { src: '衞', dst: '衛' },
186 | { src: '鹽', dst: '塩' },
187 | { src: '毆', dst: '殴' },
188 | { src: '穩', dst: '穏' },
189 | { src: '畫', dst: '画' },
190 | { src: '壞', dst: '壊' },
191 | { src: '殼', dst: '殻' },
192 | { src: '嶽', dst: '岳' },
193 | { src: '卷', dst: '巻' },
194 | { src: '關', dst: '関' },
195 | { src: '顏', dst: '顔' },
196 | { src: '僞', dst: '偽' },
197 | { src: '舊', dst: '旧' },
198 | { src: '峽', dst: '峡' },
199 | { src: '曉', dst: '暁' },
200 | { src: '勳', dst: '勲' },
201 | { src: '惠', dst: '恵' },
202 | { src: '螢', dst: '蛍' },
203 | { src: '鷄', dst: '鶏' },
204 | { src: '縣', dst: '県' },
205 | { src: '險', dst: '険' },
206 | { src: '獻', dst: '献' },
207 | { src: '驗', dst: '験' },
208 | { src: '效', dst: '効' },
209 | { src: '號', dst: '号' },
210 | { src: '濟', dst: '済' },
211 | { src: '册', dst: '冊' },
212 | { src: '棧', dst: '桟' },
213 | { src: '贊', dst: '賛' },
214 | { src: '齒', dst: '歯' },
215 | { src: '濕', dst: '湿' },
216 | { src: '寫', dst: '写' },
217 | { src: '收', dst: '収' },
218 | { src: '獸', dst: '獣' },
219 | { src: '處', dst: '処' },
220 | { src: '稱', dst: '称' },
221 | { src: '奬', dst: '奨' },
222 | { src: '淨', dst: '浄' },
223 | { src: '繩', dst: '縄' },
224 | { src: '讓', dst: '譲' },
225 | { src: '囑', dst: '嘱' },
226 | { src: '愼', dst: '慎' },
227 | { src: '粹', dst: '粋' },
228 | { src: '隨', dst: '随' },
229 | { src: '數', dst: '数' },
230 | { src: '靜', dst: '静' },
231 | { src: '專', dst: '専' },
232 | { src: '踐', dst: '践' },
233 | { src: '纖', dst: '繊' },
234 | { src: '壯', dst: '壮' },
235 | { src: '搜', dst: '捜' },
236 | { src: '總', dst: '総' },
237 | { src: '臟', dst: '臓' },
238 | { src: '墮', dst: '堕' },
239 | { src: '帶', dst: '帯' },
240 | { src: '瀧', dst: '滝' },
241 | { src: '擔', dst: '担' },
242 | { src: '團', dst: '団' },
243 | { src: '遲', dst: '遅' },
244 | { src: '晝', dst: '昼' },
245 | { src: '聽', dst: '聴' },
246 | { src: '遞', dst: '逓' },
247 | { src: '轉', dst: '転' },
248 | { src: '當', dst: '当' },
249 | { src: '稻', dst: '稲' },
250 | { src: '讀', dst: '読' },
251 | { src: '惱', dst: '悩' },
252 | { src: '拜', dst: '拝' },
253 | { src: '麥', dst: '麦' },
254 | { src: '拔', dst: '抜' },
255 | { src: '濱', dst: '浜' },
256 | { src: '竝', dst: '並' },
257 | { src: '辨', dst: '弁' },
258 | { src: '舖', dst: '舗' },
259 | { src: '襃', dst: '褒' },
260 | { src: '萬', dst: '万' },
261 | { src: '譯', dst: '訳' },
262 | { src: '豫', dst: '予' },
263 | { src: '搖', dst: '揺' },
264 | { src: '來', dst: '来' },
265 | { src: '龍', dst: '竜' },
266 | { src: '壘', dst: '塁' },
267 | { src: '隸', dst: '隷' },
268 | { src: '戀', dst: '恋' },
269 | { src: '樓', dst: '楼' },
270 | { src: '鰺', dst: '鯵' },
271 | { src: '鶯', dst: '鴬' },
272 | { src: '蠣', dst: '蛎' },
273 | { src: '攪', dst: '撹' },
274 | { src: '竈', dst: '竃' },
275 | { src: '灌', dst: '潅' },
276 | { src: '諫', dst: '諌' },
277 | { src: '頸', dst: '頚' },
278 | { src: '礦', dst: '砿' },
279 | { src: '蘂', dst: '蕊' },
280 | { src: '靱', dst: '靭' },
281 | { src: '賤', dst: '賎' },
282 | { src: '壺', dst: '壷' },
283 | { src: '礪', dst: '砺' },
284 | { src: '檮', dst: '梼' },
285 | { src: '濤', dst: '涛' },
286 | { src: '邇', dst: '迩' },
287 | { src: '蠅', dst: '蝿' },
288 | { src: '檜', dst: '桧' },
289 | { src: '儘', dst: '侭' },
290 | { src: '藪', dst: '薮' },
291 | { src: '籠', dst: '篭' },
292 | { src: '彌', dst: '弥' },
293 | { src: '麩', dst: '麸' },
294 | { src: '驒', dst: '騨' },
295 | ]
296 |
--------------------------------------------------------------------------------
/src/lib/kan2num.ts:
--------------------------------------------------------------------------------
1 | import { kanji2number, findKanjiNumbers } from '@geolonia/japanese-numeral'
2 |
3 | export const kan2num = (string: string) => {
4 | const kanjiNumbers = findKanjiNumbers(string)
5 | for (let i = 0; i < kanjiNumbers.length; i++) {
6 | try {
7 | // @ts-ignore
8 | string = string.replace(kanjiNumbers[i], kanji2number(kanjiNumbers[i]))
9 | // eslint-disable-next-line @typescript-eslint/no-unused-vars
10 | } catch (error) {
11 | // ignore
12 | }
13 | }
14 |
15 | return string
16 | }
17 |
--------------------------------------------------------------------------------
/src/lib/normalizeHelpers.ts:
--------------------------------------------------------------------------------
1 | import { zen2han } from './zen2han'
2 |
3 | /**
4 | * 入力された住所に対して以下の正規化を予め行う。
5 | *
6 | * 1. `1-2-3` や `四-五-六` のようなフォーマットのハイフンを半角に統一。
7 | * 2. 町丁目以前にあるスペースをすべて削除。
8 | * 3. 最初に出てくる `1-` や `五-` のような文字列を町丁目とみなして、それ以前のスペースをすべて削除する。
9 | */
10 | export function prenormalize(input: string): string {
11 | return (
12 | input
13 | .normalize('NFC')
14 | .replace(/ /g, ' ')
15 | .replace(/ +/g, ' ')
16 | .replace(/([0-9A-Za-z]+)/g, (match) => {
17 | // 全角のアラビア数字は問答無用で半角にする
18 | return zen2han(match)
19 | })
20 | // 数字の後または数字の前にくる横棒はハイフンに統一する
21 | .replace(
22 | /([0-90-9一二三四五六七八九〇十百千][--﹣−‐⁃‑‒–—﹘―⎯⏤ーー─━])|([--﹣−‐⁃‑‒–—﹘―⎯⏤ーー─━])[0-90-9一二三四五六七八九〇十]/g,
23 | (match) => {
24 | return match.replace(/[--﹣−‐⁃‑‒–—﹘―⎯⏤ーー─━]/g, '-')
25 | },
26 | )
27 | .replace(/(.+)(丁目?|番(町|地|丁)|条|軒|線|(の|ノ)町|地割)/, (match) => {
28 | return match.replace(/ /g, '') // 町丁目名以前のスペースはすべて削除
29 | })
30 | .replace(/(.+)((郡.+(町|村))|((市|巿).+(区|區)))/, (match) => {
31 | return match.replace(/ /g, '') // 区、郡以前のスペースはすべて削除
32 | })
33 | .replace(/.+?[0-9一二三四五六七八九〇十百千]-/, (match) => {
34 | return match.replace(/ /g, '') // 1番はじめに出てくるアラビア数字以前のスペースを削除
35 | })
36 | )
37 | }
38 |
--------------------------------------------------------------------------------
/src/lib/patchAddr.ts:
--------------------------------------------------------------------------------
1 | const addrPatches = [
2 | {
3 | pref: '香川県',
4 | city: '仲多度郡まんのう町',
5 | town: '勝浦',
6 | pattern: '^字?家[6六]',
7 | result: '家六',
8 | },
9 | {
10 | pref: '愛知県',
11 | city: 'あま市',
12 | town: '西今宿',
13 | pattern: '^字?梶村[1一]',
14 | result: '梶村一',
15 | },
16 | {
17 | pref: '香川県',
18 | city: '丸亀市',
19 | town: '原田町',
20 | pattern: '^字?東三分[1一]',
21 | result: '東三分一',
22 | },
23 | ]
24 |
25 | export const patchAddr = (
26 | prefName: string,
27 | cityName: string,
28 | townName: string,
29 | addr: string,
30 | ): string => {
31 | let _addr = addr
32 | for (let i = 0; i < addrPatches.length; i++) {
33 | const patch = addrPatches[i]
34 | if (
35 | patch.pref === prefName &&
36 | patch.city === cityName &&
37 | patch.town === townName
38 | ) {
39 | _addr = _addr.replace(new RegExp(patch.pattern), patch.result)
40 | }
41 | }
42 |
43 | return _addr
44 | }
45 |
--------------------------------------------------------------------------------
/src/lib/utils.ts:
--------------------------------------------------------------------------------
1 | import {
2 | SingleCity,
3 | SingleMachiAza,
4 | SinglePrefecture,
5 | } from '@geolonia/japanese-addresses-v2'
6 |
7 | export function removeCitiesFromPrefecture(
8 | pref: SinglePrefecture | undefined,
9 | ): Omit | undefined {
10 | if (!pref) {
11 | return undefined
12 | }
13 |
14 | const newPref: Omit & { cities?: SingleCity[] } =
15 | {
16 | ...pref,
17 | }
18 | delete newPref.cities
19 | return newPref
20 | }
21 |
22 | export function removeExtraFromMachiAza(
23 | machiAza: SingleMachiAza | undefined,
24 | ): Omit | undefined {
25 | if (!machiAza) {
26 | return undefined
27 | }
28 |
29 | const newMachiAza: SingleMachiAza = { ...machiAza }
30 | delete newMachiAza.csv_ranges
31 | return newMachiAza
32 | }
33 |
--------------------------------------------------------------------------------
/src/lib/zen2han.ts:
--------------------------------------------------------------------------------
1 | export const zen2han = (str: string) => {
2 | return str.replace(/[A-Za-z0-9]/g, (s) => {
3 | return String.fromCharCode(s.charCodeAt(0) - 0xfee0)
4 | })
5 | }
6 |
--------------------------------------------------------------------------------
/src/main-node.ts:
--------------------------------------------------------------------------------
1 | import * as Normalize from './normalize'
2 | import { __internals, FetchOptions, FetchResponseLike } from './config'
3 | import { promises as fs } from 'node:fs'
4 | import { fetch } from 'undici'
5 |
6 | export type { NormalizeResult } from './types'
7 |
8 | export const requestHandlers = {
9 | file: async (fileURL: URL, options?: FetchOptions) => {
10 | const o = options || {}
11 | const filePath =
12 | process.platform === 'win32'
13 | ? decodeURI(fileURL.pathname).substring(1)
14 | : decodeURI(fileURL.pathname)
15 | const f = await fs.open(filePath, 'r')
16 | let contents: Buffer, ok: boolean
17 | if (typeof o.length !== 'undefined' && typeof o.offset !== 'undefined') {
18 | contents = Buffer.alloc(o.length)
19 | const resp = await f.read(contents, 0, o.length, o.offset)
20 | ok = resp.bytesRead === o.length
21 | } else {
22 | contents = await f.readFile()
23 | ok = true
24 | }
25 | await f.close()
26 | return {
27 | json: async () => {
28 | return JSON.parse(contents.toString('utf-8'))
29 | },
30 | text: async () => {
31 | return contents.toString('utf-8')
32 | },
33 | ok,
34 | }
35 | },
36 | http: (fileURL: URL, options?: FetchOptions) => {
37 | const o = options || {}
38 | if (Normalize.config.geoloniaApiKey) {
39 | fileURL.search = `?geolonia-api-key=${Normalize.config.geoloniaApiKey}`
40 | }
41 | const headers: HeadersInit = {
42 | 'User-Agent':
43 | 'normalize-japanese-addresses/0.1 (+https://github.com/geolonia/normalize-japanese-addresses/)',
44 | }
45 | if (typeof o.length !== 'undefined' && typeof o.offset !== 'undefined') {
46 | headers['Range'] = `bytes=${o.offset}-${o.offset + o.length - 1}`
47 | }
48 | return fetch(fileURL.toString(), {
49 | headers,
50 | })
51 | },
52 | }
53 |
54 | /**
55 | * 正規化のためのデータを取得する
56 | * @param input - Path part like '東京都/文京区.json'
57 | * @param requestOptions - input を構造化したデータ
58 | */
59 | const fetchOrReadFile = async (
60 | input: string,
61 | options?: FetchOptions,
62 | ): Promise => {
63 | const fileURL = new URL(`${Normalize.config.japaneseAddressesApi}${input}`)
64 | if (fileURL.protocol === 'http:' || fileURL.protocol === 'https:') {
65 | return requestHandlers.http(fileURL, options)
66 | } else if (fileURL.protocol === 'file:') {
67 | return requestHandlers.file(fileURL, options)
68 | } else {
69 | throw new Error(`Unknown URL schema: ${fileURL.protocol}`)
70 | }
71 | }
72 |
73 | __internals.fetch = fetchOrReadFile
74 | export const version = Normalize.version
75 | export const config = Normalize.config
76 | export const normalize = Normalize.normalize
77 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import * as Normalize from './normalize'
2 |
3 | export type { NormalizeResult } from './types'
4 |
5 | export const version = Normalize.version
6 | export const config = Normalize.config
7 | export const normalize = Normalize.normalize
8 |
--------------------------------------------------------------------------------
/src/normalize.ts:
--------------------------------------------------------------------------------
1 | import { number2kanji } from '@geolonia/japanese-numeral'
2 | import { currentConfig } from './config'
3 | import { kan2num } from './lib/kan2num'
4 | import { zen2han } from './lib/zen2han'
5 | import { patchAddr } from './lib/patchAddr'
6 | import {
7 | getPrefectures,
8 | getPrefectureRegexPatterns,
9 | getCityRegexPatterns,
10 | getTownRegexPatterns,
11 | getSameNamedPrefectureCityRegexPatterns,
12 | getRsdt,
13 | getChiban,
14 | } from './lib/cacheRegexes'
15 | import {
16 | chibanToString,
17 | cityName,
18 | machiAzaName,
19 | prefectureName,
20 | rsdtToString,
21 | SingleChiban,
22 | SingleCity,
23 | SingleMachiAza,
24 | SinglePrefecture,
25 | SingleRsdt,
26 | } from '@geolonia/japanese-addresses-v2'
27 | import { prenormalize } from './lib/normalizeHelpers'
28 | import {
29 | cityToResultPoint,
30 | machiAzaToResultPoint,
31 | NormalizeResult,
32 | NormalizeResultPoint,
33 | prefectureToResultPoint,
34 | rsdtOrChibanToResultPoint,
35 | upgradePoint,
36 | } from './types'
37 | import {
38 | removeCitiesFromPrefecture,
39 | removeExtraFromMachiAza,
40 | } from './lib/utils'
41 |
42 | export type TransformRequestQuery = {
43 | level: number // level = -1 は旧 API。 transformRequestFunction を設定しても無視する
44 | pref?: string
45 | city?: string
46 | town?: string
47 | }
48 |
49 | const __VERSION__: string = 'dev'
50 | export const version = __VERSION__
51 |
52 | /**
53 | * normalize {@link Normalizer} の動作オプション。
54 | */
55 | export interface Config {
56 | /** 住所データを URL 形式で指定。 file:// 形式で指定するとローカルファイルを参照できます。 */
57 | japaneseAddressesApi: string
58 |
59 | /** 内部キャッシュの最大サイズ。デフォルトでは 1,000 件 */
60 | cacheSize: number
61 |
62 | geoloniaApiKey?: string
63 | }
64 | export const config: Config = currentConfig
65 |
66 | /**
67 | * 正規化関数の {@link normalize} のオプション
68 | */
69 | export interface Option {
70 | /**
71 | * 希望最大正規化を行うレベルを指定します。{@link Option.level}
72 | *
73 | * @see https://github.com/geolonia/normalize-japanese-addresses#normalizeaddress-string
74 | */
75 | level?: number
76 |
77 | geoloniaApiKey?: string
78 | }
79 |
80 | /**
81 | * 住所を正規化します。
82 | *
83 | * @param input - 住所文字列
84 | * @param option - 正規化のオプション {@link Option}
85 | *
86 | * @returns 正規化結果のオブジェクト {@link NormalizeResult}
87 | *
88 | * @see https://github.com/geolonia/normalize-japanese-addresses#normalizeaddress-string
89 | */
90 | export type Normalizer = (
91 | input: string,
92 | option?: Option,
93 | ) => Promise
94 |
95 | const defaultOption = {
96 | level: 8,
97 | }
98 |
99 | const normalizeTownName = async (
100 | input: string,
101 | pref: SinglePrefecture,
102 | city: SingleCity,
103 | apiVersion: number,
104 | ) => {
105 | input = input.trim().replace(/^大字/, '')
106 | const townPatterns = await getTownRegexPatterns(pref, city, apiVersion)
107 |
108 | const regexPrefixes = ['^']
109 | if (city.city === '京都市') {
110 | // 京都は通り名削除のために後方一致を使う
111 | regexPrefixes.push('.*')
112 | }
113 |
114 | for (const regexPrefix of regexPrefixes) {
115 | for (const [town, pattern] of townPatterns) {
116 | const regex = new RegExp(`${regexPrefix}${pattern}`)
117 | const match = input.match(regex)
118 | if (match) {
119 | return {
120 | town,
121 | other: input.substring(match[0].length),
122 | }
123 | }
124 | }
125 | }
126 | }
127 |
128 | type NormalizedAddrPart = {
129 | chiban?: SingleChiban
130 | rsdt?: SingleRsdt
131 | rest: string
132 | }
133 | async function normalizeAddrPart(
134 | addr: string,
135 | pref: SinglePrefecture,
136 | city: SingleCity,
137 | town: SingleMachiAza,
138 | apiVersion: number,
139 | ): Promise {
140 | const match = addr.match(
141 | /^([1-9][0-9]*)(?:-([1-9][0-9]*))?(?:-([1-9][0-9]*))?/,
142 | )
143 | if (!match) {
144 | return {
145 | rest: addr,
146 | }
147 | }
148 | // TODO: rsdtの場合はrsdtと地番を両方取得する
149 | if (town.rsdt) {
150 | const res = await getRsdt(pref, city, town, apiVersion)
151 | for (const rsdt of res) {
152 | const addrPart = rsdtToString(rsdt)
153 | if (match[0] === addrPart) {
154 | return {
155 | rsdt,
156 | rest: addr.substring(addrPart.length),
157 | }
158 | }
159 | }
160 | } else {
161 | const res = await getChiban(pref, city, town, apiVersion)
162 | for (const chiban of res) {
163 | const addrPart = chibanToString(chiban)
164 | if (match[0] === addrPart) {
165 | return {
166 | chiban,
167 | rest: addr.substring(addrPart.length),
168 | }
169 | }
170 | }
171 | }
172 | return {
173 | rest: addr,
174 | }
175 | }
176 |
177 | export const normalize: Normalizer = async (
178 | address,
179 | _option = defaultOption,
180 | ) => {
181 | const option = { ...defaultOption, ..._option }
182 |
183 | option.geoloniaApiKey ??= config.geoloniaApiKey
184 |
185 | // other に入っている文字列は正規化するときに
186 | let other = prenormalize(address)
187 |
188 | let pref: SinglePrefecture | undefined
189 | let city: SingleCity | undefined
190 | let town: SingleMachiAza | undefined
191 | let point: NormalizeResultPoint | undefined
192 | let addr: string | undefined
193 | let level = 0
194 |
195 | // 都道府県名の正規化
196 |
197 | const prefectures = await getPrefectures()
198 | const apiVersion = prefectures.meta.updated
199 | const prefPatterns = getPrefectureRegexPatterns(prefectures)
200 | const sameNamedPrefectureCityRegexPatterns =
201 | getSameNamedPrefectureCityRegexPatterns(prefectures)
202 |
203 | // 県名が省略されており、かつ市の名前がどこかの都道府県名と同じ場合(例.千葉県千葉市)、
204 | // あらかじめ県名を補完しておく。
205 | for (const [prefectureCity, reg] of sameNamedPrefectureCityRegexPatterns) {
206 | const match = other.match(reg)
207 | if (match) {
208 | other = other.replace(new RegExp(reg), prefectureCity)
209 | break
210 | }
211 | }
212 |
213 | for (const [_pref, pattern] of prefPatterns) {
214 | const match = other.match(pattern)
215 | if (match) {
216 | pref = _pref
217 | other = other.substring(match[0].length) // 都道府県名以降の住所
218 | point = prefectureToResultPoint(pref)
219 | break
220 | }
221 | }
222 |
223 | if (!pref) {
224 | // 都道府県名が省略されている
225 | const matched: {
226 | pref: SinglePrefecture
227 | city: SingleCity
228 | other: string
229 | }[] = []
230 | for (const _pref of prefectures.data) {
231 | const cityPatterns = getCityRegexPatterns(_pref)
232 |
233 | other = other.trim()
234 | for (const [_city, pattern] of cityPatterns) {
235 | const match = other.match(pattern)
236 | if (match) {
237 | matched.push({
238 | pref: _pref,
239 | city: _city,
240 | other: other.substring(match[0].length),
241 | })
242 | }
243 | }
244 | }
245 |
246 | // マッチする都道府県が複数ある場合は町名まで正規化して都道府県名を判別する。(例: 東京都府中市と広島県府中市など)
247 | if (1 === matched.length) {
248 | pref = matched[0].pref
249 | } else {
250 | for (const m of matched) {
251 | const normalized = await normalizeTownName(
252 | m.other,
253 | m.pref,
254 | m.city,
255 | apiVersion,
256 | )
257 | if (normalized) {
258 | pref = m.pref
259 | city = m.city
260 | town = normalized.town
261 | other = normalized.other
262 | point = upgradePoint(point, machiAzaToResultPoint(town))
263 | }
264 | }
265 | }
266 | }
267 |
268 | if (pref && option.level >= 2) {
269 | const cityPatterns = getCityRegexPatterns(pref)
270 |
271 | other = other.trim()
272 | for (const [_city, pattern] of cityPatterns) {
273 | const match = other.match(pattern)
274 | if (match) {
275 | city = _city
276 | point = upgradePoint(point, cityToResultPoint(city))
277 | other = other.substring(match[0].length) // 市区町村名以降の住所
278 | break
279 | }
280 | }
281 | }
282 |
283 | // 町丁目以降の正規化
284 | if (pref && city && option.level >= 3) {
285 | const normalized = await normalizeTownName(other, pref, city, apiVersion)
286 | if (normalized) {
287 | town = normalized.town
288 | other = normalized.other
289 | point = upgradePoint(point, machiAzaToResultPoint(town))
290 | }
291 |
292 | // townが取得できた場合にのみ、addrに対する各種の変換処理を行う。
293 | if (town) {
294 | other = other
295 | .replace(/^-/, '')
296 | .replace(/([0-9]+)(丁目)/g, (match) => {
297 | return match.replace(/([0-9]+)/g, (num) => {
298 | return number2kanji(Number(num))
299 | })
300 | })
301 | .replace(
302 | /(([0-9]+|[〇一二三四五六七八九十百千]+)(番地?)([0-9]+|[〇一二三四五六七八九十百千]+)号)\s*(.+)/,
303 | '$1 $5',
304 | )
305 | .replace(
306 | /([0-9]+|[〇一二三四五六七八九十百千]+)\s*(番地?)\s*([0-9]+|[〇一二三四五六七八九十百千]+)\s*号?/,
307 | '$1-$3',
308 | )
309 | .replace(/([0-9]+|[〇一二三四五六七八九十百千]+)番(地|$)/, '$1')
310 | .replace(/([0-9]+|[〇一二三四五六七八九十百千]+)の/g, '$1-')
311 | .replace(
312 | /([0-9]+|[〇一二三四五六七八九十百千]+)[--﹣−‐⁃‑‒–—﹘―⎯⏤ーー─━]/g,
313 | (match) => {
314 | return kan2num(match).replace(/[--﹣−‐⁃‑‒–—﹘―⎯⏤ーー─━]/g, '-')
315 | },
316 | )
317 | .replace(
318 | /[--﹣−‐⁃‑‒–—﹘―⎯⏤ーー─━]([0-9]+|[〇一二三四五六七八九十百千]+)/g,
319 | (match) => {
320 | return kan2num(match).replace(/[--﹣−‐⁃‑‒–—﹘―⎯⏤ーー─━]/g, '-')
321 | },
322 | )
323 | .replace(/([0-9]+|[〇一二三四五六七八九十百千]+)-/, (s) => {
324 | // `1-` のようなケース
325 | return kan2num(s)
326 | })
327 | .replace(/-([0-9]+|[〇一二三四五六七八九十百千]+)/, (s) => {
328 | // `-1` のようなケース
329 | return kan2num(s)
330 | })
331 | .replace(/-[^0-9]([0-9]+|[〇一二三四五六七八九十百千]+)/, (s) => {
332 | // `-あ1` のようなケース
333 | return kan2num(zen2han(s))
334 | })
335 | .replace(/([0-9]+|[〇一二三四五六七八九十百千]+)$/, (s) => {
336 | // `串本町串本1234` のようなケース
337 | return kan2num(s)
338 | })
339 | .trim()
340 | }
341 | }
342 |
343 | other = patchAddr(
344 | pref ? prefectureName(pref) : '',
345 | city ? cityName(city) : '',
346 | town ? machiAzaName(town) : '',
347 | other,
348 | )
349 |
350 | if (pref) level = level + 1
351 | if (city) level = level + 1
352 | if (town) level = level + 1
353 |
354 | if (option.level <= 3 || level < 3) {
355 | const result: NormalizeResult = {
356 | pref: pref ? prefectureName(pref) : undefined,
357 | city: city ? cityName(city) : undefined,
358 | town: town ? machiAzaName(town) : undefined,
359 | other: other,
360 | level,
361 | point,
362 | metadata: {
363 | input: address,
364 | prefecture: removeCitiesFromPrefecture(pref),
365 | city: city,
366 | machiAza: removeExtraFromMachiAza(town),
367 | },
368 | }
369 | return result
370 | }
371 |
372 | const normalizedAddrPart = await normalizeAddrPart(
373 | other,
374 | pref!,
375 | city!,
376 | town!,
377 | apiVersion,
378 | )
379 | // TODO: rsdtと地番を両方対応した時に両方返すけど、今はrsdtを優先する
380 | if (normalizedAddrPart.rsdt) {
381 | addr = rsdtToString(normalizedAddrPart.rsdt)
382 | other = normalizedAddrPart.rest
383 | point = upgradePoint(
384 | point,
385 | rsdtOrChibanToResultPoint(normalizedAddrPart.rsdt),
386 | )
387 | level = 8
388 | } else if (normalizedAddrPart.chiban) {
389 | addr = chibanToString(normalizedAddrPart.chiban)
390 | other = normalizedAddrPart.rest
391 | point = upgradePoint(
392 | point,
393 | rsdtOrChibanToResultPoint(normalizedAddrPart.chiban),
394 | )
395 | level = 8
396 | }
397 | const result: NormalizeResult = {
398 | pref: pref ? prefectureName(pref) : undefined,
399 | city: city ? cityName(city) : undefined,
400 | town: town ? machiAzaName(town) : undefined,
401 | addr,
402 | level,
403 | point,
404 | other,
405 | metadata: {
406 | input: address,
407 | prefecture: removeCitiesFromPrefecture(pref),
408 | city: city,
409 | machiAza: removeExtraFromMachiAza(town),
410 | rsdt: normalizedAddrPart.rsdt,
411 | chiban: normalizedAddrPart.chiban,
412 | },
413 | }
414 | return result
415 | }
416 |
--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------
1 | import {
2 | SingleChiban,
3 | SingleCity,
4 | SingleMachiAza,
5 | SinglePrefecture,
6 | SingleRsdt,
7 | } from '@geolonia/japanese-addresses-v2'
8 |
9 | /**
10 | * 正規化対象の住所の位置情報
11 | * 位置情報は EPSG:4326 (WGS84) です。
12 | */
13 | export type NormalizeResultPoint = {
14 | /// 緯度
15 | lat: number
16 | /// 経度
17 | lng: number
18 | /**
19 | * 緯度経度の正確さを表すレベル
20 | * - 1 - 都道府県の代表点(県庁所在地)の位置
21 | * - 2 - 市区町村の代表点(市役所など)の位置
22 | * - 3 - 丁目・町字の代表点の位置
23 | * - 8 - 住居表示住所または地番の位置
24 | */
25 | level: number
26 | }
27 |
28 | export function isNormalizeResultPoint(
29 | obj: unknown,
30 | ): obj is NormalizeResultPoint {
31 | // Check that obj is an object and not null
32 | if (typeof obj !== 'object' || obj === null) {
33 | return false
34 | }
35 |
36 | // Destructure properties from the object
37 | const { lat, lng, level } = obj as { [key: string]: unknown }
38 |
39 | // Check that lat, lng, and level are numbers
40 | if (
41 | typeof lat !== 'number' ||
42 | typeof lng !== 'number' ||
43 | typeof level !== 'number'
44 | ) {
45 | return false
46 | }
47 |
48 | // Optionally, validate that level is one of the expected values
49 | const validLevels = [1, 2, 3, 8]
50 | if (!validLevels.includes(level)) {
51 | return false
52 | }
53 |
54 | // All checks passed
55 | return true
56 | }
57 |
58 | export function prefectureToResultPoint(
59 | pref: SinglePrefecture,
60 | ): NormalizeResultPoint {
61 | return {
62 | lat: pref.point[1],
63 | lng: pref.point[0],
64 | level: 1,
65 | }
66 | }
67 |
68 | export function cityToResultPoint(city: SingleCity): NormalizeResultPoint {
69 | return {
70 | lat: city.point[1],
71 | lng: city.point[0],
72 | level: 2,
73 | }
74 | }
75 |
76 | export function machiAzaToResultPoint(
77 | machiAza: SingleMachiAza,
78 | ): NormalizeResultPoint | undefined {
79 | if (!machiAza.point) return undefined
80 | return {
81 | lat: machiAza.point[1],
82 | lng: machiAza.point[0],
83 | level: 3,
84 | }
85 | }
86 |
87 | export function rsdtOrChibanToResultPoint(
88 | input: SingleRsdt | SingleChiban,
89 | ): NormalizeResultPoint | undefined {
90 | if (!input.point) return undefined
91 | return {
92 | lat: input.point[1],
93 | lng: input.point[0],
94 | level: 8,
95 | }
96 | }
97 |
98 | export function upgradePoint(
99 | a: NormalizeResultPoint | undefined,
100 | b: NormalizeResultPoint | undefined,
101 | ): NormalizeResultPoint | undefined {
102 | if (!a) return b
103 | if (!b) return a
104 | if (a.level > b.level) return a
105 | return b
106 | }
107 |
108 | export type NormalizeResultMetadata = {
109 | input: string
110 |
111 | /** 都道府県 */
112 | prefecture?: Omit
113 | /** 市区町村 */
114 | city?: SingleCity
115 | /** 町字 */
116 | machiAza?: SingleMachiAza
117 | /** 丁目 */
118 | chiban?: SingleChiban
119 | /** 住居表示住所 */
120 | rsdt?: SingleRsdt
121 | }
122 |
123 | export type NormalizeResult = {
124 | /** 都道府県 */
125 | pref?: string
126 | /** 市区町村 */
127 | city?: string
128 | /**
129 | * 丁目・町字
130 | * 丁目の場合は、丁目名の後に漢数字で丁目が付与される。
131 | * 例:「青葉一丁目」
132 | */
133 | town?: string
134 | /** 住居表示または地番 */
135 | addr?: string
136 | /** 正規化後の住所文字列。完全に正規化された場合は、空の文字列が入ります。 */
137 | other: string
138 |
139 | /**
140 | * 住所の緯度経度
141 | * 注意: 正規化レベルが8でも、位置情報は8でもない場合もあります。
142 | */
143 | point?: NormalizeResultPoint
144 |
145 | /**
146 | * 住所文字列をどこまで判別できたかを表す正規化レベル
147 | * - 0 - 都道府県も判別できなかった。
148 | * - 1 - 都道府県まで判別できた。
149 | * - 2 - 市区町村まで判別できた。
150 | * - 3 - 丁目・町字まで判別できた。
151 | * - 8 - 住居表示住所または地番の判別ができた。
152 | */
153 | level: number
154 |
155 | /** 追加情報 */
156 | metadata: NormalizeResultMetadata
157 | }
158 |
--------------------------------------------------------------------------------
/test/addresses/addresses.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, test } from 'node:test'
2 | import { normalize } from '../../src/main-node'
3 | import fs from 'node:fs'
4 | import path from 'node:path'
5 | import Papa from 'papaparse'
6 | import { NormalizeResult } from '../../src/types'
7 | import { assertMatchCloseTo } from '../helpers'
8 |
9 | const input = fs.readFileSync(
10 | path.join(import.meta.dirname, '/addresses.csv'),
11 | {
12 | encoding: 'utf-8',
13 | },
14 | )
15 | const lines = Papa.parse(input).data
16 |
17 | describe(`address tests`, { concurrency: 4 }, () => {
18 | for (const line of lines) {
19 | const addr = line[0]
20 | if (addr === '住所') {
21 | continue
22 | }
23 |
24 | let testName = addr
25 | if (line[9] !== '') {
26 | testName += ` (${line[9]})`
27 | }
28 |
29 | test(testName, async () => {
30 | const res = await normalize(addr)
31 | const point = line[7] ? line[7].split(',').map(parseFloat) : undefined
32 | const match: Partial = {
33 | other: line[5],
34 | level: parseInt(line[6]),
35 | }
36 | if (line[1] !== '') match.pref = line[1]
37 | if (line[2] !== '') match.city = line[2]
38 | if (line[3] !== '') match.town = line[3]
39 | if (line[4] !== '') match.addr = line[4]
40 | if (point) {
41 | match.point = {
42 | lng: point[0],
43 | lat: point[1],
44 | level: parseInt(line[8]),
45 | }
46 | }
47 | assertMatchCloseTo(res, match)
48 | })
49 | }
50 | })
51 |
--------------------------------------------------------------------------------
/test/addresses/build-test-data.ts:
--------------------------------------------------------------------------------
1 | import { normalize } from '../../src/main-node'
2 | import fs from 'node:fs'
3 | import path from 'node:path'
4 | import Papa from 'papaparse'
5 |
6 | const list = fs.readFileSync(path.join(import.meta.dirname, 'list.txt'), {
7 | encoding: 'utf-8',
8 | })
9 | const data = Papa.parse(list).data
10 |
11 | ;(async () => {
12 | // data.sort()
13 |
14 | const addedAddresses: Set = new Set()
15 |
16 | const output: string[][] = [
17 | [
18 | '住所',
19 | '都道府県',
20 | '市区町村',
21 | '町字',
22 | '番地号',
23 | 'その他',
24 | 'レベル',
25 | '緯度経度',
26 | '位置情報レベル',
27 | '備考',
28 | ],
29 | ]
30 | for (const line of data) {
31 | const address = line[0]
32 | if (!address) {
33 | continue
34 | }
35 | if (addedAddresses.has(address)) {
36 | throw new Error(
37 | `重複の入力住所: ${address} 重複を除き再試行してください。`,
38 | )
39 | }
40 | addedAddresses.add(address)
41 |
42 | const result = await normalize(address)
43 | output.push([
44 | address,
45 | result.pref || '',
46 | result.city || '',
47 | result.town || '',
48 | result.addr || '',
49 | result.other,
50 | result.level.toString(),
51 | result.point ? `${result.point.lng},${result.point.lat}` : '',
52 | result.point ? result.point.level.toString() : '',
53 | line[1] || '',
54 | ])
55 | }
56 |
57 | const csv = Papa.unparse(output, {
58 | header: true,
59 | })
60 | console.log(csv)
61 | })()
62 |
--------------------------------------------------------------------------------
/test/helpers.ts:
--------------------------------------------------------------------------------
1 | import assert from 'node:assert'
2 | import { toMatchCloseTo } from 'jest-matcher-deep-close-to';
3 | import { NormalizeResult } from '../src/types';
4 |
5 | export function assertMatchCloseTo(
6 | received: NormalizeResult,
7 | expected: Partial,
8 | ) {
9 | const result = toMatchCloseTo(received, expected)
10 | assert.ok(result.pass, result.message())
11 | }
12 |
--------------------------------------------------------------------------------
/test/integration/browser.test.ts:
--------------------------------------------------------------------------------
1 | import { before, describe, test } from 'node:test'
2 | import assert from 'node:assert'
3 | import puppeteer from 'puppeteer'
4 |
5 | import fs from 'node:fs/promises'
6 | import path from 'node:path'
7 |
8 | const runTest = (type: 'esm' | 'umd') => {
9 | return async () => {
10 | const browser = await puppeteer.launch({
11 | args: [
12 | '--disable-web-security', // for loading files from file://
13 | '--no-sandbox', // for running in CI
14 | ],
15 | })
16 | try {
17 | const page = await browser.newPage()
18 | await page.goto(
19 | `file://${path.join(import.meta.dirname, `browser/index-${type}.html`)}`,
20 | )
21 |
22 | await Promise.race([
23 | page.waitForSelector('#result', { timeout: 20_000 }),
24 | page.waitForSelector('#error', { timeout: 20_000 }),
25 | ])
26 |
27 | const errorElem = await page.$$('#error')
28 | if (errorElem.length > 0) {
29 | const errorValue = await page.$eval('#error', (el) => el.textContent)
30 | assert.strictEqual(
31 | errorElem.length,
32 | 0,
33 | `#error should not exist, instead we have: ${errorValue}`,
34 | )
35 | }
36 |
37 | const result = await page.$eval('#result', (el) => el.textContent)
38 | assert.strictEqual(result, 'OK')
39 | } finally {
40 | await browser.close()
41 | }
42 | }
43 | }
44 |
45 | describe(`browser`, { timeout: 60_000 }, () => {
46 | before(async () => {
47 | await fs.copyFile(
48 | path.join(import.meta.dirname, '../../dist/main-esm.mjs'),
49 | path.join(import.meta.dirname, 'browser/main-esm.mjs'),
50 | )
51 | await fs.copyFile(
52 | path.join(import.meta.dirname, '../../dist/main-umd.cjs'),
53 | path.join(import.meta.dirname, 'browser/main-umd.cjs'),
54 | )
55 | })
56 |
57 | test(`esm`, runTest('esm'))
58 | test(`umd`, runTest('umd'))
59 | })
60 |
--------------------------------------------------------------------------------
/test/integration/browser/index-esm.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/test/integration/browser/index-umd.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/test/integration/node-cjs/index.js:
--------------------------------------------------------------------------------
1 | const assert = require('node:assert');
2 | const { normalize } = require('@geolonia/normalize-japanese-addresses');
3 |
4 | (async () => {
5 | const res = await normalize('渋谷区道玄坂1-10-8');
6 | assert.strictEqual(res.pref, '東京都');
7 | })()
8 | .then(() => {
9 | console.log('OK');
10 | process.exit(0);
11 | })
12 | .catch((err) => {
13 | console.error(err);
14 | process.exit(1);
15 | });
16 |
--------------------------------------------------------------------------------
/test/integration/node-cjs/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nja-test-cjs",
3 | "lockfileVersion": 3,
4 | "requires": true,
5 | "packages": {
6 | "": {
7 | "name": "nja-test-cjs",
8 | "dependencies": {
9 | "@geolonia/normalize-japanese-addresses": "file:../../.."
10 | }
11 | },
12 | "../../..": {
13 | "name": "@geolonia/normalize-japanese-addresses",
14 | "version": "3.0.1",
15 | "license": "MIT",
16 | "dependencies": {
17 | "@geolonia/japanese-addresses-v2": "0.0.5",
18 | "@geolonia/japanese-numeral": "^1.0.2",
19 | "lru-cache": "^11.0.1",
20 | "papaparse": "^5.4.1",
21 | "undici": "^6.19.8"
22 | },
23 | "devDependencies": {
24 | "@rollup/plugin-commonjs": "^28.0.1",
25 | "@rollup/plugin-node-resolve": "^15.3.0",
26 | "@rollup/plugin-replace": "^6.0.1",
27 | "@rollup/plugin-terser": "^0.4.4",
28 | "@rollup/plugin-typescript": "^12.1.1",
29 | "@types/node": "^22",
30 | "@types/papaparse": "^5.3.14",
31 | "@typescript-eslint/eslint-plugin": "^8.7.0",
32 | "@typescript-eslint/parser": "^8.7.0",
33 | "eslint": "^9.11.1",
34 | "eslint-config-prettier": "^9.1.0",
35 | "eslint-plugin-prettier": "^5.2.1",
36 | "eslint-plugin-tsdoc": "^0.3.0",
37 | "glob": "^11.0.0",
38 | "jest-matcher-deep-close-to": "^3.0.2",
39 | "prettier": "^3.3.3",
40 | "puppeteer": "^23.6.0",
41 | "rollup": "^4.24.0",
42 | "shx": "^0.3.4",
43 | "tsx": "^4.19.1",
44 | "typescript": "^5.6.2"
45 | },
46 | "engines": {
47 | "node": ">=20"
48 | }
49 | },
50 | "node_modules/@geolonia/normalize-japanese-addresses": {
51 | "resolved": "../../..",
52 | "link": true
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/test/integration/node-cjs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nja-test-cjs",
3 | "dependencies": {
4 | "@geolonia/normalize-japanese-addresses": "file:../../.."
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/test/integration/node-esm/index.js:
--------------------------------------------------------------------------------
1 | import assert from 'node:assert';
2 | import { normalize } from '@geolonia/normalize-japanese-addresses';
3 |
4 | (async () => {
5 | const res = await normalize('渋谷区道玄坂1-10-8');
6 | assert.strictEqual(res.pref, '東京都');
7 | })()
8 | .then(() => {
9 | console.log('OK');
10 | process.exit(0);
11 | })
12 | .catch((err) => {
13 | console.error(err);
14 | process.exit(1);
15 | });
16 |
--------------------------------------------------------------------------------
/test/integration/node-esm/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nja-test-cjs",
3 | "lockfileVersion": 3,
4 | "requires": true,
5 | "packages": {
6 | "": {
7 | "name": "nja-test-cjs",
8 | "dependencies": {
9 | "@geolonia/normalize-japanese-addresses": "file:../../.."
10 | }
11 | },
12 | "../../..": {
13 | "name": "@geolonia/normalize-japanese-addresses",
14 | "version": "3.0.1",
15 | "license": "MIT",
16 | "dependencies": {
17 | "@geolonia/japanese-addresses-v2": "0.0.5",
18 | "@geolonia/japanese-numeral": "^1.0.2",
19 | "lru-cache": "^11.0.1",
20 | "papaparse": "^5.4.1",
21 | "undici": "^6.19.8"
22 | },
23 | "devDependencies": {
24 | "@rollup/plugin-commonjs": "^28.0.1",
25 | "@rollup/plugin-node-resolve": "^15.3.0",
26 | "@rollup/plugin-replace": "^6.0.1",
27 | "@rollup/plugin-terser": "^0.4.4",
28 | "@rollup/plugin-typescript": "^12.1.1",
29 | "@types/node": "^22",
30 | "@types/papaparse": "^5.3.14",
31 | "@typescript-eslint/eslint-plugin": "^8.7.0",
32 | "@typescript-eslint/parser": "^8.7.0",
33 | "eslint": "^9.11.1",
34 | "eslint-config-prettier": "^9.1.0",
35 | "eslint-plugin-prettier": "^5.2.1",
36 | "eslint-plugin-tsdoc": "^0.3.0",
37 | "glob": "^11.0.0",
38 | "jest-matcher-deep-close-to": "^3.0.2",
39 | "prettier": "^3.3.3",
40 | "puppeteer": "^23.6.0",
41 | "rollup": "^4.24.0",
42 | "shx": "^0.3.4",
43 | "tsx": "^4.19.1",
44 | "typescript": "^5.6.2"
45 | },
46 | "engines": {
47 | "node": ">=20"
48 | }
49 | },
50 | "node_modules/@geolonia/normalize-japanese-addresses": {
51 | "resolved": "../../..",
52 | "link": true
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/test/integration/node-esm/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nja-test-cjs",
3 | "type": "module",
4 | "dependencies": {
5 | "@geolonia/normalize-japanese-addresses": "file:../../.."
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/test/integration/node.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, test } from 'node:test'
2 | import assert from 'node:assert'
3 |
4 | import { promisify } from 'node:util'
5 | import { exec as execCb } from 'node:child_process'
6 | import path from 'node:path'
7 |
8 | const exec = promisify(execCb)
9 |
10 | const runTest = (type: 'cjs' | 'esm') => {
11 | return async () => {
12 | // the test project is in ./node-${type}
13 | const cwd = path.join(import.meta.dirname, `node-${type}`)
14 | await exec(`npm install`, { cwd })
15 | const res = await exec(`node ./index.js`, { cwd })
16 |
17 | assert.strictEqual(res.stdout.trim(), 'OK')
18 | assert.strictEqual(res.stderr, '')
19 | }
20 | }
21 |
22 | describe(`node`, () => {
23 | test(`cjs`, runTest('cjs'))
24 | test(`esm`, runTest('esm'))
25 | })
26 |
--------------------------------------------------------------------------------
/test/integration/webpack-ts/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 |
--------------------------------------------------------------------------------
/test/integration/webpack-ts/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webpack-ts",
3 | "version": "1.0.0",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "webpack-ts",
9 | "version": "1.0.0",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@geolonia/normalize-japanese-addresses": "file:../../.."
13 | },
14 | "devDependencies": {
15 | "ts-loader": "^9.5.1",
16 | "typescript": "^5.6.3",
17 | "webpack": "^5.95.0",
18 | "webpack-cli": "^5.1.4"
19 | }
20 | },
21 | "../../..": {
22 | "name": "@geolonia/normalize-japanese-addresses",
23 | "version": "3.0.1",
24 | "license": "MIT",
25 | "dependencies": {
26 | "@geolonia/japanese-addresses-v2": "0.0.5",
27 | "@geolonia/japanese-numeral": "^1.0.2",
28 | "lru-cache": "^11.0.1",
29 | "papaparse": "^5.4.1",
30 | "undici": "^6.19.8"
31 | },
32 | "devDependencies": {
33 | "@rollup/plugin-commonjs": "^28.0.1",
34 | "@rollup/plugin-node-resolve": "^15.3.0",
35 | "@rollup/plugin-replace": "^6.0.1",
36 | "@rollup/plugin-terser": "^0.4.4",
37 | "@rollup/plugin-typescript": "^12.1.1",
38 | "@types/node": "^22",
39 | "@types/papaparse": "^5.3.14",
40 | "@typescript-eslint/eslint-plugin": "^8.7.0",
41 | "@typescript-eslint/parser": "^8.7.0",
42 | "eslint": "^9.11.1",
43 | "eslint-config-prettier": "^9.1.0",
44 | "eslint-plugin-prettier": "^5.2.1",
45 | "eslint-plugin-tsdoc": "^0.3.0",
46 | "glob": "^11.0.0",
47 | "jest-matcher-deep-close-to": "^3.0.2",
48 | "prettier": "^3.3.3",
49 | "puppeteer": "^23.6.0",
50 | "rollup": "^4.24.0",
51 | "shx": "^0.3.4",
52 | "tsx": "^4.19.1",
53 | "typescript": "^5.6.2"
54 | },
55 | "engines": {
56 | "node": ">=20"
57 | }
58 | },
59 | "node_modules/@discoveryjs/json-ext": {
60 | "version": "0.5.7",
61 | "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
62 | "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
63 | "dev": true,
64 | "license": "MIT",
65 | "engines": {
66 | "node": ">=10.0.0"
67 | }
68 | },
69 | "node_modules/@geolonia/normalize-japanese-addresses": {
70 | "resolved": "../../..",
71 | "link": true
72 | },
73 | "node_modules/@jridgewell/gen-mapping": {
74 | "version": "0.3.5",
75 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
76 | "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
77 | "dev": true,
78 | "license": "MIT",
79 | "dependencies": {
80 | "@jridgewell/set-array": "^1.2.1",
81 | "@jridgewell/sourcemap-codec": "^1.4.10",
82 | "@jridgewell/trace-mapping": "^0.3.24"
83 | },
84 | "engines": {
85 | "node": ">=6.0.0"
86 | }
87 | },
88 | "node_modules/@jridgewell/resolve-uri": {
89 | "version": "3.1.2",
90 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
91 | "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
92 | "dev": true,
93 | "license": "MIT",
94 | "engines": {
95 | "node": ">=6.0.0"
96 | }
97 | },
98 | "node_modules/@jridgewell/set-array": {
99 | "version": "1.2.1",
100 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
101 | "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
102 | "dev": true,
103 | "license": "MIT",
104 | "engines": {
105 | "node": ">=6.0.0"
106 | }
107 | },
108 | "node_modules/@jridgewell/source-map": {
109 | "version": "0.3.6",
110 | "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
111 | "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
112 | "dev": true,
113 | "license": "MIT",
114 | "dependencies": {
115 | "@jridgewell/gen-mapping": "^0.3.5",
116 | "@jridgewell/trace-mapping": "^0.3.25"
117 | }
118 | },
119 | "node_modules/@jridgewell/sourcemap-codec": {
120 | "version": "1.5.0",
121 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
122 | "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
123 | "dev": true,
124 | "license": "MIT"
125 | },
126 | "node_modules/@jridgewell/trace-mapping": {
127 | "version": "0.3.25",
128 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
129 | "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
130 | "dev": true,
131 | "license": "MIT",
132 | "dependencies": {
133 | "@jridgewell/resolve-uri": "^3.1.0",
134 | "@jridgewell/sourcemap-codec": "^1.4.14"
135 | }
136 | },
137 | "node_modules/@types/estree": {
138 | "version": "1.0.6",
139 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
140 | "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
141 | "dev": true,
142 | "license": "MIT"
143 | },
144 | "node_modules/@types/json-schema": {
145 | "version": "7.0.15",
146 | "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
147 | "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
148 | "dev": true,
149 | "license": "MIT"
150 | },
151 | "node_modules/@types/node": {
152 | "version": "22.7.8",
153 | "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.8.tgz",
154 | "integrity": "sha512-a922jJy31vqR5sk+kAdIENJjHblqcZ4RmERviFsER4WJcEONqxKcjNOlk0q7OUfrF5sddT+vng070cdfMlrPLg==",
155 | "dev": true,
156 | "license": "MIT",
157 | "dependencies": {
158 | "undici-types": "~6.19.2"
159 | }
160 | },
161 | "node_modules/@webassemblyjs/ast": {
162 | "version": "1.12.1",
163 | "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz",
164 | "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==",
165 | "dev": true,
166 | "license": "MIT",
167 | "dependencies": {
168 | "@webassemblyjs/helper-numbers": "1.11.6",
169 | "@webassemblyjs/helper-wasm-bytecode": "1.11.6"
170 | }
171 | },
172 | "node_modules/@webassemblyjs/floating-point-hex-parser": {
173 | "version": "1.11.6",
174 | "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz",
175 | "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==",
176 | "dev": true,
177 | "license": "MIT"
178 | },
179 | "node_modules/@webassemblyjs/helper-api-error": {
180 | "version": "1.11.6",
181 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz",
182 | "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==",
183 | "dev": true,
184 | "license": "MIT"
185 | },
186 | "node_modules/@webassemblyjs/helper-buffer": {
187 | "version": "1.12.1",
188 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz",
189 | "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==",
190 | "dev": true,
191 | "license": "MIT"
192 | },
193 | "node_modules/@webassemblyjs/helper-numbers": {
194 | "version": "1.11.6",
195 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz",
196 | "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==",
197 | "dev": true,
198 | "license": "MIT",
199 | "dependencies": {
200 | "@webassemblyjs/floating-point-hex-parser": "1.11.6",
201 | "@webassemblyjs/helper-api-error": "1.11.6",
202 | "@xtuc/long": "4.2.2"
203 | }
204 | },
205 | "node_modules/@webassemblyjs/helper-wasm-bytecode": {
206 | "version": "1.11.6",
207 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz",
208 | "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==",
209 | "dev": true,
210 | "license": "MIT"
211 | },
212 | "node_modules/@webassemblyjs/helper-wasm-section": {
213 | "version": "1.12.1",
214 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz",
215 | "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==",
216 | "dev": true,
217 | "license": "MIT",
218 | "dependencies": {
219 | "@webassemblyjs/ast": "1.12.1",
220 | "@webassemblyjs/helper-buffer": "1.12.1",
221 | "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
222 | "@webassemblyjs/wasm-gen": "1.12.1"
223 | }
224 | },
225 | "node_modules/@webassemblyjs/ieee754": {
226 | "version": "1.11.6",
227 | "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz",
228 | "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==",
229 | "dev": true,
230 | "license": "MIT",
231 | "dependencies": {
232 | "@xtuc/ieee754": "^1.2.0"
233 | }
234 | },
235 | "node_modules/@webassemblyjs/leb128": {
236 | "version": "1.11.6",
237 | "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz",
238 | "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==",
239 | "dev": true,
240 | "license": "Apache-2.0",
241 | "dependencies": {
242 | "@xtuc/long": "4.2.2"
243 | }
244 | },
245 | "node_modules/@webassemblyjs/utf8": {
246 | "version": "1.11.6",
247 | "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz",
248 | "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==",
249 | "dev": true,
250 | "license": "MIT"
251 | },
252 | "node_modules/@webassemblyjs/wasm-edit": {
253 | "version": "1.12.1",
254 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz",
255 | "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==",
256 | "dev": true,
257 | "license": "MIT",
258 | "dependencies": {
259 | "@webassemblyjs/ast": "1.12.1",
260 | "@webassemblyjs/helper-buffer": "1.12.1",
261 | "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
262 | "@webassemblyjs/helper-wasm-section": "1.12.1",
263 | "@webassemblyjs/wasm-gen": "1.12.1",
264 | "@webassemblyjs/wasm-opt": "1.12.1",
265 | "@webassemblyjs/wasm-parser": "1.12.1",
266 | "@webassemblyjs/wast-printer": "1.12.1"
267 | }
268 | },
269 | "node_modules/@webassemblyjs/wasm-gen": {
270 | "version": "1.12.1",
271 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz",
272 | "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==",
273 | "dev": true,
274 | "license": "MIT",
275 | "dependencies": {
276 | "@webassemblyjs/ast": "1.12.1",
277 | "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
278 | "@webassemblyjs/ieee754": "1.11.6",
279 | "@webassemblyjs/leb128": "1.11.6",
280 | "@webassemblyjs/utf8": "1.11.6"
281 | }
282 | },
283 | "node_modules/@webassemblyjs/wasm-opt": {
284 | "version": "1.12.1",
285 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz",
286 | "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==",
287 | "dev": true,
288 | "license": "MIT",
289 | "dependencies": {
290 | "@webassemblyjs/ast": "1.12.1",
291 | "@webassemblyjs/helper-buffer": "1.12.1",
292 | "@webassemblyjs/wasm-gen": "1.12.1",
293 | "@webassemblyjs/wasm-parser": "1.12.1"
294 | }
295 | },
296 | "node_modules/@webassemblyjs/wasm-parser": {
297 | "version": "1.12.1",
298 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz",
299 | "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==",
300 | "dev": true,
301 | "license": "MIT",
302 | "dependencies": {
303 | "@webassemblyjs/ast": "1.12.1",
304 | "@webassemblyjs/helper-api-error": "1.11.6",
305 | "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
306 | "@webassemblyjs/ieee754": "1.11.6",
307 | "@webassemblyjs/leb128": "1.11.6",
308 | "@webassemblyjs/utf8": "1.11.6"
309 | }
310 | },
311 | "node_modules/@webassemblyjs/wast-printer": {
312 | "version": "1.12.1",
313 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz",
314 | "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==",
315 | "dev": true,
316 | "license": "MIT",
317 | "dependencies": {
318 | "@webassemblyjs/ast": "1.12.1",
319 | "@xtuc/long": "4.2.2"
320 | }
321 | },
322 | "node_modules/@webpack-cli/configtest": {
323 | "version": "2.1.1",
324 | "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz",
325 | "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==",
326 | "dev": true,
327 | "license": "MIT",
328 | "engines": {
329 | "node": ">=14.15.0"
330 | },
331 | "peerDependencies": {
332 | "webpack": "5.x.x",
333 | "webpack-cli": "5.x.x"
334 | }
335 | },
336 | "node_modules/@webpack-cli/info": {
337 | "version": "2.0.2",
338 | "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz",
339 | "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==",
340 | "dev": true,
341 | "license": "MIT",
342 | "engines": {
343 | "node": ">=14.15.0"
344 | },
345 | "peerDependencies": {
346 | "webpack": "5.x.x",
347 | "webpack-cli": "5.x.x"
348 | }
349 | },
350 | "node_modules/@webpack-cli/serve": {
351 | "version": "2.0.5",
352 | "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz",
353 | "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==",
354 | "dev": true,
355 | "license": "MIT",
356 | "engines": {
357 | "node": ">=14.15.0"
358 | },
359 | "peerDependencies": {
360 | "webpack": "5.x.x",
361 | "webpack-cli": "5.x.x"
362 | },
363 | "peerDependenciesMeta": {
364 | "webpack-dev-server": {
365 | "optional": true
366 | }
367 | }
368 | },
369 | "node_modules/@xtuc/ieee754": {
370 | "version": "1.2.0",
371 | "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
372 | "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
373 | "dev": true,
374 | "license": "BSD-3-Clause"
375 | },
376 | "node_modules/@xtuc/long": {
377 | "version": "4.2.2",
378 | "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
379 | "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
380 | "dev": true,
381 | "license": "Apache-2.0"
382 | },
383 | "node_modules/acorn": {
384 | "version": "8.13.0",
385 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.13.0.tgz",
386 | "integrity": "sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==",
387 | "dev": true,
388 | "license": "MIT",
389 | "bin": {
390 | "acorn": "bin/acorn"
391 | },
392 | "engines": {
393 | "node": ">=0.4.0"
394 | }
395 | },
396 | "node_modules/acorn-import-attributes": {
397 | "version": "1.9.5",
398 | "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz",
399 | "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==",
400 | "dev": true,
401 | "license": "MIT",
402 | "peerDependencies": {
403 | "acorn": "^8"
404 | }
405 | },
406 | "node_modules/ajv": {
407 | "version": "6.12.6",
408 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
409 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
410 | "dev": true,
411 | "license": "MIT",
412 | "dependencies": {
413 | "fast-deep-equal": "^3.1.1",
414 | "fast-json-stable-stringify": "^2.0.0",
415 | "json-schema-traverse": "^0.4.1",
416 | "uri-js": "^4.2.2"
417 | },
418 | "funding": {
419 | "type": "github",
420 | "url": "https://github.com/sponsors/epoberezkin"
421 | }
422 | },
423 | "node_modules/ajv-keywords": {
424 | "version": "3.5.2",
425 | "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
426 | "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
427 | "dev": true,
428 | "license": "MIT",
429 | "peerDependencies": {
430 | "ajv": "^6.9.1"
431 | }
432 | },
433 | "node_modules/ansi-styles": {
434 | "version": "4.3.0",
435 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
436 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
437 | "dev": true,
438 | "license": "MIT",
439 | "dependencies": {
440 | "color-convert": "^2.0.1"
441 | },
442 | "engines": {
443 | "node": ">=8"
444 | },
445 | "funding": {
446 | "url": "https://github.com/chalk/ansi-styles?sponsor=1"
447 | }
448 | },
449 | "node_modules/braces": {
450 | "version": "3.0.3",
451 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
452 | "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
453 | "dev": true,
454 | "license": "MIT",
455 | "dependencies": {
456 | "fill-range": "^7.1.1"
457 | },
458 | "engines": {
459 | "node": ">=8"
460 | }
461 | },
462 | "node_modules/browserslist": {
463 | "version": "4.24.2",
464 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz",
465 | "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==",
466 | "dev": true,
467 | "funding": [
468 | {
469 | "type": "opencollective",
470 | "url": "https://opencollective.com/browserslist"
471 | },
472 | {
473 | "type": "tidelift",
474 | "url": "https://tidelift.com/funding/github/npm/browserslist"
475 | },
476 | {
477 | "type": "github",
478 | "url": "https://github.com/sponsors/ai"
479 | }
480 | ],
481 | "license": "MIT",
482 | "dependencies": {
483 | "caniuse-lite": "^1.0.30001669",
484 | "electron-to-chromium": "^1.5.41",
485 | "node-releases": "^2.0.18",
486 | "update-browserslist-db": "^1.1.1"
487 | },
488 | "bin": {
489 | "browserslist": "cli.js"
490 | },
491 | "engines": {
492 | "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
493 | }
494 | },
495 | "node_modules/buffer-from": {
496 | "version": "1.1.2",
497 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
498 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
499 | "dev": true,
500 | "license": "MIT"
501 | },
502 | "node_modules/caniuse-lite": {
503 | "version": "1.0.30001669",
504 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz",
505 | "integrity": "sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==",
506 | "dev": true,
507 | "funding": [
508 | {
509 | "type": "opencollective",
510 | "url": "https://opencollective.com/browserslist"
511 | },
512 | {
513 | "type": "tidelift",
514 | "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
515 | },
516 | {
517 | "type": "github",
518 | "url": "https://github.com/sponsors/ai"
519 | }
520 | ],
521 | "license": "CC-BY-4.0"
522 | },
523 | "node_modules/chalk": {
524 | "version": "4.1.2",
525 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
526 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
527 | "dev": true,
528 | "license": "MIT",
529 | "dependencies": {
530 | "ansi-styles": "^4.1.0",
531 | "supports-color": "^7.1.0"
532 | },
533 | "engines": {
534 | "node": ">=10"
535 | },
536 | "funding": {
537 | "url": "https://github.com/chalk/chalk?sponsor=1"
538 | }
539 | },
540 | "node_modules/chrome-trace-event": {
541 | "version": "1.0.4",
542 | "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
543 | "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==",
544 | "dev": true,
545 | "license": "MIT",
546 | "engines": {
547 | "node": ">=6.0"
548 | }
549 | },
550 | "node_modules/clone-deep": {
551 | "version": "4.0.1",
552 | "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
553 | "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==",
554 | "dev": true,
555 | "license": "MIT",
556 | "dependencies": {
557 | "is-plain-object": "^2.0.4",
558 | "kind-of": "^6.0.2",
559 | "shallow-clone": "^3.0.0"
560 | },
561 | "engines": {
562 | "node": ">=6"
563 | }
564 | },
565 | "node_modules/color-convert": {
566 | "version": "2.0.1",
567 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
568 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
569 | "dev": true,
570 | "license": "MIT",
571 | "dependencies": {
572 | "color-name": "~1.1.4"
573 | },
574 | "engines": {
575 | "node": ">=7.0.0"
576 | }
577 | },
578 | "node_modules/color-name": {
579 | "version": "1.1.4",
580 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
581 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
582 | "dev": true,
583 | "license": "MIT"
584 | },
585 | "node_modules/colorette": {
586 | "version": "2.0.20",
587 | "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
588 | "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
589 | "dev": true,
590 | "license": "MIT"
591 | },
592 | "node_modules/commander": {
593 | "version": "2.20.3",
594 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
595 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
596 | "dev": true,
597 | "license": "MIT"
598 | },
599 | "node_modules/cross-spawn": {
600 | "version": "7.0.3",
601 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
602 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
603 | "dev": true,
604 | "license": "MIT",
605 | "dependencies": {
606 | "path-key": "^3.1.0",
607 | "shebang-command": "^2.0.0",
608 | "which": "^2.0.1"
609 | },
610 | "engines": {
611 | "node": ">= 8"
612 | }
613 | },
614 | "node_modules/electron-to-chromium": {
615 | "version": "1.5.42",
616 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.42.tgz",
617 | "integrity": "sha512-gIfKavKDw1mhvic9nbzA5lZw8QSHpdMwLwXc0cWidQz9B15pDoDdDH4boIatuFfeoCatb3a/NGL6CYRVFxGZ9g==",
618 | "dev": true,
619 | "license": "ISC"
620 | },
621 | "node_modules/enhanced-resolve": {
622 | "version": "5.17.1",
623 | "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz",
624 | "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==",
625 | "dev": true,
626 | "license": "MIT",
627 | "dependencies": {
628 | "graceful-fs": "^4.2.4",
629 | "tapable": "^2.2.0"
630 | },
631 | "engines": {
632 | "node": ">=10.13.0"
633 | }
634 | },
635 | "node_modules/envinfo": {
636 | "version": "7.14.0",
637 | "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz",
638 | "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==",
639 | "dev": true,
640 | "license": "MIT",
641 | "bin": {
642 | "envinfo": "dist/cli.js"
643 | },
644 | "engines": {
645 | "node": ">=4"
646 | }
647 | },
648 | "node_modules/es-module-lexer": {
649 | "version": "1.5.4",
650 | "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz",
651 | "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==",
652 | "dev": true,
653 | "license": "MIT"
654 | },
655 | "node_modules/escalade": {
656 | "version": "3.2.0",
657 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
658 | "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
659 | "dev": true,
660 | "license": "MIT",
661 | "engines": {
662 | "node": ">=6"
663 | }
664 | },
665 | "node_modules/eslint-scope": {
666 | "version": "5.1.1",
667 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
668 | "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
669 | "dev": true,
670 | "license": "BSD-2-Clause",
671 | "dependencies": {
672 | "esrecurse": "^4.3.0",
673 | "estraverse": "^4.1.1"
674 | },
675 | "engines": {
676 | "node": ">=8.0.0"
677 | }
678 | },
679 | "node_modules/esrecurse": {
680 | "version": "4.3.0",
681 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
682 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
683 | "dev": true,
684 | "license": "BSD-2-Clause",
685 | "dependencies": {
686 | "estraverse": "^5.2.0"
687 | },
688 | "engines": {
689 | "node": ">=4.0"
690 | }
691 | },
692 | "node_modules/esrecurse/node_modules/estraverse": {
693 | "version": "5.3.0",
694 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
695 | "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
696 | "dev": true,
697 | "license": "BSD-2-Clause",
698 | "engines": {
699 | "node": ">=4.0"
700 | }
701 | },
702 | "node_modules/estraverse": {
703 | "version": "4.3.0",
704 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
705 | "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
706 | "dev": true,
707 | "license": "BSD-2-Clause",
708 | "engines": {
709 | "node": ">=4.0"
710 | }
711 | },
712 | "node_modules/events": {
713 | "version": "3.3.0",
714 | "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
715 | "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
716 | "dev": true,
717 | "license": "MIT",
718 | "engines": {
719 | "node": ">=0.8.x"
720 | }
721 | },
722 | "node_modules/fast-deep-equal": {
723 | "version": "3.1.3",
724 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
725 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
726 | "dev": true,
727 | "license": "MIT"
728 | },
729 | "node_modules/fast-json-stable-stringify": {
730 | "version": "2.1.0",
731 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
732 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
733 | "dev": true,
734 | "license": "MIT"
735 | },
736 | "node_modules/fastest-levenshtein": {
737 | "version": "1.0.16",
738 | "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
739 | "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==",
740 | "dev": true,
741 | "license": "MIT",
742 | "engines": {
743 | "node": ">= 4.9.1"
744 | }
745 | },
746 | "node_modules/fill-range": {
747 | "version": "7.1.1",
748 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
749 | "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
750 | "dev": true,
751 | "license": "MIT",
752 | "dependencies": {
753 | "to-regex-range": "^5.0.1"
754 | },
755 | "engines": {
756 | "node": ">=8"
757 | }
758 | },
759 | "node_modules/find-up": {
760 | "version": "4.1.0",
761 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
762 | "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
763 | "dev": true,
764 | "license": "MIT",
765 | "dependencies": {
766 | "locate-path": "^5.0.0",
767 | "path-exists": "^4.0.0"
768 | },
769 | "engines": {
770 | "node": ">=8"
771 | }
772 | },
773 | "node_modules/flat": {
774 | "version": "5.0.2",
775 | "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
776 | "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
777 | "dev": true,
778 | "license": "BSD-3-Clause",
779 | "bin": {
780 | "flat": "cli.js"
781 | }
782 | },
783 | "node_modules/function-bind": {
784 | "version": "1.1.2",
785 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
786 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
787 | "dev": true,
788 | "license": "MIT",
789 | "funding": {
790 | "url": "https://github.com/sponsors/ljharb"
791 | }
792 | },
793 | "node_modules/glob-to-regexp": {
794 | "version": "0.4.1",
795 | "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
796 | "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
797 | "dev": true,
798 | "license": "BSD-2-Clause"
799 | },
800 | "node_modules/graceful-fs": {
801 | "version": "4.2.11",
802 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
803 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
804 | "dev": true,
805 | "license": "ISC"
806 | },
807 | "node_modules/has-flag": {
808 | "version": "4.0.0",
809 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
810 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
811 | "dev": true,
812 | "license": "MIT",
813 | "engines": {
814 | "node": ">=8"
815 | }
816 | },
817 | "node_modules/hasown": {
818 | "version": "2.0.2",
819 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
820 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
821 | "dev": true,
822 | "license": "MIT",
823 | "dependencies": {
824 | "function-bind": "^1.1.2"
825 | },
826 | "engines": {
827 | "node": ">= 0.4"
828 | }
829 | },
830 | "node_modules/import-local": {
831 | "version": "3.2.0",
832 | "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz",
833 | "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==",
834 | "dev": true,
835 | "license": "MIT",
836 | "dependencies": {
837 | "pkg-dir": "^4.2.0",
838 | "resolve-cwd": "^3.0.0"
839 | },
840 | "bin": {
841 | "import-local-fixture": "fixtures/cli.js"
842 | },
843 | "engines": {
844 | "node": ">=8"
845 | },
846 | "funding": {
847 | "url": "https://github.com/sponsors/sindresorhus"
848 | }
849 | },
850 | "node_modules/interpret": {
851 | "version": "3.1.1",
852 | "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz",
853 | "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==",
854 | "dev": true,
855 | "license": "MIT",
856 | "engines": {
857 | "node": ">=10.13.0"
858 | }
859 | },
860 | "node_modules/is-core-module": {
861 | "version": "2.15.1",
862 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
863 | "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==",
864 | "dev": true,
865 | "license": "MIT",
866 | "dependencies": {
867 | "hasown": "^2.0.2"
868 | },
869 | "engines": {
870 | "node": ">= 0.4"
871 | },
872 | "funding": {
873 | "url": "https://github.com/sponsors/ljharb"
874 | }
875 | },
876 | "node_modules/is-number": {
877 | "version": "7.0.0",
878 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
879 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
880 | "dev": true,
881 | "license": "MIT",
882 | "engines": {
883 | "node": ">=0.12.0"
884 | }
885 | },
886 | "node_modules/is-plain-object": {
887 | "version": "2.0.4",
888 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
889 | "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
890 | "dev": true,
891 | "license": "MIT",
892 | "dependencies": {
893 | "isobject": "^3.0.1"
894 | },
895 | "engines": {
896 | "node": ">=0.10.0"
897 | }
898 | },
899 | "node_modules/isexe": {
900 | "version": "2.0.0",
901 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
902 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
903 | "dev": true,
904 | "license": "ISC"
905 | },
906 | "node_modules/isobject": {
907 | "version": "3.0.1",
908 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
909 | "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
910 | "dev": true,
911 | "license": "MIT",
912 | "engines": {
913 | "node": ">=0.10.0"
914 | }
915 | },
916 | "node_modules/jest-worker": {
917 | "version": "27.5.1",
918 | "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
919 | "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
920 | "dev": true,
921 | "license": "MIT",
922 | "dependencies": {
923 | "@types/node": "*",
924 | "merge-stream": "^2.0.0",
925 | "supports-color": "^8.0.0"
926 | },
927 | "engines": {
928 | "node": ">= 10.13.0"
929 | }
930 | },
931 | "node_modules/jest-worker/node_modules/supports-color": {
932 | "version": "8.1.1",
933 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
934 | "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
935 | "dev": true,
936 | "license": "MIT",
937 | "dependencies": {
938 | "has-flag": "^4.0.0"
939 | },
940 | "engines": {
941 | "node": ">=10"
942 | },
943 | "funding": {
944 | "url": "https://github.com/chalk/supports-color?sponsor=1"
945 | }
946 | },
947 | "node_modules/json-parse-even-better-errors": {
948 | "version": "2.3.1",
949 | "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
950 | "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
951 | "dev": true,
952 | "license": "MIT"
953 | },
954 | "node_modules/json-schema-traverse": {
955 | "version": "0.4.1",
956 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
957 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
958 | "dev": true,
959 | "license": "MIT"
960 | },
961 | "node_modules/kind-of": {
962 | "version": "6.0.3",
963 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
964 | "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
965 | "dev": true,
966 | "license": "MIT",
967 | "engines": {
968 | "node": ">=0.10.0"
969 | }
970 | },
971 | "node_modules/loader-runner": {
972 | "version": "4.3.0",
973 | "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
974 | "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==",
975 | "dev": true,
976 | "license": "MIT",
977 | "engines": {
978 | "node": ">=6.11.5"
979 | }
980 | },
981 | "node_modules/locate-path": {
982 | "version": "5.0.0",
983 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
984 | "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
985 | "dev": true,
986 | "license": "MIT",
987 | "dependencies": {
988 | "p-locate": "^4.1.0"
989 | },
990 | "engines": {
991 | "node": ">=8"
992 | }
993 | },
994 | "node_modules/merge-stream": {
995 | "version": "2.0.0",
996 | "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
997 | "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
998 | "dev": true,
999 | "license": "MIT"
1000 | },
1001 | "node_modules/micromatch": {
1002 | "version": "4.0.8",
1003 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
1004 | "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
1005 | "dev": true,
1006 | "license": "MIT",
1007 | "dependencies": {
1008 | "braces": "^3.0.3",
1009 | "picomatch": "^2.3.1"
1010 | },
1011 | "engines": {
1012 | "node": ">=8.6"
1013 | }
1014 | },
1015 | "node_modules/mime-db": {
1016 | "version": "1.52.0",
1017 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
1018 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
1019 | "dev": true,
1020 | "license": "MIT",
1021 | "engines": {
1022 | "node": ">= 0.6"
1023 | }
1024 | },
1025 | "node_modules/mime-types": {
1026 | "version": "2.1.35",
1027 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
1028 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
1029 | "dev": true,
1030 | "license": "MIT",
1031 | "dependencies": {
1032 | "mime-db": "1.52.0"
1033 | },
1034 | "engines": {
1035 | "node": ">= 0.6"
1036 | }
1037 | },
1038 | "node_modules/neo-async": {
1039 | "version": "2.6.2",
1040 | "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
1041 | "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
1042 | "dev": true,
1043 | "license": "MIT"
1044 | },
1045 | "node_modules/node-releases": {
1046 | "version": "2.0.18",
1047 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz",
1048 | "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==",
1049 | "dev": true,
1050 | "license": "MIT"
1051 | },
1052 | "node_modules/p-limit": {
1053 | "version": "2.3.0",
1054 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
1055 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
1056 | "dev": true,
1057 | "license": "MIT",
1058 | "dependencies": {
1059 | "p-try": "^2.0.0"
1060 | },
1061 | "engines": {
1062 | "node": ">=6"
1063 | },
1064 | "funding": {
1065 | "url": "https://github.com/sponsors/sindresorhus"
1066 | }
1067 | },
1068 | "node_modules/p-locate": {
1069 | "version": "4.1.0",
1070 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
1071 | "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
1072 | "dev": true,
1073 | "license": "MIT",
1074 | "dependencies": {
1075 | "p-limit": "^2.2.0"
1076 | },
1077 | "engines": {
1078 | "node": ">=8"
1079 | }
1080 | },
1081 | "node_modules/p-try": {
1082 | "version": "2.2.0",
1083 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
1084 | "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
1085 | "dev": true,
1086 | "license": "MIT",
1087 | "engines": {
1088 | "node": ">=6"
1089 | }
1090 | },
1091 | "node_modules/path-exists": {
1092 | "version": "4.0.0",
1093 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
1094 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
1095 | "dev": true,
1096 | "license": "MIT",
1097 | "engines": {
1098 | "node": ">=8"
1099 | }
1100 | },
1101 | "node_modules/path-key": {
1102 | "version": "3.1.1",
1103 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
1104 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
1105 | "dev": true,
1106 | "license": "MIT",
1107 | "engines": {
1108 | "node": ">=8"
1109 | }
1110 | },
1111 | "node_modules/path-parse": {
1112 | "version": "1.0.7",
1113 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
1114 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
1115 | "dev": true,
1116 | "license": "MIT"
1117 | },
1118 | "node_modules/picocolors": {
1119 | "version": "1.1.1",
1120 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
1121 | "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
1122 | "dev": true,
1123 | "license": "ISC"
1124 | },
1125 | "node_modules/picomatch": {
1126 | "version": "2.3.1",
1127 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
1128 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
1129 | "dev": true,
1130 | "license": "MIT",
1131 | "engines": {
1132 | "node": ">=8.6"
1133 | },
1134 | "funding": {
1135 | "url": "https://github.com/sponsors/jonschlinkert"
1136 | }
1137 | },
1138 | "node_modules/pkg-dir": {
1139 | "version": "4.2.0",
1140 | "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
1141 | "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
1142 | "dev": true,
1143 | "license": "MIT",
1144 | "dependencies": {
1145 | "find-up": "^4.0.0"
1146 | },
1147 | "engines": {
1148 | "node": ">=8"
1149 | }
1150 | },
1151 | "node_modules/punycode": {
1152 | "version": "2.3.1",
1153 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
1154 | "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
1155 | "dev": true,
1156 | "license": "MIT",
1157 | "engines": {
1158 | "node": ">=6"
1159 | }
1160 | },
1161 | "node_modules/randombytes": {
1162 | "version": "2.1.0",
1163 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
1164 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
1165 | "dev": true,
1166 | "license": "MIT",
1167 | "dependencies": {
1168 | "safe-buffer": "^5.1.0"
1169 | }
1170 | },
1171 | "node_modules/rechoir": {
1172 | "version": "0.8.0",
1173 | "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz",
1174 | "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==",
1175 | "dev": true,
1176 | "license": "MIT",
1177 | "dependencies": {
1178 | "resolve": "^1.20.0"
1179 | },
1180 | "engines": {
1181 | "node": ">= 10.13.0"
1182 | }
1183 | },
1184 | "node_modules/resolve": {
1185 | "version": "1.22.8",
1186 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
1187 | "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
1188 | "dev": true,
1189 | "license": "MIT",
1190 | "dependencies": {
1191 | "is-core-module": "^2.13.0",
1192 | "path-parse": "^1.0.7",
1193 | "supports-preserve-symlinks-flag": "^1.0.0"
1194 | },
1195 | "bin": {
1196 | "resolve": "bin/resolve"
1197 | },
1198 | "funding": {
1199 | "url": "https://github.com/sponsors/ljharb"
1200 | }
1201 | },
1202 | "node_modules/resolve-cwd": {
1203 | "version": "3.0.0",
1204 | "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
1205 | "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==",
1206 | "dev": true,
1207 | "license": "MIT",
1208 | "dependencies": {
1209 | "resolve-from": "^5.0.0"
1210 | },
1211 | "engines": {
1212 | "node": ">=8"
1213 | }
1214 | },
1215 | "node_modules/resolve-from": {
1216 | "version": "5.0.0",
1217 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
1218 | "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
1219 | "dev": true,
1220 | "license": "MIT",
1221 | "engines": {
1222 | "node": ">=8"
1223 | }
1224 | },
1225 | "node_modules/safe-buffer": {
1226 | "version": "5.2.1",
1227 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1228 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
1229 | "dev": true,
1230 | "funding": [
1231 | {
1232 | "type": "github",
1233 | "url": "https://github.com/sponsors/feross"
1234 | },
1235 | {
1236 | "type": "patreon",
1237 | "url": "https://www.patreon.com/feross"
1238 | },
1239 | {
1240 | "type": "consulting",
1241 | "url": "https://feross.org/support"
1242 | }
1243 | ],
1244 | "license": "MIT"
1245 | },
1246 | "node_modules/schema-utils": {
1247 | "version": "3.3.0",
1248 | "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
1249 | "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
1250 | "dev": true,
1251 | "license": "MIT",
1252 | "dependencies": {
1253 | "@types/json-schema": "^7.0.8",
1254 | "ajv": "^6.12.5",
1255 | "ajv-keywords": "^3.5.2"
1256 | },
1257 | "engines": {
1258 | "node": ">= 10.13.0"
1259 | },
1260 | "funding": {
1261 | "type": "opencollective",
1262 | "url": "https://opencollective.com/webpack"
1263 | }
1264 | },
1265 | "node_modules/semver": {
1266 | "version": "7.6.3",
1267 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
1268 | "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
1269 | "dev": true,
1270 | "license": "ISC",
1271 | "bin": {
1272 | "semver": "bin/semver.js"
1273 | },
1274 | "engines": {
1275 | "node": ">=10"
1276 | }
1277 | },
1278 | "node_modules/serialize-javascript": {
1279 | "version": "6.0.2",
1280 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
1281 | "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
1282 | "dev": true,
1283 | "license": "BSD-3-Clause",
1284 | "dependencies": {
1285 | "randombytes": "^2.1.0"
1286 | }
1287 | },
1288 | "node_modules/shallow-clone": {
1289 | "version": "3.0.1",
1290 | "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
1291 | "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==",
1292 | "dev": true,
1293 | "license": "MIT",
1294 | "dependencies": {
1295 | "kind-of": "^6.0.2"
1296 | },
1297 | "engines": {
1298 | "node": ">=8"
1299 | }
1300 | },
1301 | "node_modules/shebang-command": {
1302 | "version": "2.0.0",
1303 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
1304 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
1305 | "dev": true,
1306 | "license": "MIT",
1307 | "dependencies": {
1308 | "shebang-regex": "^3.0.0"
1309 | },
1310 | "engines": {
1311 | "node": ">=8"
1312 | }
1313 | },
1314 | "node_modules/shebang-regex": {
1315 | "version": "3.0.0",
1316 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
1317 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
1318 | "dev": true,
1319 | "license": "MIT",
1320 | "engines": {
1321 | "node": ">=8"
1322 | }
1323 | },
1324 | "node_modules/source-map": {
1325 | "version": "0.7.4",
1326 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
1327 | "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
1328 | "dev": true,
1329 | "license": "BSD-3-Clause",
1330 | "engines": {
1331 | "node": ">= 8"
1332 | }
1333 | },
1334 | "node_modules/source-map-support": {
1335 | "version": "0.5.21",
1336 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
1337 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
1338 | "dev": true,
1339 | "license": "MIT",
1340 | "dependencies": {
1341 | "buffer-from": "^1.0.0",
1342 | "source-map": "^0.6.0"
1343 | }
1344 | },
1345 | "node_modules/source-map-support/node_modules/source-map": {
1346 | "version": "0.6.1",
1347 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
1348 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
1349 | "dev": true,
1350 | "license": "BSD-3-Clause",
1351 | "engines": {
1352 | "node": ">=0.10.0"
1353 | }
1354 | },
1355 | "node_modules/supports-color": {
1356 | "version": "7.2.0",
1357 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
1358 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
1359 | "dev": true,
1360 | "license": "MIT",
1361 | "dependencies": {
1362 | "has-flag": "^4.0.0"
1363 | },
1364 | "engines": {
1365 | "node": ">=8"
1366 | }
1367 | },
1368 | "node_modules/supports-preserve-symlinks-flag": {
1369 | "version": "1.0.0",
1370 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
1371 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
1372 | "dev": true,
1373 | "license": "MIT",
1374 | "engines": {
1375 | "node": ">= 0.4"
1376 | },
1377 | "funding": {
1378 | "url": "https://github.com/sponsors/ljharb"
1379 | }
1380 | },
1381 | "node_modules/tapable": {
1382 | "version": "2.2.1",
1383 | "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
1384 | "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
1385 | "dev": true,
1386 | "license": "MIT",
1387 | "engines": {
1388 | "node": ">=6"
1389 | }
1390 | },
1391 | "node_modules/terser": {
1392 | "version": "5.36.0",
1393 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz",
1394 | "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==",
1395 | "dev": true,
1396 | "license": "BSD-2-Clause",
1397 | "dependencies": {
1398 | "@jridgewell/source-map": "^0.3.3",
1399 | "acorn": "^8.8.2",
1400 | "commander": "^2.20.0",
1401 | "source-map-support": "~0.5.20"
1402 | },
1403 | "bin": {
1404 | "terser": "bin/terser"
1405 | },
1406 | "engines": {
1407 | "node": ">=10"
1408 | }
1409 | },
1410 | "node_modules/terser-webpack-plugin": {
1411 | "version": "5.3.10",
1412 | "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz",
1413 | "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==",
1414 | "dev": true,
1415 | "license": "MIT",
1416 | "dependencies": {
1417 | "@jridgewell/trace-mapping": "^0.3.20",
1418 | "jest-worker": "^27.4.5",
1419 | "schema-utils": "^3.1.1",
1420 | "serialize-javascript": "^6.0.1",
1421 | "terser": "^5.26.0"
1422 | },
1423 | "engines": {
1424 | "node": ">= 10.13.0"
1425 | },
1426 | "funding": {
1427 | "type": "opencollective",
1428 | "url": "https://opencollective.com/webpack"
1429 | },
1430 | "peerDependencies": {
1431 | "webpack": "^5.1.0"
1432 | },
1433 | "peerDependenciesMeta": {
1434 | "@swc/core": {
1435 | "optional": true
1436 | },
1437 | "esbuild": {
1438 | "optional": true
1439 | },
1440 | "uglify-js": {
1441 | "optional": true
1442 | }
1443 | }
1444 | },
1445 | "node_modules/to-regex-range": {
1446 | "version": "5.0.1",
1447 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
1448 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
1449 | "dev": true,
1450 | "license": "MIT",
1451 | "dependencies": {
1452 | "is-number": "^7.0.0"
1453 | },
1454 | "engines": {
1455 | "node": ">=8.0"
1456 | }
1457 | },
1458 | "node_modules/ts-loader": {
1459 | "version": "9.5.1",
1460 | "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz",
1461 | "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==",
1462 | "dev": true,
1463 | "license": "MIT",
1464 | "dependencies": {
1465 | "chalk": "^4.1.0",
1466 | "enhanced-resolve": "^5.0.0",
1467 | "micromatch": "^4.0.0",
1468 | "semver": "^7.3.4",
1469 | "source-map": "^0.7.4"
1470 | },
1471 | "engines": {
1472 | "node": ">=12.0.0"
1473 | },
1474 | "peerDependencies": {
1475 | "typescript": "*",
1476 | "webpack": "^5.0.0"
1477 | }
1478 | },
1479 | "node_modules/typescript": {
1480 | "version": "5.6.3",
1481 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz",
1482 | "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
1483 | "dev": true,
1484 | "license": "Apache-2.0",
1485 | "bin": {
1486 | "tsc": "bin/tsc",
1487 | "tsserver": "bin/tsserver"
1488 | },
1489 | "engines": {
1490 | "node": ">=14.17"
1491 | }
1492 | },
1493 | "node_modules/undici-types": {
1494 | "version": "6.19.8",
1495 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
1496 | "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
1497 | "dev": true,
1498 | "license": "MIT"
1499 | },
1500 | "node_modules/update-browserslist-db": {
1501 | "version": "1.1.1",
1502 | "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz",
1503 | "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==",
1504 | "dev": true,
1505 | "funding": [
1506 | {
1507 | "type": "opencollective",
1508 | "url": "https://opencollective.com/browserslist"
1509 | },
1510 | {
1511 | "type": "tidelift",
1512 | "url": "https://tidelift.com/funding/github/npm/browserslist"
1513 | },
1514 | {
1515 | "type": "github",
1516 | "url": "https://github.com/sponsors/ai"
1517 | }
1518 | ],
1519 | "license": "MIT",
1520 | "dependencies": {
1521 | "escalade": "^3.2.0",
1522 | "picocolors": "^1.1.0"
1523 | },
1524 | "bin": {
1525 | "update-browserslist-db": "cli.js"
1526 | },
1527 | "peerDependencies": {
1528 | "browserslist": ">= 4.21.0"
1529 | }
1530 | },
1531 | "node_modules/uri-js": {
1532 | "version": "4.4.1",
1533 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
1534 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
1535 | "dev": true,
1536 | "license": "BSD-2-Clause",
1537 | "dependencies": {
1538 | "punycode": "^2.1.0"
1539 | }
1540 | },
1541 | "node_modules/watchpack": {
1542 | "version": "2.4.2",
1543 | "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz",
1544 | "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==",
1545 | "dev": true,
1546 | "license": "MIT",
1547 | "dependencies": {
1548 | "glob-to-regexp": "^0.4.1",
1549 | "graceful-fs": "^4.1.2"
1550 | },
1551 | "engines": {
1552 | "node": ">=10.13.0"
1553 | }
1554 | },
1555 | "node_modules/webpack": {
1556 | "version": "5.95.0",
1557 | "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.95.0.tgz",
1558 | "integrity": "sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q==",
1559 | "dev": true,
1560 | "license": "MIT",
1561 | "dependencies": {
1562 | "@types/estree": "^1.0.5",
1563 | "@webassemblyjs/ast": "^1.12.1",
1564 | "@webassemblyjs/wasm-edit": "^1.12.1",
1565 | "@webassemblyjs/wasm-parser": "^1.12.1",
1566 | "acorn": "^8.7.1",
1567 | "acorn-import-attributes": "^1.9.5",
1568 | "browserslist": "^4.21.10",
1569 | "chrome-trace-event": "^1.0.2",
1570 | "enhanced-resolve": "^5.17.1",
1571 | "es-module-lexer": "^1.2.1",
1572 | "eslint-scope": "5.1.1",
1573 | "events": "^3.2.0",
1574 | "glob-to-regexp": "^0.4.1",
1575 | "graceful-fs": "^4.2.11",
1576 | "json-parse-even-better-errors": "^2.3.1",
1577 | "loader-runner": "^4.2.0",
1578 | "mime-types": "^2.1.27",
1579 | "neo-async": "^2.6.2",
1580 | "schema-utils": "^3.2.0",
1581 | "tapable": "^2.1.1",
1582 | "terser-webpack-plugin": "^5.3.10",
1583 | "watchpack": "^2.4.1",
1584 | "webpack-sources": "^3.2.3"
1585 | },
1586 | "bin": {
1587 | "webpack": "bin/webpack.js"
1588 | },
1589 | "engines": {
1590 | "node": ">=10.13.0"
1591 | },
1592 | "funding": {
1593 | "type": "opencollective",
1594 | "url": "https://opencollective.com/webpack"
1595 | },
1596 | "peerDependenciesMeta": {
1597 | "webpack-cli": {
1598 | "optional": true
1599 | }
1600 | }
1601 | },
1602 | "node_modules/webpack-cli": {
1603 | "version": "5.1.4",
1604 | "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz",
1605 | "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==",
1606 | "dev": true,
1607 | "license": "MIT",
1608 | "dependencies": {
1609 | "@discoveryjs/json-ext": "^0.5.0",
1610 | "@webpack-cli/configtest": "^2.1.1",
1611 | "@webpack-cli/info": "^2.0.2",
1612 | "@webpack-cli/serve": "^2.0.5",
1613 | "colorette": "^2.0.14",
1614 | "commander": "^10.0.1",
1615 | "cross-spawn": "^7.0.3",
1616 | "envinfo": "^7.7.3",
1617 | "fastest-levenshtein": "^1.0.12",
1618 | "import-local": "^3.0.2",
1619 | "interpret": "^3.1.1",
1620 | "rechoir": "^0.8.0",
1621 | "webpack-merge": "^5.7.3"
1622 | },
1623 | "bin": {
1624 | "webpack-cli": "bin/cli.js"
1625 | },
1626 | "engines": {
1627 | "node": ">=14.15.0"
1628 | },
1629 | "funding": {
1630 | "type": "opencollective",
1631 | "url": "https://opencollective.com/webpack"
1632 | },
1633 | "peerDependencies": {
1634 | "webpack": "5.x.x"
1635 | },
1636 | "peerDependenciesMeta": {
1637 | "@webpack-cli/generators": {
1638 | "optional": true
1639 | },
1640 | "webpack-bundle-analyzer": {
1641 | "optional": true
1642 | },
1643 | "webpack-dev-server": {
1644 | "optional": true
1645 | }
1646 | }
1647 | },
1648 | "node_modules/webpack-cli/node_modules/commander": {
1649 | "version": "10.0.1",
1650 | "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
1651 | "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
1652 | "dev": true,
1653 | "license": "MIT",
1654 | "engines": {
1655 | "node": ">=14"
1656 | }
1657 | },
1658 | "node_modules/webpack-merge": {
1659 | "version": "5.10.0",
1660 | "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz",
1661 | "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==",
1662 | "dev": true,
1663 | "license": "MIT",
1664 | "dependencies": {
1665 | "clone-deep": "^4.0.1",
1666 | "flat": "^5.0.2",
1667 | "wildcard": "^2.0.0"
1668 | },
1669 | "engines": {
1670 | "node": ">=10.0.0"
1671 | }
1672 | },
1673 | "node_modules/webpack-sources": {
1674 | "version": "3.2.3",
1675 | "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
1676 | "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
1677 | "dev": true,
1678 | "license": "MIT",
1679 | "engines": {
1680 | "node": ">=10.13.0"
1681 | }
1682 | },
1683 | "node_modules/which": {
1684 | "version": "2.0.2",
1685 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
1686 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
1687 | "dev": true,
1688 | "license": "ISC",
1689 | "dependencies": {
1690 | "isexe": "^2.0.0"
1691 | },
1692 | "bin": {
1693 | "node-which": "bin/node-which"
1694 | },
1695 | "engines": {
1696 | "node": ">= 8"
1697 | }
1698 | },
1699 | "node_modules/wildcard": {
1700 | "version": "2.0.1",
1701 | "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz",
1702 | "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==",
1703 | "dev": true,
1704 | "license": "MIT"
1705 | }
1706 | }
1707 | }
1708 |
--------------------------------------------------------------------------------
/test/integration/webpack-ts/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webpack-ts",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "scripts": {
6 | "build": "webpack"
7 | },
8 | "keywords": [],
9 | "author": "",
10 | "license": "ISC",
11 | "description": "",
12 | "devDependencies": {
13 | "ts-loader": "^9.5.1",
14 | "typescript": "^5.6.3",
15 | "webpack": "^5.95.0",
16 | "webpack-cli": "^5.1.4"
17 | },
18 | "dependencies": {
19 | "@geolonia/normalize-japanese-addresses": "file:../../.."
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/test/integration/webpack-ts/src/index.ts:
--------------------------------------------------------------------------------
1 | import { normalize } from '@geolonia/normalize-japanese-addresses';
2 |
3 | (async () => {
4 | const res = await normalize('渋谷区道玄坂1-10-8');
5 | if (res.pref !== '東京都') {
6 | throw new Error(`Expected 東京都 but got ${res.pref}`);
7 | }
8 | })()
9 | .then(() => {
10 | console.log('OK');
11 | process.exit(0);
12 | })
13 | .catch((err) => {
14 | console.error(err);
15 | process.exit(1);
16 | });
17 |
--------------------------------------------------------------------------------
/test/integration/webpack-ts/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "outDir": "./dist/",
4 | "noImplicitAny": true,
5 | "module": "es6",
6 | "target": "es5",
7 | "jsx": "react",
8 | "allowJs": true,
9 | "moduleResolution": "node"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/test/integration/webpack-ts/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | entry: './src/index.ts',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.tsx?$/,
9 | use: 'ts-loader',
10 | exclude: /node_modules/,
11 | },
12 | ],
13 | },
14 | resolve: {
15 | extensions: ['.tsx', '.ts', '.js'],
16 | },
17 | output: {
18 | filename: 'bundle.js',
19 | path: path.resolve(__dirname, 'dist'),
20 | },
21 | };
22 |
--------------------------------------------------------------------------------
/test/integration/webpack.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, test } from 'node:test'
2 | import assert from 'node:assert'
3 |
4 | import { promisify } from 'node:util'
5 | import { exec as execCb } from 'node:child_process'
6 | import path from 'node:path'
7 |
8 | const exec = promisify(execCb)
9 |
10 | describe(`webpack with TS`, { timeout: 60_000 }, () => {
11 | test(`build & run`, async () => {
12 | const cwd = path.join(import.meta.dirname, `webpack-ts`)
13 | await exec(`npm install`, { cwd })
14 | await exec(`npm run build`, { cwd })
15 | const res = await exec(`node ./dist/bundle.js`, { cwd })
16 |
17 | assert.strictEqual(res.stdout.trim(), 'OK')
18 | assert.strictEqual(res.stderr, '')
19 | })
20 | })
21 |
--------------------------------------------------------------------------------
/test/main/filesystem-api.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, test, before, after } from 'node:test'
2 | import path from 'node:path'
3 | import os from 'node:os'
4 | import fs from 'node:fs'
5 | import assert from 'node:assert'
6 | import { pipeline } from 'node:stream/promises'
7 | import { fetch } from 'undici'
8 | import { normalize, config } from '../../src/main-node'
9 | import { assertMatchCloseTo } from '../helpers'
10 |
11 | async function downloadFile(file: string, destDir: string) {
12 | const resp = await fetch(`https://japanese-addresses-v2.geoloniamaps.com/api/${file}`)
13 | const outputFile = path.join(destDir, file)
14 | await fs.promises.mkdir(path.dirname(outputFile), { recursive: true })
15 | const writer = fs.createWriteStream(outputFile)
16 | if (!resp.body) { throw new Error('No body') }
17 | await pipeline(resp.body, writer)
18 | }
19 |
20 | describe(`API stored in filesystem`, () => {
21 | let tmpdir: string
22 | before(async () => {
23 | tmpdir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'qtile-update-csv-'))
24 | const files = [
25 | 'ja.json',
26 | 'ja/東京都/渋谷区.json',
27 | 'ja/東京都/渋谷区-住居表示.txt',
28 | ]
29 | for (const file of files) {
30 | await downloadFile(file, tmpdir)
31 | }
32 |
33 | config.japaneseAddressesApi = `file://${tmpdir}/ja`
34 | })
35 |
36 | after(async () => {
37 | await fs.promises.rm(tmpdir, { recursive: true, force: true })
38 | })
39 |
40 | test(`基本的に動く`, async () => {
41 | const res = await normalize('渋谷区道玄坂1-10-8')
42 | assertMatchCloseTo(res, {
43 | pref: '東京都',
44 | city: '渋谷区',
45 | town: '道玄坂一丁目',
46 | level: 8,
47 | })
48 | })
49 |
50 | test(`用意されていないエリアはエラーになる`, async () => {
51 | try {
52 | await normalize('東京都千代田区')
53 | } catch (e) {
54 | assert.strictEqual(e.code, 'ENOENT')
55 | }
56 | })
57 | })
58 |
--------------------------------------------------------------------------------
/test/main/main.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, test } from 'node:test'
2 | import assert from 'node:assert'
3 | import { normalize } from '../../src/main-node'
4 | import { assertMatchCloseTo } from '../helpers'
5 |
6 | describe(`basic tests`, () => {
7 | test('It should get the level `1` with `神奈川県横浜市港北区大豆戸町17番地11`', async () => {
8 | const res = await normalize('神奈川県横浜市港北区大豆戸町17番地11', {
9 | level: 1,
10 | })
11 | assertMatchCloseTo(res, {
12 | pref: '神奈川県',
13 | level: 1,
14 | })
15 | })
16 |
17 | test('It should get the level `2` with `神奈川県横浜市港北区大豆戸町17番地11`', async () => {
18 | const res = await normalize('神奈川県横浜市港北区大豆戸町17番地11', {
19 | level: 2,
20 | })
21 | assertMatchCloseTo(res, {
22 | pref: '神奈川県',
23 | city: '横浜市港北区',
24 | level: 2,
25 | })
26 | })
27 |
28 | test('It should get the level `3` with `神奈川県横浜市港北区大豆戸町17番地11`', async () => {
29 | const res = await normalize('神奈川県横浜市港北区大豆戸町17番地11', {
30 | level: 3,
31 | })
32 | assertMatchCloseTo(res, {
33 | pref: '神奈川県',
34 | city: '横浜市港北区',
35 | town: '大豆戸町',
36 | other: '17-11',
37 | level: 3,
38 | })
39 | })
40 |
41 | test('It should get the level `2` with `神奈川県横浜市港北区`', async () => {
42 | const res = await normalize('神奈川県横浜市港北区', {
43 | level: 3,
44 | })
45 | assertMatchCloseTo(res, {
46 | pref: '神奈川県',
47 | city: '横浜市港北区',
48 | level: 2,
49 | })
50 | })
51 |
52 | test('It should get the level `1` with `神奈川県`', async () => {
53 | const res = await normalize('神奈川県', {
54 | level: 3,
55 | })
56 | assertMatchCloseTo(res, {
57 | pref: '神奈川県',
58 | level: 1,
59 | })
60 | })
61 |
62 | test('It should get the level `1` with `神奈川県あいうえお市`', async () => {
63 | const res = await normalize('神奈川県あいうえお市')
64 | assertMatchCloseTo(res, {
65 | pref: '神奈川県',
66 | level: 1,
67 | })
68 | })
69 |
70 | test('It should get the level `2` with `東京都港区あいうえお`', async () => {
71 | const res = await normalize('東京都港区あいうえお')
72 | assertMatchCloseTo(res, {
73 | pref: '東京都',
74 | city: '港区',
75 | level: 2,
76 | })
77 | })
78 |
79 | test('It should get the level `0` with `あいうえお`', async () => {
80 | const res = await normalize('あいうえお')
81 | assertMatchCloseTo(res, {
82 | other: 'あいうえお',
83 | level: 0,
84 | })
85 | })
86 |
87 | describe('東京都江東区豊洲一丁目2-27 のパターンテスト', () => {
88 | const addresses = [
89 | '東京都江東区豊洲1丁目2-27',
90 | '東京都江東区豊洲 1丁目2-27',
91 | '東京都江東区豊洲 1-2-27',
92 | '東京都 江東区 豊洲 1-2-27',
93 | '東京都江東区豊洲 1ー2ー27',
94 | '東京都江東区豊洲 一丁目2-27',
95 | '江東区豊洲 一丁目2-27',
96 | ]
97 | for (const address of addresses) {
98 | test(address, async () => {
99 | const res = await normalize(address)
100 | assertMatchCloseTo(res, {
101 | pref: '東京都',
102 | city: '江東区',
103 | town: '豊洲一丁目',
104 | addr: '2-27',
105 | level: 8,
106 | point: {
107 | lat: 35.661166758,
108 | lng: 139.793685144,
109 | level: 8,
110 | },
111 | })
112 | })
113 | }
114 | })
115 |
116 | test('東京都町田市木曽東4丁目14-イ22 ジオロニアマンション', async () => {
117 | const res = await normalize(
118 | '東京都町田市木曽東四丁目14ーイ22 ジオロニアマンション',
119 | )
120 | assertMatchCloseTo(res, {
121 | other: '14-イ22 ジオロニアマンション',
122 | })
123 | })
124 |
125 | test('東京都町田市木曽東4丁目14-A22 ジオロニアマンション', async () => {
126 | const res = await normalize(
127 | '東京都町田市木曽東四丁目14ーA22 ジオロニアマンション',
128 | )
129 | assertMatchCloseTo(res, {
130 | other: '14-A22 ジオロニアマンション',
131 | })
132 | })
133 |
134 | test('東京都町田市木曽東4丁目一四━A二二 ジオロニアマンション', async () => {
135 | const res = await normalize(
136 | '東京都町田市木曽東四丁目一四━A二二 ジオロニアマンション',
137 | )
138 | assertMatchCloseTo(res, {
139 | other: '14-A22 ジオロニアマンション',
140 | })
141 | })
142 |
143 | test('東京都江東区豊洲 四-2-27', async () => {
144 | const res = await normalize('東京都江東区豊洲 四-2-27')
145 | assertMatchCloseTo(res, {
146 | town: '豊洲四丁目',
147 | })
148 | })
149 |
150 | describe('石川県七尾市藤橋町亥45番地1 のパターンテスト', () => {
151 | const addresses = [
152 | '石川県七尾市藤橋町亥45番地1',
153 | '石川県七尾市藤橋町亥四十五番地1',
154 | '石川県七尾市藤橋町 亥 四十五番地1',
155 | '石川県七尾市藤橋町 亥 45-1',
156 | '七尾市藤橋町 亥 45-1',
157 | ]
158 | for (const address of addresses) {
159 | test(address, async () => {
160 | const res = await normalize(address)
161 | assertMatchCloseTo(res, {
162 | pref: '石川県',
163 | city: '七尾市',
164 | town: '藤橋町亥',
165 | addr: '45-1',
166 | level: 8,
167 | point: {
168 | lat: 37.043108,
169 | lng: 136.967296,
170 | level: 2,
171 | },
172 | })
173 | })
174 | }
175 | })
176 |
177 | test('should handle unicode normalization', async () => {
178 | const address = `茨城県つくば市筑穂1丁目10−4`.normalize('NFKD')
179 | const resp = await normalize(address)
180 | assert.strictEqual(resp.city, 'つくば市')
181 | })
182 |
183 | test('町丁目名が判別できなかった場合、残った住所には漢数字->数字などの変換処理を施さない', async () => {
184 | const res = await normalize('北海道滝川市一の坂町西')
185 | assert.strictEqual(res.level, 2)
186 | assert.strictEqual(res.town, undefined)
187 | assert.strictEqual(res.other, '一の坂町西')
188 | })
189 |
190 | test('丁目の数字だけあるときは正しく「一丁目」まで補充できる', async () => {
191 | const res = await normalize('東京都文京区小石川1')
192 | assert.strictEqual(res.town, '小石川一丁目')
193 | assert.strictEqual(res.other, '')
194 | })
195 |
196 | test('丁目の数字だけあるときは正しく「一丁目」まで補充できる(以降も対応)', async () => {
197 | const res = await normalize('東京都文京区小石川1ビル名')
198 | assert.strictEqual(res.town, '小石川一丁目')
199 | assert.strictEqual(res.other, 'ビル名')
200 | })
201 |
202 | describe('旧漢字対応', () => {
203 | test('亞 -> 亜', async () => {
204 | const addresses = ['宮城県大崎市古川大崎東亞', '宮城県大崎市古川大崎東亜']
205 | for (const address of addresses) {
206 | const res = await normalize(address)
207 | assert.strictEqual(res.town, '古川大崎字東亜')
208 | assert.strictEqual(res.level, 3)
209 | }
210 | })
211 |
212 | test('澤 -> 沢', async () => {
213 | const addresses = [
214 | '東京都西多摩郡奥多摩町海沢',
215 | '東京都西多摩郡奥多摩町海澤',
216 | ]
217 | for (const address of addresses) {
218 | const res = await normalize(address)
219 | assert.strictEqual(res.town, '海澤')
220 | assert.strictEqual(res.level, 3)
221 | }
222 | })
223 |
224 | test('麩 -> 麸', async () => {
225 | const addresses = ['愛知県津島市池麩町', '愛知県津島市池麸町']
226 | for (const address of addresses) {
227 | const res = await normalize(address)
228 | assert.strictEqual(res.town, '池麸町')
229 | assert.strictEqual(res.level, 3)
230 | }
231 | })
232 |
233 | test('驒 -> 騨', async () => {
234 | const addresses = ['岐阜県飛驒市', '岐阜県飛騨市']
235 | for (const address of addresses) {
236 | const res = await normalize(address)
237 | assert.strictEqual(res.city, '飛騨市')
238 | assert.strictEqual(res.level, 2)
239 | }
240 | })
241 | })
242 |
243 | test('柿碕町|柿さき町', async () => {
244 | const addresses = ['愛知県安城市柿さき町', '愛知県安城市柿碕町']
245 | for (const address of addresses) {
246 | const res = await normalize(address)
247 | assert.strictEqual(res.town, '柿碕町')
248 | assert.strictEqual(res.level, 3)
249 | }
250 | })
251 |
252 | describe('漢数字の小字のケース', () => {
253 | test('愛知県豊田市西丹波町三五十', async () => {
254 | const address = '愛知県豊田市西丹波町三五十'
255 | const res = await normalize(address)
256 | assertMatchCloseTo(res, {
257 | town: '西丹波町',
258 | other: '三五十',
259 | level: 3,
260 | })
261 | })
262 |
263 | test('広島県府中市栗柄町名字八五十2459 小字以降は現在のところ無視される', async () => {
264 | const address = '広島県府中市栗柄町名字八五十2459'
265 | const res = await normalize(address)
266 | assertMatchCloseTo(res, {
267 | town: '栗柄町',
268 | other: '名字八五十2459',
269 | level: 3,
270 | })
271 | })
272 | })
273 | })
274 |
--------------------------------------------------------------------------------
/test/main/metadata.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, test } from 'node:test'
2 | import assert from 'node:assert'
3 | import { normalize } from '../../src/main-node'
4 |
5 | describe(`metadata tests`, () => {
6 | test(`all fields are present`, async () => {
7 | const res = await normalize('渋谷区道玄坂1-10-8')
8 | assert.strictEqual(res.metadata.input, '渋谷区道玄坂1-10-8')
9 |
10 | assert.strictEqual(res.metadata.prefecture?.code, 130001)
11 | assert.strictEqual(res.metadata.prefecture?.pref, '東京都')
12 | assert.strictEqual(res.metadata.prefecture?.pref_k, 'トウキョウト')
13 | assert.strictEqual(res.metadata.prefecture?.pref_r, 'Tokyo')
14 | assert.ok(!('cities' in res.metadata.prefecture))
15 |
16 | assert.strictEqual(res.metadata.city?.code, 131130)
17 | assert.strictEqual(res.metadata.city?.city, '渋谷区')
18 | assert.strictEqual(res.metadata.city?.city_k, 'シブヤク')
19 | assert.strictEqual(res.metadata.city?.city_r, 'Shibuya-ku')
20 |
21 | assert.strictEqual(res.metadata.machiAza?.oaza_cho, '道玄坂')
22 | assert.strictEqual(res.metadata.machiAza?.oaza_cho_k, 'ドウゲンザカ')
23 | assert.strictEqual(res.metadata.machiAza?.oaza_cho_r, 'Dogenzaka')
24 | assert.strictEqual(res.metadata.machiAza?.chome_n, 1)
25 |
26 | assert.strictEqual(res.metadata.rsdt?.blk_num, '10')
27 | assert.strictEqual(res.metadata.rsdt?.rsdt_num, '8')
28 |
29 | assert.strictEqual(res.metadata.chiban, undefined)
30 | })
31 |
32 | test(`the appropriate fields are not set if level is set`, async () => {
33 | const res = await normalize('渋谷区道玄坂1-10-8', { level: 2 })
34 | assert.strictEqual(res.metadata.input, '渋谷区道玄坂1-10-8')
35 |
36 | assert.ok(res.metadata.prefecture)
37 | assert.ok(res.metadata.city)
38 |
39 | assert.strictEqual(res.metadata.machiAza, undefined)
40 | assert.strictEqual(res.metadata.rsdt, undefined)
41 | assert.strictEqual(res.metadata.chiban, undefined)
42 | })
43 | })
44 |
--------------------------------------------------------------------------------
/test/run.ts:
--------------------------------------------------------------------------------
1 | import { spec as specReporter } from 'node:test/reporters';
2 | import { run } from 'node:test';
3 | import process from 'node:process';
4 | import { finished } from 'node:stream/promises';
5 | import path from 'node:path';
6 | import { glob } from 'glob';
7 |
8 | async function main(base: string, ...testNamePatterns: string[]) {
9 | // node-glob doesn't work with Windows paths, but it does work on Windows
10 | // if you give it a POSIX path.
11 | const files = await glob(path.posix.join('test', base, '**/*.test.ts'), {
12 | absolute: true,
13 | });
14 | const testStream = run({
15 | files,
16 | testNamePatterns,
17 | });
18 | testStream.on('test:fail', () => {
19 | process.exitCode = 1
20 | });
21 | const outStream = testStream.compose(new specReporter()).pipe(process.stdout);
22 | await finished(outStream);
23 | }
24 |
25 | main(process.argv[2], ...process.argv.slice(3))
26 | .then(() => {
27 | process.exit()
28 | })
29 | .catch((e) => {
30 | console.error(e)
31 | process.exit(1)
32 | })
33 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "outDir": "dist",
4 | "target": "es6",
5 | "lib": ["dom", "dom.iterable", "esnext"],
6 | "allowJs": true,
7 | "skipLibCheck": true,
8 | "esModuleInterop": true,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "esnext",
13 | "moduleResolution": "node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "declaration": true
17 | },
18 | "include": ["src"],
19 | "exclude": ["__test__", "src/**/*.test.ts", "dist", "node_modules"]
20 | }
21 |
--------------------------------------------------------------------------------