nadesiko3 3.4.13 → 3.4.14

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 (51) hide show
  1. package/batch/command.txt +292 -292
  2. package/core/package.json +1 -1
  3. package/core/src/nako_core_version.mjs +2 -2
  4. package/core/src/nako_core_version.mts +2 -2
  5. package/core/src/nako_from_dncl2.mjs +34 -2
  6. package/core/src/nako_from_dncl2.mts +31 -2
  7. package/core/src/nako_gen.mjs +110 -76
  8. package/core/src/nako_gen.mts +114 -75
  9. package/core/src/plugin_system.mjs +13 -3
  10. package/core/src/plugin_system.mts +11 -3
  11. package/core/test/dncl2_test.mjs +161 -152
  12. package/package.json +4 -33
  13. package/release/_hash.txt +20 -20
  14. package/release/_script-tags.txt +14 -14
  15. package/release/nako_gen_async.js +1 -1
  16. package/release/nako_gen_async.js.map +1 -1
  17. package/release/plugin_datetime.js +1 -1
  18. package/release/plugin_datetime.js.map +1 -1
  19. package/release/stats.json +1 -1
  20. package/release/version.js +1 -1
  21. package/release/version.js.map +1 -1
  22. package/release/wnako3.js +1 -1
  23. package/release/wnako3.js.map +1 -1
  24. package/release/wnako3webworker.js +1 -1
  25. package/release/wnako3webworker.js.map +1 -1
  26. package/src/nako_version.mjs +2 -2
  27. package/src/nako_version.mts +2 -2
  28. package/src/plugin_browser.mjs +1 -1
  29. package/src/plugin_browser.mts +1 -1
  30. package/src/plugin_browser_ajax.mjs +6 -6
  31. package/src/plugin_browser_ajax.mts +8 -8
  32. package/src/plugin_browser_canvas.mjs +2 -2
  33. package/src/plugin_browser_canvas.mts +2 -2
  34. package/src/plugin_browser_chart.mjs +17 -13
  35. package/src/plugin_browser_chart.mts +25 -21
  36. package/src/plugin_browser_crypto.mjs +1 -1
  37. package/src/plugin_browser_crypto.mts +2 -2
  38. package/src/plugin_browser_dom_basic.mjs +5 -5
  39. package/src/plugin_browser_dom_basic.mts +5 -5
  40. package/src/plugin_browser_dom_event.mjs +17 -17
  41. package/src/plugin_browser_dom_event.mts +17 -17
  42. package/src/plugin_browser_dom_parts.mjs +21 -21
  43. package/src/plugin_browser_dom_parts.mts +21 -21
  44. package/src/plugin_browser_geolocation.mjs +2 -2
  45. package/src/plugin_browser_geolocation.mts +2 -2
  46. package/src/plugin_browser_storage.mjs +3 -3
  47. package/src/plugin_browser_storage.mts +3 -3
  48. package/src/plugin_datetime.mjs +9 -9
  49. package/src/plugin_node.mjs +3 -3
  50. package/src/plugin_node.mts +3 -3
  51. package/test/node/plugin_node_test.mjs +181 -180
