japanese_address_parser 3.1.0 → 3.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -0
- data/Gemfile.lock +7 -5
- data/js/node_modules/.package-lock.json +3 -3
- data/js/node_modules/@geolonia/normalize-japanese-addresses/dist/lib/cacheRegexes.d.ts +9 -2
- data/js/node_modules/@geolonia/normalize-japanese-addresses/dist/main-browser.js +121 -18
- data/js/node_modules/@geolonia/normalize-japanese-addresses/dist/main-es.js +121 -18
- data/js/node_modules/@geolonia/normalize-japanese-addresses/dist/main-node.d.ts +6 -0
- data/js/node_modules/@geolonia/normalize-japanese-addresses/dist/main-node.js +183 -47
- data/js/node_modules/@geolonia/normalize-japanese-addresses/dist/normalize.d.ts +46 -2
- data/js/node_modules/@geolonia/normalize-japanese-addresses/package.json +4 -3
- data/js/node_modules/@geolonia/normalize-japanese-addresses/src/config.ts +1 -0
- data/js/node_modules/@geolonia/normalize-japanese-addresses/src/lib/cacheRegexes.ts +55 -9
- data/js/node_modules/@geolonia/normalize-japanese-addresses/src/lib/kan2num.ts +6 -2
- data/js/node_modules/@geolonia/normalize-japanese-addresses/src/main-node.ts +41 -12
- data/js/node_modules/@geolonia/normalize-japanese-addresses/src/normalize.ts +163 -35
- data/js/package-lock.json +7 -7
- data/js/package.json +1 -1
- data/lib/japanese_address_parser/version.rb +1 -1
- metadata +3 -3
@@ -78,6 +78,7 @@ function __generator(thisArg, body) {
|
|
78
78
|
|
79
79
|
var gh_pages_endpoint = 'https://geolonia.github.io/japanese-addresses/api/ja';
|
80
80
|
var currentConfig = {
|
81
|
+
interfaceVersion: 1,
|
81
82
|
japaneseAddressesApi: gh_pages_endpoint,
|
82
83
|
townCacheSize: 1000,
|
83
84
|
};
|
@@ -85,8 +86,13 @@ var currentConfig = {
|
|
85
86
|
var kan2num = function (string) {
|
86
87
|
var kanjiNumbers = japaneseNumeral.findKanjiNumbers(string);
|
87
88
|
for (var i = 0; i < kanjiNumbers.length; i++) {
|
88
|
-
|
89
|
-
|
89
|
+
try {
|
90
|
+
// @ts-ignore
|
91
|
+
string = string.replace(kanjiNumbers[i], japaneseNumeral.kanji2number(kanjiNumbers[i]));
|
92
|
+
}
|
93
|
+
catch (error) {
|
94
|
+
// ignore
|
95
|
+
}
|
90
96
|
}
|
91
97
|
return string;
|
92
98
|
};
|
@@ -191,6 +197,7 @@ var cachedPrefectures = undefined;
|
|
191
197
|
var cachedTowns = {};
|
192
198
|
var cachedGaikuListItem = {};
|
193
199
|
var cachedResidentials = {};
|
200
|
+
var cachedAddrs = {}; // TODO: use LRU
|
194
201
|
var cachedSameNamedPrefectureCityRegexPatterns = undefined;
|
195
202
|
var getPrefectures = function () { return __awaiter(void 0, void 0, void 0, function () {
|
196
203
|
var prefsResp, data;
|
@@ -200,7 +207,7 @@ var getPrefectures = function () { return __awaiter(void 0, void 0, void 0, func
|
|
200
207
|
if (typeof cachedPrefectures !== 'undefined') {
|
201
208
|
return [2 /*return*/, cachedPrefectures];
|
202
209
|
}
|
203
|
-
return [4 /*yield*/, __internals.fetch('.json')]; // ja.json
|
210
|
+
return [4 /*yield*/, __internals.fetch('.json', { level: 1 })]; // ja.json
|
204
211
|
case 1:
|
205
212
|
prefsResp = _a.sent() // ja.json
|
206
213
|
;
|
@@ -254,7 +261,7 @@ var getTowns = function (pref, city) { return __awaiter(void 0, void 0, void 0,
|
|
254
261
|
if (typeof cachedTown !== 'undefined') {
|
255
262
|
return [2 /*return*/, cachedTown];
|
256
263
|
}
|
257
|
-
return [4 /*yield*/, __internals.fetch(['', encodeURI(pref), encodeURI(city) + '.json'].join('/'))];
|
264
|
+
return [4 /*yield*/, __internals.fetch(['', encodeURI(pref), encodeURI(city) + '.json'].join('/'), { level: 3, pref: pref, city: city })];
|
258
265
|
case 1:
|
259
266
|
townsResp = _a.sent();
|
260
267
|
return [4 /*yield*/, townsResp.json()];
|
@@ -269,7 +276,10 @@ var getGaikuList = function (pref, city, town) { return __awaiter(void 0, void 0
|
|
269
276
|
return __generator(this, function (_b) {
|
270
277
|
switch (_b.label) {
|
271
278
|
case 0:
|
272
|
-
|
279
|
+
if (currentConfig.interfaceVersion > 1) {
|
280
|
+
throw new Error("Invalid config.interfaceVersion: " + currentConfig.interfaceVersion + "'}. Please set config.interfaceVersion to 1.");
|
281
|
+
}
|
282
|
+
cacheKey = pref + "-" + city + "-" + town + "-v" + currentConfig.interfaceVersion;
|
273
283
|
cache = cachedGaikuListItem[cacheKey];
|
274
284
|
if (typeof cache !== 'undefined') {
|
275
285
|
return [2 /*return*/, cache];
|
@@ -297,7 +307,10 @@ var getResidentials = function (pref, city, town) { return __awaiter(void 0, voi
|
|
297
307
|
return __generator(this, function (_b) {
|
298
308
|
switch (_b.label) {
|
299
309
|
case 0:
|
300
|
-
|
310
|
+
if (currentConfig.interfaceVersion > 1) {
|
311
|
+
throw new Error("Invalid config.interfaceVersion: " + currentConfig.interfaceVersion + "'}. Please set config.interfaceVersion to 1.");
|
312
|
+
}
|
313
|
+
cacheKey = pref + "-" + city + "-" + town + "-v" + currentConfig.interfaceVersion;
|
301
314
|
cache = cachedResidentials[cacheKey];
|
302
315
|
if (typeof cache !== 'undefined') {
|
303
316
|
return [2 /*return*/, cache];
|
@@ -331,6 +344,39 @@ var getResidentials = function (pref, city, town) { return __awaiter(void 0, voi
|
|
331
344
|
}
|
332
345
|
});
|
333
346
|
}); };
|
347
|
+
var getAddrs = function (pref, city, town) { return __awaiter(void 0, void 0, void 0, function () {
|
348
|
+
var cacheKey, cache, addrsResp, addrs;
|
349
|
+
return __generator(this, function (_b) {
|
350
|
+
switch (_b.label) {
|
351
|
+
case 0:
|
352
|
+
if (currentConfig.interfaceVersion < 2) {
|
353
|
+
throw new Error("Invalid config.interfaceVersion: " + currentConfig.interfaceVersion + "'}. Please set config.interfaceVersion to 2 or higher");
|
354
|
+
}
|
355
|
+
cacheKey = pref + "-" + city + "-" + town + "-v" + currentConfig.interfaceVersion;
|
356
|
+
cache = cachedAddrs[cacheKey];
|
357
|
+
if (typeof cache !== 'undefined') {
|
358
|
+
return [2 /*return*/, cache];
|
359
|
+
}
|
360
|
+
return [4 /*yield*/, __internals.fetch(['', encodeURI(pref), encodeURI(city), encodeURI(town) + '.json'].join('/'), { level: 8, pref: pref, city: city, town: town })];
|
361
|
+
case 1:
|
362
|
+
addrsResp = _b.sent();
|
363
|
+
_b.label = 2;
|
364
|
+
case 2:
|
365
|
+
_b.trys.push([2, 4, , 5]);
|
366
|
+
return [4 /*yield*/, addrsResp.json()];
|
367
|
+
case 3:
|
368
|
+
addrs = (_b.sent());
|
369
|
+
return [3 /*break*/, 5];
|
370
|
+
case 4:
|
371
|
+
_b.sent();
|
372
|
+
addrs = [];
|
373
|
+
return [3 /*break*/, 5];
|
374
|
+
case 5:
|
375
|
+
addrs.sort(function (res1, res2) { return res1.addr.length - res2.addr.length; });
|
376
|
+
return [2 /*return*/, (cachedAddrs[cacheKey] = addrs)];
|
377
|
+
}
|
378
|
+
});
|
379
|
+
}); };
|
334
380
|
// 十六町 のように漢数字と町が連結しているか
|
335
381
|
var isKanjiNumberFollewedByCho = function (targetTownName) {
|
336
382
|
var xCho = targetTownName.match(/.町/g);
|
@@ -551,10 +597,32 @@ var normalizeResidentialPart = function (addr, pref, city, town) { return __awai
|
|
551
597
|
}
|
552
598
|
});
|
553
599
|
}); };
|
600
|
+
var normalizeAddrPart = function (addr, pref, city, town) { return __awaiter(void 0, void 0, void 0, function () {
|
601
|
+
var addrListItem, addrItem, other;
|
602
|
+
return __generator(this, function (_a) {
|
603
|
+
switch (_a.label) {
|
604
|
+
case 0: return [4 /*yield*/, getAddrs(pref, city, town)
|
605
|
+
// 住居表示住所、および地番住所が見つからなかった
|
606
|
+
];
|
607
|
+
case 1:
|
608
|
+
addrListItem = _a.sent();
|
609
|
+
// 住居表示住所、および地番住所が見つからなかった
|
610
|
+
if (addrListItem.length === 0) {
|
611
|
+
return [2 /*return*/, null];
|
612
|
+
}
|
613
|
+
addrItem = addrListItem.find(function (item) { return addr.startsWith(item.addr); });
|
614
|
+
if (addrItem) {
|
615
|
+
other = addr.replace(addrItem.addr, '').trim();
|
616
|
+
return [2 /*return*/, { addr: addrItem.addr, other: other, lat: addrItem.lat, lng: addrItem.lng }];
|
617
|
+
}
|
618
|
+
return [2 /*return*/, null];
|
619
|
+
}
|
620
|
+
});
|
621
|
+
}); };
|
554
622
|
var normalize$1 = function (address, _option) {
|
555
623
|
if (_option === void 0) { _option = defaultOption; }
|
556
624
|
return __awaiter(void 0, void 0, void 0, function () {
|
557
|
-
var option, addr, pref, city, town, lat, lng, level, normalized, prefectures, prefs, prefPatterns, sameNamedPrefectureCityRegexPatterns, i, _a, prefectureCity, reg, match, i, _b, _pref, pattern, match, matched, _pref, cities, cityPatterns, i, _c, _city, pattern, match, i, normalized_1, cities, cityPatterns, i, _d, _city, pattern, match, result;
|
625
|
+
var option, addr, pref, city, town, lat, lng, level, normalized, prefectures, prefs, prefPatterns, sameNamedPrefectureCityRegexPatterns, i, _a, prefectureCity, reg, match, i, _b, _pref, pattern, match, matched, _pref, cities, cityPatterns, i, _c, _city, pattern, match, i, normalized_1, cities, cityPatterns, i, _d, _city, pattern, match, normalizedAddrPart, other, result, result;
|
558
626
|
return __generator(this, function (_e) {
|
559
627
|
switch (_e.label) {
|
560
628
|
case 0:
|
@@ -714,7 +782,7 @@ var normalize$1 = function (address, _option) {
|
|
714
782
|
// `-1` のようなケース
|
715
783
|
return kan2num(s);
|
716
784
|
})
|
717
|
-
.replace(/-[^0-9]
|
785
|
+
.replace(/-[^0-9]([0-9〇一二三四五六七八九十百千]+)/, function (s) {
|
718
786
|
// `-あ1` のようなケース
|
719
787
|
return kan2num(zen2han(s));
|
720
788
|
})
|
@@ -727,12 +795,52 @@ var normalize$1 = function (address, _option) {
|
|
727
795
|
_e.label = 8;
|
728
796
|
case 8:
|
729
797
|
addr = patchAddr(pref, city, town, addr);
|
730
|
-
if (
|
731
|
-
|
798
|
+
if (pref)
|
799
|
+
level = level + 1;
|
800
|
+
if (city)
|
801
|
+
level = level + 1;
|
802
|
+
if (town)
|
803
|
+
level = level + 1;
|
804
|
+
if (option.level <= 3 || level < 3) {
|
805
|
+
return [2 /*return*/, { pref: pref, city: city, town: town, addr: addr, level: level, lat: lat, lng: lng }];
|
806
|
+
}
|
807
|
+
if (!(currentConfig.interfaceVersion === 2)) return [3 /*break*/, 10];
|
808
|
+
return [4 /*yield*/, normalizeAddrPart(addr, pref, city, town)];
|
732
809
|
case 9:
|
733
|
-
|
734
|
-
|
810
|
+
normalizedAddrPart = _e.sent();
|
811
|
+
other = undefined;
|
812
|
+
if (normalizedAddrPart) {
|
813
|
+
addr = normalizedAddrPart.addr;
|
814
|
+
if (normalizedAddrPart.other) {
|
815
|
+
other = normalizedAddrPart.other;
|
816
|
+
}
|
817
|
+
if (normalizedAddrPart.lat !== null)
|
818
|
+
lat = parseFloat(normalizedAddrPart.lat);
|
819
|
+
if (normalizedAddrPart.lng !== null)
|
820
|
+
lng = parseFloat(normalizedAddrPart.lng);
|
821
|
+
level = 8;
|
822
|
+
}
|
823
|
+
result = {
|
824
|
+
pref: pref,
|
825
|
+
city: city,
|
826
|
+
town: town,
|
827
|
+
addr: addr,
|
828
|
+
level: level,
|
829
|
+
lat: lat,
|
830
|
+
lng: lng,
|
831
|
+
};
|
832
|
+
if (other) {
|
833
|
+
result.other = other;
|
834
|
+
}
|
835
|
+
return [2 /*return*/, result];
|
735
836
|
case 10:
|
837
|
+
if (!(currentConfig.interfaceVersion === 1)) return [3 /*break*/, 13];
|
838
|
+
if (!(option.level > 3 && normalized && town)) return [3 /*break*/, 12];
|
839
|
+
return [4 /*yield*/, normalizeResidentialPart(addr, pref, city, town)];
|
840
|
+
case 11:
|
841
|
+
normalized = _e.sent();
|
842
|
+
_e.label = 12;
|
843
|
+
case 12:
|
736
844
|
if (normalized) {
|
737
845
|
lat = parseFloat(normalized.lat);
|
738
846
|
lng = parseFloat(normalized.lng);
|
@@ -741,12 +849,6 @@ var normalize$1 = function (address, _option) {
|
|
741
849
|
lat = null;
|
742
850
|
lng = null;
|
743
851
|
}
|
744
|
-
if (pref)
|
745
|
-
level = level + 1;
|
746
|
-
if (city)
|
747
|
-
level = level + 1;
|
748
|
-
if (town)
|
749
|
-
level = level + 1;
|
750
852
|
result = {
|
751
853
|
pref: pref,
|
752
854
|
city: city,
|
@@ -766,45 +868,79 @@ var normalize$1 = function (address, _option) {
|
|
766
868
|
result.level = 8;
|
767
869
|
}
|
768
870
|
return [2 /*return*/, result];
|
871
|
+
case 13: throw new Error('invalid interfaceVersion');
|
769
872
|
}
|
770
873
|
});
|
771
874
|
});
|
772
875
|
};
|
773
876
|
|
774
|
-
var
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
});
|
797
|
-
}); },
|
798
|
-
}];
|
799
|
-
}
|
800
|
-
else {
|
801
|
-
throw new Error("Unknown URL schema: " + fileURL.protocol);
|
877
|
+
var requestHandlers = {
|
878
|
+
file: function (fileURL) {
|
879
|
+
var filePath = process.platform === 'win32'
|
880
|
+
? decodeURI(fileURL.pathname).substr(1)
|
881
|
+
: decodeURI(fileURL.pathname);
|
882
|
+
return {
|
883
|
+
json: function () { return __awaiter(void 0, void 0, void 0, function () {
|
884
|
+
var contents;
|
885
|
+
return __generator(this, function (_a) {
|
886
|
+
switch (_a.label) {
|
887
|
+
case 0: return [4 /*yield*/, fs.promises.readFile(filePath)];
|
888
|
+
case 1:
|
889
|
+
contents = _a.sent();
|
890
|
+
return [2 /*return*/, JSON.parse(contents.toString('utf-8'))];
|
891
|
+
}
|
892
|
+
});
|
893
|
+
}); },
|
894
|
+
};
|
895
|
+
},
|
896
|
+
http: function (fileURL) {
|
897
|
+
if (config$1.geoloniaApiKey) {
|
898
|
+
fileURL.search = "?geolonia-api-key=" + config$1.geoloniaApiKey;
|
802
899
|
}
|
900
|
+
return unfetch__default['default'](fileURL.toString());
|
901
|
+
},
|
902
|
+
};
|
903
|
+
/**
|
904
|
+
* 正規化のためのデータを取得する
|
905
|
+
* @param input - Path part like '東京都/文京区.json'
|
906
|
+
* @param requestOptions - input を構造化したデータ
|
907
|
+
*/
|
908
|
+
var fetchOrReadFile = function (input, requestOptions) {
|
909
|
+
if (requestOptions === void 0) { requestOptions = { level: -1 }; }
|
910
|
+
return __awaiter(void 0, void 0, void 0, function () {
|
911
|
+
var fileURL, result_1;
|
912
|
+
return __generator(this, function (_a) {
|
913
|
+
switch (_a.label) {
|
914
|
+
case 0:
|
915
|
+
fileURL = new URL("" + config$1.japaneseAddressesApi + input);
|
916
|
+
if (!(config$1.transformRequest && requestOptions.level !== -1)) return [3 /*break*/, 2];
|
917
|
+
return [4 /*yield*/, config$1.transformRequest(fileURL, requestOptions)];
|
918
|
+
case 1:
|
919
|
+
result_1 = _a.sent();
|
920
|
+
return [2 /*return*/, {
|
921
|
+
json: function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
|
922
|
+
return [2 /*return*/, Promise.resolve(result_1)];
|
923
|
+
}); }); },
|
924
|
+
}];
|
925
|
+
case 2:
|
926
|
+
if (fileURL.protocol === 'http:' || fileURL.protocol === 'https:') {
|
927
|
+
return [2 /*return*/, requestHandlers.http(fileURL)];
|
928
|
+
}
|
929
|
+
else if (fileURL.protocol === 'file:') {
|
930
|
+
return [2 /*return*/, requestHandlers.file(fileURL)];
|
931
|
+
}
|
932
|
+
else {
|
933
|
+
throw new Error("Unknown URL schema: " + fileURL.protocol);
|
934
|
+
}
|
935
|
+
case 3: return [2 /*return*/];
|
936
|
+
}
|
937
|
+
});
|
803
938
|
});
|
804
|
-
}
|
939
|
+
};
|
805
940
|
__internals.fetch = fetchOrReadFile;
|
806
941
|
var config = config$1;
|
807
942
|
var normalize = normalize$1;
|
808
943
|
|
809
944
|
exports.config = config;
|
810
945
|
exports.normalize = normalize;
|
946
|
+
exports.requestHandlers = requestHandlers;
|
@@ -1,18 +1,35 @@
|
|
1
|
+
import { PrefectureList, TownList, AddrList } from './lib/cacheRegexes';
|
2
|
+
declare type TransformRequestResponse = null | PrefectureList | TownList | AddrList;
|
3
|
+
export declare type TransformRequestQuery = {
|
4
|
+
level: number;
|
5
|
+
pref?: string;
|
6
|
+
city?: string;
|
7
|
+
town?: string;
|
8
|
+
};
|
9
|
+
export declare type TransformRequestFunction = (url: URL, query: TransformRequestQuery) => TransformRequestResponse | Promise<TransformRequestResponse>;
|
1
10
|
/**
|
2
11
|
* normalize {@link Normalizer} の動作オプション。
|
3
12
|
*/
|
4
13
|
export interface Config {
|
14
|
+
/**
|
15
|
+
* レスポンス型のバージョン。デフォルト 1
|
16
|
+
* 1 の場合は jyukyo: string, gaiku: string
|
17
|
+
* 2 の場合は addr: string, other: string
|
18
|
+
*/
|
19
|
+
interfaceVersion: number;
|
5
20
|
/** 住所データを URL 形式で指定。 file:// 形式で指定するとローカルファイルを参照できます。 */
|
6
21
|
japaneseAddressesApi: string;
|
7
22
|
/** 町丁目のデータを何件までキャッシュするか。デフォルト 1,000 */
|
8
23
|
townCacheSize: number;
|
24
|
+
/** 住所データへのリクエストを変形するオプション。 interfaceVersion === 2 で有効 */
|
25
|
+
transformRequest?: TransformRequestFunction;
|
9
26
|
geoloniaApiKey?: string;
|
10
27
|
}
|
11
28
|
export declare const config: Config;
|
12
29
|
/**
|
13
30
|
* 住所の正規化結果として戻されるオブジェクト
|
14
31
|
*/
|
15
|
-
|
32
|
+
interface NormalizeResult_v1 {
|
16
33
|
/** 都道府県 */
|
17
34
|
pref: string;
|
18
35
|
/** 市区町村 */
|
@@ -40,6 +57,32 @@ export interface NormalizeResult {
|
|
40
57
|
*/
|
41
58
|
level: number;
|
42
59
|
}
|
60
|
+
declare type NormalizeResult_v2 = {
|
61
|
+
/** 都道府県 */
|
62
|
+
pref: string;
|
63
|
+
/** 市区町村 */
|
64
|
+
city: string;
|
65
|
+
/** 町丁目 */
|
66
|
+
town: string;
|
67
|
+
/** 住居表示または地番 */
|
68
|
+
addr: string;
|
69
|
+
/** 正規化後の住所文字列 */
|
70
|
+
other?: string;
|
71
|
+
/** 緯度。データが存在しない場合は null */
|
72
|
+
lat: number | null;
|
73
|
+
/** 経度。データが存在しない場合は null */
|
74
|
+
lng: number | null;
|
75
|
+
/**
|
76
|
+
* 住所文字列をどこまで判別できたかを表す正規化レベル
|
77
|
+
* - 0 - 都道府県も判別できなかった。
|
78
|
+
* - 1 - 都道府県まで判別できた。
|
79
|
+
* - 2 - 市区町村まで判別できた。
|
80
|
+
* - 3 - 町丁目まで判別できた。
|
81
|
+
* - 8 - 住居表示住所の街区符号・住居番号までの判別または地番住所の判別ができた。
|
82
|
+
*/
|
83
|
+
level: number;
|
84
|
+
};
|
85
|
+
export declare type NormalizeResult = NormalizeResult_v1 | NormalizeResult_v2;
|
43
86
|
/**
|
44
87
|
* 正規化関数の {@link normalize} のオプション
|
45
88
|
*/
|
@@ -64,7 +107,7 @@ export interface Option {
|
|
64
107
|
* @see https://github.com/geolonia/normalize-japanese-addresses#normalizeaddress-string
|
65
108
|
*/
|
66
109
|
export declare type Normalizer = (input: string, option?: Option) => Promise<NormalizeResult>;
|
67
|
-
export declare type FetchLike = (input: string) => Promise<Response | {
|
110
|
+
export declare type FetchLike = (input: string, requestQuery?: TransformRequestQuery) => Promise<Response | {
|
68
111
|
json: () => Promise<unknown>;
|
69
112
|
}>;
|
70
113
|
/**
|
@@ -74,3 +117,4 @@ export declare const __internals: {
|
|
74
117
|
fetch: FetchLike;
|
75
118
|
};
|
76
119
|
export declare const normalize: Normalizer;
|
120
|
+
export {};
|
@@ -1,16 +1,17 @@
|
|
1
1
|
{
|
2
2
|
"name": "@geolonia/normalize-japanese-addresses",
|
3
|
-
"version": "2.
|
3
|
+
"version": "2.9.2",
|
4
4
|
"description": "",
|
5
5
|
"browser": "./dist/main-browser.js",
|
6
6
|
"main": "./dist/main-node.js",
|
7
7
|
"types": "./dist/normalize.d.ts",
|
8
8
|
"scripts": {
|
9
|
-
"test": "npm run test:main && npm run test:addresses && npm run test:node:platform && npm run test:
|
9
|
+
"test": "npm run test:main && npm run test:addresses && npm run test:node:platform && npm run test:advanced",
|
10
10
|
"test:node:platform": "npm run test:node-win || npm run test:node",
|
11
11
|
"test:main": "jest test/main.test.ts",
|
12
12
|
"test:addresses": "jest test/addresses.test.ts",
|
13
|
-
"test:
|
13
|
+
"test:advanced": "jest test/advanced --runInBand",
|
14
|
+
"test:util": "jest test/util.test.ts",
|
14
15
|
"test:node": "curl -sL https://github.com/geolonia/japanese-addresses/archive/refs/heads/master.tar.gz | tar xvfz - -C ./test > nul 2>&1 && jest test/fs.test.ts",
|
15
16
|
"test:node-win": "curl -sL https://github.com/geolonia/japanese-addresses/archive/refs/heads/master.tar.gz -o master.tar.gz && 7z x master.tar.gz -y -o./ && 7z x ./master.tar -y -o./test && del master.tar.gz master.tar && jest test/fs.test.ts",
|
16
17
|
"test:generate-test-data": "npx ts-node -O '{\"module\":\"commonjs\"}' test/build-test-data.ts > test/addresses.csv",
|
@@ -5,7 +5,7 @@ import { currentConfig } from '../config'
|
|
5
5
|
import { __internals } from '../normalize'
|
6
6
|
import { findKanjiNumbers } from '@geolonia/japanese-numeral'
|
7
7
|
|
8
|
-
type PrefectureList = { [key: string]: string[] }
|
8
|
+
export type PrefectureList = { [key: string]: string[] }
|
9
9
|
interface SingleTown {
|
10
10
|
town: string
|
11
11
|
originalTown?: string
|
@@ -13,8 +13,13 @@ interface SingleTown {
|
|
13
13
|
lat: string
|
14
14
|
lng: string
|
15
15
|
}
|
16
|
-
type TownList = SingleTown[]
|
17
|
-
|
16
|
+
export type TownList = SingleTown[]
|
17
|
+
interface SingleAddr {
|
18
|
+
addr: string
|
19
|
+
lat: string | null
|
20
|
+
lng: string | null
|
21
|
+
}
|
22
|
+
export type AddrList = SingleAddr[]
|
18
23
|
interface GaikuListItem {
|
19
24
|
gaiku: string
|
20
25
|
lat: string
|
@@ -40,16 +45,16 @@ let cachedPrefectures: PrefectureList | undefined = undefined
|
|
40
45
|
const cachedTowns: { [key: string]: TownList } = {}
|
41
46
|
const cachedGaikuListItem: { [key: string]: GaikuListItem[] } = {}
|
42
47
|
const cachedResidentials: { [key: string]: ResidentialList } = {}
|
43
|
-
|
44
|
-
|
45
|
-
|
48
|
+
const cachedAddrs: { [key: string]: AddrList } = {} // TODO: use LRU
|
49
|
+
let cachedSameNamedPrefectureCityRegexPatterns: [string, string][] | undefined =
|
50
|
+
undefined
|
46
51
|
|
47
52
|
export const getPrefectures = async () => {
|
48
53
|
if (typeof cachedPrefectures !== 'undefined') {
|
49
54
|
return cachedPrefectures
|
50
55
|
}
|
51
56
|
|
52
|
-
const prefsResp = await __internals.fetch('.json') // ja.json
|
57
|
+
const prefsResp = await __internals.fetch('.json', { level: 1 }) // ja.json
|
53
58
|
const data = (await prefsResp.json()) as PrefectureList
|
54
59
|
return cachePrefectures(data)
|
55
60
|
}
|
@@ -104,6 +109,7 @@ export const getTowns = async (pref: string, city: string) => {
|
|
104
109
|
|
105
110
|
const townsResp = await __internals.fetch(
|
106
111
|
['', encodeURI(pref), encodeURI(city) + '.json'].join('/'),
|
112
|
+
{ level: 3, pref, city },
|
107
113
|
)
|
108
114
|
const towns = (await townsResp.json()) as TownList
|
109
115
|
return (cachedTowns[cacheKey] = towns)
|
@@ -114,7 +120,13 @@ export const getGaikuList = async (
|
|
114
120
|
city: string,
|
115
121
|
town: string,
|
116
122
|
) => {
|
117
|
-
|
123
|
+
if (currentConfig.interfaceVersion > 1) {
|
124
|
+
throw new Error(
|
125
|
+
`Invalid config.interfaceVersion: ${currentConfig.interfaceVersion}'}. Please set config.interfaceVersion to 1.`,
|
126
|
+
)
|
127
|
+
}
|
128
|
+
|
129
|
+
const cacheKey = `${pref}-${city}-${town}-v${currentConfig.interfaceVersion}`
|
118
130
|
const cache = cachedGaikuListItem[cacheKey]
|
119
131
|
if (typeof cache !== 'undefined') {
|
120
132
|
return cache
|
@@ -136,7 +148,13 @@ export const getResidentials = async (
|
|
136
148
|
city: string,
|
137
149
|
town: string,
|
138
150
|
) => {
|
139
|
-
|
151
|
+
if (currentConfig.interfaceVersion > 1) {
|
152
|
+
throw new Error(
|
153
|
+
`Invalid config.interfaceVersion: ${currentConfig.interfaceVersion}'}. Please set config.interfaceVersion to 1.`,
|
154
|
+
)
|
155
|
+
}
|
156
|
+
|
157
|
+
const cacheKey = `${pref}-${city}-${town}-v${currentConfig.interfaceVersion}`
|
140
158
|
const cache = cachedResidentials[cacheKey]
|
141
159
|
if (typeof cache !== 'undefined') {
|
142
160
|
return cache
|
@@ -166,6 +184,34 @@ export const getResidentials = async (
|
|
166
184
|
return (cachedResidentials[cacheKey] = residentials)
|
167
185
|
}
|
168
186
|
|
187
|
+
export const getAddrs = async (pref: string, city: string, town: string) => {
|
188
|
+
if (currentConfig.interfaceVersion < 2) {
|
189
|
+
throw new Error(
|
190
|
+
`Invalid config.interfaceVersion: ${currentConfig.interfaceVersion}'}. Please set config.interfaceVersion to 2 or higher`,
|
191
|
+
)
|
192
|
+
}
|
193
|
+
|
194
|
+
const cacheKey = `${pref}-${city}-${town}-v${currentConfig.interfaceVersion}`
|
195
|
+
const cache = cachedAddrs[cacheKey]
|
196
|
+
if (typeof cache !== 'undefined') {
|
197
|
+
return cache
|
198
|
+
}
|
199
|
+
|
200
|
+
const addrsResp = await __internals.fetch(
|
201
|
+
['', encodeURI(pref), encodeURI(city), encodeURI(town) + '.json'].join('/'),
|
202
|
+
{ level: 8, pref, city, town },
|
203
|
+
)
|
204
|
+
let addrs: AddrList
|
205
|
+
try {
|
206
|
+
addrs = (await addrsResp.json()) as AddrList
|
207
|
+
} catch {
|
208
|
+
addrs = []
|
209
|
+
}
|
210
|
+
|
211
|
+
addrs.sort((res1, res2) => res1.addr.length - res2.addr.length)
|
212
|
+
return (cachedAddrs[cacheKey] = addrs)
|
213
|
+
}
|
214
|
+
|
169
215
|
// 十六町 のように漢数字と町が連結しているか
|
170
216
|
const isKanjiNumberFollewedByCho = (targetTownName: string) => {
|
171
217
|
const xCho = targetTownName.match(/.町/g)
|
@@ -3,8 +3,12 @@ import { kanji2number, findKanjiNumbers } from '@geolonia/japanese-numeral'
|
|
3
3
|
export const kan2num = (string: string) => {
|
4
4
|
const kanjiNumbers = findKanjiNumbers(string)
|
5
5
|
for (let i = 0; i < kanjiNumbers.length; i++) {
|
6
|
-
|
7
|
-
|
6
|
+
try {
|
7
|
+
// @ts-ignore
|
8
|
+
string = string.replace(kanjiNumbers[i], kanji2number(kanjiNumbers[i]));
|
9
|
+
} catch (error) {
|
10
|
+
// ignore
|
11
|
+
}
|
8
12
|
}
|
9
13
|
|
10
14
|
return string
|
@@ -1,26 +1,55 @@
|
|
1
1
|
import * as Normalize from './normalize'
|
2
2
|
import { promises as fs } from 'fs'
|
3
3
|
import unfetch from 'isomorphic-unfetch'
|
4
|
+
import { TransformRequestQuery } from './normalize'
|
4
5
|
|
5
|
-
const
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
fileURL.search = `?geolonia-api-key=${Normalize.config.geoloniaApiKey}`
|
12
|
-
}
|
13
|
-
return unfetch(fileURL.toString())
|
14
|
-
} else if (fileURL.protocol === 'file:') {
|
15
|
-
const filePath = process.platform === 'win32' ? decodeURI(fileURL.pathname).substr(1) : decodeURI(fileURL.pathname);
|
6
|
+
export const requestHandlers = {
|
7
|
+
file: (fileURL: URL) => {
|
8
|
+
const filePath =
|
9
|
+
process.platform === 'win32'
|
10
|
+
? decodeURI(fileURL.pathname).substr(1)
|
11
|
+
: decodeURI(fileURL.pathname)
|
16
12
|
return {
|
17
13
|
json: async () => {
|
18
14
|
const contents = await fs.readFile(filePath)
|
19
15
|
return JSON.parse(contents.toString('utf-8'))
|
20
16
|
},
|
21
17
|
}
|
18
|
+
},
|
19
|
+
http: (fileURL: URL) => {
|
20
|
+
if (Normalize.config.geoloniaApiKey) {
|
21
|
+
fileURL.search = `?geolonia-api-key=${Normalize.config.geoloniaApiKey}`
|
22
|
+
}
|
23
|
+
return unfetch(fileURL.toString())
|
24
|
+
},
|
25
|
+
}
|
26
|
+
|
27
|
+
/**
|
28
|
+
* 正規化のためのデータを取得する
|
29
|
+
* @param input - Path part like '東京都/文京区.json'
|
30
|
+
* @param requestOptions - input を構造化したデータ
|
31
|
+
*/
|
32
|
+
const fetchOrReadFile = async (
|
33
|
+
input: string,
|
34
|
+
requestOptions: TransformRequestQuery = { level: -1 },
|
35
|
+
): Promise<Response | { json: () => Promise<unknown> }> => {
|
36
|
+
const fileURL = new URL(`${Normalize.config.japaneseAddressesApi}${input}`)
|
37
|
+
if (Normalize.config.transformRequest && requestOptions.level !== -1) {
|
38
|
+
const result = await Normalize.config.transformRequest(
|
39
|
+
fileURL,
|
40
|
+
requestOptions,
|
41
|
+
)
|
42
|
+
return {
|
43
|
+
json: async () => Promise.resolve(result),
|
44
|
+
}
|
22
45
|
} else {
|
23
|
-
|
46
|
+
if (fileURL.protocol === 'http:' || fileURL.protocol === 'https:') {
|
47
|
+
return requestHandlers.http(fileURL)
|
48
|
+
} else if (fileURL.protocol === 'file:') {
|
49
|
+
return requestHandlers.file(fileURL)
|
50
|
+
} else {
|
51
|
+
throw new Error(`Unknown URL schema: ${fileURL.protocol}`)
|
52
|
+
}
|
24
53
|
}
|
25
54
|
}
|
26
55
|
|