Skip to content

Commit

Permalink
feat: add node n-api bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
aminya committed Jul 11, 2021
1 parent 2b912a1 commit 7a5ffd5
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 58 deletions.
21 changes: 21 additions & 0 deletions dub.sdl
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,34 @@ dependency "automem" version="~>0.6.6"
configuration "executable" {
targetType "executable"
mainSourceFile "./src/native/cli.d"
excludedSourceFiles "./src/native/libc.d" "./src/node/node.d"
}

configuration "library" {
excludedSourceFiles "./src/native/cli.d" "./src/node/node.d"
targetType "library"
targetName "minijson"
}

configuration "node-executable" {
targetType "executable"
excludedSourceFiles "./src/native/cli.d" "./src/native/libc.d"

postGenerateCommands "node ./src/node/build.js"
}

configuration "node-lib" {
targetType "dynamicLibrary"
targetName "minijson.node"

mainSourceFile "./src/node/node.d"
excludedSourceFiles "./src/native/cli.d" "./src/native/libc.d"

dependency "node_dlang" version="0.4.11"

postGenerateCommands "node ./src/node/build.js"
}

configuration "benchmark" {
targetType "executable"
targetName "minijson-benchmark"
Expand Down
1 change: 1 addition & 0 deletions dub.selections.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"fileVersion": 1,
"versions": {
"automem": "0.6.6",
"node_dlang": "0.4.11",
"test_allocator": "0.3.3",
"unit-threaded": "2.0.0"
}
Expand Down
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
"build.profile": "pnpm build -- --build profile --compiler=ldc2 && node ./src/node/build.js && npm run build.node.js",
"build.benchmark": "dub build --config=benchmark --build release-nobounds --compiler=ldc2",
"start.profile": "shx rm -rf ./trace.* && npm run start.benchmark && profdump.exe --dot trace.log trace.dot && dot -Tsvg trace.dot -o trace.svg && ./trace.svg",
"build.node": "npm run build.release && node ./src/node/build.js && npm run build.node.js",
"build.node.exe": "dub build --config=node-executable --build=release-nobounds --compiler=ldc2 && tsc -p ./src/node/tsconfig.json",
"build.node.lib": "dub build --config=node-lib --build=release-nobounds --compiler=ldc2 && tsc -p ./src/node/tsconfig.json",
"build.node": "npm run build.node.exe && npm run build.node.lib",
"build.node.js": "tsc -p ./src/node/tsconfig.json",
"build.wasm": "ldc2 ./src/wasm/wasm.d ./src/native/lib.d --od ./dist --O3 --mtriple=wasm32-unknown-unknown-wasm",
"build.browser": "npm run build.wasm && parcel build --target browser ./src/browser/index.html",
Expand All @@ -34,6 +36,9 @@
"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",
"prepublishOnly": "shx rm -rf ./dist/tsconfig.tsbuildinfo ./dist/build.*"
},
"dependencies": {
"node-addon-api": "^4.0.0"
},
"devDependencies": {
"@types/jasmine": "^3.7.7",
"@types/node": "16.0.0",
Expand Down
8 changes: 8 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/native/lib.d
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const spaceOrBreakRegex = ctRegex!(`\s`);
Return:
the minified json string
*/
string minifyString(in string jsonString, in bool hasComment = false) @trusted
extern (C) string minifyString(string jsonString, bool hasComment = false) @trusted
{
auto in_string = false;
auto in_multiline_comment = false;
Expand Down Expand Up @@ -134,7 +134,7 @@ private bool notSlashAndNoSpaceOrBreak(in string matchFrontHit) @safe
files = the paths to the files.
hasComment = a boolean to support comments in json. Default: `false`.
*/
void minifyFiles(in string[] files, in bool hasComment = false)
extern (C) void minifyFiles(string[] files, bool hasComment = false)
{
import std.parallelism : parallel;
import std.file : readText, write;
Expand Down
31 changes: 22 additions & 9 deletions src/node/build.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,37 @@
const { join, dirname } = require("path")
const { renameSync, mkdirSync } = require("fs")
const { renameSync, mkdirSync, existsSync } = require("fs")
const { execFileSync } = require("child_process")

const exeExtention = process.platform === "win32" ? ".exe" : ""
const binName = `minijson${exeExtention}`

const distFolder = join(dirname(dirname(__dirname)), "dist")
const minijsonSource = join(distFolder, binName)

const distPlatformFolder = join(distFolder, `${process.platform}-${process.arch}`)
mkdirSync(distPlatformFolder, { recursive: true })

function stripBin(file) {
if (process.platform === "win32") {
return
}
return execFileSync(process.env.STRIP || "strip", [file, process.platform === "darwin" ? "-Sx" : "--strip-all"])
}
stripBin(minijsonSource)

mkdirSync(distPlatformFolder, { recursive: true })

// exe

const exeExtention = process.platform === "win32" ? ".exe" : ""
const binName = `minijson${exeExtention}`
const minijsonSource = join(distFolder, binName)
const minijsonDist = join(distPlatformFolder, binName)

renameSync(minijsonSource, minijsonDist)
if (existsSync(minijsonSource)) {
stripBin(minijsonSource)
renameSync(minijsonSource, minijsonDist)
}

// lib

const libExtension = process.platform === "win32" ? ".dll" : ".so"
const minijsonLibSource = join(distFolder, `${process.platform === "linux" ? "lib" : ""}minijson.node${libExtension}`)
const minijsonLibDist = join(distPlatformFolder, `minijson.node`)

if (existsSync(minijsonLibSource)) {
renameSync(minijsonLibSource, minijsonLibDist)
}
29 changes: 28 additions & 1 deletion src/node/cli.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,31 @@
import { spawnMinijson } from "./lib"
import { execFile } from "child_process"
import { join } from "path"

const exeExtention = process.platform === "win32" ? ".exe" : ""
const binName = `minijson${exeExtention}`

const minijsonBin = join(__dirname, `${process.platform}-${process.arch}`, binName)

/**
* Spawn minijson with the given arguments
*
* @param args An array of arguments
* @returns {Promise<string>} Returns a promise that resolves to stdout output string when the operation finishes
* @throws {Promise<string | Error>} The promise is rejected with the reason for failure
*/
export function spawnMinijson(args: string[]): Promise<string> {
return new Promise<string>((resolve, reject) => {
execFile(minijsonBin, args, (err, stdout, stderr) => {
if (err) {
reject(err)
}
if (stderr !== "") {
reject(stderr)
}
resolve(stdout)
})
})
}

async function main() {
await spawnMinijson(process.argv)
Expand Down
50 changes: 5 additions & 45 deletions src/node/lib.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { execFile } from "child_process"
import { join } from "path"
const minijsonLib = join(__dirname, `${process.platform}-${process.arch}`, "minijson.node")

const nativeLib = require(minijsonLib) // eslint-disable-line @typescript-eslint/no-var-requires

/**
* Minify all the given JSON files in place. It minifies the files in parallel.
Expand All @@ -14,19 +16,7 @@ export async function minifyFiles(files: string[], hasComment = false): Promise<
if (filesNum === 0) {
return Promise.resolve()
}

const args = [...files]
const spliceUpper = 2 * filesNum - 2

for (let iSplice = 0; iSplice <= spliceUpper; iSplice += 2) {
args.splice(iSplice, 0, "--file")
}

if (hasComment) {
args.push("--comment")
}

await spawnMinijson(args)
nativeLib.minifyFiles(files, hasComment)
}

/**
Expand All @@ -38,36 +28,6 @@ export async function minifyFiles(files: string[], hasComment = false): Promise<
* @throws {Promise<string | Error>} The promise is rejected with the reason for failure
*/
export async function minifyString(jsonString: string, hasComment = false): Promise<string> {
const args = ["--string", jsonString]
if (hasComment) {
args.push("--comment")
}
// trim is needed due to using stdout for interop
return (await spawnMinijson(args)).trim()
}

const exeExtention = process.platform === "win32" ? ".exe" : ""
const binName = `minijson${exeExtention}`

const minijsonBin = join(__dirname, `${process.platform}-${process.arch}`, binName)

/**
* Spawn minijson with the given arguments
*
* @param args An array of arguments
* @returns {Promise<string>} Returns a promise that resolves to stdout output string when the operation finishes
* @throws {Promise<string | Error>} The promise is rejected with the reason for failure
*/
export function spawnMinijson(args: string[]): Promise<string> {
return new Promise<string>((resolve, reject) => {
execFile(minijsonBin, args, (err, stdout, stderr) => {
if (err) {
reject(err)
}
if (stderr !== "") {
reject(stderr)
}
resolve(stdout)
})
})
return nativeLib.minifyFiles(jsonString, hasComment)
}
11 changes: 11 additions & 0 deletions src/node/node.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module minijson.node;

import node_dlang;

import minijson.lib : minifyString;

private extern (C) void atStart(napi_env env)
{
}

mixin exportToJs!(minifyString, MainFunction!atStart);

0 comments on commit 7a5ffd5

Please sign in to comment.