Skip to content

Commit 87b6de3

Browse files
committed
feat: add node n-api bindings
1 parent 477d53c commit 87b6de3

File tree

9 files changed

+103
-58
lines changed

9 files changed

+103
-58
lines changed

dub.sdl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,31 @@ dependency "despacer" path="./src/native/despacer/bindings/d"
1616
configuration "executable" {
1717
targetType "executable"
1818
mainSourceFile "./src/native/cli.d"
19+
excludedSourceFiles "./src/native/libc.d" "./src/node/node.d"
1920
}
2021

2122
configuration "library" {
2223
targetType "library"
2324
targetName "minijson"
25+
excludedSourceFiles "./src/native/cli.d" "./src/node/node.d"
26+
}
27+
28+
configuration "node-executable" {
29+
targetType "executable"
30+
excludedSourceFiles "./src/native/cli.d" "./src/native/libc.d"
31+
32+
postGenerateCommands "node ./src/node/build.js"
33+
}
34+
35+
configuration "node-lib" {
36+
targetType "dynamicLibrary"
37+
targetName "minijson.node"
38+
mainSourceFile "./src/node/node.d"
39+
excludedSourceFiles "./src/native/cli.d" "./src/native/libc.d"
40+
41+
dependency "node_dlang" version="0.4.11"
42+
43+
postGenerateCommands "node ./src/node/build.js"
2444
}
2545

