Skip to content

Commit

Permalink
n-api & *Sync() (#2)
Browse files Browse the repository at this point in the history
- Update to N-API
- Add support for `GetACP`
- Add asynchronously APIs
  • Loading branch information
gucong3000 authored Dec 21, 2018
1 parent e00ea54 commit d231387
Show file tree
Hide file tree
Showing 17 changed files with 389 additions and 213 deletions.
15 changes: 0 additions & 15 deletions .babelrc

This file was deleted.

16 changes: 16 additions & 0 deletions .babelrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"use strict";
module.exports = {
"presets": [
[
"@babel/preset-env",
{
"targets": process.env.NYC_CONFIG ? {} : {
"node": 6,
},
},
],
],
"plugins": [
"@babel/plugin-transform-runtime",
],
};
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,7 @@ typings/

# End of https://www.gitignore.io/api/node

build
lib
*.tar.gz
build-tmp-napi-*/
build/
lib/
6 changes: 5 additions & 1 deletion .npmignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
*.log
*.pid
*.seed
*.tar.gz
*.tgz
.circleci
.editorconfig
Expand All @@ -24,4 +25,7 @@ npm-debug.log*
pids
test
src/*.js
build
build/
build-tmp-napi-*/
lib/binding/**/*
!lib/binding/win32-x64-napi-v3/stdcp.node
19 changes: 16 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,28 @@ stdcp
An effort to encapsulate the output code page used by the console of current process.

This library provides native bindings for Windows APIs:
- [SetConsoleOutputCP](https://docs.microsoft.com/windows/console/setconsoleoutputcp)
- [GetACP](https://docs.microsoft.com/windows/desktop/api/winnls/nf-winnls-getacp)
- [GetConsoleOutputCP](https://docs.microsoft.com/windows/console/getconsoleoutputcp)
- [SetConsoleOutputCP](https://docs.microsoft.com/windows/console/setconsoleoutputcp)

## Use Case

```javascript
const stdcp = require("stdcp");
stdcp.set(65001);
console.log(stdcp.get()) // 65001

// Asynchronously APIs
(async () => {
console.log(await stdcp.get(true)) // Get current Windows code page.
console.log(await stdcp.get()) // Get code page for current console.
await stdcp.set(65001); // Set code page for current console.
})();

// Synchronously APIs
(() => {
console.log(stdcp.getSync(true)) // Get current Windows code page.
console.log(stdcp.getSync()) // Get code page for current console.
stdcp.setSync(65001) // Set code page for current console.
})();
```

## Related
Expand Down
10 changes: 5 additions & 5 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ environment:
matrix:
- nodejs_version: current
- nodejs_version: lts
- nodejs_version: 8
- nodejs_version: 6

platform:
Expand All @@ -18,19 +17,20 @@ install:
# install Node.js
- ps: Install-Product node $env:nodejs_version $env:platform
# install modules
- npm install --build-from-source
- if %nodejs_version% LSS 8 npm i -g npm@6
- npm install --build-from-source=stdcp

# to run your custom scripts instead of automatic tests
test_script:
- if not %nodejs_version% LSS 8 npm test
- npm run build
- npm test
- if "%nodejs_version%"=="lts" npm run build

# to run your custom scripts instead of provider deployments
after_test:
- if not %nodejs_version% LSS 8 npm run report-coverage

artifacts:
- path: 'build\stage\**\*.tar.gz'
- path: '**\*.tar.gz'
name: binding

deploy:
Expand Down
3 changes: 3 additions & 0 deletions binding.gyp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
# NOTE: 'module_name' and 'module_path' come from the 'binary' property in package.json
# node-pre-gyp handles passing them down to node-gyp when you build from source
"defines": [
"NAPI_VERSION=<(napi_build_version)"
],
"targets": [
{
"target_name": "<(module_name)",
Expand Down
34 changes: 21 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
{
"name": "stdcp",
"version": "1.0.0",
"version": "2.0.0",
"description": "An effort to encapsulate the output code page used by the console of current process.",
"keywords": [
"SetConsoleOutputCP",
"GetACP",
"GetConsoleOutputCP",
"SetConsoleOutputCP",
"chcp",
"console",
"terminal",
Expand All @@ -31,11 +32,13 @@
"node-pre-gyp": "^0.12.0"
},
"devDependencies": {
"@babel/cli": "^7.2.0",
"@babel/core": "^7.2.0",
"@babel/cli": "^7.2.3",
"@babel/core": "^7.2.2",
"@babel/plugin-transform-runtime": "^7.2.0",
"@babel/preset-env": "^7.2.0",
"@babel/preset-env": "^7.2.3",
"@babel/register": "^7.0.0",
"@babel/runtime": "^7.2.0",
"chai": "^4.2.0",
"codecov": "^3.1.0",
"eclint": "^2.8.1",
"eslint": "^5.10.0",
Expand All @@ -44,17 +47,21 @@
"eslint-plugin-node": "^8.0.0",
"eslint-plugin-promise": "^4.0.1",
"eslint-plugin-standard": "^4.0.0",
"expect.js": "^0.3.1",
"fs-extra": "^7.0.1",
"mocha": "^5.2.0",
"nyc": "^13.1.0"
},
"binary": {
"module_name": "stdcp",
"module_path": "./build/Release/binding/{node_abi}-{platform}-{arch}",
"package_name": "{node_abi}-{platform}-{arch}.tar.gz",
"module_path": "./lib/binding/{platform}-{arch}-{node_napi_label}",
"package_name": "{platform}-{arch}-{node_napi_label}.tar.gz",
"host": "https://github.com/gucong3000/stdcp/releases/download/",
"remote_path": "v{version}"
"remote_path": "v{version}",
"napi_versions": [
1,
2,
3
]
},
"nyc": {
"reporter": [
Expand All @@ -65,11 +72,12 @@
},
"scripts": {
"install": "node-pre-gyp install --fallback-to-build || echo fallback",
"build": "rm -rf lib && babel src --out-dir lib && node-pre-gyp rebuild --build-from-source && node-pre-gyp package",
"prepare": "npm run build",
"unit": "nyc mocha --no-timeouts",
"build:babel": "rm -rf lib/**/*.js && babel src --out-dir lib",
"build:gyp": "node-pre-gyp rebuild --build-from-source && node-pre-gyp package",
"build": "npm run build:babel && npm run build:gyp",
"unit": "nyc mocha --require test/polyfill --no-timeouts",
"lint:eclint": "eclint check $(git ls-files | tee /tmp/git-files)",
"lint:eslint": "eslint $(grep \"\\.js$\" /tmp/git-files)",
"lint:eslint": "eslint --ignore-pattern ! $(grep \"\\.js$\" /tmp/git-files)",
"lint": "npm run lint:eclint && npm run lint:eslint",
"pretest": "env npm run lint --script-shell=/bin/sh",
"test": "npm run unit",
Expand Down
16 changes: 15 additions & 1 deletion src/binding.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
"use strict";
const binary = require("node-pre-gyp");
const bindingPath = binary.find(require.resolve("../package.json"));
module.exports = require(bindingPath);
const binding = require(bindingPath);

binding.get = function get (global) {
return Promise.resolve().then(() => (
binding.getSync(global)
));
};

binding.set = function set (codepage) {
return Promise.resolve().then(() => (
binding.setSync(codepage)
));
};

module.exports = binding;
127 changes: 86 additions & 41 deletions src/fallback.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,94 @@
"use strict";
const childProcess = require("child_process");
const path = require("path");
const chcpCom = path.join(
process.env.windir || process.env.SystemRoot || "C:/Windows",
"System32/chcp.com"
);
const stdout = process.stdout;
const key = "-ms-codepage";

function getCP () {
if (stdout[key]) {
return stdout[key];
}
let cp = childProcess.spawnSync(chcpCom, {
stdio: [
"inherit",
"pipe",
"ignore",
],
env: {},
encoding: "ascii",
}).stdout;
cp = +/\d+\s*$/.exec(cp)[0];
stdout[key] = cp;
return cp;
}

function setCP (codepage) {
if (stdout[key] && (stdout[key] === codepage)) {
return 0;
}
const status = childProcess.spawnSync("chcp", [String(codepage)], {
stdio: [
"inherit",
"ignore",
"pipe",
const sysDir = path.join(process.env.windir || process.env.SystemRoot || "C:/Windows", "System32");
const wmicExe = path.join(sysDir, "wbem/WMIC.exe");
const chcpCom = path.join(sysDir, "chcp.com");
const spawnOpts = {
stdio: [
"inherit",
"pipe",
"ignore",
],
env: {},
encoding: "ascii",
};

function spawnAsync (args, callback) {
const child = childProcess.spawn(args.shift(), args, spawnOpts);
const stdout = [];
child.stdout.on("data", stdout.push.bind(stdout));
child.on("close", code => {
// eslint-disable-next-line standard/no-callback-literal
callback({
status: code || 0,
stdout: Buffer.concat(stdout).toString(spawnOpts.encoding),
});
});
}

function spawnSync (args, callback) {
callback(childProcess.spawnSync(args.shift(), args, spawnOpts));
}

function getHelper (spawn, global, callback) {
spawn(
global
? [wmicExe, "os", "get", "codeset"]
: [chcpCom],
result => {
const cp = +/\d+\s*$/.exec(result.stdout)[0];
callback(cp);
}
);
}

function setHelper (spawn, codepage, callback) {
spawn(
[
chcpCom,
String(codepage),
],
}).status;
if (!status) {
stdout[key] = codepage;
}
return status;
result => {
result = !result.status;
callback(result);
}
);
}

function cb2sync (fn, args) {
let rst;
fn.apply(this, args.concat(result => {
rst = result;
}));
return rst;
}

function cb2promise (fn, args) {
return new Promise(resolve => {
fn.apply(this, args.concat(resolve));
});
}

function get (global) {
return cb2promise(getHelper, [spawnAsync, global]);
}

function getSync (global) {
return cb2sync(getHelper, [spawnSync, global]);
}

function set (codepage) {
return cb2promise(setHelper, [spawnAsync, codepage]);
}

function setSync (codepage) {
return cb2sync(setHelper, [spawnSync, codepage]);
}

module.exports = {
set: setCP,
get: getCP,
get,
set,
getSync,
setSync,
};
Loading

0 comments on commit d231387

Please sign in to comment.