nadesiko3
Version:
Japanese Programming Language
1,449 lines (1,448 loc) • 47.3 kB
JavaScript
/* eslint-disable @typescript-eslint/no-explicit-any */
/**
* file: plugin_node.mjs
* node.js のためのプラグイン
*/
import fs from 'node:fs';
import fse from 'fs-extra';
import fetch, { FormData, Blob } from 'node-fetch';
import { exec, execSync } from 'node:child_process';
import shellQuote from 'shell-quote';
import path from 'node:path';
import iconv from 'iconv-lite';
import opener from 'opener';
import assert from 'node:assert';
// ハッシュ関数で利用
import crypto from 'node:crypto';
import os from 'node:os';
import url from 'node:url';
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { isWindows, getCommandLineArgs } from './deno_wrapper.mjs';
const __filename = url.fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// ローカル関数
function fileExists(f) {
try {
fs.statSync(f);
return true;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
}
catch (err) {
return false;
}
}
function isDir(f) {
try {
const st = fs.statSync(f);
return st.isDirectory();
// eslint-disable-next-line @typescript-eslint/no-unused-vars
}
catch (err) {
return false;
}
}
let nodeProcess = globalThis.process;
// Denoのためのラッパー
if (typeof globalThis.Deno !== 'undefined') {
nodeProcess = {
platform: globalThis.Deno.build.os,
arch: globalThis.Deno.build.arch,
argv: getCommandLineArgs(),
exit: (code) => {
globalThis.Deno.exit(code);
},
cwd: () => {
return globalThis.Deno.cwd();
}
};
}
export default {
'meta': {
type: 'const',
value: {
pluginName: 'plugin_node', // プラグインの名前
description: 'Node.js向けプラグイン', // プラグインの説明
pluginVersion: '3.6.0', // プラグインのバージョン
nakoRuntime: ['cnako'], // 対象ランタイム
nakoVersion: '3.6.0' // 要求なでしこバージョン
}
},
'初期化': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
// OS判定
const isWin = isWindows();
sys.tags.isWin = isWin;
// プラグインの初期化
sys.tags.__quotePath = (fpath) => {
if (isWin) {
fpath = fpath.replace(/"/g, '');
fpath = fpath.replace(/%/g, '"^%"');
fpath = '"' + fpath + '"';
}
else {
// console.log('before:', fpath)
fpath = shellQuote.quote([fpath]);
// console.log('after:', fpath)
}
return fpath;
};
sys.tags.__getBinPath = (tool) => {
let fpath = tool;
if (isWin) {
if (!fileExists(tool)) {
const root = path.resolve(path.join(__dirname, '..'));
fpath = path.join(root, 'bin', tool + '.exe');
if (fileExists(fpath)) {
return `${fpath}`;
}
return tool;
}
}
return fpath;
};
sys.tags.__getBokanPath = () => {
// Electronから実行した場合
if (nodeProcess.argv.length === 1) {
return path.dirname(path.resolve(nodeProcess.argv[0]));
}
// cnako3のときランタイムを除いたメインファイルのパスを取得する
let mainfile = '.';
for (let i = 0; i < nodeProcess.argv.length; i++) {
const f = nodeProcess.argv[i];
const bf = path.basename(f);
if (bf === 'node' || bf === 'node.exe') {
continue;
} // runtime
if (bf === 'cnako3.mjs' || bf === 'cnako3.mts') {
continue;
} // mts/mjs
if (bf.substring(0, 1) === '-') {
continue;
} // options
mainfile = f;
break;
}
return path.dirname(path.resolve(mainfile));
};
sys.__setSysVar('コマンドライン', nodeProcess.argv);
sys.__setSysVar('ナデシコランタイムパス', nodeProcess.argv[0]);
sys.__setSysVar('ナデシコランタイム', path.basename(nodeProcess.argv[0]));
sys.__setSysVar('母艦パス', sys.tags.__getBokanPath());
sys.__setSysVar('AJAX:ONERROR', null);
// 『尋』『文字尋』『標準入力取得時』『標準入力全取得』のための一時変数
// nadesiko3-serverを起動した時、ctrl+cでプロセスが止まらない(#1668)を考慮した設計にする
// 非同期通信を使うと標準入力を占有してしまうため、一時的に全部の標準入力を取得しておいて、残りをバッファに入れておく仕組みにする
// 加えて、pause/resumeを使わない仕掛けにする
sys.tags.readBuffers = [];
sys.tags.readline = (question, handler) => {
if (question) {
nodeProcess.stdout.write(question);
}
if (sys.tags.readBuffers.length > 0) {
const buf = sys.tags.readBuffers.shift();
return buf;
}
let data = '';
nodeProcess.stdin.on('data', (buf) => {
const bufStr = buf.toString();
let line = data;
for (let i = 0; i < bufStr.length; i++) {
const c = bufStr.charAt(i);
if (c === '\r') {
continue;
}
if (c === '\n') {
if (handler) {
handler(line);
}
else {
sys.tags.readBuffers.push(line);
}
line = '';
continue;
}
line += c;
}
data = line;
});
nodeProcess.stdin.on('end', () => {
if (handler) {
handler(data);
}
else {
if (data !== '') {
sys.tags.readBuffers.push(data);
}
}
data = '';
});
if (handler !== undefined) {
return true;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
return new Promise((resolve, _reject) => {
const timerCallback = () => {
if (sys.tags.readBuffers.length > 0) {
const buf = sys.tags.readBuffers.shift();
nodeProcess.stdin.removeAllListeners();
resolve(buf);
}
else {
setTimeout(timerCallback, 100);
}
};
// 100msごとにチェック
setTimeout(() => { timerCallback(); }, 10);
});
};
}
},
// @ファイル入出力
'開': {
type: 'func',
josi: [['を', 'から']],
pure: true,
fn: function (f) {
return fs.readFileSync(f, 'utf-8');
}
},
'読': {
type: 'func',
josi: [['を', 'から']],
pure: true,
fn: function (f) {
return fs.readFileSync(f, 'utf-8');
}
},
'バイナリ読': {
type: 'func',
josi: [['を', 'から']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (s, sys) {
return fs.readFileSync(s);
}
},
'保存': {
type: 'func',
josi: [['を'], ['へ', 'に']],
pure: true,
asyncFn: true,
fn: function (s, f) {
return new Promise((resolve, reject) => {
// 引数sの型によって書き込みオプションを変更する
const options = {};
if (typeof s === 'string') {
options.encoding = 'utf-8';
}
if (s instanceof ArrayBuffer) {
s = Buffer.from(s);
}
// データをファイルへ書き込む
fs.writeFile(f, s, options, (err) => {
if (err) {
reject(new Error(`ファイル『${f}』に保存できませんでした。理由:${err.message}`));
return;
}
resolve(null);
});
});
},
return_none: true
},
'SJISファイル読': {
type: 'func',
josi: [['を', 'から']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (s, sys) {
// iconv.skipDecodeWarning = true
const buf = fs.readFileSync(s);
const text = iconv.decode(Buffer.from(buf), 'sjis');
return text;
}
},
'SJISファイル保存': {
type: 'func',
josi: [['を'], ['へ', 'に']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (s, f, sys) {
// iconv.skipDecodeWarning = true
const buf = iconv.encode(s, 'Shift_JIS');
fs.writeFileSync(f, buf);
},
return_none: true
},
'EUCファイル読': {
type: 'func',
josi: [['を', 'から']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (s, sys) {
const buf = fs.readFileSync(s);
const text = iconv.decode(Buffer.from(buf), 'euc-jp');
return text;
}
},
'EUCファイル保存': {
type: 'func',
josi: [['を'], ['へ', 'に']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (s, f, sys) {
const buf = iconv.encode(s, 'euc-jp');
fs.writeFileSync(f, buf);
},
return_none: true
},
'起動待機': {
type: 'func',
josi: [['を']],
pure: true,
fn: function (s) {
const r = execSync(s);
return r.toString();
}
},
'起動': {
type: 'func',
josi: [['を']],
pure: true,
fn: function (s) {
exec(s, (err, stdout, stderr) => {
if (err) {
console.error(stderr);
}
else {
if (stdout) {
console.log(stdout);
}
}
});
}
},
'起動時': {
type: 'func',
josi: [['で'], ['を']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (callback, s, sys) {
exec(s, (err, stdout, stderr) => {
if (err) {
throw new Error(stderr);
}
else {
callback(stdout);
}
});
}
},
'ブラウザ起動': {
type: 'func',
josi: [['を']],
pure: true,
fn: function (url) {
opener(url);
}
},
'ファイル列挙': {
type: 'func',
josi: [['の', 'を', 'で']],
pure: true,
fn: function (s) {
if (s.indexOf('*') >= 0) { // ワイルドカードがある場合
const searchPath = path.dirname(s);
const mask1 = path.basename(s)
.replace(/\./g, '\\.')
.replace(/\*/g, '.*');
const mask2 = (mask1.indexOf(';') < 0)
? mask1 + '$'
: '(' + mask1.replace(/;/g, '|') + ')$';
const maskRE = new RegExp(mask2, 'i');
const list = fs.readdirSync(searchPath);
return list.filter((n) => maskRE.test(n));
}
else {
return fs.readdirSync(s);
}
}
},
'全ファイル列挙': {
type: 'func',
josi: [['の', 'を', 'で']],
pure: true,
fn: function (s) {
/** @type {string[]} */
const result = [];
// ワイルドカードの有無を確認
let mask = '.*';
let basepath = s;
if (s.indexOf('*') >= 0) {
basepath = path.dirname(s);
const mask1 = path.basename(s)
.replace(/\./g, '\\.')
.replace(/\*/g, '.*');
mask = (mask1.indexOf(';') < 0)
? mask1 + '$'
: '(' + mask1.replace(/;/g, '|') + ')$';
}
basepath = path.resolve(basepath);
const maskRE = new RegExp(mask, 'i');
// 再帰関数を定義
const enumR = (base) => {
const list = fs.readdirSync(base);
for (const f of list) {
if (f === '.' || f === '..') {
continue;
}
const fullpath = path.join(base, f);
let st;
try {
st = fs.statSync(fullpath);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
}
catch (e) {
continue;
}
if (st.isDirectory()) {
enumR(fullpath);
continue;
}
if (maskRE.test(f)) {
result.push(fullpath);
}
}
};
// 検索実行
enumR(basepath);
return result;
}
},
'存在': {
type: 'func',
josi: [['が', 'の']],
pure: true,
fn: function (path) {
return fileExists(path);
}
},
'フォルダ存在': {
type: 'func',
josi: [['が', 'の']],
pure: true,
fn: function (path) {
return isDir(path);
}
},
'フォルダ作成': {
type: 'func',
josi: [['の', 'を', 'に', 'へ']],
pure: true,
fn: function (path) {
return fse.mkdirpSync(path);
}
},
'ファイルコピー': {
type: 'func',
josi: [['から', 'を'], ['に', 'へ']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (a, b, sys) {
return fse.copySync(a, b);
}
},
'ファイルコピー時': {
type: 'func',
josi: [['で'], ['から', 'を'], ['に', 'へ']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (callback, a, b, sys) {
return fse.copy(a, b, (err) => {
if (err) {
throw new Error('ファイルコピー時:' + err);
}
callback();
});
},
return_none: false
},
'ファイル移動': {
type: 'func',
josi: [['から', 'を'], ['に', 'へ']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (a, b, sys) {
return fse.moveSync(a, b);
}
},
'ファイル移動時': {
type: 'func',
josi: [['で'], ['から', 'を'], ['に', 'へ']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (callback, a, b, sys) {
fse.move(a, b, (err) => {
if (err) {
throw new Error('ファイル移動時:' + err);
}
callback();
});
},
return_none: false
},
'ファイル削除': {
type: 'func',
josi: [['の', 'を']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (path, sys) {
return fse.removeSync(path);
}
},
'ファイル削除時': {
type: 'func',
josi: [['で'], ['の', 'を']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (callback, path, sys) {
return fse.remove(path, (err) => {
if (err) {
throw new Error('ファイル削除時:' + err);
}
callback();
});
},
return_none: false
},
'ファイル情報取得': {
type: 'func',
josi: [['の', 'から']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (path, sys) {
return fs.statSync(path);
}
},
'ファイルサイズ取得': {
type: 'func',
josi: [['の', 'から']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (path, sys) {
const st = fs.statSync(path);
if (!st) {
return -1;
}
return st.size;
}
},
// @パス操作
'ファイル名抽出': {
type: 'func',
josi: [['から', 'の']],
pure: true,
fn: function (s) {
return path.basename(s);
}
},
'パス抽出': {
type: 'func',
josi: [['から', 'の']],
pure: true,
fn: function (s) {
return path.dirname(s);
}
},
'絶対パス変換': {
type: 'func',
josi: [['を', 'の']],
pure: true,
fn: function (a) {
return path.resolve(a);
}
},
'相対パス展開': {
type: 'func',
josi: [['を'], ['で']],
pure: true,
fn: function (a, b) {
return path.resolve(path.join(a, b));
}
},
// @フォルダ取得
'カレントディレクトリ取得': {
type: 'func',
josi: [],
pure: true,
fn: function () {
const cwd = nodeProcess.cwd();
return path.resolve(cwd);
}
},
'カレントディレクトリ変更': {
type: 'func',
josi: [['に', 'へ']],
pure: true,
fn: function (dir) {
nodeProcess.chdir(dir);
},
return_none: true
},
'作業フォルダ取得': {
type: 'func',
josi: [],
pure: true,
fn: function () {
const cwd = nodeProcess.cwd();
return path.resolve(cwd);
}
},
'作業フォルダ変更': {
type: 'func',
josi: [['に', 'へ']],
pure: true,
fn: function (dir) {
nodeProcess.chdir(dir);
},
return_none: true
},
'ホームディレクトリ取得': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
return nodeProcess.env[sys.tags.isWin ? 'USERPROFILE' : 'HOME'];
}
},
'デスクトップ': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
const home = sys.__exec('ホームディレクトリ取得', [sys]);
return path.join(home, 'Desktop');
}
},
'マイドキュメント': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
const home = sys.__exec('ホームディレクトリ取得', [sys]);
return path.join(home, 'Documents');
}
},
'母艦パス': { type: 'const', value: '' }, // @ぼかんぱす
'母艦パス取得': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
return sys.tags.__getBokanPath();
}
},
'テンポラリフォルダ': {
type: 'func',
josi: [],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (sys) {
// 環境変数からテンポラリフォルダを取得
return os.tmpdir();
}
},
'一時フォルダ作成': {
type: 'func',
josi: [['に', 'へ']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (dir, sys) {
if (dir === '' || !dir) {
dir = os.tmpdir();
}
// 環境変数からテンポラリフォルダを取得
return fs.mkdtempSync(dir);
}
},
// @環境変数
'環境変数取得': {
type: 'func',
josi: [['の']],
pure: true,
fn: function (s) {
return nodeProcess.env[s];
}
},
'環境変数一覧取得': {
type: 'func',
josi: [],
pure: true,
fn: function () {
return nodeProcess.env;
}
},
// @圧縮・解凍
'圧縮解凍ツールパス': { type: 'const', value: '7z' }, // @あっしゅくかいとうつーるぱす
'圧縮解凍ツールパス変更': {
type: 'func',
josi: [['に', 'へ']],
pure: true,
fn: function (v, sys) {
sys.__setSysVar('圧縮解凍ツールパス', v);
},
return_none: true
},
'解凍': {
type: 'func',
josi: [['を', 'から'], ['に', 'へ']],
pure: true,
fn: function (a, b, sys) {
const tpath = sys.tags.__quotePath(sys.tags.__getBinPath(sys.__getSysVar('圧縮解凍ツールパス')));
a = sys.tags.__quotePath(a);
b = sys.tags.__quotePath(b);
const cmd = `${tpath} x ${a} -o${b} -y`;
execSync(cmd);
return true;
}
},
'解凍時': {
type: 'func',
josi: [['で'], ['を', 'から'], ['に', 'へ']],
pure: true,
fn: function (callback, a, b, sys) {
const tpath = sys.tags.__quotePath(sys.tags.__getBinPath(sys.__getSysVar('圧縮解凍ツールパス')));
a = sys.tags.__quotePath(a);
b = sys.tags.__quotePath(b);
const cmd = `${tpath} x ${a} -o${b} -y`;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
exec(cmd, (err, stdout, stderr) => {
if (err) {
throw new Error('[エラー]『解凍時』' + err);
}
callback(stdout);
});
},
return_none: false
},
'圧縮': {
type: 'func',
josi: [['を', 'から'], ['に', 'へ']],
pure: true,
fn: function (a, b, sys) {
const tpath = sys.tags.__quotePath(sys.tags.__getBinPath(sys.__getSysVar('圧縮解凍ツールパス')));
a = sys.tags.__quotePath(a);
b = sys.tags.__quotePath(b);
const cmd = `${tpath} a -r ${b} ${a} -y`;
execSync(cmd);
return true;
}
},
'圧縮時': {
type: 'func',
josi: [['で'], ['を', 'から'], ['に', 'へ']],
pure: true,
fn: function (callback, a, b, sys) {
const tpath = sys.tags.__quotePath(sys.tags.__getBinPath(sys.__getSysVar('圧縮解凍ツールパス')));
a = sys.tags.__quotePath(a);
b = sys.tags.__quotePath(b);
const cmd = `${tpath} a -r ${b} ${a} -y`;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
exec(cmd, (err, stdout, stderr) => {
if (err) {
throw new Error('[エラー]『圧縮時』' + err);
}
callback(stdout);
});
},
return_none: true
},
// @Nodeプロセス
'終': {
type: 'func',
josi: [],
pure: true,
fn: function () {
nodeProcess.exit();
},
return_none: true
},
'強制終了時': {
type: 'func',
josi: [['を']],
pure: true,
fn: function (func, sys) {
if (typeof (func) === 'string') {
func = sys.__findFunc(func, '強制終了時');
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
nodeProcess.on('SIGINT', (signal) => {
const flag = func(sys);
if (flag) {
nodeProcess.exit();
}
});
},
return_none: true
},
'終了': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
sys.__exec('終', []);
},
return_none: true
},
'OS取得': {
type: 'func',
josi: [],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (sys) {
return nodeProcess.platform;
}
},
'OSアーキテクチャ取得': {
type: 'func',
josi: [],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (sys) {
return nodeProcess.arch;
}
},
// @コマンドラインと標準入出力
'コマンドライン': { type: 'const', value: '' }, // @こまんどらいん
'ナデシコランタイム': { type: 'const', value: '' }, // @なでしこらんたいむ
'ナデシコランタイムパス': { type: 'const', value: '' }, // @なでしこらんたいむぱす
'標準入力取得時': {
type: 'func',
josi: [['を']],
pure: true,
fn: function (callback, sys) {
if (!sys.tags.readline) {
throw new Error('『標準入力取得時』命令で標準入力が取得できません');
}
if (typeof callback === 'string') {
callback = sys.__findFunc(callback, '標準入力取得時');
}
sys.tags.readline('', (line) => {
sys.__setSysVar('対象', line);
callback(line);
});
}
},
'尋': {
type: 'func',
josi: [['と', 'を']],
pure: true,
asyncFn: true,
fn: async function (msg, sys) {
if (!sys.tags.readline) {
throw new Error('『尋』命令で標準入力が取得できません');
}
const line = await sys.tags.readline(msg);
const lineAsNumber = Number(line);
if (isNaN(lineAsNumber)) {
return line;
}
else {
return lineAsNumber;
}
}
},
'文字尋': {
type: 'func',
josi: [['と', 'を']],
pure: true,
asyncFn: true,
fn: async function (msg, sys) {
if (!sys.tags.readline) {
throw new Error('『尋』命令で標準入力が取得できません');
}
const line = await sys.tags.readline(msg);
return line;
}
},
'標準入力全取得': {
type: 'func',
josi: [],
pure: true,
asyncFn: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (sys) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
return new Promise((resolve, _reject) => {
let dataStr = '';
nodeProcess.stdin.on('data', (data) => {
dataStr += data.toString();
});
nodeProcess.stdin.on('end', () => {
nodeProcess.stdin.removeAllListeners();
resolve(dataStr);
});
});
}
},
// @テスト
'ASSERT等': {
type: 'func',
josi: [['と'], ['が']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (a, b, sys) {
assert.strictEqual(a, b);
}
},
// @ネットワーク
'自分IPアドレス取得': {
type: 'func',
josi: [],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (sys) {
const nif = os.networkInterfaces();
if (!nif) {
throw new Error('『自分IPアドレス取得』でネットワークのインターフェイスが種畜できません。');
}
/**
* @type {string[]}
*/
const result = [];
for (const dev in nif) {
const n = nif[dev];
if (!n) {
continue;
}
n.forEach((detail) => {
if (detail.family === 'IPv4') {
result.push(detail.address);
}
});
}
return result;
}
},
'自分IPV6アドレス取得': {
type: 'func',
josi: [],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (sys) {
const nif = os.networkInterfaces();
if (!nif) {
throw new Error('『自分IPアドレス取得』でネットワークのインターフェイスが種畜できません。');
}
const result = [];
for (const dev in nif) {
const n = nif[dev];
if (!n) {
continue;
}
n.forEach((detail) => {
if (detail.family === 'IPv6') {
result.push(detail.address);
}
});
}
return result;
}
},
// @Ajax
'AJAX送信時': {
type: 'func',
josi: [['の'], ['まで', 'へ', 'に']],
pure: true,
fn: function (callback, url, sys) {
let options = sys.__getSysVar('AJAXオプション');
if (options === '') {
options = { method: 'GET' };
}
fetch(url, options).then((res) => {
return res.text();
}).then((text) => {
sys.__setSysVar('対象', text);
callback(text);
}).catch((err) => {
console.log('[fetch.error]', err);
throw err;
});
},
return_none: true
},
'AJAX受信時': {
type: 'func',
josi: [['で'], ['から', 'を']],
pure: true,
fn: function (callback, url, sys) {
sys.__exec('AJAX送信時', [callback, url, sys]);
},
return_none: true
},
'GET送信時': {
type: 'func',
josi: [['の'], ['まで', 'へ', 'に']],
pure: true,
fn: function (callback, url, sys) {
sys.__exec('AJAX送信時', [callback, url, sys]);
},
return_none: true
},
'POST送信時': {
type: 'func',
josi: [['の'], ['まで', 'へ', 'に'], ['を']],
pure: true,
fn: function (callback, url, params, sys) {
const flist = [];
for (const key in params) {
const v = params[key];
const kv = encodeURIComponent(key) + '=' + encodeURIComponent(v);
flist.push(kv);
}
const bodyData = flist.join('&');
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: bodyData
};
fetch(url, options).then((res) => {
return res.text();
}).then((text) => {
sys.__setSysVar('対象', text);
callback(text);
}).catch((err) => {
sys.__getSysVar('AJAX:ONERROR')(err);
});
}
},
'POSTフォーム送信時': {
type: 'func',
josi: [['の'], ['まで', 'へ', 'に'], ['を']],
pure: true,
fn: function (callback, url, params, sys) {
const fd = new FormData();
for (const key in params) {
fd.set(key, params[key]);
}
const options = {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data'
},
body: fd
};
fetch(url, options).then((res) => {
return res.text();
}).then((text) => {
sys.__setSysVar('対象', text);
callback(text);
}).catch((err) => {
sys.__getSysVar('AJAX:ONERROR')(err);
});
}
},
'AJAX失敗時': {
type: 'func',
josi: [['の']],
pure: true,
fn: function (callback, sys) {
sys.__setSysVar('AJAX:ONERROR', callback);
}
},
'AJAXオプション': { type: 'const', value: '' }, // @Ajax関連のオプションを指定 // @AJAXおぷしょん
'AJAXオプション設定': {
type: 'func',
josi: [['に', 'へ', 'と']],
pure: true,
fn: function (option, sys) {
sys.__setSysVar('AJAXオプション', option);
},
return_none: true
},
'AJAX保障送信': {
type: 'func',
josi: [['まで', 'へ', 'に']],
pure: true,
fn: function (url, sys) {
let options = sys.__getSysVar('AJAXオプション');
if (options === '') {
options = { method: 'GET' };
}
return fetch(url, options);
},
return_none: false
},
'HTTP保障取得': {
type: 'func',
josi: [['の', 'から', 'を']],
pure: true,
fn: function (url, sys) {
return sys.__exec('AJAX保障送信', [url, sys]);
},
return_none: false
},
'GET保障送信': {
type: 'func',
josi: [['まで', 'へ', 'に']],
pure: true,
fn: function (url, sys) {
return sys.__exec('AJAX保障送信', [url, sys]);
},
return_none: false
},
'POST保障送信': {
type: 'func',
josi: [['まで', 'へ', 'に'], ['を']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (url, params, sys) {
const flist = [];
for (const key in params) {
const v = params[key];
const kv = encodeURIComponent(key) + '=' + encodeURIComponent(v);
flist.push(kv);
}
const bodyData = flist.join('&');
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: bodyData
};
return fetch(url, options);
},
return_none: false
},
'POSTフォーム保障送信': {
type: 'func',
josi: [['まで', 'へ', 'に'], ['を']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (url, params, sys) {
const fd = new FormData();
for (const key in params) {
fd.set(key, params[key]);
}
const options = {
method: 'POST',
body: fd
};
return fetch(url, options);
},
return_none: false
},
'AJAX内容取得': {
type: 'func',
josi: [['から'], ['で']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (res, type, sys) {
type = type.toString().toUpperCase();
if (type === 'TEXT' || type === 'テキスト') {
return res.text();
}
else if (type === 'JSON') {
return res.json();
}
else if (type === 'BLOB') {
return res.blob();
}
else if (type === 'ARRAY' || type === '配列') {
return res.arrayBuffer();
}
else if (type === 'BODY' || type === '本体') {
return res.body;
}
return res.body();
},
return_none: false
},
'AJAX受信': {
type: 'func',
josi: [['から', 'を']],
pure: true,
fn: function (url, sys) {
let options = sys.__getSysVar('AJAXオプション');
if (options === '') {
options = { method: 'GET' };
}
// fetch 実行
fetch(url, options).then((res) => {
if (res.ok) { // 成功したとき
return res.text();
}
else { // 失敗したとき
throw new Error('status=' + res.status);
}
}).then((text) => {
sys.__setSysVar('対象', text);
}).catch((err) => {
console.error('[AJAX受信のエラー]', err);
});
},
return_none: true
},
'POSTデータ生成': {
type: 'func',
josi: [['の', 'を']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (params, sys) {
const flist = [];
for (const key in params) {
const v = params[key];
const kv = encodeURIComponent(key) + '=' + encodeURIComponent(v);
flist.push(kv);
}
return flist.join('&');
}
},
'POST送信': {
type: 'func',
josi: [['まで', 'へ', 'に'], ['を']],
pure: true,
asyncFn: true,
fn: function (url, params, sys) {
return new Promise((resolve, reject) => {
const bodyData = sys.__exec('POSTデータ生成', [params, sys]);
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: bodyData
};
fetch(url, options).then(res => {
return res.text();
}).then(text => {
resolve(text);
}).catch(err => {
reject(err.message);
});
});
}
},
'POSTフォーム送信': {
type: 'func',
josi: [['まで', 'へ', 'に'], ['を']],
pure: true,
asyncFn: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (url, params, sys) {
return new Promise((resolve, reject) => {
const fd = new FormData();
for (const key in params) {
fd.set(key, params[key]);
}
const options = {
method: 'POST',
body: fd
};
fetch(url, options).then(res => {
return res.text();
}).then(text => {
resolve(text);
}).catch(err => {
reject(err.message);
});
});
}
},
// @新AJAX
'AJAXテキスト取得': {
type: 'func',
josi: [['から']],
pure: true,
asyncFn: true,
fn: async function (url, sys) {
let options = sys.__getSysVar('AJAXオプション');
if (options === '') {
options = { method: 'GET' };
}
// console.log(url, options)
const res = await fetch(url, options);
const txt = await res.text();
return txt;
},
return_none: false
},
'AJAX_JSON取得': {
type: 'func',
josi: [['から']],
pure: true,
asyncFn: true,
fn: async function (url, sys) {
let options = sys.__getSysVar('AJAXオプション');
if (options === '') {
options = { method: 'GET' };
}
const res = await fetch(url, options);
const txt = await res.json();
return txt;
},
return_none: false
},
'AJAXバイナリ取得': {
type: 'func',
josi: [['から']],
pure: true,
asyncFn: true,
fn: async function (url, sys) {
let options = sys.__getSysVar('AJAXオプション');
if (options === '') {
options = { method: 'GET' };
}
const res = await fetch(url, options);
const bin = await res.arrayBuffer();
return bin;
},
return_none: false
},
// @LINE
'LINE送信': {
type: 'func',
josi: [['へ', 'に'], ['を']],
pure: true,
asyncFn: true,
fn: async function (token, message, sys) {
const lineNotifyUrl = 'https://notify-api.line.me/api/notify';
const bodyData = sys.__exec('POSTデータ生成', [{ message }, sys]);
const options = {
'method': 'POST',
'headers': {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': `Bearer ${token}`
},
'body': bodyData
};
const res = await fetch(lineNotifyUrl, options);
const jsonObj = await res.json();
return JSON.stringify(jsonObj);
},
return_none: false
},
'LINE画像送信': {
type: 'func',
josi: [['へ', 'に'], ['と'], ['を']],
pure: true,
asyncFn: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: async function (token, imageFile, message, sys) {
const lineNotifyUrl = 'https://notify-api.line.me/api/notify';
const formData = new FormData();
formData.append('message', message);
const imageData = fs.readFileSync(imageFile);
formData.append('imageFile', new Blob([imageData]));
const options = {
'method': 'POST',
'headers': {
'Authorization': `Bearer ${token}`
},
'body': formData
};
const res = await fetch(lineNotifyUrl, options);
const jsonObj = await res.json();
return JSON.stringify(jsonObj);
},
return_none: false
},
// @文字コード
'文字コード変換サポート判定': {
type: 'func',
josi: [['の', 'を']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (code, sys) {
return iconv.encodingExists(code);
}
},
'SJIS変換': {
type: 'func',
josi: [['に', 'へ', 'を']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (str, sys) {
// iconv.skipDecodeWarning = true
return iconv.encode(str, 'Shift_JIS');
}
},
'SJIS取得': {
type: 'func',
josi: [['から', 'を', 'で']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (buf, sys) {
// iconv.skipDecodeWarning = true
return iconv.decode(Buffer.from(buf), 'sjis');
}
},
'エンコーディング変換': {
type: 'func',
josi: [['を'], ['へ', 'で']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (s, code, sys) {
// iconv.skipDecodeWarning = true
return iconv.encode(s, code);
}
},
'エンコーディング取得': {
type: 'func',
josi: [['を'], ['から', 'で']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (buf, code, sys) {
// iconv.skipDecodeWarning = true
return iconv.decode(Buffer.from(buf), code);
}
},
// @ハッシュ関数
'ハッシュ関数一覧取得': {
type: 'func',
josi: [],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (sys) {
return crypto.getHashes();
}
},
'ハッシュ値計算': {
type: 'func',
josi: [['を'], ['の'], ['で']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (s, alg, enc, sys) {
const hashsum = crypto.createHash(alg);
hashsum.update(s);
return hashsum.digest(enc);
}
},
'ランダムUUID生成': {
type: 'func',
josi: [],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (sys) {
const uuid = crypto.randomUUID();
return uuid;
}
},
'ランダム配列生成': {
type: 'func',
josi: [['の']],
pure: true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fn: function (cnt, sys) {
const a = new Uint8Array(cnt);
crypto.getRandomValues(a);
return a;
}
}
};