2646
configuration "benchmark" {

dub.selections.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"fileVersion": 1,
33
"versions": {
44
"automem": "0.6.6",
5+
"node_dlang": "0.4.11",
56
"test_allocator": "0.3.3",
67
"unit-threaded": "2.0.0"
78
}

package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
"build.profile": "pnpm build -- --build profile --compiler=ldc2 && node ./src/node/build.js && npm run build.node.js",
2525
"build.benchmark": "dub build --config=benchmark --build release-nobounds --compiler=ldc2",
2626
"start.profile": "shx rm -rf ./trace.* && npm run start.benchmark.node && profdump.exe --dot trace.log trace.dot && dot -Tsvg trace.dot -o trace.svg && ./trace.svg",
27-
"build.node": "npm run build.release && node ./src/node/build.js && npm run build.node.js",
27+
"build.node.exe": "dub build --config=node-executable --build=release-nobounds --compiler=ldc2 && tsc -p ./src/node/tsconfig.json",
28+
"build.node.lib": "dub build --config=node-lib --build=release-nobounds --compiler=ldc2 && tsc -p ./src/node/tsconfig.json",
29+
"build.node": "npm run build.node.exe && npm run build.node.lib",
2830
"build.node.js": "tsc -p ./src/node/tsconfig.json",
2931
"build.wasm": "ldc2 ./src/wasm/wasm.d ./src/native/lib.d --od ./dist --O3 --mtriple=wasm32-unknown-unknown-wasm",
3032
"build.browser": "npm run build.wasm && parcel build --target browser ./src/browser/index.html",
@@ -34,6 +36,9 @@
3436
"zip": "zip -9 -j ./dist/minijson-windows-x64.zip ./dist/win32-x64/minijson.exe && zip -9 -j ./dist/minijson-macos-x64.zip ./dist/darwin-x64/minijson && zip -9 -j ./dist/minijson-linux-x64.zip ./dist/linux-x64/minijson",
3537
"prepublishOnly": "shx rm -rf ./dist/tsconfig.tsbuildinfo ./dist/build.*"
3638
},
39+
"dependencies": {
40+
"node-addon-api": "^4.0.0"
41+
},
3742
"devDependencies": {
3843
"@types/jasmine": "^3.7.7",
3944
"@types/node": "16.0.0",

pnpm-lock.yaml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/native/lib.d

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const tokenizerNoComment = ctRegex!(`[\n\r"[]]`, "g");
1717
Return:
1818
the minified json string
1919
*/
20-
string minifyString(in string jsonString, in bool hasComment = false) @trusted
20+
extern (C) string minifyString(string jsonString, bool hasComment = false) @trusted
2121
{
2222
auto in_string = false;
2323
auto in_multiline_comment = false;
@@ -170,7 +170,7 @@ private bool hasNoSpace(const ref string matchFrontHit) @trusted
170170
files = the paths to the files.
171171
hasComment = a boolean to support comments in json. Default: `false`.
172172
*/
173-
void minifyFiles(in string[] files, in bool hasComment = false)
173+
extern (C) void minifyFiles(string[] files, bool hasComment = false)
174174
{
175175
import std.parallelism : parallel;
176176
import std.file : readText, write;

src/node/build.js

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,37 @@
11
const { join, dirname } = require("path")
2-
const { renameSync, mkdirSync } = require("fs")
2+
const { renameSync, mkdirSync, existsSync } = require("fs")
33
const { execFileSync } = require("child_process")
44

5-
const exeExtention = process.platform === "win32" ? ".exe" : ""
6-
const binName = `minijson${exeExtention}`
7-
85
const distFolder = join(dirname(dirname(__dirname)), "dist")
9-
const minijsonSource = join(distFolder, binName)
10-
116
const distPlatformFolder = join(distFolder, `${process.platform}-${process.arch}`)
12-
mkdirSync(distPlatformFolder, { recursive: true })
137

148
function stripBin(file) {
159
if (process.platform === "win32") {
1610
return
1711
}
1812
return execFileSync(process.env.STRIP || "strip", [file, process.platform === "darwin" ? "-Sx" : "--strip-all"])
1913
}
20-
stripBin(minijsonSource)
2114

15+
mkdirSync(distPlatformFolder, { recursive: true })
16+
17+
// exe
18+
19+
const exeExtention = process.platform === "win32" ? ".exe" : ""
20+
const binName = `minijson${exeExtention}`
21+
const minijsonSource = join(distFolder, binName)
2222
const minijsonDist = join(distPlatformFolder, binName)
2323

24-
renameSync(minijsonSource, minijsonDist)
24+
if (existsSync(minijsonSource)) {
25+
stripBin(minijsonSource)
26+
renameSync(minijsonSource, minijsonDist)
27+
}
28+
29+
// lib
30+
31+
const libExtension = process.platform === "win32" ? ".dll" : ".so"
32+
const minijsonLibSource = join(distFolder, `${process.platform === "linux" ? "lib" : ""}minijson.node${libExtension}`)
33+
const minijsonLibDist = join(distPlatformFolder, `minijson.node`)
34+
35+
if (existsSync(minijsonLibSource)) {
36+
renameSync(minijsonLibSource, minijsonLibDist)
37+
}

src/node/cli.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,31 @@
1-
import { spawnMinijson } from "./lib"
1+
import { execFile } from "child_process"
2+
import { join } from "path"
3+
4+
const exeExtention = process.platform === "win32" ? ".exe" : ""
5+
const binName = `minijson${exeExtention}`
6+
7+
const minijsonBin = join(__dirname, `${process.platform}-${process.arch}`, binName)
8+
9+
/**
10+
* Spawn minijson with the given arguments
11+
*
12+
* @param args An array of arguments
13+
* @returns {Promise<string>} Returns a promise that resolves to stdout output string when the operation finishes
14+
* @throws {Promise<string | Error>} The promise is rejected with the reason for failure
15+
*/
16+
export function spawnMinijson(args: string[]): Promise<string> {
17+
return new Promise<string>((resolve, reject) => {
18+
execFile(minijsonBin, args, (err, stdout, stderr) => {
19+
if (err) {
20+
reject(err)
21+
}
22+
if (stderr !== "") {
23+
reject(stderr)
24+
}
25+
resolve(stdout)
26+
})
27+
})
28+
}
229

330
async function main() {
431
await spawnMinijson(process.argv)

src/node/lib.ts

Lines changed: 5 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
import { execFile } from "child_process"
21
import { join } from "path"
2+
const minijsonLib = join(__dirname, `${process.platform}-${process.arch}`, "minijson.node")
3+
4+
const nativeLib = require(minijsonLib) // eslint-disable-line @typescript-eslint/no-var-requires
35

46
/**
57
* Minify all the given JSON files in place. It minifies the files in parallel.
@@ -14,19 +16,7 @@ export async function minifyFiles(files: string[], hasComment = false): Promise<
1416
if (filesNum === 0) {
1517
return Promise.resolve()
1618
}
17-
18-
const args = [...files]
19-
const spliceUpper = 2 * filesNum - 2
20-
21-
for (let iSplice = 0; iSplice <= spliceUpper; iSplice += 2) {
22-
args.splice(iSplice, 0, "--file")
23-
}
24-
25-
if (hasComment) {
26-
args.push("--comment")
27-
}
28-
29-
await spawnMinijson(args)
19+
nativeLib.minifyFiles(files, hasComment)
3020
}
3121

3222
/**
@@ -38,36 +28,6 @@ export async function minifyFiles(files: string[], hasComment = false): Promise<
3828
* @throws {Promise<string | Error>} The promise is rejected with the reason for failure
3929
*/
4030
export async function minifyString(jsonString: string, hasComment = false): Promise<string> {
41-
const args = ["--string", jsonString]
42-
if (hasComment) {
43-
args.push("--comment")
44-
}
4531
// trim is needed due to using stdout for interop
46-
return (await spawnMinijson(args)).trim()
47-
}
48-
49-
const exeExtention = process.platform === "win32" ? ".exe" : ""
50-
const binName = `minijson${exeExtention}`
51-
52-
const minijsonBin = join(__dirname, `${process.platform}-${process.arch}`, binName)
53-
54-
/**
55-
* Spawn minijson with the given arguments
56-
*
57-
* @param args An array of arguments
58-
* @returns {Promise<string>} Returns a promise that resolves to stdout output string when the operation finishes
59-
* @throws {Promise<string | Error>} The promise is rejected with the reason for failure
60-
*/
61-
export function spawnMinijson(args: string[]): Promise<string> {
62-
return new Promise<string>((resolve, reject) => {
63-
execFile(minijsonBin, args, (err, stdout, stderr) => {
64-
if (err) {
65-
reject(err)
66-
}
67-
if (stderr !== "") {
68-
reject(stderr)
69-
}
70-
resolve(stdout)
71-
})
72-
})
32+
return nativeLib.minifyFiles(jsonString, hasComment)
7333
}

src/node/node.d

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module minijson.node;
2+
3+
import node_dlang;
4+
5+
import minijson.lib : minifyString;
6+
7+
private extern (C) void atStart(napi_env env)
8+
{
9+
}
10+
11+
mixin exportToJs!(minifyString, MainFunction!atStart);

0 commit comments

Comments
 (0)