nadesiko3 3.7.21 → 3.7.23

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 (212) hide show
  1. package/README.md +20 -1
  2. package/batch/command.txt +370 -334
  3. package/batch/generate_command_list.mjs +102 -0
  4. package/batch/jsplugin2text.nako3 +1 -1
  5. package/batch/pickup_command.nako3 +12 -0
  6. package/batch/search_command.mjs +34 -0
  7. package/batch/search_command.nako3 +430 -0
  8. package/core/command/snako.mts +5 -1
  9. package/core/deno/snako.ts +5 -1
  10. package/core/package-lock.json +382 -21
  11. package/core/package.json +7 -4
  12. package/core/sample/algorithms/README.md +43 -0
  13. package/core/sample/algorithms/graph/dijkstra.nako3 +47 -0
  14. package/core/sample/algorithms/graph/kruskal.nako3 +69 -0
  15. package/core/sample/algorithms/math/euclidean_gcd.nako3 +15 -0
  16. package/core/sample/algorithms/math/sieve_of_eratosthenes.nako3 +26 -0
  17. package/core/sample/algorithms/search/binary_search.nako3 +17 -0
  18. package/core/sample/algorithms/search/breadth_first_search.nako3 +33 -0
  19. package/core/sample/algorithms/search/depth_first_search.nako3 +25 -0
  20. package/core/sample/algorithms/sort/heap_sort.nako3 +37 -0
  21. package/core/sample/algorithms/sort/insertion_sort.nako3 +18 -0
  22. package/core/sample/algorithms/sort/merge_sort.nako3 +40 -0
  23. package/core/sample/algorithms/sort/quick_sort.nako3 +36 -0
  24. package/core/sample/algorithms/string/knuth_morris_pratt.nako3 +50 -0
  25. package/core/sample/algorithms/string/run_length_encoding.nako3 +25 -0
  26. package/core/src/nako3.mts +178 -614
  27. package/core/src/nako_basic_plugins.mts +39 -0
  28. package/core/src/nako_core_version.mts +2 -2
  29. package/core/src/nako_csv.mts +0 -1
  30. package/core/src/nako_event.mts +49 -0
  31. package/core/src/nako_gen.mts +320 -209
  32. package/core/src/nako_global.mts +18 -0
  33. package/core/src/nako_indent_inline.mts +2 -2
  34. package/core/src/nako_lex_rules.mts +1 -1
  35. package/core/src/nako_parser3.mts +111 -166
  36. package/core/src/nako_parser_async.mts +165 -0
  37. package/core/src/nako_parser_base.mts +4 -55
  38. package/core/src/nako_parser_message.mts +105 -0
  39. package/core/src/nako_parser_operator.mts +93 -0
  40. package/core/src/nako_plugin_manager.mts +260 -0
  41. package/core/src/nako_require.mts +292 -0
  42. package/core/src/nako_runner.mts +208 -0
  43. package/core/src/nako_tokenizer.mts +221 -0
  44. package/core/src/plugin_csv.mts +1 -1
  45. package/core/src/plugin_system.mts +34 -3259
  46. package/core/src/plugin_system_array.mts +699 -0
  47. package/core/src/plugin_system_datetime.mts +368 -0
  48. package/core/src/plugin_system_debug.mts +403 -0
  49. package/core/src/plugin_system_dict.mts +85 -0
  50. package/core/src/plugin_system_json.mts +73 -0
  51. package/core/src/plugin_system_math.mts +383 -0
  52. package/core/src/plugin_system_regexp.mts +120 -0
  53. package/core/src/plugin_system_stdio.mts +86 -0
  54. package/core/src/plugin_system_string.mts +666 -0
  55. package/core/src/plugin_system_timer.mts +152 -0
  56. package/core/src/plugin_system_types.mts +151 -0
  57. package/core/src/plugin_system_url.mts +193 -0
  58. package/core/src/plugin_toml.mts +3 -3
  59. package/core/test/algorithm_samples_test.mjs +58 -0
  60. package/core/test/algorithms/graph/dijkstra_test.nako3 +21 -0
  61. package/core/test/algorithms/graph/kruskal_test.nako3 +21 -0
  62. package/core/test/algorithms/helper.mjs +13 -0
  63. package/core/test/algorithms/math/euclidean_gcd_test.nako3 +13 -0
  64. package/core/test/algorithms/math/sieve_of_eratosthenes_test.nako3 +10 -0
  65. package/core/test/algorithms/search/binary_search_test.nako3 +15 -0
  66. package/core/test/algorithms/search/breadth_first_search_test.nako3 +13 -0
  67. package/core/test/algorithms/search/depth_first_search_test.nako3 +13 -0
  68. package/core/test/algorithms/sort/heap_sort_test.nako3 +13 -0
  69. package/core/test/algorithms/sort/insertion_sort_test.nako3 +13 -0
  70. package/core/test/algorithms/sort/merge_sort_test.nako3 +18 -0
  71. package/core/test/algorithms/sort/quick_sort_test.nako3 +34 -0
  72. package/core/test/algorithms/string/knuth_morris_pratt_test.nako3 +16 -0
  73. package/core/test/algorithms/string/run_length_encoding_test.nako3 +13 -0
  74. package/core/test/array_test.mjs +3 -0
  75. package/core/test/fixtures/README.md +39 -0
  76. package/core/test/fixtures/make_parser_ast_golden.mjs +31 -0
  77. package/core/test/fixtures/parser_ast_golden.json +8027 -0
  78. package/core/test/fixtures/parser_corpus.mjs +120 -0
  79. package/core/test/func_call.mjs +18 -0
  80. package/core/test/func_test.mjs +28 -0
  81. package/core/test/indent_test.mjs +6 -0
  82. package/core/test/nako_basic_plugins_test.mjs +44 -0
  83. package/core/test/nako_event_test.mjs +127 -0
  84. package/core/test/nako_gen_perf_test.mjs +178 -0
  85. package/core/test/nako_parser_async_test.mjs +385 -0
  86. package/core/test/nako_parser_test.mjs +160 -0
  87. package/core/test/nako_plugin_manager_test.mjs +185 -0
  88. package/core/test/nako_require_test.mjs +153 -0
  89. package/core/test/nako_runner_test.mjs +174 -0
  90. package/core/test/nako_tokenizer_test.mjs +115 -0
  91. package/core/test/plugin_system_debug_test.mjs +138 -0
  92. package/core/test/plugin_system_split_test.mjs +179 -0
  93. package/core/test/plugin_system_test.mjs +6 -0
  94. package/core/tsconfig.json +0 -1
  95. package/demo/browsers.html +1 -1
  96. package/doc/SETUP.md +1 -1
  97. package/doc/ai-code-generation.md +136 -0
  98. package/doc/browsers.md +1 -1
  99. package/doc/command_list.json +16842 -0
  100. package/doc/search_command.md +222 -0
  101. package/doc/syntax-nako3.md +344 -0
  102. package/package.json +29 -26
  103. package/release/_hash.txt +40 -40
  104. package/release/_script-tags.txt +16 -16
  105. package/release/command.json +1 -1
  106. package/release/command.json.js +1 -1
  107. package/release/command_cnako3.json +1 -1
  108. package/release/command_list.json +1 -1
  109. package/release/edit_main.js +6 -6
  110. package/release/edit_main.js.map +3 -3
  111. package/release/editor.js +6 -6
  112. package/release/plugin_caniuse.js +1 -1
  113. package/release/plugin_caniuse.js.map +2 -2
  114. package/release/plugin_keigo.js.map +3 -3
  115. package/release/plugin_markup.js +46 -46
  116. package/release/plugin_markup.js.map +3 -3
  117. package/release/plugin_weykturtle3d.js +1 -1
  118. package/release/plugin_weykturtle3d.js.map +3 -3
  119. package/release/version.js +2 -2
  120. package/release/version_main.js +2 -2
  121. package/release/version_main.js.map +1 -1
  122. package/release/wnako3.js +219 -230
  123. package/release/wnako3.js.map +4 -4
  124. package/release/wnako3webworker.js +193 -204
  125. package/release/wnako3webworker.js.map +4 -4
  126. package/src/browsers.mjs +1 -1
  127. package/src/browsers.txt +0 -1
  128. package/src/cnako3mod.mjs +7 -2
  129. package/src/cnako3mod.mts +7 -2
  130. package/src/nako_version.mjs +2 -2
  131. package/src/nako_version.mts +2 -2
  132. package/src/plugin_browser_ajax.mjs +4 -4
  133. package/src/plugin_browser_ajax.mts +4 -4
  134. package/src/plugin_browser_audio.mjs +10 -10
  135. package/src/plugin_browser_audio.mts +10 -10
  136. package/src/plugin_browser_camera.mjs +4 -4
  137. package/src/plugin_browser_camera.mts +4 -4
  138. package/src/plugin_browser_canvas.mjs +2 -2
  139. package/src/plugin_browser_canvas.mts +2 -2
  140. package/src/plugin_browser_crypto.mjs +3 -3
  141. package/src/plugin_browser_crypto.mts +3 -3
  142. package/src/plugin_browser_dom_event.mjs +1 -1
  143. package/src/plugin_browser_dom_event.mts +1 -1
  144. package/src/plugin_browser_geolocation.mjs +1 -1
  145. package/src/plugin_browser_geolocation.mts +1 -1
  146. package/src/plugin_browser_hotkey.mjs +1 -1
  147. package/src/plugin_browser_hotkey.mts +1 -1
  148. package/src/plugin_browser_html.mjs +1 -1
  149. package/src/plugin_browser_html.mts +1 -1
  150. package/src/plugin_browser_location.mjs +1 -1
  151. package/src/plugin_browser_location.mts +1 -1
  152. package/src/plugin_browser_speech.mjs +1 -1
  153. package/src/plugin_browser_speech.mts +1 -1
  154. package/src/plugin_browser_storage.mjs +2 -2
  155. package/src/plugin_browser_storage.mts +2 -2
  156. package/src/plugin_httpserver.mjs +3 -3
  157. package/src/plugin_httpserver.mts +3 -3
  158. package/src/plugin_keigo.mjs +2 -2
  159. package/src/plugin_keigo.mts +2 -2
  160. package/src/plugin_node.mjs +48 -48
  161. package/src/plugin_node.mts +53 -53
  162. package/src/plugin_weykturtle3d.mjs +56 -56
  163. package/src/plugin_weykturtle3d.mts +56 -56
  164. package/src/wnako3.mjs +1 -1
  165. package/src/wnako3.mts +1 -1
  166. package/src/wnako3_editor.mjs +5 -5
  167. package/src/wnako3_editor.mts +5 -5
  168. package/src/wnako3mod.mjs +2 -2
  169. package/src/wnako3mod.mts +2 -2
  170. package/test/nako3edit/index_nako3_test.mjs +282 -0
  171. package/test/nako3server/index_nako3_test.mjs +239 -0
  172. package/test/node/ai_code_generation_guide_test.mjs +29 -0
  173. package/test/node/node_version_support_test.mjs +45 -0
  174. package/test/node/search_command_test.mjs +174 -0
  175. package/tools/nako3edit/AGENTS.md +23 -0
  176. package/tools/nako3edit/index.nako3 +404 -0
  177. package/tools/nako3server/AGENTS.md +23 -0
  178. package/tools/nako3server/index.nako3 +156 -23
  179. package/core/src/nako3.mjs +0 -1021
  180. package/core/src/nako_ast.mjs +0 -4
  181. package/core/src/nako_colors.mjs +0 -77
  182. package/core/src/nako_core_version.mjs +0 -8
  183. package/core/src/nako_csv.mjs +0 -193
  184. package/core/src/nako_errors.mjs +0 -166
  185. package/core/src/nako_from_dncl.mjs +0 -285
  186. package/core/src/nako_from_dncl2.mjs +0 -347
  187. package/core/src/nako_gen.mjs +0 -2500
  188. package/core/src/nako_global.mjs +0 -138
  189. package/core/src/nako_indent.mjs +0 -442
  190. package/core/src/nako_indent_chars.mjs +0 -29
  191. package/core/src/nako_indent_inline.mjs +0 -361
  192. package/core/src/nako_josi_list.mjs +0 -47
  193. package/core/src/nako_lex_rules.mjs +0 -319
  194. package/core/src/nako_lexer.mjs +0 -794
  195. package/core/src/nako_logger.mjs +0 -221
  196. package/core/src/nako_parser3.mjs +0 -3250
  197. package/core/src/nako_parser_base.mjs +0 -403
  198. package/core/src/nako_parser_const.mjs +0 -37
  199. package/core/src/nako_prepare.mjs +0 -329
  200. package/core/src/nako_reserved_words.mjs +0 -42
  201. package/core/src/nako_source_mapping.mjs +0 -207
  202. package/core/src/nako_test.mjs +0 -37
  203. package/core/src/nako_token.mjs +0 -1
  204. package/core/src/nako_tools.mjs +0 -53
  205. package/core/src/nako_types.mjs +0 -14
  206. package/core/src/plugin_api.mjs +0 -4
  207. package/core/src/plugin_csv.mjs +0 -97
  208. package/core/src/plugin_math.mjs +0 -352
  209. package/core/src/plugin_promise.mjs +0 -102
  210. package/core/src/plugin_system.mjs +0 -3810
  211. package/core/src/plugin_test.mjs +0 -52
  212. package/core/src/plugin_toml.mjs +0 -39
