Paepoi » JavaScript Tips » Gjs, JXA, Node.js
Gjs, JXA, Node.js
# 最終更新日 2024.03.30
- Node.js 関連を ESM 化、及び promises 仕様に書き換えしました
- 動作確認バージョンを追記しました
スタンドアロン(単独で利用できる)の JavaScript 実行環境での基本機能の覚書
UNIX 系(macOS 含む)のみで動作確認
- Node.js 関連を ESM 化、及び promises 仕様に書き換えしました
- 動作確認バージョンを追記しました
スタンドアロン(単独で利用できる)の JavaScript 実行環境での基本機能の覚書
UNIX 系(macOS 含む)のみで動作確認
| 通称 | コマンド名 | 動作環境 | コア | 動作確認 |
|---|---|---|---|---|
| Gjs | gjs | GNOME | SpiderMonkey | 1.78 |
| JXA | osascript | macOS | JavaScriptCore | 10.11(放置) |
| Node.js | node | マルチ | V8 | 20.01 |
標準入出力
echo ほげ | gjs test.js のようなパイプ入力にも対応
/**
* Gjs (gjs コマンドに -m オプションが必要)
*/
import GLib from 'gi://GLib';
// readline は自作
let readline = function(prpt) {
// stdin=0 stdout=1
let channel = GLib.IOChannel.unix_new(0);
let stdin = '端末入力';
if (channel.get_flags() == GLib.IOFlags.IS_READABLE) {
stdin = 'パイプ';
} else {
channel.write_chars(prpt, -1);
}
let [status, str_return] = channel.read_line();
let line = str_return.trimEnd();
return [stdin, line];
}
let [stdin, line] = readline('何か入力して Enter :');
console.log(`${stdin}から ${line} が渡されました`);
/**
* JXA (GNU readline 同様に使える)
*/
ObjC.import('readline');
ObjC.import('unistd');
let prefix = $.isatty(0) ? '端末入力' : 'パイプ';
let line = $.readline('何か入力して return :');
console.log(`${prefix}から ${line} が渡されました`);
/**
* Node.js (拡張子を *.mjs にする必要があります)
*/
import * as readline from 'node:readline/promises';
import * as tty from 'node:tty';
import { stdin as input, stdout as output } from 'node:process';
let rl = readline.createInterface({ input, output, terminal:false });
let [prpt, prefix] = tty.isatty(0) ? ['何か入力して return :', '端末入力'] : ['', 'パイプ'];
let line = await rl.question(prpt);
console.log(`${prefix}から ${line} が渡されました`);
rl.close();
ファイルの読み書き
Gjs は Gio を使ったほうがいいけどそれは別のページにて
/**
* Gjs
*/
import GLib from 'gi://GLib';
const FILE = 'write_gjs.txt';
const TEXT = `出力では JavaScript 文字列のままイケます
入力は Uint8Array になりますので以下のように`;
let result = GLib.file_set_contents(FILE, TEXT); // Write
if (result) {
console.log('Write Success');
}
let [result2, contents] = GLib.file_get_contents(FILE); // Read
if (result2) {
let dec = new TextDecoder();
let text = dec.decode(contents);
console.log(text);
}
/**
* JXA
*/
ObjC.import('Cocoa');
const FILE = $('write_jxa.txt');
const TEXT = $('日本語を書き込むよ\n改行もしてみるよ');
let nil = $();
// Write
let res = TEXT.writeToFileAtomicallyEncodingError(FILE, true, $.NSUTF8StringEncoding, nil);
if (res) {
console.log('Write Success!');
}
// Read
let s = $.NSString.alloc.initWithContentsOfFileEncodingError(FILE, $.NSUTF8StringEncoding, nil);
console.log(s.js);
/**
* Node.js
*/
import fs from 'node:fs/promises';
const FILE = 'write_node.txt';
const TEXT = '日本語を書き込むよ\n改行もしてみるよ';
try {
await fs.writeFile(FILE, TEXT);
console.log('Write Success!');
} catch(err) {
console.log(err);
}
try {
let content = await fs.readFile(FILE, 'utf8')
console.log(content.trim());
} catch(err) {
console.log(err);
}
起動パラメータ
Node.js はシェルそのままなパラメータになる、他は全部引数のみの配列
/**
* Gjs (1.52 からUNICODE 化されました)
*/
if (ARGV.length == 0) {
console.log('No argv');
} else {
for (let s of ARGV) {
console.log(s)
}
}
/**
* JXA
*/
function run(argv) {
if (argv.length == 0) {
console.log('No argv');
} else {
for (let s of argv) {
console.log(s);
}
}
}
/**
* Node.js (実行ファイル名, スクリプトファイル名, argv[0], argv[1], ...)
*/
if (process.argv.length < 3) {
console.log('No argv');
} else {
for (let s of process.argv) {
console.log(s);
}
}
環境変数
$HOME を表示する例
/**
* Gjs
*/
import GLib from 'gi://GLib';
console.log(GLib.getenv('HOME'));
/**
* JXA
*/
ObjC.import('stdlib');
console.log($.getenv('HOME'));
/**
* Node.js
*/
console.log(process.env.HOME);
シェルコマンドの実行
ls -l の結果を得て表示する例
/**
* Gjs
*/
import GLib from 'gi://GLib';
let output = GLib.spawn_command_line_sync('ls -l')[1];
let dec = new TextDecoder();
let text = dec.decode(output);
console.log(text);
/**
* JXA
*/
let app = Application.currentApplication();
app.includeStandardAdditions = true;
// alteringLineEndings オプション無しだと改行が CR に変換される
let res = app.doShellScript('ls -l', {alteringLineEndings: false});
console.log(res);
/**
* Node.js
*/
import {exec} from 'node:child_process';
exec('ls -l', (err, stdout, stderr)=> {
console.log(stdout);
});
タイマー
setInterval, setTimeout は Gjs でも使えるようになりました
/**
* Gjs (メインループが必要)
*/
import GLib from 'gi://GLib';
const mainloop = new GLib.MainLoop(null, false);
let count = 1;
let id = setInterval(()=> {
if (count == 5) {
clearInterval(id);
mainloop.quit();
}
console.log(count);
count++;
}, 1000);
mainloop.run();
/**
* JXA
*/
ObjC.import('Cocoa');
let count = 1;
let operation = $.NSBlockOperation.blockOperationWithBlock(()=> {
if (count == 5)
timer.invalidate;
console.log(count);
count++;
});
let timer = $.NSTimer.timerWithTimeIntervalTargetSelectorUserInfoRepeats(
1, operation, 'main', null, true);
$.NSRunLoop.currentRunLoop.addTimerForMode(timer, 'timer');
// 戻り値が表示されないよう変数に入れる
let r = $.NSRunLoop.currentRunLoop.runModeBeforeDate('timer', $.NSDate.distantFuture);
/**
* Node.js (ブラウザと同じ、メインループは node がやってくれる)
*/
let count = 1;
let id = setInterval(()=> {
if (count == 5) clearInterval(id);
console.log(count);
count++;
}, 1000);
Copyright(C) sasakima-nao All rights reserved 2002 --- 2025.