WSH(JScript)用エラー出力ファイル情報付加:ErrorUtility.FileInfo.js
WSH(JScript)用エラー出力ファイル情報付加です。
機能概要は、以下の通りです。
- エラー出力用のトレース文字列にファイル情報を付加する
サンプル
準備中
参考リンク
- WSH(JScript)でコードを書いてみる
- WSH(JScript)でJSONを使う
- WSH(JScript)用エラーライブラリ:ErrorUtility.js
- WSH(JScript)用コンソール:Console.js
ErrorUtility.FileInfo.js
GitHubで公開しました。最新版は、k08045kk/WSHLibraryから取得してください。
ErrorUtility.FileInfo.js/*!
* ErrorUtility.FileInfo.js v1
*
* Copyright (c) 2019 toshi
* Released under the MIT license.
* see https://opensource.org/licenses/MIT
*/
/**
* WSH(JScript)用エラー出力ファイル情報付加
* エラー出力用のトレース文字列にファイル情報を付加する。
* 実行中のWSF/JS/JSEファイルを読み込んで指定関数を検索し、関数のファイルパス、行数、列数を返す。
* @requires ErrorUtility.js
* @auther toshi(https://www.bugbugnow.net/)
* @license MIT License
* @version 1
* @see 1.20190823 - add - 初版(ErrorUtility.js v4、Process.js v12、FileUtility.js v16分離)
*/
(function(root, factory) {
if (root.ErrorUtility && !root.ErrorUtility._plugin_FileInfo) {
root.ErrorUtility._plugin_FileInfo = true;
factory(root.ErrorUtility);
}
})(this, function(_this) {
"use strict";
// -------------------- private --------------------
var fs = new ActiveXObject('Scripting.FileSystemObject');
var _codes = null; // 実行ソースコード {ファイルパス:ソースコード, ...}
/**
* PrivateUnderscore.js
* @version 4
*/
{
function _Process_createActiveXObjects(progIDs) {
for (var i=0; i<progIDs.length; ++i) {
try {
return new ActiveXObject(progIDs[i]);
} catch (e) {
if (i == progIDs.length - 1) { throw e; }
}
}
return null;
};
function _Process_createDOMDocument() {
return _Process_createActiveXObjects([
'MSXML2.DOMDocument.6.0',
'MSXML2.DOMDocument.3.0',
'Msxml2.DOMDocument',
'Msxml.DOMDocument',
'Microsoft.XMLDOM']);
};
function _loadText(path, opt_charset) {
var ret, fullpath,
charset = opt_charset,
skip = false;
if (charset == null) { charset = '_autodetect_all'; }
charset = charset.toLowerCase();
fullpath = fs.GetAbsolutePathName(path);
if (!fs.FileExists(fullpath)) {
// ファイルなし
return null;
} else if (fs.GetFile(fullpath).size === 0) {
// 空ファイル
return '';
}
var sr = new ActiveXObject('ADODB.Stream');
sr.Type = 2;
if (charset == '_autodetect_all' || charset == 'utf-16be') {
// BOMを確認してUTF-8とUTF-16だけ、手動で判定する
// UTF-16BEは、BOMあり時にBOM削除されないため、手動でスキップする
var pre = new ActiveXObject('ADODB.Stream');
pre.Type = 2;
pre.Charset = 'us-ascii';
pre.Open();
pre.LoadFromFile(fullpath);
var bom = [];
bom.push(pre.EOS || escape(pre.ReadText(1)));
bom.push(pre.EOS || escape(pre.ReadText(1)));
bom.push(pre.EOS || escape(pre.ReadText(1)));
if (charset == 'utf-16be') {
if (bom[0] == '%7E' && bom[1]== '%7F') {
skip = true;
}
} else if (bom[0] == 'o' && bom[1]== '%3B' && bom[2]== '%3F') {
charset = 'utf-8';
} else if (bom[0] == '%7F' && bom[1]== '%7E') {
charset = 'utf-16le';
} else if (bom[0] == '%7E' && bom[1]== '%7F') {
charset = 'utf-16be';
skip = true;
}
pre.Close();
pre = null;
}
sr.Charset = charset;
// ファイルから読み出し
sr.Open();
sr.LoadFromFile(fullpath);
if (skip) {
// 先頭一文字(BOM)を空読み
sr.ReadText(1);
ret = sr.ReadText();
} else {
ret = sr.ReadText();
}
// 終了処理
sr.Close();
sr = null;
return ret;
};
}
// -------------------- static --------------------
/**
* スタックトレース
* @param {Array} frame - エラー情報
* @return {string} トレース文字列
* @override
*/
_this._createStackTraceText = function ErrorUtility$FileInfo__createStackTraceText(frame) {
var msg = [];
msg.push(_this.trace(frame, true));
// 拡張情報(ファイル名:行数:列数/文字列)
try {
var scripts = _this.searchScripts(frame[0]);
if (scripts.length == 1) {
msg.push(' - '+scripts[0].name+':'+scripts[0].row+':'+scripts[0].column+'');
}
// 補足:0個の可能性あり、2個以上の可能性あり、全部表示するのもあり?
} catch (e) {} // エラー出力処理中であるため、なにもしない
return msg.join('');
};
/**
* エラー作成
* エラー作成と同時にキャプチャする。
* エラー作成箇所は、本関数を直接コールすること。
* @param {string} opt_message - エラーメッセージ
* @param {Function} opt_root - トレースを開始する直前の関数(null:本関数)
* @param {(string|Function)} opt_error - エラー
* @return {Error} エラー
* @override
*/
_this._create_Backup = _this.create;
_this.create = function ErrorUtility$FileInfo_create(opt_message, opt_root, opt_error) {
var error = _this._create_Backup(opt_message, opt_root, opt_error);
// 補助情報を追加
try {
var scripts = _this.searchScripts(error.stackframes[0][0]);
if (scripts.length === 1) {
error.fileName = scripts[0].name;
error.lineNumber = scripts[0].row;
error.columnNumber = scripts[0].column;
}
} catch (e) {} // エラー出力処理中であるため、なにもしない
return error;
};
/**
* スクリプトをロードする
* searchScripts()用のため、wsfファイルは、XML構造を消去して保存する。
* @return {Object} コード
*/
_this.loadScripts = function ErrorUtility$FileInfo_loadScripts() {
if (_codes == null) {
_codes = {};
var wsf = WScript.ScriptFullName;
var ext = fs.GetExtensionName(wsf).toLowerCase();
if (ext == 'wsf') {
// wsfを解析
var text = _loadText(wsf)
.replace(/\r\n?/g,'\n');
var xml = _Process_createDOMDocument();
xml.loadXML(text);
_codes[wsf] = '';
var idx = 0;
var scripts = xml.selectNodes('//script');
for (var i=0; i<scripts.length; i++) {
var src = scripts[i].getAttribute('src');
if (src != null) {
// 外部ファイル読み込み
_codes[src] = _loadText(src);
}
if (scripts[i].text != '') {
// wsfをjseに変換
// XML部分を削除(行番号を揃える)
var eidx = text.indexOf(scripts[i].text, idx);
while ((idx=text.indexOf('\n', idx)+1) < eidx && idx != -1) {
_codes[wsf] += '\n';
}
idx = eidx + scripts[i].text.length;
_codes[wsf] += scripts[i].text;
// 補足:複数のスクリプト記述がある場合、
// スクリプトの実行順を維持できない可能性がある(実行しなければOK)
}
}
text = xml = scripts = null;
} else if (ext == 'js' || ext == 'jse') {
_codes[wsf] = _loadText(wsf);
}
for (var key in _codes) {
if (_codes.hasOwnProperty(key)) {
// 改行文字統一
_codes[key] = _codes[key].replace(/\r\n?/g,'\n');
}
}
}
return _codes;
};
/**
* 関数検索
* 実行中のスクリプトの関数を検索する。
* ソースコードのファイル名、行数、列数を返す。
* @param {Functionn} func - 戻り値
* @param {Object[]} 検索結果
*/
_this.searchScripts = function ErrorUtility$FileInfo_searchScripts(func) {
// 関数文字列化 && 改行文字統一
var text = func.toString().replace(/\r\n?/g,'\n');
var fi = text.indexOf('function');
text = (fi > 0)? text.substring(fi): text;
var ret = [];
var codes = _this.loadScripts();
for (var key in codes) {
if (codes.hasOwnProperty(key)) {
var code = codes[key];
for (var idx=0; ; idx++) {
idx = code.indexOf(text, idx);
if (idx != -1) {
var row = 1;
var col = -1;
for (var i=0,n=0; ; i=n+1,row++) {
// 関数の行番号取得(\nを探す)
n = code.indexOf('\n', i);
if (n > idx || n == -1) {
// 直前の改行文字からの文字数
col = 1 + (idx - i);
break;
}
}
ret.push({
'path': key,
'name': fs.GetFileName(key),
'index': idx, 'row': row, 'column': col});
} else {
break;
}
}
}
}
return ret;
// 補足:func.toString()は、時々失敗する。
// 末尾の'}'がなくなる。タブが別の文字に置き換わる等
};
});
変更履歴
更新日 | 内容 |
---|---|
2019/08/23 | v1 - add - 初版(ErrorUtility.js v4、Process.js v12、FileUtility.js v16分離) |