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.
Files changed (105) hide show
  1. package/core/.editorconfig +6 -0
  2. package/core/.eslintrc.cjs +33 -0
  3. package/core/.github/dependabot.yml +7 -0
  4. package/core/.github/workflows/nodejs.yml +37 -0
  5. package/core/.github/workflows/super-linter.yml +61 -0
  6. package/core/.github/workflows/textlint.yml +199 -0
  7. package/core/LICENSE +21 -0
  8. package/core/README.md +66 -0
  9. package/core/batch/build_nako_version.nako3 +42 -0
  10. package/core/command/snako.mjs +105 -0
  11. package/core/command/snako.mts +116 -0
  12. package/core/index.mjs +21 -0
  13. package/core/index.mts +21 -0
  14. package/core/package.json +47 -0
  15. package/core/sample/hello.nako3 +7 -0
  16. package/core/sample/hoge.mjs +4 -0
  17. package/core/sample/hoge.mts +6 -0
  18. package/core/src/nako3.mjs +858 -0
  19. package/core/src/nako3.mts +967 -0
  20. package/core/src/nako_colors.mjs +78 -0
  21. package/core/src/nako_colors.mts +86 -0
  22. package/core/src/nako_core_version.mjs +8 -0
  23. package/core/src/nako_core_version.mts +19 -0
  24. package/core/src/nako_csv.mjs +185 -0
  25. package/core/src/nako_csv.mts +188 -0
  26. package/core/src/nako_errors.mjs +173 -0
  27. package/core/src/nako_errors.mts +197 -0
  28. package/core/src/nako_from_dncl.mjs +255 -0
  29. package/core/src/nako_from_dncl.mts +250 -0
  30. package/core/src/nako_gen.mjs +1648 -0
  31. package/core/src/nako_gen.mts +1719 -0
  32. package/core/src/nako_gen_async.mjs +1659 -0
  33. package/core/src/nako_gen_async.mts +1732 -0
  34. package/core/src/nako_global.mjs +107 -0
  35. package/core/src/nako_global.mts +138 -0
  36. package/core/src/nako_indent.mjs +445 -0
  37. package/core/src/nako_indent.mts +492 -0
  38. package/core/src/nako_josi_list.mjs +38 -0
  39. package/core/src/nako_josi_list.mts +45 -0
  40. package/core/src/nako_lex_rules.mjs +253 -0
  41. package/core/src/nako_lex_rules.mts +260 -0
  42. package/core/src/nako_lexer.mjs +609 -0
  43. package/core/src/nako_lexer.mts +612 -0
  44. package/core/src/nako_logger.mjs +199 -0
  45. package/core/src/nako_logger.mts +232 -0
  46. package/core/src/nako_parser3.mjs +2439 -0
  47. package/core/src/nako_parser3.mts +2195 -0
  48. package/core/src/nako_parser_base.mjs +370 -0
  49. package/core/src/nako_parser_base.mts +370 -0
  50. package/core/src/nako_parser_const.mjs +37 -0
  51. package/core/src/nako_parser_const.mts +37 -0
  52. package/core/src/nako_prepare.mjs +304 -0
  53. package/core/src/nako_prepare.mts +315 -0
  54. package/core/src/nako_reserved_words.mjs +38 -0
  55. package/core/src/nako_reserved_words.mts +38 -0
  56. package/core/src/nako_source_mapping.mjs +207 -0
  57. package/core/src/nako_source_mapping.mts +262 -0
  58. package/core/src/nako_test.mjs +37 -0
  59. package/core/src/nako_types.mjs +25 -0
  60. package/core/src/nako_types.mts +151 -0
  61. package/core/src/plugin_csv.mjs +49 -0
  62. package/core/src/plugin_csv.mts +50 -0
  63. package/core/src/plugin_math.mjs +328 -0
  64. package/core/src/plugin_math.mts +326 -0
  65. package/core/src/plugin_promise.mjs +91 -0
  66. package/core/src/plugin_promise.mts +91 -0
  67. package/core/src/plugin_system.mjs +2832 -0
  68. package/core/src/plugin_system.mts +2690 -0
  69. package/core/src/plugin_test.mjs +34 -0
  70. package/core/src/plugin_test.mts +34 -0
  71. package/core/test/array_test.mjs +34 -0
  72. package/core/test/basic_test.mjs +344 -0
  73. package/core/test/calc_test.mjs +140 -0
  74. package/core/test/core_module_test.mjs +23 -0
  75. package/core/test/debug_test.mjs +16 -0
  76. package/core/test/dncl_test.mjs +94 -0
  77. package/core/test/error_message_test.mjs +210 -0
  78. package/core/test/error_test.mjs +16 -0
  79. package/core/test/flow_test.mjs +373 -0
  80. package/core/test/func_call.mjs +160 -0
  81. package/core/test/func_test.mjs +149 -0
  82. package/core/test/indent_test.mjs +364 -0
  83. package/core/test/lex_test.mjs +168 -0
  84. package/core/test/literal_test.mjs +73 -0
  85. package/core/test/nako_lexer_test.mjs +35 -0
  86. package/core/test/nako_logger_test.mjs +76 -0
  87. package/core/test/nako_logger_test.mts +78 -0
  88. package/core/test/plugin_csv_test.mjs +38 -0
  89. package/core/test/plugin_promise_test.mjs +18 -0
  90. package/core/test/plugin_system_test.mjs +630 -0
  91. package/core/test/prepare_test.mjs +96 -0
  92. package/core/test/re_test.mjs +22 -0
  93. package/core/test/side_effects_test.mjs +92 -0
  94. package/core/test/variable_scope_test.mjs +149 -0
  95. package/core/tsconfig.json +101 -0
  96. package/package.json +4 -2
  97. package/release/_hash.txt +12 -12
  98. package/release/_script-tags.txt +14 -14
  99. package/release/editor.js +1 -1
  100. package/release/stats.json +1 -1
  101. package/release/version.js +1 -1
  102. package/release/wnako3.js +1 -1
  103. package/src/nako_version.mjs +2 -2
  104. package/src/nako_version.mts +2 -2
  105. 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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;');
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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;')
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,8 @@
1
+ // 実際のバージョン定義 (自動生成されるので以下を編集しない)
2
+ const coreVersion = {
3
+ version: '3.3.47',
4
+ major: 3,
5
+ minor: 3,
6
+ patch: 47
7
+ };
8
+ export default coreVersion;
@@ -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
+ }