use the ESM standard

This commit is contained in:
lion 2025-10-13 14:35:45 +08:00
parent 4507c2f706
commit 5a8d7c4152
9 changed files with 53 additions and 68 deletions

View File

@ -5,3 +5,6 @@
// ip2region.js // ip2region.js
// @Author Lion <chenxin619315@gmail.com> // @Author Lion <chenxin619315@gmail.com>
// Re-export all utilities and searcher functions
export * from './util.js';
export * from './searcher.js';

View File

@ -5,7 +5,7 @@
"type": "module", "type": "module",
"main": "ip2region.js", "main": "ip2region.js",
"scripts": { "scripts": {
"test": "jest" "test": "NODE_OPTIONS='--experimental-vm-modules --no-warnings' jest"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -5,14 +5,14 @@
// searcher implementation // searcher implementation
// @Author Lion <chenxin619315@gmail.com> // @Author Lion <chenxin619315@gmail.com>
const fs = require('fs'); import fs from 'fs';
const { import {
parseIP, parseIP,
HeaderInfoLength, VectorIndexCols, VectorIndexSize, HeaderInfoLength, VectorIndexCols, VectorIndexSize,
ipToString ipToString
} = require('./util'); } from './util.js';
class Searcher { export class Searcher {
constructor(version, dbPath, vectorIndex, cBuffer) { constructor(version, dbPath, vectorIndex, cBuffer) {
this.ioCount = 0; this.ioCount = 0;
this.version = version; this.version = version;
@ -114,20 +114,14 @@ class Searcher {
} }
} }
function newWithFileOnly(version, dbPath) { export function newWithFileOnly(version, dbPath) {
return new Searcher(version, dbPath, null, null); return new Searcher(version, dbPath, null, null);
} }
function newWithVectorIndex(version, dbPath, vectorIndex) { export function newWithVectorIndex(version, dbPath, vectorIndex) {
return new Searcher(version, dbPath, vectorIndex, null); return new Searcher(version, dbPath, vectorIndex, null);
} }
function newWithBuffer(version, cBuffer) { export function newWithBuffer(version, cBuffer) {
return new Searcher(version, null, null, cBuffer); return new Searcher(version, null, null, cBuffer);
}
module.exports = {
newWithFileOnly,
newWithVectorIndex,
newWithBuffer
} }

View File

@ -5,9 +5,11 @@
// util test script // util test script
// @Author Lion <chenxin619315@gmail.com> // @Author Lion <chenxin619315@gmail.com>
const util = require('../util.js'); import * as util from '../util.js';
const path = require('path'); import path from 'node:path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const dbPath = path.join(__dirname, '..', '..', '..', 'data', 'ip2region_v4.xdb') const dbPath = path.join(__dirname, '..', '..', '..', 'data', 'ip2region_v4.xdb')
test('test load header', () => { test('test load header', () => {

View File

@ -5,7 +5,7 @@
// util test script // util test script
// @Author Lion <chenxin619315@gmail.com> // @Author Lion <chenxin619315@gmail.com>
const util = require('../util.js'); import * as util from '../util.js';
test('parse ip address', () => { test('parse ip address', () => {
let ip_list = [ let ip_list = [

View File

@ -5,10 +5,12 @@
// searcher search tester // searcher search tester
// @Author Lion <chenxin619315@gmail.com> // @Author Lion <chenxin619315@gmail.com>
const {IPv4, IPv6, parseIP, ipToString} = require('../util'); import {IPv4, IPv6, parseIP, ipToString} from '../util.js';
const {newWithFileOnly} = require('../searcher'); import {newWithFileOnly} from '../searcher.js';
const path = require('path'); import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const dbPath = { const dbPath = {
v4: path.join(__dirname, '..', '..', '..', 'data', 'ip2region_v4.xdb'), v4: path.join(__dirname, '..', '..', '..', 'data', 'ip2region_v4.xdb'),
v6: path.join(__dirname, '..', '..', '..', 'data', 'ip2region_v6.xdb') v6: path.join(__dirname, '..', '..', '..', 'data', 'ip2region_v6.xdb')

View File

@ -5,10 +5,12 @@
// searcher new tester // searcher new tester
// @Author Lion <chenxin619315@gmail.com> // @Author Lion <chenxin619315@gmail.com>
const {IPv4, IPv6, loadVectorIndexFromFile, XdbIPv4Id, loadContentFromFile} = require('../util'); import {IPv4, IPv6, loadVectorIndexFromFile, XdbIPv4Id, loadContentFromFile} from '../util.js';
const {newWithFileOnly, newWithVectorIndex, newWithBuffer} = require('../searcher'); import {newWithFileOnly, newWithVectorIndex, newWithBuffer} from '../searcher.js';
const path = require('path'); import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const dbPath = { const dbPath = {
v4: path.join(__dirname, '..', '..', '..', 'data', 'ip2region_v4.xdb'), v4: path.join(__dirname, '..', '..', '..', 'data', 'ip2region_v4.xdb'),
v6: path.join(__dirname, '..', '..', '..', 'data', 'ip2region_v6.xdb') v6: path.join(__dirname, '..', '..', '..', 'data', 'ip2region_v6.xdb')

View File

@ -5,7 +5,7 @@
// version test script // version test script
// @Author Lion <chenxin619315@gmail.com> // @Author Lion <chenxin619315@gmail.com>
const util = require('../util'); import * as util from '../util.js';
test('const print', () => { test('const print', () => {
console.log("IPv4: ", util.IPv4.toString()); console.log("IPv4: ", util.IPv4.toString());

View File

@ -5,19 +5,19 @@
// util functions // util functions
// @Author Lion <chenxin619315@gmail.com> // @Author Lion <chenxin619315@gmail.com>
const fs = require('fs'); import fs from 'fs';
const XdbStructure20 = 2; export const XdbStructure20 = 2;
const XdbStructure30 = 3; export const XdbStructure30 = 3;
const XdbIPv4Id = 4; export const XdbIPv4Id = 4;
const XdbIPv6Id = 6; export const XdbIPv6Id = 6;
const HeaderInfoLength = 256; export const HeaderInfoLength = 256;
const VectorIndexRows = 256; export const VectorIndexRows = 256;
const VectorIndexCols = 256; export const VectorIndexCols = 256;
const VectorIndexSize = 8; export const VectorIndexSize = 8;
class Header { export class Header {
constructor(buff) { constructor(buff) {
this.version = buff.readUInt16LE(0); this.version = buff.readUInt16LE(0);
this.indexPolicy = buff.readUInt16LE(2); this.indexPolicy = buff.readUInt16LE(2);
@ -134,7 +134,7 @@ function _parse_ipv6_addr(v6String) {
// parse the specified string ip and return its bytes // parse the specified string ip and return its bytes
// @param ip string // @param ip string
// @return Buffer // @return Buffer
function parseIP(ipString) { export function parseIP(ipString) {
let sDot = ipString.indexOf('.'); let sDot = ipString.indexOf('.');
let cDot = ipString.indexOf(':'); let cDot = ipString.indexOf(':');
if (sDot > -1 && cDot == -1) { if (sDot > -1 && cDot == -1) {
@ -205,7 +205,7 @@ function _ipv6_to_string(v6Bytes, compress) {
} }
// bytes ip to humen-readable string ip // bytes ip to humen-readable string ip
function ipToString(ipBytes, compress) { export function ipToString(ipBytes, compress) {
if (!Buffer.isBuffer(ipBytes)) { if (!Buffer.isBuffer(ipBytes)) {
throw new Error('invalid bytes ip, not a Buffer'); throw new Error('invalid bytes ip, not a Buffer');
} }
@ -219,7 +219,7 @@ function ipToString(ipBytes, compress) {
} }
} }
function ipBytesString(ipBytes) { export function ipBytesString(ipBytes) {
if (!Buffer.isBuffer(ipBytes)) { if (!Buffer.isBuffer(ipBytes)) {
throw new Error('invalid bytes ip, not a Buffer'); throw new Error('invalid bytes ip, not a Buffer');
} }
@ -235,17 +235,17 @@ function ipBytesString(ipBytes) {
// compare two byte ips // compare two byte ips
// ip2 = buff[offset:ip1.length] // ip2 = buff[offset:ip1.length]
// returns: -1 if ip1 < ip2, 1 if ip1 > ip2 or 0 // returns: -1 if ip1 < ip2, 1 if ip1 > ip2 or 0
function ipSubCompare(ip1, buff, offset) { export function ipSubCompare(ip1, buff, offset) {
return ip1.compare(buff, offset, offset + ip1.length); return ip1.compare(buff, offset, offset + ip1.length);
} }
function ipCompare(ip1, ip2) { export function ipCompare(ip1, ip2) {
return ipSubCompare(ip1, ip2, 0); return ipSubCompare(ip1, ip2, 0);
} }
// --- // ---
class Version { export class Version {
constructor(id, name, bytes, indexSize, ipCompareFunc) { constructor(id, name, bytes, indexSize, ipCompareFunc) {
this.id = id; this.id = id;
this.name = name; this.name = name;
@ -268,7 +268,7 @@ class Version {
} }
// 14 = 4 + 4 + 2 + 4 // 14 = 4 + 4 + 2 + 4
const IPv4 = new Version(XdbIPv4Id, "IPv4", 4, 14, function(ip1, buff, offset){ export const IPv4 = new Version(XdbIPv4Id, "IPv4", 4, 14, function(ip1, buff, offset){
// ip1: Big endian byte order parsed from input // ip1: Big endian byte order parsed from input
// ip2: Little endian byte order read from xdb index. // ip2: Little endian byte order read from xdb index.
// @Note: to compatible with the old Litten endian index encode implementation. // @Note: to compatible with the old Litten endian index encode implementation.
@ -289,9 +289,9 @@ const IPv4 = new Version(XdbIPv4Id, "IPv4", 4, 14, function(ip1, buff, offset){
}); });
// 38 = 16 + 16 + 2 + 4 // 38 = 16 + 16 + 2 + 4
const IPv6 = new Version(XdbIPv6Id, "IPv6", 16, 38, ipSubCompare); export const IPv6 = new Version(XdbIPv6Id, "IPv6", 16, 38, ipSubCompare);
function versionFromName(name) { export function versionFromName(name) {
let n = name.toUpperCase(); let n = name.toUpperCase();
if (n == "V4" || n == "IPV4") { if (n == "V4" || n == "IPV4") {
return IPv4; return IPv4;
@ -302,7 +302,7 @@ function versionFromName(name) {
} }
} }
function versionFromHeader(h) { export function versionFromHeader(h) {
let v = h.version(); let v = h.version();
// old structure with ONLY IPv4 supporting // old structure with ONLY IPv4 supporting
@ -327,7 +327,7 @@ function versionFromHeader(h) {
// --- // ---
function loadHeader(fd) { export function loadHeader(fd) {
const buffer = Buffer.alloc(HeaderInfoLength); const buffer = Buffer.alloc(HeaderInfoLength);
const rBytes = fs.readSync(fd, buffer, 0, HeaderInfoLength, 0); const rBytes = fs.readSync(fd, buffer, 0, HeaderInfoLength, 0);
if (rBytes != HeaderInfoLength) { if (rBytes != HeaderInfoLength) {
@ -336,14 +336,14 @@ function loadHeader(fd) {
return new Header(buffer); return new Header(buffer);
} }
function loadHeaderFromFile(dbPath) { export function loadHeaderFromFile(dbPath) {
const fd = fs.openSync(dbPath, "r"); const fd = fs.openSync(dbPath, "r");
const header = loadHeader(fd); const header = loadHeader(fd);
fs.closeSync(fd); fs.closeSync(fd);
return header; return header;
} }
function loadVectorIndex(fd) { export function loadVectorIndex(fd) {
const vBytes = VectorIndexCols * VectorIndexRows * VectorIndexSize; const vBytes = VectorIndexCols * VectorIndexRows * VectorIndexSize;
const buffer = Buffer.alloc(vBytes); const buffer = Buffer.alloc(vBytes);
const rBytes = fs.readSync(fd, buffer, 0, vBytes, HeaderInfoLength); const rBytes = fs.readSync(fd, buffer, 0, vBytes, HeaderInfoLength);
@ -353,14 +353,14 @@ function loadVectorIndex(fd) {
return buffer; return buffer;
} }
function loadVectorIndexFromFile(dbPath) { export function loadVectorIndexFromFile(dbPath) {
const fd = fs.openSync(dbPath, "r"); const fd = fs.openSync(dbPath, "r");
const vIndex = loadVectorIndex(fd); const vIndex = loadVectorIndex(fd);
fs.closeSync(fd); fs.closeSync(fd);
return vIndex; return vIndex;
} }
function loadContent(fd) { export function loadContent(fd) {
const stats = fs.fstatSync(fd); const stats = fs.fstatSync(fd);
const buffer = Buffer.alloc(stats.size); const buffer = Buffer.alloc(stats.size);
const rBytes = fs.readSync(fd, buffer, 0, buffer.length, 0); const rBytes = fs.readSync(fd, buffer, 0, buffer.length, 0);
@ -370,27 +370,9 @@ function loadContent(fd) {
return buffer; return buffer;
} }
function loadContentFromFile(dbPath) { export function loadContentFromFile(dbPath) {
const fd = fs.openSync(dbPath, "r"); const fd = fs.openSync(dbPath, "r");
const content = loadContent(fd); const content = loadContent(fd);
fs.close(fd, function(){}); fs.close(fd, function(){});
return content; return content;
}
module.exports = {
// header
XdbStructure20, XdbStructure30, XdbIPv4Id, XdbIPv6Id,
HeaderInfoLength, VectorIndexRows, VectorIndexCols, VectorIndexSize,
// version
IPv4, IPv6,
versionFromName, versionFromHeader,
// utils
parseIP, ipToString, ipBytesString,
ipSubCompare, ipCompare,
loadHeader, loadHeaderFromFile,
loadVectorIndex, loadVectorIndexFromFile,
loadContent, loadContentFromFile
} }