@uruhalushia/rule-converter-napi 0.0.0 → 0.1.1
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.
- package/README.md +86 -1
- package/index.d.ts +50 -0
- package/index.js +104 -1
- package/package.json +58 -7
package/README.md
CHANGED
|
@@ -1,3 +1,88 @@
|
|
|
1
1
|
# @uruhalushia/rule-converter-napi
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Node.js bindings for the Rust rule converter. Inputs are auto-detected from payload/file content by default, and can be overridden with input options when needed.
|
|
4
|
+
|
|
5
|
+
## Build
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm --dir napi install
|
|
9
|
+
pnpm --dir napi build
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
import { writeFileSync } from 'node:fs'
|
|
16
|
+
import { convertPayloadStringToMrs, convertFileToPath } from '@uruhalushia/rule-converter-napi'
|
|
17
|
+
|
|
18
|
+
const payload = `
|
|
19
|
+
payload:
|
|
20
|
+
- DOMAIN,example.com
|
|
21
|
+
- DOMAIN-SUFFIX,example.net
|
|
22
|
+
- IP-CIDR,192.168.1.0/24,no-resolve
|
|
23
|
+
`
|
|
24
|
+
|
|
25
|
+
const result = convertPayloadStringToMrs(payload, {
|
|
26
|
+
inputTarget: 'mihomo',
|
|
27
|
+
inputFormat: 'yaml',
|
|
28
|
+
inputBehavior: 'classical',
|
|
29
|
+
outputTarget: 'mihomo',
|
|
30
|
+
outputFormat: 'mrs',
|
|
31
|
+
outputBehavior: 'domain',
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
for (const output of result.outputs) {
|
|
35
|
+
writeFileSync(`${output.behavior}.mrs`, output.bytes)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const written = convertFileToPath('rules.yaml', 'dist/rules.list', {
|
|
39
|
+
outputTarget: 'general',
|
|
40
|
+
outputFormat: 'text',
|
|
41
|
+
outputBehavior: 'classical',
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
console.log(written.outputs)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Multiple files can be merged by passing a path array, a directory path, or a final-component `*` wildcard:
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
convertFileToPath(['/path/rules-a.yaml', '/path/rules-b.yaml'], 'dist/ad.mrs', {
|
|
51
|
+
outputTarget: 'mihomo',
|
|
52
|
+
outputFormat: 'mrs',
|
|
53
|
+
outputBehavior: 'domain',
|
|
54
|
+
})
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## API
|
|
58
|
+
|
|
59
|
+
- `convertPayloadToMrs(payload, options?)`: accepts `Uint8Array` and returns generated MRS files in memory.
|
|
60
|
+
- `convertPayloadStringToMrs(payload, options?)`: accepts a string and returns generated MRS files in memory.
|
|
61
|
+
- `convertFileToMrs(input, options?)`: reads one file, directory, wildcard, or path array and returns generated MRS files in memory.
|
|
62
|
+
- `convertFileToPath(input, output, options?)`: writes converted outputs to disk.
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
interface ConvertOptions {
|
|
66
|
+
inputTarget?: 'mihomo' | 'general' | 'egern' | 'sing-box'
|
|
67
|
+
inputFormat?: 'yaml' | 'mrs' | 'text' | 'json' | 'srs'
|
|
68
|
+
inputBehavior?: 'auto' | 'domain' | 'ip' | 'classical'
|
|
69
|
+
outputTarget?: 'mihomo' | 'general' | 'egern' | 'sing-box'
|
|
70
|
+
outputFormat?: 'mrs' | 'text' | 'yaml' | 'json' | 'srs' | 'domainset' | 'ruleset' | 'ipset'
|
|
71
|
+
outputBehavior?: 'domain' | 'ip' | 'classical'
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Defaults:
|
|
76
|
+
|
|
77
|
+
- `inputTarget`: auto-detected
|
|
78
|
+
- `inputFormat`: auto-detected
|
|
79
|
+
- `inputBehavior`: `auto`
|
|
80
|
+
- `outputTarget`: `mihomo`
|
|
81
|
+
- `outputFormat`: `mrs`
|
|
82
|
+
- `outputBehavior`: `domain`
|
|
83
|
+
|
|
84
|
+
mihomo MRS output supports only `domain` and `ip`. sing-box JSON/SRS is available with `outputTarget: 'sing-box'` and `outputFormat: 'json' | 'srs'`.
|
|
85
|
+
|
|
86
|
+
`mihomo + text/yaml + domain` uses mihomo/Clash domain wildcard syntax such as `+.example.com`; `general + domainset + domain` uses domain-set syntax where `.example.com` means the domain itself and all subdomains.
|
|
87
|
+
|
|
88
|
+
`no-resolve` is preserved only between mixed text, mihomo YAML, and Egern ruleset YAML. MRS, sing-box JSON/SRS, and domain-set output do not have a field for it.
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/* auto-generated by NAPI-RS */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
export declare function convertFileToMrs(input: string | string[], options?: ConvertOptions | undefined | null): ConvertResult
|
|
4
|
+
|
|
5
|
+
export declare function convertFileToPath(input: string | string[], output: string, options?: ConvertOptions | undefined | null): WriteResult
|
|
6
|
+
|
|
7
|
+
export type RuleTarget = 'mihomo' | 'general' | 'egern' | 'sing-box'
|
|
8
|
+
export type RuleFormat = 'mrs' | 'text' | 'yaml' | 'json' | 'srs' | 'domainset' | 'ruleset' | 'ipset'
|
|
9
|
+
export type InputBehavior = 'auto' | 'domain' | 'ip' | 'classical'
|
|
10
|
+
export type OutputBehavior = 'auto' | 'domain' | 'ip' | 'classical'
|
|
11
|
+
|
|
12
|
+
export interface ConvertOptions {
|
|
13
|
+
inputTarget?: RuleTarget
|
|
14
|
+
inputFormat?: RuleFormat
|
|
15
|
+
inputBehavior?: InputBehavior
|
|
16
|
+
outputTarget?: RuleTarget
|
|
17
|
+
outputFormat?: RuleFormat
|
|
18
|
+
outputBehavior?: OutputBehavior
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ConvertOutput {
|
|
22
|
+
behavior: 'domain' | 'ip'
|
|
23
|
+
count: number
|
|
24
|
+
bytes: Uint8Array
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export declare function convertPayloadStringToMrs(payload: string, options?: ConvertOptions | undefined | null): ConvertResult
|
|
28
|
+
|
|
29
|
+
export declare function convertPayloadToMrs(payload: Uint8Array, options?: ConvertOptions | undefined | null): ConvertResult
|
|
30
|
+
|
|
31
|
+
export interface ConvertResult {
|
|
32
|
+
outputs: Array<ConvertOutput>
|
|
33
|
+
skipped: Array<SkippedRule>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface SkippedRule {
|
|
37
|
+
rule: string
|
|
38
|
+
reason: string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface WriteResult {
|
|
42
|
+
outputs: Array<WrittenOutput>
|
|
43
|
+
skipped: Array<SkippedRule>
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface WrittenOutput {
|
|
47
|
+
behavior: 'domain' | 'ip'
|
|
48
|
+
count: number
|
|
49
|
+
path: string
|
|
50
|
+
}
|
package/index.js
CHANGED
|
@@ -1 +1,104 @@
|
|
|
1
|
-
|
|
1
|
+
// prettier-ignore
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
// @ts-nocheck
|
|
4
|
+
|
|
5
|
+
import { existsSync } from 'node:fs'
|
|
6
|
+
import { join } from 'node:path'
|
|
7
|
+
import { createRequire } from 'node:module'
|
|
8
|
+
import packageJson from './package.json' with { type: 'json' }
|
|
9
|
+
|
|
10
|
+
const require = createRequire(import.meta.url)
|
|
11
|
+
const __dirname = new URL('.', import.meta.url).pathname.replace(/^\/([A-Za-z]:)/, '$1')
|
|
12
|
+
|
|
13
|
+
const packageName = '@uruhalushia/rule-converter-napi'
|
|
14
|
+
const packageVersion = packageJson.version
|
|
15
|
+
const binaryName = 'rule-converter'
|
|
16
|
+
const loadErrors = []
|
|
17
|
+
|
|
18
|
+
function isMusl() {
|
|
19
|
+
try {
|
|
20
|
+
return require('node:child_process').execSync('ldd --version', { encoding: 'utf8' }).includes('musl')
|
|
21
|
+
} catch (_) {
|
|
22
|
+
return false
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function requireLocal(tuple) {
|
|
27
|
+
const filename = join(__dirname, `${binaryName}.${tuple}.node`)
|
|
28
|
+
if (!existsSync(filename)) {
|
|
29
|
+
loadErrors.push(new Error(`Native binding not found: ${filename}`))
|
|
30
|
+
return null
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
return require(filename)
|
|
34
|
+
} catch (err) {
|
|
35
|
+
loadErrors.push(err)
|
|
36
|
+
return null
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function requirePackage(tuple) {
|
|
41
|
+
const nativePackage = `${packageName}-${tuple}`
|
|
42
|
+
try {
|
|
43
|
+
const binding = require(nativePackage)
|
|
44
|
+
const bindingPackageVersion = require(`${nativePackage}/package.json`).version
|
|
45
|
+
if (
|
|
46
|
+
bindingPackageVersion !== packageVersion &&
|
|
47
|
+
process.env.NAPI_RS_ENFORCE_VERSION_CHECK &&
|
|
48
|
+
process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0'
|
|
49
|
+
) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
`Native binding package version mismatch, expected ${packageVersion} but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`,
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
return binding
|
|
55
|
+
} catch (err) {
|
|
56
|
+
loadErrors.push(err)
|
|
57
|
+
return null
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function requireBinding(tuple) {
|
|
62
|
+
return requireLocal(tuple) || requirePackage(tuple)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function requireNative() {
|
|
66
|
+
if (process.env.NAPI_RS_NATIVE_LIBRARY_PATH) {
|
|
67
|
+
try {
|
|
68
|
+
return require(process.env.NAPI_RS_NATIVE_LIBRARY_PATH)
|
|
69
|
+
} catch (err) {
|
|
70
|
+
loadErrors.push(err)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (process.platform === 'win32') {
|
|
75
|
+
if (process.arch === 'x64') return requireBinding('win32-x64-msvc')
|
|
76
|
+
if (process.arch === 'arm64') return requireBinding('win32-arm64-msvc')
|
|
77
|
+
} else if (process.platform === 'darwin') {
|
|
78
|
+
if (process.arch === 'x64') return requireBinding('darwin-x64')
|
|
79
|
+
if (process.arch === 'arm64') return requireBinding('darwin-arm64')
|
|
80
|
+
} else if (process.platform === 'linux') {
|
|
81
|
+
const musl = isMusl()
|
|
82
|
+
if (process.arch === 'x64') return requireBinding(musl ? 'linux-x64-musl' : 'linux-x64-gnu')
|
|
83
|
+
if (process.arch === 'arm64') return requireBinding(musl ? 'linux-arm64-musl' : 'linux-arm64-gnu')
|
|
84
|
+
if (process.arch === 'riscv64') return requireBinding(musl ? 'linux-riscv64-musl' : 'linux-riscv64-gnu')
|
|
85
|
+
if (process.arch === 'loong64') return requireBinding(musl ? 'linux-loong64-musl' : 'linux-loong64-gnu')
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
loadErrors.push(new Error(`Unsupported OS or architecture: ${process.platform} ${process.arch}`))
|
|
89
|
+
return null
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const nativeBinding = requireNative()
|
|
93
|
+
|
|
94
|
+
if (!nativeBinding) {
|
|
95
|
+
const error = new Error('Failed to load rule-converter native binding')
|
|
96
|
+
error.cause = loadErrors
|
|
97
|
+
throw error
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export default nativeBinding
|
|
101
|
+
export const convertPayloadToMrs = nativeBinding.convertPayloadToMrs
|
|
102
|
+
export const convertPayloadStringToMrs = nativeBinding.convertPayloadStringToMrs
|
|
103
|
+
export const convertFileToMrs = nativeBinding.convertFileToMrs
|
|
104
|
+
export const convertFileToPath = nativeBinding.convertFileToPath
|
package/package.json
CHANGED
|
@@ -1,16 +1,67 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uruhalushia/rule-converter-napi",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Node.js bindings for converting mihomo, sing-box, Egern, and generic rule sets.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
7
|
+
"types": "index.d.ts",
|
|
8
|
+
"packageManager": "pnpm@10.33.0",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/UruhaLushia/rule-converter.git"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/UruhaLushia/rule-converter",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/UruhaLushia/rule-converter/issues"
|
|
16
|
+
},
|
|
17
|
+
"license": "GPL-3.0-only",
|
|
7
18
|
"files": [
|
|
8
19
|
"index.js",
|
|
20
|
+
"index.d.ts",
|
|
9
21
|
"README.md"
|
|
10
22
|
],
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
"
|
|
14
|
-
|
|
23
|
+
"napi": {
|
|
24
|
+
"binaryName": "rule-converter",
|
|
25
|
+
"targets": [
|
|
26
|
+
"x86_64-unknown-linux-gnu",
|
|
27
|
+
"aarch64-unknown-linux-gnu",
|
|
28
|
+
"riscv64gc-unknown-linux-gnu",
|
|
29
|
+
"loongarch64-unknown-linux-gnu",
|
|
30
|
+
"x86_64-unknown-linux-musl",
|
|
31
|
+
"aarch64-unknown-linux-musl",
|
|
32
|
+
"riscv64gc-unknown-linux-musl",
|
|
33
|
+
"loongarch64-unknown-linux-musl",
|
|
34
|
+
"x86_64-apple-darwin",
|
|
35
|
+
"aarch64-apple-darwin",
|
|
36
|
+
"x86_64-pc-windows-msvc",
|
|
37
|
+
"aarch64-pc-windows-msvc"
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "napi build --platform --release --no-js",
|
|
42
|
+
"build:debug": "napi build --platform --no-js",
|
|
43
|
+
"create-npm-dirs": "napi create-npm-dirs",
|
|
44
|
+
"artifacts": "napi artifacts",
|
|
45
|
+
"test": "node -e \"import('./index.js').then((m) => console.log(Object.keys(m).sort().join(',')))\""
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=16"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@napi-rs/cli": "^3"
|
|
52
|
+
},
|
|
53
|
+
"optionalDependencies": {
|
|
54
|
+
"@uruhalushia/rule-converter-napi-linux-x64-gnu": "0.1.1",
|
|
55
|
+
"@uruhalushia/rule-converter-napi-linux-arm64-gnu": "0.1.1",
|
|
56
|
+
"@uruhalushia/rule-converter-napi-linux-riscv64-gnu": "0.1.1",
|
|
57
|
+
"@uruhalushia/rule-converter-napi-linux-loong64-gnu": "0.1.1",
|
|
58
|
+
"@uruhalushia/rule-converter-napi-linux-x64-musl": "0.1.1",
|
|
59
|
+
"@uruhalushia/rule-converter-napi-linux-arm64-musl": "0.1.1",
|
|
60
|
+
"@uruhalushia/rule-converter-napi-linux-riscv64-musl": "0.1.1",
|
|
61
|
+
"@uruhalushia/rule-converter-napi-linux-loong64-musl": "0.1.1",
|
|
62
|
+
"@uruhalushia/rule-converter-napi-darwin-x64": "0.1.1",
|
|
63
|
+
"@uruhalushia/rule-converter-napi-darwin-arm64": "0.1.1",
|
|
64
|
+
"@uruhalushia/rule-converter-napi-win32-x64-msvc": "0.1.1",
|
|
65
|
+
"@uruhalushia/rule-converter-napi-win32-arm64-msvc": "0.1.1"
|
|
15
66
|
}
|
|
16
|
-
}
|
|
67
|
+
}
|