@@ -0,0 +1,152 @@
1
+ /**
2
+ * @fileOverview なでしこ3 plugin_system の分割ファイル
3
+ *
4
+ * タイマー処理の命令を定義する。
5
+ * このファイルは単独のプラグインではなく、plugin_system.mts へマージされる。(#2351)
6
+ */
7
+ import { NakoRuntimeError } from './nako_errors.mjs'
8
+ import { NakoSystem } from './plugin_api.mjs'
9
+
10
+ export default {
11
+ // @タイマー
12
+ '秒待': { // @ N秒の間待機する // @びょうまつ
13
+ type: 'func',
14
+ josi: [['']],
15
+ pure: true,
16
+ asyncFn: true,
17
+ fn: function(n: any, sys:any): Promise<void> {
18
+ return new Promise((resolve, reject) => {
19
+ try {
20
+ // タイマーを仕掛ける
21
+ const timerId = setTimeout(() => {
22
+ // タイマー使用中リストに追加したIDを削除
23
+ const i = sys.__timeout.indexOf(timerId)
24
+ if (i >= 0) { sys.__timeout.splice(i, 1) }
25
+ // Promiseを終了
26
+ resolve()
27
+ }, parseFloat(n) * 1000)
28
+ // タイマー使用中リストに追加
29
+ sys.__timeout.push(timerId)
30
+ } catch (err: any) {
31
+ reject(err)
32
+ }
33
+ })
34
+ },
35
+ return_none: true
36
+ },
37
+ '秒待機': { // @ N秒の間待機する(『秒待』と同じ) // @びょうたいき
38
+ type: 'func',
39
+ josi: [['']],
40
+ pure: true,
41
+ asyncFn: true,
42
+ fn: async function(n: any, sys: any) {
43
+ const p = sys.__exec('秒待', [n, sys])
44
+ return await p
45
+ },
46
+ return_none: true
47
+ },
48
+ '秒逐次待機': { // @ (非推奨) 逐次実行構文にて、N秒の間待機する (廃止予定) // @びょうちくじたいき
49
+ type: 'func',
50
+ josi: [['']],
51
+ pure: true,
52
+ asyncFn: true,
53
+ fn: async function(n: any, sys: any) {
54
+ const p = sys.__exec('秒待', [n, sys])
55
+ return await p
56
+ },
57
+ return_none: true
58
+ },
59
+ '秒後': { // @無名関数(あるいは、文字列で関数名を指定)FをN秒後に実行する。変数『対象』にタイマーIDを代入する。 // @びょうご
60
+ type: 'func',
61
+ josi: [['を'], ['']],
62
+ pure: true,
63
+ fn: function(f: any, n: any, sys: any) {
64
+ // 文字列で指定された関数をオブジェクトに変換
65
+ if (typeof f === 'string') { f = sys.__findFunc(f, '秒後') }
66
+ // 1回限りのタイマーをセット
67
+ const timerId = setTimeout(() => {
68
+ // 使用中リストに追加したIDを削除
69
+ const i = sys.__timeout.indexOf(timerId)
70
+ if (i >= 0) { sys.__timeout.splice(i, 1) }
71
+ try {
72
+ f(timerId, sys)
73
+ } catch (e: any) {
74
+ let err = e
75
+ if (!(e instanceof NakoRuntimeError)) {
76
+ err = new NakoRuntimeError(e, sys.__getSysVar('__line'))
77
+ }
78
+ sys.logger.error(err)
79
+ }
80
+ }, parseFloat(n) * 1000)
81
+ sys.__timeout.unshift(timerId)
82
+ sys.__setSysVar('対象', timerId)
83
+ return timerId
84
+ }
85
+ },
86
+ '秒毎': { // @無名関数(あるいは、文字列で関数名を指定)FをN秒ごとに実行する(『タイマー停止』で停止できる)。変数『対象』にタイマーIDを代入する。 // @びょうごと
87
+ type: 'func',
88
+ josi: [['を'], ['']],
89
+ pure: false,
90
+ fn: function(f: any, n: any, sys: any) {
91
+ // 文字列で指定された関数をオブジェクトに変換
92
+ if (typeof f === 'string') { f = sys.__findFunc(f, '秒毎') }
93
+ // タイマーをセット
94
+ const timerId = setInterval(() => {
95
+ f(timerId, sys)
96
+ }, parseFloat(n) * 1000)
97
+ // タイマーIDを追加
98
+ sys.__interval.unshift(timerId)
99
+ sys.__setSysVar('対象', timerId)
100
+ return timerId
101
+ }
102
+ },
103
+ '秒タイマー開始時': { // @無名関数(あるいは、文字列で関数名を指定)FをN秒ごとに実行する(『秒毎』と同じ) // @びょうたいまーかいししたとき
104
+ type: 'func',
105
+ josi: [['を'], ['']],
106
+ pure: false,
107
+ fn: function(f: any, n: any, sys: any) {
108
+ return sys.__exec('秒毎', [f, n, sys])
109
+ }
110
+ },
111
+ 'タイマー停止': { // @『秒毎』『秒後』や『秒タイマー開始』で開始したタイマーを停止する // @たいまーていし
112
+ type: 'func',
113
+ josi: [['の', 'で']],
114
+ pure: true,
115
+ fn: function(timerId: any, sys: any) {
116
+ const i = sys.__interval.indexOf(timerId)
117
+ if (i >= 0) {
118
+ sys.__interval.splice(i, 1)
119
+ clearInterval(timerId)
120
+ return true
121
+ }
122
+ const j = sys.__timeout.indexOf(timerId)
123
+ if (j >= 0) {
124
+ sys.__timeout.splice(j, 1)
125
+ clearTimeout(timerId)
126
+ return true
127
+ }
128
+ return false
129
+ },
130
+ return_none: false
131
+ },
132
+ '全タイマー停止': { // @『秒毎』『秒後』や『秒タイマー開始』で開始したタイマーを全部停止する // @ぜんたいまーていし
133
+ type: 'func',
134
+ josi: [],
135
+ pure: true,
136
+ fn: function(sys: NakoSystem) {
137
+ // clearInterval
138
+ for (let i = 0; i < sys.__interval.length; i++) {
139
+ const timerId = sys.__interval[i]
140
+ clearInterval(timerId)
141
+ }
142
+ sys.__interval = []
143
+ // clearTimeout
144
+ for (let i = 0; i < sys.__timeout.length; i++) {
145
+ const timerId = sys.__timeout[i]
146
+ clearTimeout(timerId)
147
+ }
148
+ sys.__timeout = []
149
+ },
150
+ return_none: true
151
+ },
152
+ }
@@ -0,0 +1,151 @@
1
+ /**
2
+ * @fileOverview なでしこ3 plugin_system の分割ファイル
3
+ *
4
+ * 型変換の命令を定義する。
5
+ * このファイルは単独のプラグインではなく、plugin_system.mts へマージされる。(#2351)
6
+ */
7
+ export default {
8
+ // @型変換
9
+ '変数型確認': { // @変数Vの型を返す // @へんすうかたかくにん
10
+ type: 'func',
11
+ josi: [['の']],
12
+ pure: true,
13
+ fn: function(v: any) {
14
+ return (typeof v)
15
+ }
16
+ },
17
+ 'TYPEOF': { // @変数Vの型を返す // @TYPEOF
18
+ type: 'func',
19
+ josi: [['の']],
20
+ pure: true,
21
+ fn: function(v: any) {
22
+ return (typeof v)
23
+ }
24
+ },
25
+ '文字列変換': { // @値Vを文字列に変換 // @もじれつへんかん
26
+ type: 'func',
27
+ josi: [['を']],
28
+ pure: true,
29
+ fn: function(v: any): string {
30
+ return String(v)
31
+ }
32
+ },
33
+ 'TOSTR': { // @値Vを文字列に変換 // @TOSTR
34
+ type: 'func',
35
+ josi: [['を']],
36
+ pure: true,
37
+ fn: function(v: any): string {
38
+ return String(v)
39
+ }
40
+ },
41
+ '整数変換': { // @値Vを整数に変換 // @せいすうへんかん
42
+ type: 'func',
43
+ josi: [['を']],
44
+ pure: true,
45
+ fn: function(v: any): number {
46
+ return parseInt(v)
47
+ }
48
+ },
49
+ 'TOINT': { // @値Vを整数に変換 // @TOINT
50
+ type: 'func',
51
+ josi: [['を']],
52
+ pure: true,
53
+ fn: function(v: any): number {
54
+ return parseInt(v)
55
+ }
56
+ },
57
+ '実数変換': { // @値Vを実数に変換 // @じっすうへんかん
58
+ type: 'func',
59
+ josi: [['を']],
60
+ pure: true,
61
+ fn: function(v: any): number {
62
+ return parseFloat(v)
63
+ }
64
+ },
65
+ 'TOFLOAT': { // @値Vを実数に変換 // @TOFLOAT
66
+ type: 'func',
67
+ josi: [['を']],
68
+ pure: true,
69
+ fn: function(v: any): number {
70
+ return parseFloat(v)
71
+ }
72
+ },
73
+ 'INT': { // @値Vを整数に変換 // @INT
74
+ type: 'func',
75
+ josi: [['の']],
76
+ pure: true,
77
+ fn: function(v: any): number {
78
+ return parseInt(v)
79
+ }
80
+ },
81
+ 'FLOAT': { // @値Vを実数に変換 // @FLOAT
82
+ type: 'func',
83
+ josi: [['の']],
84
+ pure: true,
85
+ fn: function(v: any): number {
86
+ return parseFloat(v)
87
+ }
88
+ },
89
+ 'NAN判定': { // @値VがNaNかどうかを判定(命令『非数判定』を使う事を推奨) // @NANはんてい
90
+ type: 'func',
91
+ josi: [['を']],
92
+ pure: true,
93
+ fn: function(v: any): boolean {
94
+ return isNaN(v)
95
+ }
96
+ },
97
+ '非数判定': { // @値Vが非数かどうかを判定(NAN判定より堅牢) // @ひすうはんてい
98
+ type: 'func',
99
+ josi: [['を']],
100
+ pure: true,
101
+ fn: function(v: any): boolean {
102
+ // https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN
103
+ return Number.isNaN(v)
104
+ }
105
+ },
106
+ 'HEX': { // @値Vを16進数に変換 // @HEX
107
+ type: 'func',
108
+ josi: [['の']],
109
+ pure: true,
110
+ fn: function(a: any): string {
111
+ return parseInt(a).toString(16)
112
+ }
113
+ },
114
+ '進数変換': { // @値VをN進数に変換 // @しんすうへんかん
115
+ type: 'func',
116
+ josi: [['を', 'の'], ['']],
117
+ pure: true,
118
+ fn: function(v: any, n: number): string {
119
+ return parseInt(v).toString(n)
120
+ }
121
+ },
122
+ '二進': { // @値Vを2進数に変換 // @にしん
123
+ type: 'func',
124
+ josi: [['を', 'の', 'から']],
125
+ pure: true,
126
+ fn: function(v: any): string {
127
+ return parseInt(v).toString(2)
128
+ }
129
+ },
130
+ '二進表示': { // @値Vを2進数に変換して表示 // @にしんひょうじ
131
+ type: 'func',
132
+ josi: [['を', 'の', 'から']],
133
+ pure: true,
134
+ fn: function(v: any, sys: any) {
135
+ const s = parseInt(v).toString(2)
136
+ sys.__exec('表示', [s, sys])
137
+ }
138
+ },
139
+ 'RGB': { // @HTML用のカラーコードを返すRGB(R,G,B)で各値は0-255 // @RGB
140
+ type: 'func',
141
+ josi: [['と'], ['の'], ['で']],
142
+ pure: true,
143
+ fn: function(r: any, g: any, b: any): string {
144
+ const z2 = (v: any): string => {
145
+ const v2: string = '00' + (parseInt(String(v)).toString(16))
146
+ return v2.substring(v2.length - 2, v2.length)
147
+ }
148
+ return '#' + z2(r) + z2(g) + z2(b)
149
+ }
150
+ },
151
+ }
@@ -0,0 +1,193 @@
1
+ /**
2
+ * @fileOverview なでしこ3 plugin_system の分割ファイル
3
+ *
4
+ * URLエンコード・パラメータ処理・BASE64・パス操作の命令を定義する。
5
+ * このファイルは単独のプラグインではなく、plugin_system.mts へマージされる。(#2351)
6
+ */
7
+ import { NakoSystem } from './plugin_api.mjs'
8
+
9
+ export default {
10
+ // @URLエンコードとパラメータ
11
+ 'URLエンコード': { // @URLエンコードして返す // @URLえんこーど
12
+ type: 'func',
13
+ josi: [['を', 'から']],
14
+ pure: true,
15
+ fn: function(text: any) {
16
+ return encodeURIComponent(text)
17
+ }
18
+ },
19
+ 'URLデコード': { // @URLデコードして返す // @URLでこーど
20
+ type: 'func',
21
+ josi: [['を', 'へ', 'に']],
22
+ pure: true,
23
+ fn: function(text: any) {
24
+ return decodeURIComponent(text)
25
+ }
26
+ },
27
+ 'URLパラメータ解析': { // @URLパラメータを解析してハッシュで返す // @URLぱらめーたかいせき
28
+ type: 'func',
29
+ josi: [['を', 'の', 'から']],
30
+ pure: true,
31
+ fn: function(url: string, sys: any) {
32
+ const res: any = {}
33
+ if (typeof url !== 'string') {
34
+ return res
35
+ }
36
+ const p = url.split('?')
37
+ if (p.length <= 1) {
38
+ return res
39
+ }
40
+ const params = p[1].split('&')
41
+ for (const line of params) {
42
+ if (line === '') { continue }
43
+ const eqIdx = line.indexOf('=')
44
+ let k: string
45
+ let v: string
46
+ if (eqIdx < 0) {
47
+ k = line
48
+ v = ''
49
+ } else {
50
+ k = line.substring(0, eqIdx)
51
+ v = line.substring(eqIdx + 1)
52
+ }
53
+ const decodedKey = sys.__exec('URLデコード', [k])
54
+ const decodedVal = sys.__exec('URLデコード', [v])
55
+ res[decodedKey] = decodedVal
56
+ }
57
+ return res
58
+ }
59
+ },
60
+
61
+ // @BASE64
62
+ 'BASE64エンコード': { // @BASE64エンコードして返す // @BASE64えんこーど
63
+ type: 'func',
64
+ josi: [['を', 'から']],
65
+ pure: true,
66
+ fn: function(text: any) {
67
+ // browser?
68
+ if (typeof (window) !== 'undefined' && (window as any).btoa) {
69
+ const u8a: any = new TextEncoder().encode(text)
70
+ const utf8str = String.fromCharCode.apply(null, u8a)
71
+ return btoa(utf8str)
72
+ }
73
+ // Node?
74
+ if (typeof (Buffer) !== 'undefined') {
75
+ return Buffer.from(text).toString('base64')
76
+ }
77
+ throw new Error('『BASE64エンコード』は利用できません。')
78
+ }
79
+ },
80
+ 'BASE64デコード': { // @BASE64デコードして返す // @BASE64でこーど
81
+ type: 'func',
82
+ josi: [['を', 'へ', 'に']],
83
+ pure: true,
84
+ fn: function(text: any) {
85
+ if (typeof (window) !== 'undefined' && (window as any).atob) {
86
+ const decodedUtf8str = atob(text)
87
+ const dec: any = Array.prototype.map.call(decodedUtf8str, c => c.charCodeAt())
88
+ const decodedArray = new Uint8Array(dec)
89
+ return new TextDecoder('UTF-8').decode(decodedArray)
90
+ }
91
+ // Node?
92
+ if (typeof (Buffer) !== 'undefined') {
93
+ return Buffer.from(text, 'base64').toString()
94
+ }
95
+ throw new Error('『BASE64デコード』は利用できません。')
96
+ }
97
+ },
98
+
99
+ // @パス操作
100
+ '拡張子抽出': { // @ファイル名Sから拡張子を抽出する // @かくちょうしちゅうしゅつ
101
+ type: 'func',
102
+ josi: [['から', 'の']],
103
+ pure: true,
104
+ fn: function(fname: string, sys: NakoSystem) {
105
+ if (fname === null || fname === undefined) { return '' }
106
+ const sep = sys.pathSeparator || '/'
107
+ if (fname.indexOf(sep) >= 0) { // パス記号があればファイル名を抽出
108
+ const parts = fname.split(sep)
109
+ fname = parts[parts.length - 1]
110
+ }
111
+ const m = fname.match(/(\.[a-zA-Z0-9_\-+]+)$/)
112
+ if (m) { return m[1] }
113
+ return ''
114
+ }
115
+ },
116
+ '拡張子変更': { // @ファイル名Aの拡張子をBに変更して返す // @かくちょうしへんこう
117
+ type: 'func',
118
+ josi: [['の', 'を', 'から'], ['に', 'へ']],
119
+ pure: true,
120
+ fn: function(fname: string, ext: string, sys: NakoSystem) {
121
+ if (fname === null || fname === undefined) { return ext }
122
+ const sep = sys.pathSeparator || '/'
123
+ const pathList = fname.split(sep)
124
+ const filename = pathList[pathList.length - 1]
125
+ const pathStr = pathList.slice(0, -1).join(sep)
126
+ const rawExt = (ext ?? '').trim()
127
+ let extWithDot = rawExt
128
+ if (rawExt !== '' ) {
129
+ extWithDot = rawExt.startsWith('.') ? rawExt : '.' + rawExt
130
+ }
131
+ const newFilename = filename.replace(/(\.[a-zA-Z0-9_\-+]+)?$/, extWithDot)
132
+ return sys.__exec('終端パス追加', [pathStr, sys]) + newFilename
133
+ }
134
+ },
135
+ '終端パス追加': { // @パスSの終端にパス区切り文字を追加して返す // @しゅうたんぱすついか
136
+ type: 'func',
137
+ josi: [['に', 'へ']],
138
+ pure: true,
139
+ fn: function(path: string, sys: NakoSystem) {
140
+ const sep = sys.pathSeparator || '/'
141
+ if (path === undefined || path === null || path === '') {
142
+ return ''
143
+ }
144
+ if (path.endsWith(sep)) {
145
+ return path
146
+ }
147
+ return path + sep
148
+ }
149
+ },
150
+ '終端パス除去': { // @フォルダ名DIRの末尾にあるパス記号を削除する // @しゅうたんぱすじょきょ
151
+ type: 'func',
152
+ josi: [['の', 'から']],
153
+ pure: true,
154
+ fn: function(dir: string, sys: NakoSystem) {
155
+ const sep = sys.pathSeparator || '/'
156
+ if (!dir) { return '' }
157
+ if (dir.endsWith(sep)) {
158
+ return dir.substring(0, dir.length - 1)
159
+ } else {
160
+ return dir
161
+ }
162
+ }
163
+ },
164
+ '終端パス削除': { // @フォルダ名DIRの末尾にあるパス記号を削除する // @しゅうたんぱすさくじょ
165
+ type: 'func',
166
+ josi: [['の', 'から']],
167
+ pure: true,
168
+ fn: function(dir: string, sys: NakoSystem) {
169
+ return sys.__exec('終端パス除去', [dir, sys])
170
+ }
171
+ },
172
+ 'ファイル名抽出': { // @パスPATHからファイル名を抽出して返す // @ふぁいるめいちゅうしゅつ
173
+ type: 'func',
174
+ josi: [['の', 'から']],
175
+ pure: true,
176
+ fn: function(dir: string, sys: NakoSystem) {
177
+ const sep = sys.pathSeparator || '/'
178
+ const parts = dir.split(sep)
179
+ return parts[parts.length - 1]
180
+ }
181
+ },
182
+ 'パス抽出': { // @パスPATHからディレクトリ部分を抽出して返す // @ぱすちゅうしゅつ
183
+ type: 'func',
184
+ josi: [['の', 'から']],
185
+ pure: true,
186
+ fn: function(dir: string, sys: NakoSystem) {
187
+ const sep = sys.pathSeparator || '/'
188
+ const parts = dir.split(sep)
189
+ parts.pop()
190
+ return parts.join(sep)
191
+ }
192
+ }
193
+ }
@@ -16,7 +16,7 @@ const PluginTOML = {
16
16
  type: 'func',
17
17
  josi: [],
18
18
  pure: true,
19
- fn: function(sys: any) {
19
+ fn: function(_sys: any) {
20
20
  }
21
21
  },
22
22
  // @TOML
@@ -24,7 +24,7 @@ const PluginTOML = {
24
24
  type: 'func',
25
25
  josi: [['を', 'の', 'から']],
26
26
  pure: true,
27
- fn: function(s: string, sys: any) {
27
+ fn: function(s: string, _sys: any) {
28
28
  return TOML.parse(s)
29
29
  }
30
30
  },
@@ -32,7 +32,7 @@ const PluginTOML = {
32
32
  type: 'func',
33
33
  josi: [['を', 'から', 'の']],
34
34
  pure: true,
35
- fn: function(s: any, sys: any) {
35
+ fn: function(s: any, _sys: any) {
36
36
  return TOML.stringify(s)
37
37
  }
38
38
  }
@@ -0,0 +1,58 @@
1
+ import { describe, it } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+ import fs from 'node:fs/promises'
4
+ import path from 'node:path'
5
+ import { fileURLToPath } from 'node:url'
6
+ import { runAlgorithmTest } from './algorithms/helper.mjs'
7
+
8
+ const testRoot = path.dirname(fileURLToPath(import.meta.url))
9
+ const casesRoot = path.join(testRoot, 'algorithms')
10
+ const sampleRoot = path.resolve(testRoot, '../sample/algorithms')
11
+
12
+ async function findFiles (dir, suffix) {
13
+ const entries = await fs.readdir(dir, { withFileTypes: true })
14
+ const files = []
15
+ for (const entry of entries) {
16
+ const entryPath = path.join(dir, entry.name)
17
+ if (entry.isDirectory()) {
18
+ files.push(...await findFiles(entryPath, suffix))
19
+ } else if (entry.name.endsWith(suffix)) {
20
+ files.push(entryPath)
21
+ }
22
+ }
23
+ return files.sort()
24
+ }
25
+
26
+ function relativePath (base, target) {
27
+ return path.relative(base, target).split(path.sep).join('/')
28
+ }
29
+
30
+ const testFiles = await findFiles(casesRoot, '_test.nako3')
31
+ const tests = testFiles.map(testPath => {
32
+ const relativeTest = relativePath(casesRoot, testPath)
33
+ return {
34
+ id: relativeTest.replace(/_test\.nako3$/, ''),
35
+ source: relativeTest.replace(/_test\.nako3$/, '.nako3'),
36
+ testPath
37
+ }
38
+ })
39
+
40
+ describe('アルゴリズムサンプル', () => {
41
+ it('全ての実装とテスト定義が1対1で対応している', async () => {
42
+ const sampleFiles = await findFiles(sampleRoot, '.nako3')
43
+ const sampleSources = sampleFiles.map(file => relativePath(sampleRoot, file))
44
+ const registeredSources = tests.map(test => test.source).sort()
45
+ const ids = tests.map(test => test.id)
46
+
47
+ assert.strictEqual(new Set(ids).size, ids.length, 'アルゴリズムIDが重複しています')
48
+ assert.strictEqual(new Set(registeredSources).size, registeredSources.length, '実装ファイルが重複登録されています')
49
+ assert.deepStrictEqual(registeredSources, sampleSources)
50
+ })
51
+
52
+ for (const test of tests) {
53
+ it(test.id, async () => {
54
+ const log = await runAlgorithmTest(sampleRoot, test.source, test.testPath)
55
+ assert.strictEqual(log, '')
56
+ })
57
+ }
58
+ })
@@ -0,0 +1,21 @@
1
+ # ダイクストラ法のテスト
2
+
3
+ G=[
4
+ [{"先":1,"重み":4},{"先":2,"重み":1}],
5
+ [{"先":3,"重み":1}],
6
+ [{"先":1,"重み":2},{"先":3,"重み":5}],
7
+ []
8
+ ]
9
+ 実際はGを0からダイクストラ法処理してJSONエンコード
10
+ 実際と『[0,3,1,4]』がASSERT等
11
+
12
+ G=[
13
+ [{"先":1,"重み":2}],
14
+ [],
15
+ []
16
+ ]
17
+ 実際はGを0からダイクストラ法処理してJSONエンコード
18
+ 実際と『[0,2,-1]』がASSERT等
19
+
20
+ 実際はGを4からダイクストラ法処理してJSONエンコード
21
+ 実際と『[]』がASSERT等
@@ -0,0 +1,21 @@
1
+ # クラスカル法のテスト
2
+
3
+ E=[
4
+ {"始":0,"終":1,"重み":10},
5
+ {"始":0,"終":2,"重み":6},
6
+ {"始":0,"終":3,"重み":5},
7
+ {"始":1,"終":3,"重み":15},
8
+ {"始":2,"終":3,"重み":4}
9
+ ]
10
+ 実際は4とEでクラスカル法処理してJSONエンコード
11
+ 実際と『[{"始":2,"終":3,"重み":4},{"始":0,"終":3,"重み":5},{"始":0,"終":1,"重み":10}]』がASSERT等
12
+
13
+ E=[
14
+ {"始":0,"終":1,"重み":1},
15
+ {"始":2,"終":3,"重み":2}
16
+ ]
17
+ 実際は4とEでクラスカル法処理してJSONエンコード
18
+ 実際と『[{"始":0,"終":1,"重み":1},{"始":2,"終":3,"重み":2}]』がASSERT等
19
+
20
+ 実際は0と[]でクラスカル法処理してJSONエンコード
21
+ 実際と『[]』がASSERT等
@@ -0,0 +1,13 @@
1
+ import fs from 'node:fs/promises'
2
+ import path from 'node:path'
3
+ import { NakoCompiler } from '../../src/nako3.mjs'
4
+
5
+ export async function runAlgorithmTest (sampleRoot, source, testPath) {
6
+ const sourcePath = path.resolve(sampleRoot, source)
7
+ const sourceCode = await fs.readFile(sourcePath, 'utf8')
8
+ const test = await fs.readFile(testPath, 'utf8')
9
+ const code = `${sourceCode}\n${test}\n`
10
+ const compiler = new NakoCompiler()
11
+ const result = await compiler.runAsync(code, testPath)
12
+ return result.log
13
+ }
@@ -0,0 +1,13 @@
1
+ # ユークリッドの互除法のテスト
2
+
3
+ 実際は1071と462の最大公約数計算処理
4
+ 実際と21がASSERT等
5
+
6
+ 実際は24と0の最大公約数計算処理
7
+ 実際と24がASSERT等
8
+
9
+ 実際は0と0の最大公約数計算処理
10
+ 実際と0がASSERT等
11
+
12
+ 実際は-54と24の最大公約数計算処理
13
+ 実際と6がASSERT等
@@ -0,0 +1,10 @@
1
+ # エラトステネスの篩のテスト
2
+
3
+ 実際は30までの素数列挙処理してJSONエンコード
4
+ 実際と『[2,3,5,7,11,13,17,19,23,29]』がASSERT等
5
+
6
+ 実際は2までの素数列挙処理してJSONエンコード
7
+ 実際と『[2]』がASSERT等
8
+
9
+ 実際は1までの素数列挙処理してJSONエンコード
10
+ 実際と『[]』がASSERT等
@@ -0,0 +1,15 @@
1
+ # 二分探索処理のテスト
2
+
3
+ A=[1,3,5,7,9]
4
+ 実際はAから5を二分探索処理
5
+ 実際と2がASSERT等
6
+
7
+ 実際はAから9を二分探索処理
8
+ 実際と4がASSERT等
9
+
10
+ 実際はAから4を二分探索処理
11
+ 実際と-1がASSERT等
12
+
13
+ A=[]
14
+ 実際はAから1を二分探索処理
15
+ 実際と-1がASSERT等