markdownで書かれた文章から、JSONを作るライブラリ。
# h1, ## h2, ### h3, #### h4
のヘッダを判定。
tableを判定。以下、仕様。
例
FORMAT : TD
# schema : SSE19
## table_id : orders
### table_comment : 注文ヘッダ
- 注文のヘッダレコード
- 注文IDで、注文の明細レコードと紐づく。
## definition : table items
| no | identifier | type | size | not_null | pk | comment |
| -----|---------------------|--------|--------|----------|------|------------- |
| 01 | id | int | (16) | NOT NULL | PK | 注文ID |
| 02 | order_date | date | | NOT NULL | | 注文日 |
| 03 | cust_delivery_date | date | | | | 希望納期 |
| 04 | cust_order_id | string | (16) | | | 顧客注文番号 |
| 05 | order_total_amt | int | (10) | | | 注文合計金額 |
| 06 | comsuption_tax_rate | float | (3,3) | | | 消費税率 |
| 07 | comsuption_tax | int | (10) | | | 消費税金額 |
| 08 | discount_amt | int | (10) | | | 値引き金額 |
| 09 | cust_user_id | int | (16) | NOT NULL | | 顧客コード |
| 10 | cust_user_name | string | (3000) | | | 顧客名 |
| 11 | create_date | date | | NOT NULL | | 作成日 |
| 12 | created | int | | NOT NULL | | 作成者 |
| 13 | update_date | date | | | | 更新日 |
| 14 | updated | int | | | | 更新者 |
| 15 | del_flag | string | (3) | | | 削除フラグ |
| | | | | | | |
## history :
- 19/12/17 comsuption_tax_rate を追加
{
"first_p.contents": "FORMAT : TD",
"schema": "SSE19",
"schema.table_id": "orders",
"schema.table_id.table_comment": "注文ヘッダ",
"schema.table_id.table_comment.contents": "\t- 注文のヘッダレコード\r\n\t- 注文IDで、注文の明細レコードと紐づく。",
"schema.definition": "table items",
"schema.definition.rows": [{
"no": "01",
"identifier": "id",
"type": "int",
"size": "(16)",
"not_null": "NOT NULL",
"pk": "PK",
"comment": "注文ID"
}, {
"no": "02",
"identifier": "order_date",
"type": "date",
"size": "",
"not_null": "NOT NULL",
"pk": "",
"comment": "注文日"
}, {
"no": "03",
"identifier": "cust_delivery_date",
"type": "date",
"size": "",
"not_null": "",
"pk": "",
"comment": "希望納期"
}, {
"no": "04",
"identifier": "cust_order_id",
"type": "string",
"size": "(16)",
"not_null": "",
"pk": "",
"comment": "顧客注文番号"
}, {
"no": "05",
"identifier": "order_total_amt",
"type": "int",
"size": "(10)",
"not_null": "",
"pk": "",
"comment": "注文合計金額"
}, {
"no": "06",
"identifier": "comsuption_tax_rate",
"type": "float",
"size": "(3,3)",
"not_null": "",
"pk": "",
"comment": "消費税率"
}, {
"no": "07",
"identifier": "comsuption_tax",
"type": "int",
"size": "(10)",
"not_null": "",
"pk": "",
"comment": "消費税金額"
}, {
"no": "08",
"identifier": "discount_amt",
"type": "int",
"size": "(10)",
"not_null": "",
"pk": "",
"comment": "値引き金額"
}, {
"no": "09",
"identifier": "cust_user_id",
"type": "int",
"size": "(16)",
"not_null": "NOT NULL",
"pk": "",
"comment": "顧客コード"
}, {
"no": "10",
"identifier": "cust_user_name",
"type": "string",
"size": "(3000)",
"not_null": "",
"pk": "",
"comment": "顧客名"
}, {
"no": "11",
"identifier": "create_date",
"type": "date",
"size": "",
"not_null": "NOT NULL",
"pk": "",
"comment": "作成日"
}, {
"no": "12",
"identifier": "created",
"type": "int",
"size": "",
"not_null": "NOT NULL",
"pk": "",
"comment": "作成者"
}, {
"no": "13",
"identifier": "update_date",
"type": "date",
"size": "",
"not_null": "",
"pk": "",
"comment": "更新日"
}, {
"no": "14",
"identifier": "updated",
"type": "int",
"size": "",
"not_null": "",
"pk": "",
"comment": "更新者"
}, {
"no": "15",
"identifier": "del_flag",
"type": "string",
"size": "(3)",
"not_null": "",
"pk": "",
"comment": "削除フラグ"
}],
"schema.history": "",
"schema.history.contents": "\t- 19/12/17 comsuption_tax_rate を追加"
}
// Set your module name collectly.
var this_file_name = 'MD.jse'; // Notice! If you rename this module file name.
var exports = typeof exports !== 'undefined' ? exports : {};
/////////////////////////////////////////////////////////////////
// MD.jse
// Markdown Format simple Parser (not consider complex format)
// 19/12/17 memoru
//
// static method
// - MD.converttoJSON(str)
// Dependency
// - underscore.js
// - StringUtil.jse
(function(){
var CLS_ = {};
CLS_.module_name = this_file_name;
// local const
var CONS_TABLE_HEAD_POS = 1;
var CONS_TABLE_HEAD = 'no';
var CONS_FORMAT_FNAME = '.*';
var CONS_FORMAT_SHEETID = '.*';
var CONS_TABLE_COLSIZE = 3;
// local method
//
var check_firstLine = function(line){
/** To check Format Sheet ID */
var ret = false;
var check_ary = line.split(':');
if(check_ary.length == 2){
check_ary = _.map(check_ary, function(elm){
return StringUtil.trim(elm);
})
if(check_line[0] === CONS_FORMAT_FNAME) {
if(check_line[1] === CONS_FORMAT_SHEETID) {
ret = true;
}
}
}
return ret
}
var check_lineCategory = function(line){
/** categorize line context */
var ret = '';
var regx_header = new RegExp('\\s*#{1,4}');
var regx_table = new RegExp('\\s*\\|');
var regx_spaces = new RegExp('^\\s*$','m');
var regx_numeric = new RegExp('\\d+');
//
if (regx_spaces.test(line)){
ret = 'spaces';
} else if(regx_header.test(line)){
ret = 'h1234';
} else if(regx_table.test(line)){
if(!StringUtil.contains(line, '-')){
var check_col = line.split('|');
if(check_col.length >= 2){
var first_colStr = StringUtil.trim(check_col[CONS_TABLE_HEAD_POS]);
if(first_colStr === CONS_TABLE_HEAD){
ret = 'th';
} else if(regx_numeric.test(first_colStr)){
ret = 'tr';
} else {
ret = 'tr-space'; // no column is space.
}
} else {
ret = 'tr-column-num-error'; // not target column number
}
} else {
ret = 'thr'; // table border inside a table
}
} else {
ret = 'pre'; // such as <pre> or <p> or <li>
}
//console.log('L080 : ' + ret)
return ret
}
var convertto_headerObj = function(line,idx){
/** analyze header's statement */
var ret = [];
var regx = new RegExp('#{1,4}\\s+');
if(!StringUtil.contains(line, ':')){
line = line + ' : '
}
var hlevel = line.match(/#{1,4}\s+/);
var ary = line.split(':');
ary = _.map(ary,function(elm){
elm = elm.replace(regx,'');
return StringUtil.trim(elm);
})
// array size is equal 2 and array is of key and value
var level = StringUtil.trim(hlevel[0]).length
if(ary.length == 2){
ret = {
line_no : idx,
level : '' + level,
header_ary : ary
}
}
return ret
}
var convertto_colums = function(line){
/** convert a table row to an arrray of columns */
var ret = [];
//line = StringUtil.chopDouble(StringUtil.trim(line),1);
var ary = line.split('|');
ary = _.map(ary,function(elm){
return StringUtil.trim(elm);
})
if(ary.length >= CONS_TABLE_COLSIZE){
// check Table COLSIZE by config setting
ret = _.initial(_.rest(ary));
}
return ret
}
var convertfrom_headersObj = function(headers){
/** convert headers composed into an arrray of
* header line no and composed header
*/
var len = headers.length;
var pre_level = 0;
var ary = [];
var h1234_buff = [];
var obj = {};
for(var i = 0; i < len; i++){
if(pre_level < headers[i].level){
h1234_buff.push(headers[i].header_ary[0]);
} else if(pre_level >= headers[i].level) {
h1234_buff = _.first(h1234_buff, headers[i].level-1);
h1234_buff.push(headers[i].header_ary[0]);
}
obj = {
line_no : headers[i].line_no,
composedHeader : h1234_buff.join('.')
}
ary.push(obj);
pre_level = headers[i].level;
}
var ret_ary = _.map(ary, function(elm,idx){
var buf = {};
buf[elm['line_no']] = elm['composedHeader'];
return buf
})
return ret_ary
}
var extend_arrayOfObj = function(ary){
var ret = {};
var len = ary.length;
for(var i = 0; i < len; i++){
var key_ = _.keys(ary[i])[0]
var val_ = ary[i][key_]
ret[key_] = val_
}
return ret
}
var convertto_object = function(lines, i_start,line_code){
var ret_obj = {};
var len = lines.length;
var target_line_no = 0;
var target_line_no_headOfRows = 0;
var col_head = [];
var col_row = [];
var buff_h1234 = [];
var buff_obj = {};
var buff_paragraph = [];
var buff_rows = [];
var row_obj = {}; // for row
var line_category = '';
for(var i = i_start; i < len; i++){
line_category = check_lineCategory(lines[i])
//console.log('L181 : line_category = ' + line_category);
//console.log('L182 : line = ' + lines[i]);
//
// process for each category
if(line_category === 'h1234'){
if(buff_paragraph.length !== 0){
buff_obj[target_line_no + '.contents'] = buff_paragraph.join(line_code);
buff_paragraph.length = 0;
}
if(buff_rows.length !== 0){
buff_obj[target_line_no + '.rows'] = [].concat(buff_rows);
buff_rows.length = 0;
}
var header_obj = convertto_headerObj(lines[i],i);
// console.log('L195 : ');
// console.dir(header_obj);
target_line_no = header_obj.line_no;
buff_h1234.push(header_obj);
buff_obj[header_obj.line_no] = header_obj.header_ary[1];
}
if(line_category === 'th'){
if(buff_paragraph.length !== 0){
buff_obj[target_line_no + '.contents'] = buff_paragraph.join(line_code);
buff_paragraph.length = 0;
}
col_head = convertto_colums(lines[i]);
}
if(line_category === 'tr'){
col_row = convertto_colums(lines[i]);
if(col_head.length == col_row.length){
row_obj = _.object(col_head, col_row);
buff_rows.push(row_obj);
}
}
if(line_category == 'pre'){
buff_paragraph.push(lines[i]);
}
}
if(buff_paragraph.length !== 0){
buff_obj[target_line_no + '.contents'] = buff_paragraph.join(line_code);
}
if(buff_rows.length !== 0){
buff_obj[target_line_no + '.rows'] = [].concat(buff_rows);
}
ret_obj = {
'headers_ary' : buff_h1234,
'converted_obj' : buff_obj
}
return ret_obj
}
var generate_dictOfHeader = function(ary){
var ary_headersOfLineNoAndComposedName = convertfrom_headersObj(ary);
//console.log('L234 : ary' + ary_headersOfLineNoAndComposedName);
var dict = extend_arrayOfObj(ary_headersOfLineNoAndComposedName);
_.defaults(dict, {'0': 'first_p'});
return dict
}
var reorganize_data = function(obj,dict){
var ret = {}
for(var key_ in obj){
if(obj.hasOwnProperty(key_)){
var buff = key_.split('.');
var line_no = buff[0];
var composedHead = dict[line_no];
if(buff.length == 2){
composedHead = composedHead + '.' + buff[1];
}
}
ret[composedHead] = obj[key_]
}
return ret
}
// static method
//
CLS_.converttoJSON = function(lines, line_code, isFormatCheck, CONFIG){
var ret_obj = {};
// set config
CONS_TABLE_HEAD_POS = typeof CONFIG.TABLE_HEAD_POS !== 'undefined'? CONFIG.TABLE_HEAD_POS : 1;
CONS_TABLE_HEAD = typeof CONFIG.TABLE_HEAD !== 'undefined'? CONFIG.TABLE_HEAD : 'no';
CONS_FORMAT_FNAME = typeof CONFIG.FORMAT_FNAME !== 'undefined'? CONFIG.FORMAT_FNAME : '.*';
CONS_FORMAT_SHEETID = typeof CONFIG.FORMAT_SHEETID !== 'undefined'? CONFIG.FORMAT_SHEETID : '.*';
CONS_TABLE_COLSIZE = typeof CONFIG.TABLE_COLSIZE !== 'undefined'? CONFIG.TABLE_COLSIZE : 3;
//
var dict_headerKeys = {};
var converted = {};
var ary_h1234 = [];
var obj_converted = {};
var line_category = '';
var i_start = 0;
if(isFormatCheck) {
i_start = 1;
}
converted = convertto_object(lines, i_start, line_code);
obj_converted = converted['converted_obj'];
ary_h1234 = converted['headers_ary'];
//
// organize return object
var dict_headerKeys = generate_dictOfHeader(ary_h1234);
ret_obj = reorganize_data(obj_converted,dict_headerKeys);
//console.log('L283');
//console.dir(ret_obj);
return ret_obj
}
CLS_.doDebug = function(){
WScript.Echo('------------ debug start');
WScript.Echo('module name = ' + MD.module_name);
}
exports.MD = CLS_;
}());
// --------------------------------------------------- do debug
var doDebugMain = function(){
var CONFIG = typeof CONFIG !== 'undefined' ? CONFIG : {};
CONFIG.IS_CHECKED_FORM = false;
CONFIG.FORMAT_FNAME = 'FORMAT';
CONFIG.FORMAT_SHEETID = 'TD';
CONFIG.TABLE_HEAD = 'no';
CONFIG.TABLE_HEAD_POS = 1;
CONFIG.TABLE_COLSIZE = 7;
var form_target = function(str, line_code){
/* unifiy linecode and rtrim */
if(typeof line_code === 'undefined') line_code = '\r\n';
str = StringUtil.unifyLineCode(str, line_code)
var lines = str.split(line_code);
return _.map(lines, function(elm, idx){
return StringUtil.rtrim(elm);
})
}
console.log('------------------------- start //');
console.log('APP : ' + CONFIG.APP_NAME);
var isCheckedForm = typeof CONFIG.IS_CHECKED_FORM !== 'undefined' ? CONFIG.IS_CHECKED_FORM: false;
var target_ = CLIP.get_clipboard();
//console.log('target_ = ' + target_);
var lines_formatted = [];
var line_code = '\r\n';
lines_formatted = form_target(target_, line_code);
var obj = MD.converttoJSON(lines_formatted, line_code, isCheckedForm, CONFIG);
console.dir(obj);
}
// --------------------------------------------------- entry point
function is_module(this_module_name){
// reference : https://senooken.jp/blog/2016/08/20/
// https://gist.github.com/lamsh/f16ee7032051868844fc081926bf0854
var isWSH = (typeof(WScript) !== "undefined" && WScript.ScriptName === this_module_name);
var isEditor = (typeof(Editor) !== "undefined" && Editor.ExpandParameter('$f') === this_module_name);
var isBrowser = (typeof(alert) !== "undefined");
return (isWSH || isEditor || isBrowser)
}
if(typeof(Editor) !== 'undefined'){
if (is_module(this_file_name)){
null;
}
} else {
if (is_module(this_file_name)){
var CONS_COMMON_LIBPATH = 'G:\\Users\\sakai\\AppData\\Roaming\\sakura';
var CONS_COMMON_LIBS = [
"./lib/json2.js",
"./lib/underscore.js",
"./lib/StringUtil.jse",
"./lib/Clipboard3.jse",
"./lib/DateUtil.jse"
]
//
// load external libraries
var check_env = function(){
// set env_name for targetting wsh, sakura, node
var env_name = '';
if (typeof(WScript) !== "undefined") env_name = 'wsh';
if (typeof(Editor) !== "undefined") env_name = 'sakura';
if (typeof(alert) !== "undefined") {env_name = 'browser';}
else if (typeof(console) !== "undefined") env_name = 'node';
return env_name;
}
var flag = check_env();
var exports = typeof exports !== 'undefined' ? exports : {};
//
if(flag == "wsh"||flag == "sakura"){
var objFS = new ActiveXObject("Scripting.FileSystemObject");
var lib_path = CONS_COMMON_LIBPATH ? CONS_COMMON_LIBPATH: './';
// require common module
with({
libs : CONS_COMMON_LIBS,
get_moduleCode : function(path){
return objFS.OpenTextFile(path,1).ReadAll();
}
}) {
var len = libs.length;
for (var i = 0; i < len; i++){
try {
var module_path = objFS.BuildPath(lib_path,libs[i]);
//WScript.Echo( module_path );
eval(get_moduleCode(module_path));
} catch (e) {
//WScript.Echo( e.description || e.message || "error" );
null;
}
}
};
objFS = null;
}
var CONFIG = typeof CONFIG !== 'undefined' ? CONFIG : {};
var debug_mode = typeof CONFIG.DEBUG_MODE !== 'undefined' ? CONFIG.DEBUG_MODE: true ;
var DateUtil = exports.DateUtil;
// pretend console.log
var console = typeof console !== 'undefined' ? console : {};
if(console){
if(debug_mode){
if(flag == "sakura"){
console.log=function(str){
var log_str = "[DEBUG] $d$t ($f) > " + str;
Editor.TraceOut(log_str,1)
}
console.info=function(str){
var log_str = "[INFO] $d$t ($f) > " + str;
Editor.TraceOut(log_str,1)
}
console.dir = function(obj){
var str = "[DUMP] $d$t ($f) > " + JSON.stringify(obj);
Editor.TraceOut(str,1);
}
};
if(flag == "wsh"){
console.info = function(str){WScript.Echo('[INFO] ' + DateUtil.get_todayString() + ' (' + DateUtil.get_todayDayString() + ') ' + DateUtil.get_nowTimeString() + ' > ' + str)};
console.log = function(str){WScript.Echo('[DEBUG] ' + DateUtil.get_todayString() + ' (' + DateUtil.get_todayDayString() + ') ' + DateUtil.get_nowTimeString() + ' > ' + str)};
console.dir = function(obj){
var str = JSON.stringify(obj);
WScript.Echo('[DUMP] ' + str);
}
}
}else{
if(flag == "wsh") console.info = function(str){WScript.Echo(str)};
if(flag == "sakura") console.info =function(str){Editor.InfoMsg(str)};
if(flag == "wsh") console.log = function(str){null;};
if(flag == "sakura") console.log = function(str){null;};
if(flag == "wsh") console.dir = function(str){null;};
if(flag == "sakura") console.dir = function(str){null;};
}
}
//
CONFIG.debug_mode = true;
var MD = exports.MD;
var _ = exports._;
var StringUtil = exports.StringUtil;
var CLIP = exports.CLIP;
console.dir(exports);
doDebugMain();
} else {
console.log('Test on IE11')
}
}