nadesiko3 3.3.48 → 3.3.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/.editorconfig +6 -0
- package/core/.eslintrc.cjs +33 -0
- package/core/.github/dependabot.yml +7 -0
- package/core/.github/workflows/nodejs.yml +37 -0
- package/core/.github/workflows/super-linter.yml +61 -0
- package/core/.github/workflows/textlint.yml +199 -0
- package/core/LICENSE +21 -0
- package/core/README.md +66 -0
- package/core/batch/build_nako_version.nako3 +42 -0
- package/core/command/snako.mjs +105 -0
- package/core/command/snako.mts +116 -0
- package/core/index.mjs +21 -0
- package/core/index.mts +21 -0
- package/core/package.json +47 -0
- package/core/sample/hello.nako3 +7 -0
- package/core/sample/hoge.mjs +4 -0
- package/core/sample/hoge.mts +6 -0
- package/core/src/nako3.mjs +858 -0
- package/core/src/nako3.mts +967 -0
- package/core/src/nako_colors.mjs +78 -0
- package/core/src/nako_colors.mts +86 -0
- package/core/src/nako_core_version.mjs +8 -0
- package/core/src/nako_core_version.mts +19 -0
- package/core/src/nako_csv.mjs +185 -0
- package/core/src/nako_csv.mts +188 -0
- package/core/src/nako_errors.mjs +173 -0
- package/core/src/nako_errors.mts +197 -0
- package/core/src/nako_from_dncl.mjs +255 -0
- package/core/src/nako_from_dncl.mts +250 -0
- package/core/src/nako_gen.mjs +1648 -0
- package/core/src/nako_gen.mts +1719 -0
- package/core/src/nako_gen_async.mjs +1659 -0
- package/core/src/nako_gen_async.mts +1732 -0
- package/core/src/nako_global.mjs +107 -0
- package/core/src/nako_global.mts +138 -0
- package/core/src/nako_indent.mjs +445 -0
- package/core/src/nako_indent.mts +492 -0
- package/core/src/nako_josi_list.mjs +38 -0
- package/core/src/nako_josi_list.mts +45 -0
- package/core/src/nako_lex_rules.mjs +253 -0
- package/core/src/nako_lex_rules.mts +260 -0
- package/core/src/nako_lexer.mjs +609 -0
- package/core/src/nako_lexer.mts +612 -0
- package/core/src/nako_logger.mjs +199 -0
- package/core/src/nako_logger.mts +232 -0
- package/core/src/nako_parser3.mjs +2439 -0
- package/core/src/nako_parser3.mts +2195 -0
- package/core/src/nako_parser_base.mjs +370 -0
- package/core/src/nako_parser_base.mts +370 -0
- package/core/src/nako_parser_const.mjs +37 -0
- package/core/src/nako_parser_const.mts +37 -0
- package/core/src/nako_prepare.mjs +304 -0
- package/core/src/nako_prepare.mts +315 -0
- package/core/src/nako_reserved_words.mjs +38 -0
- package/core/src/nako_reserved_words.mts +38 -0
- package/core/src/nako_source_mapping.mjs +207 -0
- package/core/src/nako_source_mapping.mts +262 -0
- package/core/src/nako_test.mjs +37 -0
- package/core/src/nako_types.mjs +25 -0
- package/core/src/nako_types.mts +151 -0
- package/core/src/plugin_csv.mjs +49 -0
- package/core/src/plugin_csv.mts +50 -0
- package/core/src/plugin_math.mjs +328 -0
- package/core/src/plugin_math.mts +326 -0
- package/core/src/plugin_promise.mjs +91 -0
- package/core/src/plugin_promise.mts +91 -0
- package/core/src/plugin_system.mjs +2832 -0
- package/core/src/plugin_system.mts +2690 -0
- package/core/src/plugin_test.mjs +34 -0
- package/core/src/plugin_test.mts +34 -0
- package/core/test/array_test.mjs +34 -0
- package/core/test/basic_test.mjs +344 -0
- package/core/test/calc_test.mjs +140 -0
- package/core/test/core_module_test.mjs +23 -0
- package/core/test/debug_test.mjs +16 -0
- package/core/test/dncl_test.mjs +94 -0
- package/core/test/error_message_test.mjs +210 -0
- package/core/test/error_test.mjs +16 -0
- package/core/test/flow_test.mjs +373 -0
- package/core/test/func_call.mjs +160 -0
- package/core/test/func_test.mjs +149 -0
- package/core/test/indent_test.mjs +364 -0
- package/core/test/lex_test.mjs +168 -0
- package/core/test/literal_test.mjs +73 -0
- package/core/test/nako_lexer_test.mjs +35 -0
- package/core/test/nako_logger_test.mjs +76 -0
- package/core/test/nako_logger_test.mts +78 -0
- package/core/test/plugin_csv_test.mjs +38 -0
- package/core/test/plugin_promise_test.mjs +18 -0
- package/core/test/plugin_system_test.mjs +630 -0
- package/core/test/prepare_test.mjs +96 -0
- package/core/test/re_test.mjs +22 -0
- package/core/test/side_effects_test.mjs +92 -0
- package/core/test/variable_scope_test.mjs +149 -0
- package/core/tsconfig.json +101 -0
- package/package.json +4 -2
- package/release/_hash.txt +12 -12
- package/release/_script-tags.txt +14 -14
- package/release/editor.js +1 -1
- package/release/stats.json +1 -1
- package/release/version.js +1 -1
- package/release/wnako3.js +1 -1
- package/src/nako_version.mjs +2 -2
- package/src/nako_version.mts +2 -2
- package/test/async/async_basic_test.mjs +3 -3
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ブラウザとNode.jsでテキストへの色付けを共通化するためのコード
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* ANSI escape code の一部
|
|
6
|
+
*/
|
|
7
|
+
const color = { reset: '\x1b[0m', bold: '\x1b[1m', black: '\x1b[30m', red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m', blue: '\x1b[34m', magenta: '\x1b[35m', cyan: '\x1b[36m', white: '\x1b[37m' };
|
|
8
|
+
// 30 ~ 37
|
|
9
|
+
const colorNames = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'];
|
|
10
|
+
/** @param {string} t */
|
|
11
|
+
const escapeHTML = (t) => t.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''');
|
|
12
|
+
/**
|
|
13
|
+
* ANSI escape code で色付けしたテキストを、HTMLやブラウザのconsole.log用のフォーマットに変換する。
|
|
14
|
+
* たとえば `convertColorTextFormat(`foo${color.red}bar`).html` で `"foobar"` の `"bar"` の部分が赤く表示されるHTMLを取得できる。
|
|
15
|
+
* @param {string} text
|
|
16
|
+
* @returns {{ nodeConsole: string, noColor: string, html: string, browserConsole: string[] }}
|
|
17
|
+
*/
|
|
18
|
+
const convertColorTextFormat = (text) => {
|
|
19
|
+
// textから [ANSI escape code](https://en.wikipedia.org/wiki/ANSI_escape_code) を削除して、色の無いテキストを作る。
|
|
20
|
+
// eslint-disable-next-line no-control-regex
|
|
21
|
+
const noColor = text.replace(/\x1b\[\d+m/g, '');
|
|
22
|
+
// nodeConsoleからbrowserConsoleを作る
|
|
23
|
+
/** @type {string[]} */
|
|
24
|
+
const browserConsoleStyles = [];
|
|
25
|
+
let consoleColor = 'inherit'; // 文字色
|
|
26
|
+
let consoleFontWeight = 'inherit'; // 文字の太さ
|
|
27
|
+
// /\x1b\[(\d+)m/ で正規表現マッチし、それぞれを %c で置換すると同時に browserConsoleStyles にCSSでの表現をpushする。
|
|
28
|
+
// console.log(browserConsoleText, ...browserConsoleStyles) で表示することを想定。
|
|
29
|
+
const browserConsoleText = text === noColor
|
|
30
|
+
? noColor
|
|
31
|
+
// eslint-disable-next-line no-control-regex
|
|
32
|
+
: text.replace(/\x1b\[(\d+)m/g, (_, m1str) => {
|
|
33
|
+
const m1 = +m1str;
|
|
34
|
+
if (m1 === 0) {
|
|
35
|
+
consoleColor = 'inherit';
|
|
36
|
+
consoleFontWeight = 'inherit';
|
|
37
|
+
}
|
|
38
|
+
if (m1 === 1) {
|
|
39
|
+
consoleFontWeight = 'bold';
|
|
40
|
+
}
|
|
41
|
+
if (m1 >= 30 && m1 <= 37) {
|
|
42
|
+
consoleColor = colorNames[m1 - 30];
|
|
43
|
+
}
|
|
44
|
+
browserConsoleStyles.push(`color: ${consoleColor}; font-weight: ${consoleFontWeight};`);
|
|
45
|
+
return '%c';
|
|
46
|
+
});
|
|
47
|
+
// nodeConsoleからhtmlを作る
|
|
48
|
+
let htmlColor = 'inherit'; // 文字色
|
|
49
|
+
let htmlFontWeight = 'inherit'; // 文字の太さ
|
|
50
|
+
// textが色情報を含まないならそれをそのまま使い、含むなら全体を <span>で囲んで、更に、ANSI escape code で囲まれた部分を対応する style を付けた <span> で囲む。
|
|
51
|
+
// eslint-disable-next-line multiline-ternary
|
|
52
|
+
const html = text === noColor ? noColor : ('<span>' + escapeHTML(text)
|
|
53
|
+
// eslint-disable-next-line no-control-regex
|
|
54
|
+
.replace(/\x1b\[(\d+)m/g, (_, m1str) => {
|
|
55
|
+
const m1 = +m1str;
|
|
56
|
+
if (m1 === 0) { // リセット
|
|
57
|
+
htmlColor = 'inherit';
|
|
58
|
+
htmlFontWeight = 'inherit';
|
|
59
|
+
}
|
|
60
|
+
if (m1 === 1) { // 太字化
|
|
61
|
+
htmlFontWeight = 'bold';
|
|
62
|
+
}
|
|
63
|
+
if (m1 >= 30 && m1 <= 37) { // 文字色の変更
|
|
64
|
+
htmlColor = colorNames[m1 - 30];
|
|
65
|
+
}
|
|
66
|
+
return `</span><span style="color: ${htmlColor}; font-weight: ${htmlFontWeight};">`;
|
|
67
|
+
}) + '</span>');
|
|
68
|
+
// 各表現を返す。
|
|
69
|
+
return {
|
|
70
|
+
noColor,
|
|
71
|
+
nodeConsole: text === noColor
|
|
72
|
+
? noColor // textが色の情報を含まないならnoColorを返す。
|
|
73
|
+
: text + '\x1b[0m',
|
|
74
|
+
html,
|
|
75
|
+
browserConsole: [browserConsoleText, ...browserConsoleStyles]
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
export const NakoColors = { convertColorTextFormat, colorNames, color };
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ブラウザとNode.jsでテキストへの色付けを共通化するためのコード
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* ANSI escape code の一部
|
|
7
|
+
*/
|
|
8
|
+
const color = { reset: '\x1b[0m', bold: '\x1b[1m', black: '\x1b[30m', red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m', blue: '\x1b[34m', magenta: '\x1b[35m', cyan: '\x1b[36m', white: '\x1b[37m' }
|
|
9
|
+
|
|
10
|
+
// 30 ~ 37
|
|
11
|
+
const colorNames = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white']
|
|
12
|
+
|
|
13
|
+
/** @param {string} t */
|
|
14
|
+
const escapeHTML = (t: string) => t.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''')
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* ANSI escape code で色付けしたテキストを、HTMLやブラウザのconsole.log用のフォーマットに変換する。
|
|
18
|
+
* たとえば `convertColorTextFormat(`foo${color.red}bar`).html` で `"foobar"` の `"bar"` の部分が赤く表示されるHTMLを取得できる。
|
|
19
|
+
* @param {string} text
|
|
20
|
+
* @returns {{ nodeConsole: string, noColor: string, html: string, browserConsole: string[] }}
|
|
21
|
+
*/
|
|
22
|
+
const convertColorTextFormat = (text: string) => {
|
|
23
|
+
// textから [ANSI escape code](https://en.wikipedia.org/wiki/ANSI_escape_code) を削除して、色の無いテキストを作る。
|
|
24
|
+
// eslint-disable-next-line no-control-regex
|
|
25
|
+
const noColor = text.replace(/\x1b\[\d+m/g, '')
|
|
26
|
+
|
|
27
|
+
// nodeConsoleからbrowserConsoleを作る
|
|
28
|
+
/** @type {string[]} */
|
|
29
|
+
const browserConsoleStyles: string[] = []
|
|
30
|
+
let consoleColor = 'inherit' // 文字色
|
|
31
|
+
let consoleFontWeight = 'inherit' // 文字の太さ
|
|
32
|
+
// /\x1b\[(\d+)m/ で正規表現マッチし、それぞれを %c で置換すると同時に browserConsoleStyles にCSSでの表現をpushする。
|
|
33
|
+
// console.log(browserConsoleText, ...browserConsoleStyles) で表示することを想定。
|
|
34
|
+
const browserConsoleText = text === noColor
|
|
35
|
+
? noColor
|
|
36
|
+
// eslint-disable-next-line no-control-regex
|
|
37
|
+
: text.replace(/\x1b\[(\d+)m/g, (_, m1str) => {
|
|
38
|
+
const m1 = +m1str
|
|
39
|
+
if (m1 === 0) {
|
|
40
|
+
consoleColor = 'inherit'
|
|
41
|
+
consoleFontWeight = 'inherit'
|
|
42
|
+
}
|
|
43
|
+
if (m1 === 1) {
|
|
44
|
+
consoleFontWeight = 'bold'
|
|
45
|
+
}
|
|
46
|
+
if (m1 >= 30 && m1 <= 37) {
|
|
47
|
+
consoleColor = colorNames[m1 - 30]
|
|
48
|
+
}
|
|
49
|
+
browserConsoleStyles.push(`color: ${consoleColor}; font-weight: ${consoleFontWeight};`)
|
|
50
|
+
return '%c'
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
// nodeConsoleからhtmlを作る
|
|
54
|
+
let htmlColor = 'inherit' // 文字色
|
|
55
|
+
let htmlFontWeight = 'inherit' // 文字の太さ
|
|
56
|
+
// textが色情報を含まないならそれをそのまま使い、含むなら全体を <span>で囲んで、更に、ANSI escape code で囲まれた部分を対応する style を付けた <span> で囲む。
|
|
57
|
+
// eslint-disable-next-line multiline-ternary
|
|
58
|
+
const html = text === noColor ? noColor : ('<span>' + escapeHTML(text)
|
|
59
|
+
// eslint-disable-next-line no-control-regex
|
|
60
|
+
.replace(/\x1b\[(\d+)m/g, (_, m1str) => { // ANSI escape code(の一部)にマッチして置換
|
|
61
|
+
const m1 = +m1str
|
|
62
|
+
if (m1 === 0) { // リセット
|
|
63
|
+
htmlColor = 'inherit'
|
|
64
|
+
htmlFontWeight = 'inherit'
|
|
65
|
+
}
|
|
66
|
+
if (m1 === 1) { // 太字化
|
|
67
|
+
htmlFontWeight = 'bold'
|
|
68
|
+
}
|
|
69
|
+
if (m1 >= 30 && m1 <= 37) { // 文字色の変更
|
|
70
|
+
htmlColor = colorNames[m1 - 30]
|
|
71
|
+
}
|
|
72
|
+
return `</span><span style="color: ${htmlColor}; font-weight: ${htmlFontWeight};">`
|
|
73
|
+
}) + '</span>')
|
|
74
|
+
|
|
75
|
+
// 各表現を返す。
|
|
76
|
+
return {
|
|
77
|
+
noColor,
|
|
78
|
+
nodeConsole: text === noColor
|
|
79
|
+
? noColor // textが色の情報を含まないならnoColorを返す。
|
|
80
|
+
: text + '\x1b[0m', // そうでなければtextの末尾に色をリセットするコードを付けて返す。
|
|
81
|
+
html,
|
|
82
|
+
browserConsole: [browserConsoleText, ...browserConsoleStyles]
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export const NakoColors = { convertColorTextFormat, colorNames, color }
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* なでしこのバージョン情報
|
|
3
|
+
* package.json から自動的に作成されます。このファイルを編集しないでください。
|
|
4
|
+
*/
|
|
5
|
+
// 型定義
|
|
6
|
+
export interface NakoCoreVersion {
|
|
7
|
+
version: string;
|
|
8
|
+
major: number;
|
|
9
|
+
minor: number;
|
|
10
|
+
patch: number;
|
|
11
|
+
}
|
|
12
|
+
// 実際のバージョン定義 (自動生成されるので以下を編集しない)
|
|
13
|
+
const coreVersion: NakoCoreVersion = {
|
|
14
|
+
version: '3.3.47',
|
|
15
|
+
major: 3,
|
|
16
|
+
minor: 3,
|
|
17
|
+
patch: 47
|
|
18
|
+
}
|
|
19
|
+
export default coreVersion
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
export const options = {
|
|
2
|
+
delimiter: ',',
|
|
3
|
+
eol: '\r\n'
|
|
4
|
+
};
|
|
5
|
+
export function resetEnv() {
|
|
6
|
+
options.delimiter = ',';
|
|
7
|
+
options.eol = '\r\n';
|
|
8
|
+
}
|
|
9
|
+
export function parse(txt, delimiter = undefined) {
|
|
10
|
+
// delimiter
|
|
11
|
+
if (delimiter === undefined) {
|
|
12
|
+
delimiter = options.delimiter;
|
|
13
|
+
}
|
|
14
|
+
// check txt
|
|
15
|
+
txt = '' + txt + '\n';
|
|
16
|
+
// convert CRLF to LF, and CR to LF
|
|
17
|
+
txt = txt.replace(/(\r\n|\r)/g, '\n');
|
|
18
|
+
// trim right
|
|
19
|
+
txt = txt.replace(/\s+$/, '') + '\n';
|
|
20
|
+
// set pattern
|
|
21
|
+
const patToDelim = '^(.*?)([\\' + delimiter + '\\n])';
|
|
22
|
+
const reToDelim = new RegExp(patToDelim);
|
|
23
|
+
// if value is number then convert to float
|
|
24
|
+
const convType = function (v) {
|
|
25
|
+
if (typeof (v) === 'string') {
|
|
26
|
+
if (v.search(/^[0-9.]+$/) >= 0) {
|
|
27
|
+
v = parseFloat(v); // convert number
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return v;
|
|
31
|
+
};
|
|
32
|
+
// parse txt
|
|
33
|
+
const res = [];
|
|
34
|
+
let cells = [];
|
|
35
|
+
let c = '';
|
|
36
|
+
while (txt !== '') {
|
|
37
|
+
// first check delimiter (because /^\s+/ skip delimiter'\t') (#3)
|
|
38
|
+
c = txt.charAt(0);
|
|
39
|
+
if (c === delimiter) {
|
|
40
|
+
txt = txt.substring(1);
|
|
41
|
+
cells.push('');
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
// second check LF (#7)
|
|
45
|
+
if (c === '\n') {
|
|
46
|
+
cells.push('');
|
|
47
|
+
res.push(cells);
|
|
48
|
+
cells = [];
|
|
49
|
+
txt = txt.substring(1);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
// trim white space
|
|
53
|
+
txt = txt.replace(/^\s+/, '');
|
|
54
|
+
c = txt.charAt(0);
|
|
55
|
+
// no data
|
|
56
|
+
if (c === delimiter) {
|
|
57
|
+
console.log('delimiter');
|
|
58
|
+
cells.push('');
|
|
59
|
+
txt = txt.substring(delimiter.length);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
// written using the dialect of Excel
|
|
63
|
+
if (c === '=' && txt.charAt(1) === '"') {
|
|
64
|
+
txt = txt.substring(1);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
// number or simple string
|
|
68
|
+
if (c !== '"') { // number or simple str
|
|
69
|
+
const m = reToDelim.exec(txt);
|
|
70
|
+
if (!m) {
|
|
71
|
+
cells.push(convType(txt));
|
|
72
|
+
res.push(cells);
|
|
73
|
+
cells = [];
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
if (m[2] === '\n') {
|
|
77
|
+
cells.push(convType(m[1]));
|
|
78
|
+
res.push(cells);
|
|
79
|
+
cells = [];
|
|
80
|
+
}
|
|
81
|
+
else if (m[2] === delimiter) {
|
|
82
|
+
cells.push(convType(m[1]));
|
|
83
|
+
}
|
|
84
|
+
txt = txt.substring(m[0].length);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
// "" ... blank data
|
|
88
|
+
if (txt.substring(0, 2) === '""') {
|
|
89
|
+
cells.push('');
|
|
90
|
+
txt = txt.substring(2);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
// "..."
|
|
94
|
+
let i = 1;
|
|
95
|
+
let s = '';
|
|
96
|
+
while (i < txt.length) {
|
|
97
|
+
const c1 = txt.charAt(i);
|
|
98
|
+
const c2 = txt.charAt(i + 1);
|
|
99
|
+
// console.log("@" + c1 + c2);
|
|
100
|
+
// 2quote => 1quote char
|
|
101
|
+
if (c1 === '"' && c2 === '"') {
|
|
102
|
+
i += 2;
|
|
103
|
+
s += '"';
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (c1 === '"') {
|
|
107
|
+
i++;
|
|
108
|
+
if (c2 === delimiter) {
|
|
109
|
+
i++;
|
|
110
|
+
cells.push(convType(s));
|
|
111
|
+
s = '';
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
if (c2 === '\n') {
|
|
115
|
+
i++;
|
|
116
|
+
cells.push(convType(s));
|
|
117
|
+
res.push(cells);
|
|
118
|
+
cells = [];
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
// if (c2 === " " || c2 === "\t") {
|
|
122
|
+
i++;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
s += c1;
|
|
126
|
+
i++;
|
|
127
|
+
}
|
|
128
|
+
txt = txt.substr(i);
|
|
129
|
+
}
|
|
130
|
+
if (cells.length > 0)
|
|
131
|
+
res.push(cells);
|
|
132
|
+
return res;
|
|
133
|
+
}
|
|
134
|
+
export function stringify(ary, delimiter = undefined, eol = undefined) {
|
|
135
|
+
// check arguments
|
|
136
|
+
if (delimiter === undefined) {
|
|
137
|
+
delimiter = options.delimiter;
|
|
138
|
+
}
|
|
139
|
+
if (eol === undefined) {
|
|
140
|
+
eol = options.eol;
|
|
141
|
+
}
|
|
142
|
+
const valueConv = genValueConverter(delimiter);
|
|
143
|
+
if (ary === undefined)
|
|
144
|
+
return '';
|
|
145
|
+
let r = '';
|
|
146
|
+
for (let i = 0; i < ary.length; i++) {
|
|
147
|
+
const cells = ary[i];
|
|
148
|
+
if (cells === undefined) {
|
|
149
|
+
r += eol;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
for (let j = 0; j < cells.length; j++) {
|
|
153
|
+
cells[j] = valueConv(cells[j]);
|
|
154
|
+
}
|
|
155
|
+
r += cells.join(delimiter) + eol;
|
|
156
|
+
}
|
|
157
|
+
// replace return code
|
|
158
|
+
r = r.replace(/(\r\n|\r|\n)/g, eol);
|
|
159
|
+
return r;
|
|
160
|
+
}
|
|
161
|
+
export function replaceEolMark(eol) {
|
|
162
|
+
eol = eol.replace(/\n\r/g, '[CRLF]');
|
|
163
|
+
eol = eol.replace(/\r/g, '[CR]');
|
|
164
|
+
eol = eol.replace(/\n/g, '[LF]');
|
|
165
|
+
return eol;
|
|
166
|
+
}
|
|
167
|
+
function genValueConverter(delimiter) {
|
|
168
|
+
return function (s) {
|
|
169
|
+
s = '' + s;
|
|
170
|
+
let fQuot = false;
|
|
171
|
+
if (s.indexOf('\n') >= 0 || s.indexOf('\r') >= 0) {
|
|
172
|
+
fQuot = true;
|
|
173
|
+
}
|
|
174
|
+
if (s.indexOf(delimiter) >= 0) {
|
|
175
|
+
fQuot = true;
|
|
176
|
+
}
|
|
177
|
+
if (s.indexOf('"') >= 0) {
|
|
178
|
+
fQuot = true;
|
|
179
|
+
s = s.replace(/"/g, '""');
|
|
180
|
+
}
|
|
181
|
+
if (fQuot)
|
|
182
|
+
s = '"' + s + '"';
|
|
183
|
+
return s;
|
|
184
|
+
};
|
|
185
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// csv-lite.js --- for Browser
|
|
2
|
+
export interface CSVOptions {
|
|
3
|
+
delimiter: string;
|
|
4
|
+
eol: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const options: CSVOptions = {
|
|
8
|
+
delimiter: ',',
|
|
9
|
+
eol: '\r\n'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function resetEnv (): void {
|
|
13
|
+
options.delimiter = ','
|
|
14
|
+
options.eol = '\r\n'
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function parse (txt: string, delimiter: string|undefined = undefined): string[][] {
|
|
18
|
+
// delimiter
|
|
19
|
+
if (delimiter === undefined) {
|
|
20
|
+
delimiter = options.delimiter
|
|
21
|
+
}
|
|
22
|
+
// check txt
|
|
23
|
+
txt = '' + txt + '\n'
|
|
24
|
+
// convert CRLF to LF, and CR to LF
|
|
25
|
+
txt = txt.replace(/(\r\n|\r)/g, '\n')
|
|
26
|
+
// trim right
|
|
27
|
+
txt = txt.replace(/\s+$/, '') + '\n'
|
|
28
|
+
// set pattern
|
|
29
|
+
const patToDelim = '^(.*?)([\\' + delimiter + '\\n])'
|
|
30
|
+
const reToDelim = new RegExp(patToDelim)
|
|
31
|
+
// if value is number then convert to float
|
|
32
|
+
const convType = function (v: any) {
|
|
33
|
+
if (typeof (v) === 'string') {
|
|
34
|
+
if (v.search(/^[0-9.]+$/) >= 0) {
|
|
35
|
+
v = parseFloat(v) // convert number
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return v
|
|
39
|
+
}
|
|
40
|
+
// parse txt
|
|
41
|
+
const res = []; let cells = []; let c = ''
|
|
42
|
+
while (txt !== '') {
|
|
43
|
+
// first check delimiter (because /^\s+/ skip delimiter'\t') (#3)
|
|
44
|
+
c = txt.charAt(0)
|
|
45
|
+
if (c === delimiter) {
|
|
46
|
+
txt = txt.substring(1)
|
|
47
|
+
cells.push('')
|
|
48
|
+
continue
|
|
49
|
+
}
|
|
50
|
+
// second check LF (#7)
|
|
51
|
+
if (c === '\n') {
|
|
52
|
+
cells.push('')
|
|
53
|
+
res.push(cells)
|
|
54
|
+
cells = []
|
|
55
|
+
txt = txt.substring(1)
|
|
56
|
+
continue
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// trim white space
|
|
60
|
+
txt = txt.replace(/^\s+/, '')
|
|
61
|
+
c = txt.charAt(0)
|
|
62
|
+
|
|
63
|
+
// no data
|
|
64
|
+
if (c === delimiter) {
|
|
65
|
+
console.log('delimiter')
|
|
66
|
+
cells.push('')
|
|
67
|
+
txt = txt.substring(delimiter.length)
|
|
68
|
+
continue
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// written using the dialect of Excel
|
|
72
|
+
if (c === '=' && txt.charAt(1) === '"') {
|
|
73
|
+
txt = txt.substring(1)
|
|
74
|
+
continue
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// number or simple string
|
|
78
|
+
if (c !== '"') { // number or simple str
|
|
79
|
+
const m = reToDelim.exec(txt)
|
|
80
|
+
if (!m) {
|
|
81
|
+
cells.push(convType(txt))
|
|
82
|
+
res.push(cells)
|
|
83
|
+
cells = []
|
|
84
|
+
break
|
|
85
|
+
}
|
|
86
|
+
if (m[2] === '\n') {
|
|
87
|
+
cells.push(convType(m[1]))
|
|
88
|
+
res.push(cells)
|
|
89
|
+
cells = []
|
|
90
|
+
} else if (m[2] === delimiter) {
|
|
91
|
+
cells.push(convType(m[1]))
|
|
92
|
+
}
|
|
93
|
+
txt = txt.substring(m[0].length)
|
|
94
|
+
continue
|
|
95
|
+
}
|
|
96
|
+
// "" ... blank data
|
|
97
|
+
if (txt.substring(0, 2) === '""') {
|
|
98
|
+
cells.push('')
|
|
99
|
+
txt = txt.substring(2)
|
|
100
|
+
continue
|
|
101
|
+
}
|
|
102
|
+
// "..."
|
|
103
|
+
let i = 1; let s = ''
|
|
104
|
+
while (i < txt.length) {
|
|
105
|
+
const c1 = txt.charAt(i)
|
|
106
|
+
const c2 = txt.charAt(i + 1)
|
|
107
|
+
// console.log("@" + c1 + c2);
|
|
108
|
+
// 2quote => 1quote char
|
|
109
|
+
if (c1 === '"' && c2 === '"') {
|
|
110
|
+
i += 2
|
|
111
|
+
s += '"'
|
|
112
|
+
continue
|
|
113
|
+
}
|
|
114
|
+
if (c1 === '"') {
|
|
115
|
+
i++
|
|
116
|
+
if (c2 === delimiter) {
|
|
117
|
+
i++
|
|
118
|
+
cells.push(convType(s))
|
|
119
|
+
s = ''
|
|
120
|
+
break
|
|
121
|
+
}
|
|
122
|
+
if (c2 === '\n') {
|
|
123
|
+
i++
|
|
124
|
+
cells.push(convType(s))
|
|
125
|
+
res.push(cells)
|
|
126
|
+
cells = []
|
|
127
|
+
break
|
|
128
|
+
}
|
|
129
|
+
// if (c2 === " " || c2 === "\t") {
|
|
130
|
+
i++
|
|
131
|
+
continue
|
|
132
|
+
}
|
|
133
|
+
s += c1
|
|
134
|
+
i++
|
|
135
|
+
}
|
|
136
|
+
txt = txt.substr(i)
|
|
137
|
+
}
|
|
138
|
+
if (cells.length > 0) res.push(cells)
|
|
139
|
+
return res
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function stringify (ary: string[][], delimiter: string|undefined = undefined, eol: string|undefined = undefined): string {
|
|
143
|
+
// check arguments
|
|
144
|
+
if (delimiter === undefined) {
|
|
145
|
+
delimiter = options.delimiter
|
|
146
|
+
}
|
|
147
|
+
if (eol === undefined) {
|
|
148
|
+
eol = options.eol
|
|
149
|
+
}
|
|
150
|
+
const valueConv = genValueConverter(delimiter)
|
|
151
|
+
if (ary === undefined) return ''
|
|
152
|
+
let r = ''
|
|
153
|
+
for (let i = 0; i < ary.length; i++) {
|
|
154
|
+
const cells = ary[i]
|
|
155
|
+
if (cells === undefined) {
|
|
156
|
+
r += eol; continue
|
|
157
|
+
}
|
|
158
|
+
for (let j = 0; j < cells.length; j++) {
|
|
159
|
+
cells[j] = valueConv(cells[j])
|
|
160
|
+
}
|
|
161
|
+
r += cells.join(delimiter) + eol
|
|
162
|
+
}
|
|
163
|
+
// replace return code
|
|
164
|
+
r = r.replace(/(\r\n|\r|\n)/g, eol)
|
|
165
|
+
return r
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function replaceEolMark (eol: string): string {
|
|
169
|
+
eol = eol.replace(/\n\r/g, '[CRLF]')
|
|
170
|
+
eol = eol.replace(/\r/g, '[CR]')
|
|
171
|
+
eol = eol.replace(/\n/g, '[LF]')
|
|
172
|
+
return eol
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function genValueConverter (delimiter: string) {
|
|
176
|
+
return function (s: string) {
|
|
177
|
+
s = '' + s
|
|
178
|
+
let fQuot = false
|
|
179
|
+
if (s.indexOf('\n') >= 0 || s.indexOf('\r') >= 0) { fQuot = true }
|
|
180
|
+
if (s.indexOf(delimiter) >= 0) { fQuot = true }
|
|
181
|
+
if (s.indexOf('"') >= 0) {
|
|
182
|
+
fQuot = true
|
|
183
|
+
s = s.replace(/"/g, '""')
|
|
184
|
+
}
|
|
185
|
+
if (fQuot) s = '"' + s + '"'
|
|
186
|
+
return s
|
|
187
|
+
}
|
|
188
|
+
}
|