@@ -4,7 +4,7 @@ export default {
4
4
  '位置情報取得時': {
5
5
  type: 'func',
6
6
  josi: [['の', 'に', 'へ']],
7
- pure: false,
7
+ pure: true,
8
8
  fn: function (func, sys) {
9
9
  let cb = func;
10
10
  if (typeof cb === 'string') {
@@ -26,7 +26,7 @@ export default {
26
26
  '位置情報監視時': {
27
27
  type: 'func',
28
28
  josi: [['の', 'に', 'へ']],
29
- pure: false,
29
+ pure: true,
30
30
  fn: function (func, sys) {
31
31
  let cb = func;
32
32
  if (typeof cb === 'string') {
@@ -4,7 +4,7 @@ export default {
4
4
  '位置情報取得時': { // @位置情報を取得してコールバック関数内で変数「対象」に配列で[緯度,経度]を返す // @いちじょうほうしゅとくしたとき
5
5
  type: 'func',
6
6
  josi: [['の', 'に', 'へ']],
7
- pure: false,
7
+ pure: true,
8
8
  fn: function (func: any, sys: any) {
9
9
  let cb = func
10
10
  if (typeof cb === 'string') { cb = sys.__findVar(cb) }
@@ -23,7 +23,7 @@ export default {
23
23
  '位置情報監視時': { // @位置情報を監視してIDを返す。引数に指定したコールバック関数内で変数「対象」に配列で[緯度,経度]を返す // @いちじょうほうかんししたとき
24
24
  type: 'func',
25
25
  josi: [['の', 'に', 'へ']],
26
- pure: false,
26
+ pure: true,
27
27
  fn: function (func: any, sys: any) {
28
28
  let cb = func
29
29
  if (typeof cb === 'string') { cb = sys.__findVar(cb) }
@@ -4,7 +4,7 @@ export default {
4
4
  '保存': {
5
5
  type: 'func',
6
6
  josi: [['を'], ['に', 'へ']],
7
- pure: false,
7
+ pure: true,
8
8
  fn: function (v, key, sys) {
9
9
  sys.__exec('ローカルストレージ保存', [v, key, sys]);
10
10
  },
@@ -13,7 +13,7 @@ export default {
13
13
  '開': {
14
14
  type: 'func',
15
15
  josi: [['を', 'から', 'の']],
16
- pure: false,
16
+ pure: true,
17
17
  fn: function (key, sys) {
18
18
  return sys.__exec('ローカルストレージ読', [key, sys]);
19
19
  },
@@ -22,7 +22,7 @@ export default {
22
22
  '読': {
23
23
  type: 'func',
24
24
  josi: [['を', 'から', 'の']],
25
- pure: false,
25
+ pure: true,
26
26
  fn: function (key, sys) {
27
27
  return sys.__exec('ローカルストレージ読', [key, sys]);
28
28
  },
@@ -4,7 +4,7 @@ export default {
4
4
  '保存': { // @ブラウザのlocalStorageのキーKに文字列Vを保存 // @ほぞん
5
5
  type: 'func',
6
6
  josi: [['を'], ['に', 'へ']],
7
- pure: false,
7
+ pure: true,
8
8
  fn: function (v: any, key: any, sys: any) {
9
9
  sys.__exec('ローカルストレージ保存', [v, key, sys])
10
10
  },
@@ -13,7 +13,7 @@ export default {
13
13
  '開': { // @ブラウザのlocalStorageからVを読む // @ひらく
14
14
  type: 'func',
15
15
  josi: [['を', 'から', 'の']],
16
- pure: false,
16
+ pure: true,
17
17
  fn: function (key: any, sys: any) {
18
18
  return sys.__exec('ローカルストレージ読', [key, sys])
19
19
  },
@@ -22,7 +22,7 @@ export default {
22
22
  '読': { // @ブラウザのlocalStorageからVを読む // @よむ
23
23
  type: 'func',
24
24
  josi: [['を', 'から', 'の']],
25
- pure: false,
25
+ pure: true,
26
26
  fn: function (key: any, sys: any) {
27
27
  return sys.__exec('ローカルストレージ読', [key, sys])
28
28
  },
@@ -126,7 +126,7 @@ const PluginDateTime = {
126
126
  'UNIX時間変換': { // @日時SをUNIX時間 (UTC(1970/1/1)からの経過秒数) に変換して返す(v1非互換) // @UNIXじかんへんかん
127
127
  type: 'func',
128
128
  josi: [['の', 'を', 'から']],
129
- pure: false,
129
+ pure: true,
130
130
  fn: function (s, sys) {
131
131
  return sys.__exec('UNIXTIME変換', [s])
132
132
  }
@@ -173,7 +173,7 @@ const PluginDateTime = {
173
173
  '年数差': { // @日付AとBの差を年数で求めて返す。A<Bなら正の数、そうでないなら負の数を返す (v1非互換)。 // @ねんすうさ
174
174
  type: 'func',
175
175
  josi: [['と', 'から'], ['の', 'までの']],
176
- pure: false,
176
+ pure: true,
177
177
  fn: function (a, b, sys) {
178
178
  return sys.__exec('日時差', [a, b, '年'])
179
179
  }
@@ -181,7 +181,7 @@ const PluginDateTime = {
181
181
  '月数差': { // @日付AとBの差を月数で求めて返す。A<Bなら正の数、そうでないなら負の数を返す (v1非互換)。 // @げっすうさ
182
182
  type: 'func',
183
183
  josi: [['と', 'から'], ['の', 'までの']],
184
- pure: false,
184
+ pure: true,
185
185
  fn: function (a, b, sys) {
186
186
  return sys.__exec('日時差', [a, b, '月'])
187
187
  }
@@ -189,7 +189,7 @@ const PluginDateTime = {
189
189
  '日数差': { // @日付AとBの差を日数で求めて返す。A<Bなら正の数、そうでないなら負の数を返す。 // @にっすうさ
190
190
  type: 'func',
191
191
  josi: [['と', 'から'], ['の', 'までの']],
192
- pure: false,
192
+ pure: true,
193
193
  fn: function (a, b, sys) {
194
194
  return sys.__exec('日時差', [a, b, '日'])
195
195
  }
@@ -252,7 +252,7 @@ const PluginDateTime = {
252
252
  '時間差': { // @時間AとBの時間の差を求めて返す。A<Bなら正の数、そうでないなら負の数を返す。 // @じかんさ
253
253
  type: 'func',
254
254
  josi: [['と', 'から'], ['の', 'までの']],
255
- pure: false,
255
+ pure: true,
256
256
  fn: function (a, b, sys) {
257
257
  return sys.__exec('日時差', [a, b, '時間'])
258
258
  }
@@ -260,7 +260,7 @@ const PluginDateTime = {
260
260
  '分差': { // @時間AとBの分数の差を求めて返す。A<Bなら正の数、そうでないなら負の数を返す。 // @ふんさ
261
261
  type: 'func',
262
262
  josi: [['と', 'から'], ['の', 'までの']],
263
- pure: false,
263
+ pure: true,
264
264
  fn: function (a, b, sys) {
265
265
  return sys.__exec('日時差', [a, b, '分'])
266
266
  }
@@ -268,7 +268,7 @@ const PluginDateTime = {
268
268
  '秒差': { // @時間AとBの差を秒差で求めて返す。A<Bなら正の数、そうでないなら負の数を返す。 // @びょうさ
269
269
  type: 'func',
270
270
  josi: [['と', 'から'], ['の', 'までの']],
271
- pure: false,
271
+ pure: true,
272
272
  fn: function (a, b, sys) {
273
273
  return sys.__exec('日時差', [a, b, '秒'])
274
274
  }
@@ -276,7 +276,7 @@ const PluginDateTime = {
276
276
  '時間加算': { // @時間SにAを加えて返す。Aには「(+|-)hh:nn:dd」で指定する。 // @じかんかさん
277
277
  type: 'func',
278
278
  josi: [['に'], ['を']],
279
- pure: false,
279
+ pure: true,
280
280
  fn: function (s, a, sys) {
281
281
  const pm = a.slice(0, 1)
282
282
 
@@ -297,7 +297,7 @@ const PluginDateTime = {
297
297
  '日付加算': { // @日付SにAを加えて返す。Aには「(+|-)yyyy/mm/dd」で指定する。 // @ひづけかさん
298
298
  type: 'func',
299
299
  josi: [['に'], ['を']],
300
- pure: false,
300
+ pure: true,
301
301
  fn: function (s, a, sys) {
302
302
  const pm = a.slice(0, 1)
303
303
 
@@ -82,7 +82,7 @@ export default {
82
82
  '読': {
83
83
  type: 'func',
84
84
  josi: [['を', 'から']],
85
- pure: false,
85
+ pure: true,
86
86
  fn: function (s, sys) {
87
87
  return sys.__exec('開', [s]);
88
88
  }
@@ -638,7 +638,7 @@ export default {
638
638
  '終了': {
639
639
  type: 'func',
640
640
  josi: [],
641
- pure: false,
641
+ pure: true,
642
642
  fn: function (sys) {
643
643
  sys.__exec('終', []);
644
644
  },
@@ -795,7 +795,7 @@ export default {
795
795
  'GET送信時': {
796
796
  type: 'func',
797
797
  josi: [['の'], ['まで', 'へ', 'に']],
798
- pure: false,
798
+ pure: true,
799
799
  fn: function (callback, url, sys) {
800
800
  sys.__exec('AJAX送信時', [callback, url, sys]);
801
801
  },
@@ -76,7 +76,7 @@ export default {
76
76
  '読': { // @ファイルSを開く // @よむ
77
77
  type: 'func',
78
78
  josi: [['を', 'から']],
79
- pure: false,
79
+ pure: true,
80
80
  fn: function (s: string, sys: any) {
81
81
  return sys.__exec('開', [s])
82
82
  }
@@ -587,7 +587,7 @@ export default {
587
587
  '終了': { // @Nodeでプログラム実行を強制終了する // @しゅうりょう
588
588
  type: 'func',
589
589
  josi: [],
590
- pure: false,
590
+ pure: true,
591
591
  fn: function (sys: any) {
592
592
  sys.__exec('終', [])
593
593
  },
@@ -730,7 +730,7 @@ export default {
730
730
  'GET送信時': { // @非同期通信(Ajax)でURLにデータを送信し、成功するとcallbackが実行される。その際『対象』にデータが代入される。 // @GETそうしんしたとき
731
731
  type: 'func',
732
732
  josi: [['の'], ['まで', 'へ', 'に']],
733
- pure: false,
733
+ pure: true,
734
734
  fn: function (callback: any, url: string, sys: any) {
735
735
  sys.__exec('AJAX送信時', [callback, url, sys])
736
736
  },
@@ -1,180 +1,181 @@
1
- /* eslint-disable no-undef */
2
- // import fs from 'fs'
3
- import os from 'os'
4
- import fs from 'fs'
5
- import assert from 'assert'
6
- import path from 'path'
7
- import { execSync } from 'child_process'
8
-
9
- import { NakoCompiler } from '../../core/src/nako3.mjs'
10
- import PluginNode from '../../src/plugin_node.mjs'
11
- import PluginCSV from '../../core/src/plugin_csv.mjs'
12
-
13
- // __dirname のために
14
- import url from 'url'
15
- // @ts-ignore
16
- const __filename = url.fileURLToPath(import.meta.url)
17
- const __dirname = path.dirname(__filename)
18
- const testFileMe = path.join(__dirname, 'plugin_node_test.mjs')
19
-
20
- describe('plugin_node_test', async () => {
21
- const cmp = async (/** @type {string} */ code, /** @type {string | undefined} */ res) => {
22
- const nako = new NakoCompiler()
23
- nako.addPluginFile('PluginNode', 'plugin_node.js', PluginNode)
24
- nako.addPluginFile('PluginCSV', 'plugin_csv.js', PluginCSV)
25
- const g = await nako.runAsync(code, 'main')
26
- assert.strictEqual(g.log, res)
27
- }
28
- const cmd = async (/** @type {string} */ code) => {
29
- const nako = new NakoCompiler()
30
- nako.addPluginFile('PluginNode', 'plugin_node.js', PluginNode)
31
- nako.addPluginFile('PluginCSV', 'plugin_csv.js', PluginCSV)
32
- await nako.runAsync(code, 'main')
33
- }
34
- // --- test ---
35
- it('表示', async () => {
36
- await cmp('3を表示', '3')
37
- await cmp('1+2*3を表示', '7')
38
- await cmp('A=30;「--{A}--」を表示', '--30--')
39
- })
40
- it('存在1', async () => {
41
- await cmp('「/xxx/xxx/xxx/xxx」が存在;もしそうならば;「NG」と表示。違えば「OK」と表示。', 'OK')
42
- })
43
- it('存在2', async () => {
44
- await cmp('「' + testFileMe + '」が存在;もしそうならば;「OK」と表示。違えば「NG」と表示。', 'OK')
45
- })
46
- it('フォルダ存在', async () => {
47
- const dir = __dirname
48
- await cmp('「' + dir + '」が存在;もしそうならば;「OK」と表示。違えば「NG」と表示。', 'OK')
49
- await cmp('「' + dir + '/xxx」が存在;もしそうならば;「OK」と表示。違えば「NG」と表示。', 'NG')
50
- })
51
- it('ASSERT', async () => {
52
- cmd('3と3がASSERT等')
53
- })
54
- it('環境変数取得', async () => {
55
- const path = process.env.PATH
56
- await cmp('「PATH」の環境変数取得して表示。', path)
57
- })
58
- it('ファイルサイズ取得', async () => {
59
- await cmp('「' + testFileMe + '」のファイルサイズ取得;もし、それが2000以上ならば;「OK」と表示。違えば「NG」と表示。', 'OK')
60
- })
61
- it('ファイル情報取得', async () => {
62
- await cmp('「' + testFileMe + '」のファイル情報取得;もし、それ["size"]が2000以上ならば;「OK」と表示。違えば「NG」と表示。', 'OK')
63
- })
64
- it('クリップボード', async () => {
65
- try {
66
- const rnd = 'a' + Math.random()
67
- await cmp('クリップボード="' + rnd + '";クリップボードを表示。', rnd)
68
- } catch (err) {
69
- // テストは必須ではない(Linuxコンソール環境に配慮)
70
- }
71
- })
72
- it('文字エンコーディング', async () => {
73
- const sjisfile = path.join(__dirname, 'sjis.txt')
74
- await cmp(`「${sjisfile}」をバイナリ読む。` +
75
- 'SJIS取得。CSV取得してCに代入。C[2][1]を表示',
76
- 'ホームセンター')
77
- await cmp(`「${sjisfile}」をバイナリ読む。` +
78
- '「Shift_JIS」からエンコーディング取得。' +
79
- 'CSV取得してCに代入。C[2][1]を表示',
80
- 'ホームセンター')
81
- })
82
- it('ハッシュ値計算', async () => {
83
- await cmp('「hello world」を「sha256」の「base64」でハッシュ値計算して表示。', 'uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek=')
84
- await cmp('「hello world」を「sha256」の「hex」でハッシュ値計算して表示。', 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9')
85
- await cmp('「some data to hash」を「sha256」の「hex」でハッシュ値計算して表示。', '6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50')
86
- })
87
- it('テンポラリフォルダ', async () => {
88
- await cmp('F=「{テンポラリフォルダ}/test.txt」;「abc」をFに保存。Fを読んでトリムして表示。', 'abc')
89
- })
90
- it('圧縮解凍', async () => {
91
- let path7z = '7z'
92
- if (process.platform === 'win32') {
93
- path7z = path.join(__dirname, '../../bin/7z.exe')
94
- }
95
- let tmp = '/tmp'
96
- if (process.platform === 'linux') {
97
- tmp = path.join(os.tmpdir(), 'nadesiko3test')
98
- } else {
99
- tmp = fs.mkdtempSync(os.tmpdir())
100
- }
101
- const code = 'FIN=「' + testFileMe + '」;' +
102
- `TMP=「${tmp}」へ一時フォルダ作成。` +
103
- '『' + path7z + '』に圧縮解凍ツールパス変更;' +
104
- 'もし、TMPが存在しないならば、TMPのフォルダ作成。' +
105
- 'FZIP=「{TMP}/test.zip」;\n' +
106
- 'FINをFZIPへ圧縮。FZIPを「{TMP}/」に解凍。\n' +
107
- 'S1=「{TMP}/plugin_node_test.mjs」を読む。\n' +
108
- 'S2=FINを読む。\n' +
109
- 'もし(S1=S2)ならば、"OK"と表示。\n'
110
- await cmp(code, 'OK')
111
- })
112
- it('圧縮/解凍', async function () {
113
- if (process.platform === 'win32') { return this.skip() }
114
- try { execSync('which 7z').toString() } catch (e) { return this.skip() }
115
- let tmp = '/tmp'
116
- if (process.platform === 'linux') {
117
- tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'nadesiko3zip-test'))
118
- } else {
119
- tmp = fs.mkdtempSync(os.tmpdir())
120
- }
121
- const pathSrc = `TMP="${tmp}";FILE=「{TMP}/test.txt」;ZIP=「{TMP}/test.zip」;`
122
- await cmp(`${pathSrc}FILEへ「abc」を保存。FILEをZIPに圧縮。ZIPが存在。もし,そうならば「ok」と表示。`, 'ok')
123
- await cmp(`${pathSrc}FILEをファイル削除。ZIPをTMPに解凍。FILEを読む。トリム。それを表示。`, 'abc')
124
- })
125
- it('圧縮/解凍 - OSコマンドインジェクション対策がなされているか #1325', async function () {
126
- // 7z がない環境ではテストを飛ばす
127
- if (process.platform === 'win32') {
128
- return this.skip()
129
- } else {
130
- try { execSync('which 7z').toString() } catch (e) { return this.skip() }
131
- }
132
- let tmp = '/tmp'
133
- if (process.platform === 'linux') {
134
- tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'test_nako3zip'))
135
- } else {
136
- tmp = fs.mkdtempSync(os.tmpdir())
137
- }
138
- // (1) 元ファイルへのインジェクション
139
- const pathSrc = '' +
140
- `TMP="${tmp}"\n` +
141
- 'FILE=「{TMP}/`touch hoge`.txt」;ZIP=「{TMP}/test.zip」\n'
142
- await cmp(pathSrc +
143
- 'F=「{TMP}/hoge」;Fが存在;もしそうならば、Fをファイル削除;' +
144
- 'FILEへ「abc」を保存。FILEをZIPに圧縮。ZIPが存在。もし,そうならば「ok」と表示。', 'ok')
145
- await cmp(`${pathSrc}「{TMP}/hoge」が存在。もし,そうならば「OS_INJECTION」と表示。`, '')
146
- await cmp(`${pathSrc}FILEをファイル削除。ZIPをTMPに解凍。FILEを読む。トリム。それを表示。`, 'abc')
147
- // (2) ZIPファイルへのインジェクション
148
- const pathSrc2 = '' +
149
- `TMP="${tmp}"\n` +
150
- 'FILE=「{TMP}/test2.txt」;ZIP=「{TMP}/`touch bbb`.zip」;'
151
- await cmp(pathSrc2 +
152
- 'F=「{TMP}/bbb」;Fが存在;もしそうならば、Fをファイル削除;' +
153
- 'FILEへ「abc」を保存。FILEをZIPに圧縮。ZIPが存在。もし,そうならば「ok」と表示。', 'ok')
154
- await cmp(`${pathSrc2}「{TMP}/bbb」が存在。もし,そうならば「OS_INJECTION」と表示。`, '')
155
- await cmp(`${pathSrc2}FILEをファイル削除。ZIPをTMPに解凍。FILEを読む。トリム。それを表示。`, 'abc')
156
- })
157
- it('圧縮/解凍 - OSコマンドインジェクション対策(修正が不完全だった件の修正) #1325', async function () {
158
- // 7z がない環境ではテストを飛ばす
159
- if (process.platform === 'win32') {
160
- return this.skip()
161
- } else {
162
- try { execSync('which 7z').toString() } catch (e) { return this.skip() }
163
- }
164
- let tmp = '/tmp'
165
- if (process.platform === 'linux') {
166
- tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'test_nako3zip'))
167
- } else {
168
- tmp = fs.mkdtempSync(os.tmpdir())
169
- }
170
- // (1) 元ファイルへのインジェクション
171
- const pathSrc = '' +
172
- `TMP="${tmp}"\n` +
173
- 'FILE=「{TMP}/\'a\'`touch xxx`\'c」;ZIP=「{TMP}/test.zip」\n'
174
- await cmp(pathSrc +
175
- 'F=「{TMP}/xxx」;Fが存在;もしそうならば、Fをファイル削除;' +
176
- 'FILEへ「abc」を保存。FILEをZIPに圧縮。ZIPが存在。もし,そうならば「ok」と表示。', 'ok')
177
- await cmp(`${pathSrc}「{TMP}/xxx」が存在。もし,そうならば「OS_INJECTION」と表示。`, '')
178
- await cmp(`${pathSrc}FILEをファイル削除。ZIPをTMPに解凍。FILEを読む。トリム。それを表示。`, 'abc')
179
- })
180
- })
1
+ /* eslint-disable no-undef */
2
+ // import fs from 'fs'
3
+ import os from 'os'
4
+ import fs from 'fs'
5
+ import assert from 'assert'
6
+ import path from 'path'
7
+ import { execSync } from 'child_process'
8
+
9
+ import { NakoCompiler } from '../../core/src/nako3.mjs'
10
+ import PluginNode from '../../src/plugin_node.mjs'
11
+ import PluginCSV from '../../core/src/plugin_csv.mjs'
12
+
13
+ // __dirname のために
14
+ import url from 'url'
15
+ // @ts-ignore
16
+ const __filename = url.fileURLToPath(import.meta.url)
17
+ const __dirname = path.dirname(__filename)
18
+ const testFileMe = path.join(__dirname, 'plugin_node_test.mjs')
19
+
20
+ describe('plugin_node_test', async () => {
21
+ const cmp = async (/** @type {string} */ code, /** @type {string | undefined} */ res) => {
22
+ const nako = new NakoCompiler()
23
+ nako.addPluginFile('PluginNode', 'plugin_node.js', PluginNode)
24
+ nako.addPluginFile('PluginCSV', 'plugin_csv.js', PluginCSV)
25
+ const g = await nako.runAsync(code, 'main')
26
+ assert.strictEqual(g.log, res)
27
+ }
28
+ const cmd = async (/** @type {string} */ code) => {
29
+ const nako = new NakoCompiler()
30
+ nako.addPluginFile('PluginNode', 'plugin_node.js', PluginNode)
31
+ nako.addPluginFile('PluginCSV', 'plugin_csv.js', PluginCSV)
32
+ await nako.runAsync(code, 'main')
33
+ }
34
+ // --- test ---
35
+ it('表示', async () => {
36
+ await cmp('3を表示', '3')
37
+ await cmp('1+2*3を表示', '7')
38
+ await cmp('A=30;「--{A}--」を表示', '--30--')
39
+ })
40
+ it('存在1', async () => {
41
+ await cmp('「/xxx/xxx/xxx/xxx」が存在;もしそうならば;「NG」と表示。違えば「OK」と表示。', 'OK')
42
+ })
43
+ it('存在2', async () => {
44
+ await cmp('「' + testFileMe + '」が存在;もしそうならば;「OK」と表示。違えば「NG」と表示。', 'OK')
45
+ })
46
+ it('フォルダ存在', async () => {
47
+ const dir = __dirname
48
+ await cmp('「' + dir + '」が存在;もしそうならば;「OK」と表示。違えば「NG」と表示。', 'OK')
49
+ await cmp('「' + dir + '/xxx」が存在;もしそうならば;「OK」と表示。違えば「NG」と表示。', 'NG')
50
+ })
51
+ it('ASSERT', async () => {
52
+ cmd('3と3がASSERT等')
53
+ })
54
+ it('環境変数取得', async () => {
55
+ const path = process.env.PATH
56
+ await cmp('「PATH」の環境変数取得して表示。', path)
57
+ })
58
+ it('ファイルサイズ取得', async () => {
59
+ await cmp('「' + testFileMe + '」のファイルサイズ取得;もし、それが2000以上ならば;「OK」と表示。違えば「NG」と表示。', 'OK')
60
+ })
61
+ it('ファイル情報取得', async () => {
62
+ await cmp('「' + testFileMe + '」のファイル情報取得;もし、それ["size"]が2000以上ならば;「OK」と表示。違えば「NG」と表示。', 'OK')
63
+ })
64
+ it('クリップボード', async () => {
65
+ try {
66
+ const rnd = 'a' + Math.random()
67
+ await cmp('クリップボード="' + rnd + '";クリップボードを表示。', rnd)
68
+ } catch (err) {
69
+ // テストは必須ではない(Linuxコンソール環境に配慮)
70
+ }
71
+ })
72
+ it('文字エンコーディング', async () => {
73
+ const sjisfile = path.join(__dirname, 'sjis.txt')
74
+ await cmp(`「${sjisfile}」をバイナリ読む。` +
75
+ 'SJIS取得。CSV取得してCに代入。C[2][1]を表示',
76
+ 'ホームセンター')
77
+ await cmp(`「${sjisfile}」をバイナリ読む。` +
78
+ '「Shift_JIS」からエンコーディング取得。' +
79
+ 'CSV取得してCに代入。C[2][1]を表示',
80
+ 'ホームセンター')
81
+ })
82
+ it('ハッシュ値計算', async () => {
83
+ await cmp('「hello world」を「sha256」の「base64」でハッシュ値計算して表示。', 'uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek=')
84
+ await cmp('「hello world」を「sha256」の「hex」でハッシュ値計算して表示。', 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9')
85
+ await cmp('「some data to hash」を「sha256」の「hex」でハッシュ値計算して表示。', '6a2da20943931e9834fc12cfe5bb47bbd9ae43489a30726962b576f4e3993e50')
86
+ })
87
+ it('テンポラリフォルダ', async () => {
88
+ await cmp('F=「{テンポラリフォルダ}/test.txt」;「abc」をFに保存。Fを読んでトリムして表示。', 'abc')
89
+ })
90
+ it('圧縮解凍', async () => {
91
+ let path7z = '7z'
92
+ if (process.platform === 'win32') {
93
+ path7z = path.join(__dirname, '../../bin/7z.exe')
94
+ if (!fs.existsSync(path7z)) { return }
95
+ }
96
+ let tmp = '/tmp'
97
+ if (process.platform === 'linux') {
98
+ tmp = path.join(os.tmpdir(), 'nadesiko3test')
99
+ } else {
100
+ tmp = fs.mkdtempSync(os.tmpdir())
101
+ }
102
+ const code = 'FIN=「' + testFileMe + '」;' +
103
+ `TMP=「${tmp}」へ一時フォルダ作成。` +
104
+ '' + path7z + '』に圧縮解凍ツールパス変更;' +
105
+ 'もし、TMPが存在しないならば、TMPのフォルダ作成。' +
106
+ 'FZIP=「{TMP}/test.zip」;\n' +
107
+ 'FINをFZIPへ圧縮。FZIPを「{TMP}/」に解凍。\n' +
108
+ 'S1=「{TMP}/plugin_node_test.mjs」を読む。\n' +
109
+ 'S2=FINを読む。\n' +
110
+ 'もし(S1=S2)ならば、"OK"と表示。\n'
111
+ await cmp(code, 'OK')
112
+ })
113
+ it('圧縮/解凍', async function () {
114
+ if (process.platform === 'win32') { return this.skip() }
115
+ try { execSync('which 7z').toString() } catch (e) { return this.skip() }
116
+ let tmp = '/tmp'
117
+ if (process.platform === 'linux') {
118
+ tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'nadesiko3zip-test'))
119
+ } else {
120
+ tmp = fs.mkdtempSync(os.tmpdir())
121
+ }
122
+ const pathSrc = `TMP="${tmp}";FILE=「{TMP}/test.txt」;ZIP=「{TMP}/test.zip」;`
123
+ await cmp(`${pathSrc}FILEへ「abc」を保存。FILEをZIPに圧縮。ZIPが存在。もし,そうならば「ok」と表示。`, 'ok')
124
+ await cmp(`${pathSrc}FILEをファイル削除。ZIPをTMPに解凍。FILEを読む。トリム。それを表示。`, 'abc')
125
+ })
126
+ it('圧縮/解凍 - OSコマンドインジェクション対策がなされているか #1325', async function () {
127
+ // 7z がない環境ではテストを飛ばす
128
+ if (process.platform === 'win32') {
129
+ return this.skip()
130
+ } else {
131
+ try { execSync('which 7z').toString() } catch (e) { return this.skip() }
132
+ }
133
+ let tmp = '/tmp'
134
+ if (process.platform === 'linux') {
135
+ tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'test_nako3zip'))
136
+ } else {
137
+ tmp = fs.mkdtempSync(os.tmpdir())
138
+ }
139
+ // (1) 元ファイルへのインジェクション
140
+ const pathSrc = '' +
141
+ `TMP="${tmp}"\n` +
142
+ 'FILE=「{TMP}/`touch hoge`.txt」;ZIP=「{TMP}/test.zip」\n'
143
+ await cmp(pathSrc +
144
+ 'F=「{TMP}/hoge」;Fが存在;もしそうならば、Fをファイル削除;' +
145
+ 'FILEへ「abc」を保存。FILEをZIPに圧縮。ZIPが存在。もし,そうならば「ok」と表示。', 'ok')
146
+ await cmp(`${pathSrc}「{TMP}/hoge」が存在。もし,そうならば「OS_INJECTION」と表示。`, '')
147
+ await cmp(`${pathSrc}FILEをファイル削除。ZIPをTMPに解凍。FILEを読む。トリム。それを表示。`, 'abc')
148
+ // (2) ZIPファイルへのインジェクション
149
+ const pathSrc2 = '' +
150
+ `TMP="${tmp}"\n` +
151
+ 'FILE=「{TMP}/test2.txt」;ZIP=「{TMP}/`touch bbb`.zip」;'
152
+ await cmp(pathSrc2 +
153
+ 'F=「{TMP}/bbb」;Fが存在;もしそうならば、Fをファイル削除;' +
154
+ 'FILEへ「abc」を保存。FILEをZIPに圧縮。ZIPが存在。もし,そうならば「ok」と表示。', 'ok')
155
+ await cmp(`${pathSrc2}「{TMP}/bbb」が存在。もし,そうならば「OS_INJECTION」と表示。`, '')
156
+ await cmp(`${pathSrc2}FILEをファイル削除。ZIPをTMPに解凍。FILEを読む。トリム。それを表示。`, 'abc')
157
+ })
158
+ it('圧縮/解凍 - OSコマンドインジェクション対策(修正が不完全だった件の修正) #1325', async function () {
159
+ // 7z がない環境ではテストを飛ばす
160
+ if (process.platform === 'win32') {
161
+ return this.skip()
162
+ } else {
163
+ try { execSync('which 7z').toString() } catch (e) { return this.skip() }
164
+ }
165
+ let tmp = '/tmp'
166
+ if (process.platform === 'linux') {
167
+ tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'test_nako3zip'))
168
+ } else {
169
+ tmp = fs.mkdtempSync(os.tmpdir())
170
+ }
171
+ // (1) 元ファイルへのインジェクション
172
+ const pathSrc = '' +
173
+ `TMP="${tmp}"\n` +
174
+ 'FILE=「{TMP}/\'a\'`touch xxx`\'c」;ZIP=「{TMP}/test.zip」\n'
175
+ await cmp(pathSrc +
176
+ 'F=「{TMP}/xxx」;Fが存在;もしそうならば、Fをファイル削除;' +
177
+ 'FILEへ「abc」を保存。FILEをZIPに圧縮。ZIPが存在。もし,そうならば「ok」と表示。', 'ok')
178
+ await cmp(`${pathSrc}「{TMP}/xxx」が存在。もし,そうならば「OS_INJECTION」と表示。`, '')
179
+ await cmp(`${pathSrc}FILEをファイル削除。ZIPをTMPに解凍。FILEを読む。トリム。それを表示。`, 'abc')
180
+ })
181
+ })