nadesiko3 3.3.45 → 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 (329) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +143 -132
  3. package/batch/browsers.template.md +3 -3
  4. package/batch/build_browsers.nako3 +72 -72
  5. package/batch/build_command.nako3 +44 -44
  6. package/batch/build_nako_version.nako3 +42 -42
  7. package/batch/calc_hash.nako3 +29 -29
  8. package/batch/cmd_txt2json.nako3 +74 -74
  9. package/batch/command.txt +270 -338
  10. package/batch/command_nakopad.txt +9 -69
  11. package/batch/download-extlib.nako3 +43 -43
  12. package/batch/gen_command_nakopad.nako3 +57 -57
  13. package/batch/jsplugin2text.nako3 +285 -285
  14. package/batch/pickup_command.nako3 +110 -110
  15. package/batch/pickup_reserved_words.nako3 +11 -11
  16. package/batch/publish_version.nako3 +46 -46
  17. package/batch/show_agents.js +14 -14
  18. package/batch/turtle2js.nako3 +21 -21
  19. package/bin/cnako3 +10 -10
  20. package/core/.editorconfig +6 -0
  21. package/core/.eslintrc.cjs +33 -0
  22. package/core/.github/dependabot.yml +7 -0
  23. package/core/.github/workflows/nodejs.yml +37 -0
  24. package/core/.github/workflows/super-linter.yml +61 -0
  25. package/core/.github/workflows/textlint.yml +199 -0
  26. package/core/LICENSE +21 -0
  27. package/core/README.md +66 -0
  28. package/core/batch/build_nako_version.nako3 +42 -0
  29. package/core/command/snako.mjs +105 -0
  30. package/core/command/snako.mts +116 -0
  31. package/core/index.mjs +21 -0
  32. package/core/index.mts +21 -0
  33. package/core/package.json +47 -0
  34. package/core/sample/hello.nako3 +7 -0
  35. package/core/sample/hoge.mjs +4 -0
  36. package/core/sample/hoge.mts +6 -0
  37. package/core/src/nako3.mjs +858 -0
  38. package/core/src/nako3.mts +967 -0
  39. package/core/src/nako_colors.mjs +78 -0
  40. package/core/src/nako_colors.mts +86 -0
  41. package/core/src/nako_core_version.mjs +8 -0
  42. package/core/src/nako_core_version.mts +19 -0
  43. package/core/src/nako_csv.mjs +185 -0
  44. package/core/src/nako_csv.mts +188 -0
  45. package/core/src/nako_errors.mjs +173 -0
  46. package/core/src/nako_errors.mts +197 -0
  47. package/core/src/nako_from_dncl.mjs +255 -0
  48. package/core/src/nako_from_dncl.mts +250 -0
  49. package/core/src/nako_gen.mjs +1648 -0
  50. package/core/src/nako_gen.mts +1719 -0
  51. package/core/src/nako_gen_async.mjs +1659 -0
  52. package/core/src/nako_gen_async.mts +1732 -0
  53. package/core/src/nako_global.mjs +107 -0
  54. package/core/src/nako_global.mts +138 -0
  55. package/core/src/nako_indent.mjs +445 -0
  56. package/core/src/nako_indent.mts +492 -0
  57. package/core/src/nako_josi_list.mjs +38 -0
  58. package/core/src/nako_josi_list.mts +45 -0
  59. package/core/src/nako_lex_rules.mjs +253 -0
  60. package/core/src/nako_lex_rules.mts +260 -0
  61. package/core/src/nako_lexer.mjs +609 -0
  62. package/core/src/nako_lexer.mts +612 -0
  63. package/core/src/nako_logger.mjs +199 -0
  64. package/core/src/nako_logger.mts +232 -0
  65. package/core/src/nako_parser3.mjs +2439 -0
  66. package/core/src/nako_parser3.mts +2195 -0
  67. package/core/src/nako_parser_base.mjs +370 -0
  68. package/core/src/nako_parser_base.mts +370 -0
  69. package/core/src/nako_parser_const.mjs +37 -0
  70. package/core/src/nako_parser_const.mts +37 -0
  71. package/core/src/nako_prepare.mjs +304 -0
  72. package/core/src/nako_prepare.mts +315 -0
  73. package/core/src/nako_reserved_words.mjs +38 -0
  74. package/core/src/nako_reserved_words.mts +38 -0
  75. package/core/src/nako_source_mapping.mjs +207 -0
  76. package/core/src/nako_source_mapping.mts +262 -0
  77. package/core/src/nako_test.mjs +37 -0
  78. package/core/src/nako_types.mjs +25 -0
  79. package/core/src/nako_types.mts +151 -0
  80. package/core/src/plugin_csv.mjs +49 -0
  81. package/core/src/plugin_csv.mts +50 -0
  82. package/core/src/plugin_math.mjs +328 -0
  83. package/core/src/plugin_math.mts +326 -0
  84. package/core/src/plugin_promise.mjs +91 -0
  85. package/core/src/plugin_promise.mts +91 -0
  86. package/core/src/plugin_system.mjs +2832 -0
  87. package/core/src/plugin_system.mts +2690 -0
  88. package/core/src/plugin_test.mjs +34 -0
  89. package/core/src/plugin_test.mts +34 -0
  90. package/core/test/array_test.mjs +34 -0
  91. package/core/test/basic_test.mjs +344 -0
  92. package/core/test/calc_test.mjs +140 -0
  93. package/core/test/core_module_test.mjs +23 -0
  94. package/core/test/debug_test.mjs +16 -0
  95. package/core/test/dncl_test.mjs +94 -0
  96. package/core/test/error_message_test.mjs +210 -0
  97. package/core/test/error_test.mjs +16 -0
  98. package/core/test/flow_test.mjs +373 -0
  99. package/core/test/func_call.mjs +160 -0
  100. package/core/test/func_test.mjs +149 -0
  101. package/core/test/indent_test.mjs +364 -0
  102. package/core/test/lex_test.mjs +168 -0
  103. package/core/test/literal_test.mjs +73 -0
  104. package/core/test/nako_lexer_test.mjs +35 -0
  105. package/core/test/nako_logger_test.mjs +76 -0
  106. package/core/test/nako_logger_test.mts +78 -0
  107. package/core/test/plugin_csv_test.mjs +38 -0
  108. package/core/test/plugin_promise_test.mjs +18 -0
  109. package/core/test/plugin_system_test.mjs +630 -0
  110. package/core/test/prepare_test.mjs +96 -0
  111. package/core/test/re_test.mjs +22 -0
  112. package/core/test/side_effects_test.mjs +92 -0
  113. package/core/test/variable_scope_test.mjs +149 -0
  114. package/core/tsconfig.json +101 -0
  115. package/demo/ace_editor.html +89 -89
  116. package/demo/ace_editor_tabs.html +161 -161
  117. package/demo/basic.html +71 -71
  118. package/demo/browsers.html +9 -10
  119. package/demo/css/basic.css +3 -3
  120. package/demo/css/common.css +157 -157
  121. package/demo/css/editor.css +8 -8
  122. package/demo/css/flow.css +3 -3
  123. package/demo/css/index.css +3 -3
  124. package/demo/flow.html +98 -98
  125. package/demo/graph.html +53 -53
  126. package/demo/image/nakopad-icon256.png +0 -0
  127. package/demo/index.html +133 -133
  128. package/demo/js/common.js +17 -17
  129. package/demo/js/turtle3d_test.js +44 -44
  130. package/demo/js/turtle_test.js +45 -45
  131. package/demo/nako3/calc.nako3 +4 -4
  132. package/demo/runscript.html +47 -47
  133. package/demo/runscript2.html +33 -33
  134. package/demo/runscript3.html +35 -35
  135. package/demo/runscript4.html +33 -33
  136. package/demo/turtle.html +58 -58
  137. package/demo/turtle2.html +141 -141
  138. package/demo/turtle3.html +279 -279
  139. package/demo/turtle3d.html +58 -58
  140. package/demo/turtle3d2.html +107 -107
  141. package/demo/version.html +24 -24
  142. package/doc/SETUP.md +157 -157
  143. package/doc/about.md +17 -17
  144. package/doc/browsers.md +26 -26
  145. package/doc/docgen.md +21 -21
  146. package/doc/editor.md +44 -44
  147. package/doc/files.md +39 -39
  148. package/doc/plugins.md +234 -234
  149. package/doc/release.md +79 -79
  150. package/doc/textlint.md +43 -43
  151. package/doc/win32.md +57 -57
  152. package/package.json +195 -192
  153. package/release/_hash.txt +28 -28
  154. package/release/_script-tags.txt +14 -14
  155. package/release/command.json +1 -1
  156. package/release/command.json.js +1 -1
  157. package/release/command_cnako3.json +1 -1
  158. package/release/command_list.json +1 -1
  159. package/release/editor.js +1 -1
  160. package/release/nako_gen_async.js +1 -1
  161. package/release/plugin_csv.js +1 -1
  162. package/release/stats.json +1 -1
  163. package/release/version.js +1 -1
  164. package/release/wnako3.js +1 -1
  165. package/release/wnako3webworker.js +1 -1
  166. package/src/browsers.txt +11 -12
  167. package/src/browsers_agents.json +2 -2
  168. package/src/browsers_agents.mjs +1 -1
  169. package/src/cnako3.mjs +17 -10
  170. package/src/cnako3.mts +18 -12
  171. package/src/cnako3mod.mjs +707 -687
  172. package/src/cnako3mod.mts +712 -696
  173. package/src/commander_ja.mjs +164 -164
  174. package/src/commander_ja.mts +161 -161
  175. package/src/enako3.mjs +68 -69
  176. package/src/era.mjs +22 -22
  177. package/src/image_turtle-elephant.mjs +2 -5
  178. package/src/image_turtle-panda.mjs +2 -5
  179. package/src/image_turtle64.mjs +2 -5
  180. package/src/index.mjs +9 -9
  181. package/src/index.mts +10 -11
  182. package/src/nako3editorfix.sfd +106 -106
  183. package/src/nako_version.mjs +8 -8
  184. package/src/nako_version.mts +2 -2
  185. package/src/plugin_browser.mjs +213 -212
  186. package/src/plugin_browser.mts +206 -205
  187. package/src/plugin_browser_ajax.mjs +399 -399
  188. package/src/plugin_browser_audio.mjs +109 -109
  189. package/src/plugin_browser_canvas.mjs +449 -449
  190. package/src/plugin_browser_chart.mjs +294 -294
  191. package/src/plugin_browser_color.mjs +49 -49
  192. package/src/plugin_browser_crypto.mjs +26 -26
  193. package/src/plugin_browser_dialog.mjs +53 -53
  194. package/src/plugin_browser_dom_basic.mjs +336 -336
  195. package/src/plugin_browser_dom_event.mjs +193 -193
  196. package/src/plugin_browser_dom_parts.mjs +396 -396
  197. package/src/plugin_browser_geolocation.mjs +51 -51
  198. package/src/plugin_browser_hotkey.mjs +25 -25
  199. package/src/plugin_browser_html.mjs +59 -59
  200. package/src/plugin_browser_in_worker.mjs +45 -45
  201. package/src/plugin_browser_location.mjs +21 -21
  202. package/src/plugin_browser_speech.mjs +111 -111
  203. package/src/plugin_browser_storage.mjs +121 -121
  204. package/src/plugin_browser_system.mjs +31 -31
  205. package/src/plugin_browser_websocket.mjs +73 -73
  206. package/src/plugin_caniuse.mjs +29 -29
  207. package/src/plugin_datetime.mjs +394 -394
  208. package/src/plugin_httpserver.mjs +277 -0
  209. package/src/plugin_httpserver.mts +286 -0
  210. package/src/plugin_kansuji.mjs +224 -224
  211. package/src/plugin_keigo.mjs +55 -55
  212. package/src/plugin_markup.mjs +32 -32
  213. package/src/plugin_node.mjs +1047 -1047
  214. package/src/plugin_node.mts +980 -980
  215. package/src/plugin_turtle.mjs +647 -647
  216. package/src/plugin_webworker.mjs +334 -334
  217. package/src/plugin_weykturtle3d.mjs +1214 -1214
  218. package/src/plugin_worker.mjs +95 -95
  219. package/src/repl.nako3 +63 -63
  220. package/src/wnako3.mjs +12 -12
  221. package/src/wnako3.mts +11 -11
  222. package/src/wnako3_editor.css +215 -215
  223. package/src/wnako3_editor.mjs +1542 -1542
  224. package/src/wnako3_editor.mts +1657 -1656
  225. package/src/wnako3mod.mjs +213 -213
  226. package/src/wnako3mod.mts +214 -214
  227. package/src/wnako3webworker.mjs +69 -68
  228. package/test/ace_editor/karma.config.js +94 -94
  229. package/test/ace_editor/test/.babelrc.json +3 -3
  230. package/test/ace_editor/test/ace_editor_test.js +178 -178
  231. package/test/ace_editor/test/html/custom_context.html +139 -139
  232. package/test/async/async_basic_test.mjs +122 -122
  233. package/test/browser/karma.config.js +221 -221
  234. package/test/browser/test/.babelrc.json +3 -3
  235. package/test/browser/test/compare_util.js +50 -50
  236. package/test/browser/test/html/div_basic.html +2 -2
  237. package/test/browser/test/html/event_dom_form.html +4 -4
  238. package/test/browser/test/html/event_dom_scrolldiv.html +5 -5
  239. package/test/browser/test/import_plugin_checker.js +24 -24
  240. package/test/browser/test/plugin_browser_test.js +51 -51
  241. package/test/browser/test/plugin_browser_test_ajax.js +123 -123
  242. package/test/browser/test/plugin_browser_test_color.js +18 -18
  243. package/test/browser/test/plugin_browser_test_dialog.js +72 -72
  244. package/test/browser/test/plugin_browser_test_dom_event.js +598 -598
  245. package/test/browser/test/plugin_browser_test_dom_parts.js +125 -125
  246. package/test/browser/test/plugin_browser_test_system.js +9 -9
  247. package/test/browser/test/plugin_turtle_test.js +817 -817
  248. package/test/browser/test/plugin_webworker_test.js +86 -86
  249. package/test/browser/test/require_test.js +68 -68
  250. package/test/bundled/karma.config.base.js +117 -117
  251. package/test/bundled/karma.config.js +86 -86
  252. package/test/bundled/test/.babelrc.json +3 -3
  253. package/test/bundled/test/bundled_test.js +69 -69
  254. package/test/bundled/test/html/custom_context.html +65 -65
  255. package/test/bundled/test/html/custom_debug.html +66 -66
  256. package/test/bundled/test4b.cmd +52 -52
  257. package/test/bundled/test_base/.babelrc.json +3 -3
  258. package/test/bundled/test_base/_checktool_test.js +25 -25
  259. package/test/bundled/test_base/basic_ajax_test.js +56 -56
  260. package/test/bundled/test_base/basic_async_test.js +18 -18
  261. package/test/bundled/test_base/basic_test.js +153 -153
  262. package/test/bundled/test_base/calc_test.js +132 -132
  263. package/test/bundled/test_base/css/browsers_box.css +114 -114
  264. package/test/bundled/test_base/html/custom_context.html +69 -69
  265. package/test/bundled/test_base/html/custom_debug.html +71 -71
  266. package/test/bundled/test_base/js/browsers_box.js +72 -72
  267. package/test/bundled/test_base/plugin_csv_test.js +37 -37
  268. package/test/bundled/test_base/plugin_datetime_test.js +115 -115
  269. package/test/bundled/test_base/plugin_kansuji_test.js +49 -49
  270. package/test/bundled/test_base/plugin_system_test.js +410 -410
  271. package/test/bundled/test_base/plugin_webworker_test.js +53 -53
  272. package/test/bundled/test_base/test_utils.js +191 -191
  273. package/test/common/plugin_browser_test.mjs +22 -24
  274. package/test/common/plugin_browser_ut_audio_test.mjs +108 -108
  275. package/test/common/plugin_browser_ut_color_test.mjs +21 -21
  276. package/test/common/plugin_browser_ut_dialog_test.mjs +100 -100
  277. package/test/common/plugin_browser_ut_html_test.mjs +13 -13
  278. package/test/common/plugin_browser_ut_system_test.mjs +10 -10
  279. package/test/common/plugin_markup_test.mjs +23 -23
  280. package/test/jsconfig.json +19 -19
  281. package/test/karma.config.js +91 -91
  282. package/test/node/async_test.mjs +96 -82
  283. package/test/node/commander_ja_test.mjs +89 -89
  284. package/test/node/error_message_test.mjs +243 -253
  285. package/test/node/kai_test.nako3 +6 -6
  286. package/test/node/node_test.mjs +60 -60
  287. package/test/node/plugin_broken.js.txt +3 -3
  288. package/test/node/plugin_browser_ut_ajax_test.mjs.todo +357 -357
  289. package/test/node/plugin_browser_ut_location_test.mjs +42 -42
  290. package/test/node/plugin_markup_test.mjs +47 -46
  291. package/test/node/plugin_math_test.mjs +45 -44
  292. package/test/node/plugin_node_test.mjs +98 -97
  293. package/test/node/plugin_test.mjs +44 -43
  294. package/test/node/relative_import_test_1.nako3 +1 -1
  295. package/test/node/relative_import_test_2.nako3 +2 -2
  296. package/test/node/require_nako3_test.mjs +67 -66
  297. package/test/node/requiretest.nako3 +4 -4
  298. package/test/node/requiretest_indirect.nako3 +1 -1
  299. package/test/node/requiretest_name.nako3 +5 -5
  300. package/test/node/runtime_error.nako3 +2 -2
  301. package/test/node/scope1.nako3 +10 -10
  302. package/test/node/scope2.nako3 +12 -12
  303. package/test/node/side_effects_test.mjs +39 -119
  304. package/test/node/sjis.txt +5 -5
  305. package/test/node/syntax_error.nako3 +1 -1
  306. package/test/node/wnako3_editor_test.mjs +384 -384
  307. package/tools/README.md +12 -7
  308. package/tools/check_new_version.nako3 +25 -25
  309. package/tools/nako3edit/html/daisyui/LICENSE +22 -22
  310. package/tools/nako3edit/html/daisyui/version_2.14.1 +1 -1
  311. package/tools/nako3edit/html/edit.html +170 -170
  312. package/tools/nako3edit/html/edit_plugin.js +6 -6
  313. package/tools/nako3edit/html/files.html +125 -125
  314. package/tools/nako3edit/html/nako3edit.css +65 -65
  315. package/tools/nako3edit/index.mjs +248 -244
  316. package/tools/nako3server/index.html +10 -0
  317. package/tools/nako3server/index.mjs +116 -116
  318. package/tools/nako3server/index.nako3 +34 -0
  319. package/release/nako_gen_async.js.LICENSE.txt +0 -35
  320. package/release/plugin_caniuse.js.LICENSE.txt +0 -11
  321. package/release/plugin_csv.js.LICENSE.txt +0 -15
  322. package/release/plugin_datetime.js.LICENSE.txt +0 -15
  323. package/release/plugin_kansuji.js.LICENSE.txt +0 -3
  324. package/release/plugin_markup.js.LICENSE.txt +0 -11
  325. package/release/plugin_turtle.js.LICENSE.txt +0 -15
  326. package/release/plugin_webworker.js.LICENSE.txt +0 -3
  327. package/release/plugin_weykturtle3d.js.LICENSE.txt +0 -3
  328. package/release/wnako3webworker.js.LICENSE.txt +0 -131
  329. package/tools/nako3edit/a.sqlite3 +0 -0
package/src/cnako3mod.mts CHANGED
@@ -1,696 +1,712 @@
1
- /**
2
- * コマンドライン版のなでしこ3をモジュールとして定義
3
- * 実際には cnako3.mjs から読み込まれる
4
- */
5
- import fs from 'fs'
6
- import fse from 'fs-extra'
7
- import { exec } from 'child_process'
8
- import path from 'path'
9
-
10
- import { NakoCompiler, LoaderTool, LoaderToolTask } from 'nadesiko3core/src/nako3.mjs'
11
- import { NakoImportError } from 'nadesiko3core/src/nako_errors.mjs'
12
-
13
- import { Ast } from 'nadesiko3core/src/nako_types.mjs'
14
- import { NakoGlobal } from 'nadesiko3core/src/nako_global.mjs'
15
- import nakoVersion from './nako_version.mjs'
16
-
17
- import PluginNode from './plugin_node.mjs'
18
- import app from './commander_ja.mjs'
19
- import fetch from 'node-fetch'
20
-
21
- import { NakoGenOptions } from 'nadesiko3core/src/nako_gen.mjs'
22
-
23
- // __dirname のために
24
- import url from 'url'
25
- const __filename = url.fileURLToPath(import.meta.url)
26
- const __dirname = path.dirname(__filename)
27
-
28
- /** コマンドラインアクション */
29
- interface CNako3ArgOptions {
30
- warn: boolean
31
- debug: boolean
32
- compile: any | boolean
33
- test: any | boolean
34
- one_liner: any | boolean
35
- trace: any | boolean
36
- run: any | boolean
37
- repl: any | boolean
38
- source: any | string
39
- mainfile: any | string
40
- man: string
41
- browsers: boolean
42
- ast: boolean
43
- }
44
-
45
- interface CNako3Options {
46
- nostd: boolean
47
- }
48
-
49
- /** CNako3 */
50
- export class CNako3 extends NakoCompiler {
51
- debug: boolean
52
- filename: string
53
- version: string
54
-
55
- constructor (opts:CNako3Options = { nostd: false }) {
56
- super({ useBasicPlugin: !opts.nostd })
57
- this.debug = false
58
- this.filename = 'main.nako3'
59
- this.version = nakoVersion.version
60
- if (!opts.nostd) {
61
- this.addPluginFile('PluginNode', path.join(__dirname, 'plugin_node.mjs'), PluginNode)
62
- }
63
- // 必要な定数を設定
64
- this.addListener('beforeRun', (g: NakoGlobal) => {
65
- g.__varslist[0]['ナデシコ種類'] = 'cnako3'
66
- g.__varslist[0]['ナデシコバージョン'] = this.version
67
- })
68
- }
69
-
70
- // CNAKO3で使えるコマンドを登録する
71
- registerCommands () {
72
- // コマンド引数がないならば、ヘルプを表示(-hはcommandarにデフォルト用意されている)
73
- if (process.argv.length <= 2) { process.argv.push('-h') }
74
-
75
- const verInfo = `v${nakoVersion.version}`
76
- // commanderを使って引数を解析する
77
- app
78
- .title('日本語プログラミング言語「なでしこ」' + verInfo)
79
- .version(verInfo, '-v, --version')
80
- .usage('[オプション] 入力ファイル.nako3')
81
- .option('-h, --help', 'コマンドの使い方を表示')
82
- .option('-w, --warn', '警告を表示する')
83
- .option('-d, --debug', 'デバッグモードの指定')
84
- .option('-D, --trace', '詳細デバッグモードの指定')
85
- .option('-c, --compile', 'コンパイルモードの指定')
86
- .option('-t, --test', 'コンパイルモードの指定 (テスト用コードを出力)')
87
- .option('-r, --run', 'コンパイルモードでも実行する')
88
- .option('-e, --eval [src]', '直接プログラムを実行するワンライナーモード')
89
- .option('-o, --output', '出力ファイル名の指定')
90
- .option('-s, --silent', 'サイレントモードの指定')
91
- .option('-l, --repl', '対話シェル(REPL)の実行')
92
- .option('-b, --browsers', '対応機器/Webブラウザを表示する')
93
- .option('-m, --man [command]', 'マニュアルを表示する')
94
- .option('-p, --speed', 'スピード優先モードの指定')
95
- .option('-A, --ast', 'パースした結果をASTで出力する')
96
- // .option('-h, --help', '使い方を表示する')
97
- // .option('-v, --version', 'バージョンを表示する')
98
- .parse(process.argv)
99
- return app
100
- }
101
-
102
- /** コマンドライン引数を解析 */
103
- checkArguments (): CNako3ArgOptions {
104
- const app: any = this.registerCommands()
105
-
106
- let logLevel = 'error'
107
- if (app.trace) {
108
- logLevel = 'trace'
109
- } else if (app.debug) {
110
- logLevel = 'debug'
111
- } else if (app.warn) {
112
- logLevel = 'warn'
113
- }
114
- this.getLogger().addListener(logLevel, ({ level, nodeConsole }) => {
115
- console.log(nodeConsole)
116
- })
117
-
118
- const args: any = {
119
- compile: app.compile || false,
120
- run: app.run || false,
121
- source: app.eval || '',
122
- man: app.man || '',
123
- one_liner: app.eval || false,
124
- debug: this.debug || false,
125
- trace: app.trace,
126
- warn: app.warn,
127
- repl: app.repl || false,
128
- test: app.test || false,
129
- browsers: app.browsers || false,
130
- speed: app.speed || false,
131
- ast: app.ast || false
132
- }
133
- args.mainfile = app.args[0]
134
- args.output = app.output
135
-
136
- // todo: ESModule 対応の '.mjs' のコードを吐くように修正 #1217
137
- const ext = '.mjs'
138
- if (/\.(nako|nako3|txt|bak)$/.test(args.mainfile)) {
139
- if (!args.output) {
140
- if (args.test) {
141
- args.output = args.mainfile.replace(/\.(nako|nako3)$/, '.spec' + ext)
142
- } else {
143
- args.output = args.mainfile.replace(/\.(nako|nako3)$/, ext)
144
- }
145
- }
146
- } else {
147
- if (!args.output) {
148
- if (args.test) {
149
- args.output = args.mainfile + '.spec' + ext
150
- } else {
151
- args.output = args.mainfile + ext
152
- }
153
- }
154
- args.mainfile += '.nako3'
155
- }
156
- return args
157
- }
158
-
159
- // 実行する
160
- async execCommand () {
161
- // コマンドを解析
162
- const opt = this.checkArguments()
163
- // 使い方の表示か?
164
- if (opt.man) {
165
- this.cnakoMan(opt.man)
166
- return
167
- }
168
- // 対応ブラウザを表示する
169
- if (opt.browsers) {
170
- this.cnakoBrowsers()
171
- return
172
- }
173
- // REPLを実行する
174
- if (opt.repl) {
175
- this.cnakoRepl(opt)
176
- return
177
- }
178
- // ワンライナーで実行する
179
- if (opt.one_liner) {
180
- this.cnakoOneLiner(opt)
181
- return
182
- }
183
-
184
- // メインプログラムを読み込む
185
- this.filename = opt.mainfile
186
- const src = fs.readFileSync(opt.mainfile, 'utf-8')
187
- if (opt.compile) {
188
- await this.nakoCompile(opt, src, false)
189
- return
190
- }
191
-
192
- // ASTを出力する
193
- if (opt.ast) {
194
- try {
195
- await this.loadDependencies(src, opt.mainfile, '')
196
- } catch (e) {
197
- if (this.numFailures > 0) {
198
- process.exit(1)
199
- }
200
- }
201
- this.outputAST(opt, src)
202
- return
203
- }
204
-
205
- // テストを実行する
206
- if (opt.test) {
207
- try {
208
- await this.loadDependencies(src, opt.mainfile, '')
209
- this.test(src, opt.mainfile)
210
- return
211
- } catch (e) {
212
- if (this.numFailures > 0) {
213
- process.exit(1)
214
- }
215
- }
216
- }
217
-
218
- // ファイルを読んで実行する
219
- try {
220
- // コンパイルと実行を行うメソッド
221
- const g = await this.runAsync(src, opt.mainfile)
222
- return g
223
- } catch (e: any) {
224
- // 文法エラーなどがあった場合
225
- if (opt.debug || opt.trace) {
226
- throw e
227
- }
228
- }
229
- }
230
-
231
- /**
232
- * コンパイルモードの場合
233
- * @param opt
234
- * @param {string} src
235
- * @param {boolean} isTest
236
- */
237
- async nakoCompile (opt: any, src: string, isTest: boolean) {
238
- // 依存ライブラリなどを読み込む
239
- await this.loadDependencies(src, this.filename, '')
240
- // JSにコンパイル
241
- const genOpt = new NakoGenOptions(
242
- isTest,
243
- ['plugin_node.mjs'],
244
- 'self.__varslist[0][\'ナデシコ種類\']=\'cnako3\';'
245
- )
246
- const jscode = this.compileStandalone(src, this.filename, genOpt)
247
- console.log(opt.output)
248
- fs.writeFileSync(opt.output, jscode, 'utf-8')
249
-
250
- // 実行に必要なファイルをコピー
251
- const nakoRuntime = __dirname
252
- const outRuntime = path.join(path.dirname(opt.output), 'nako3runtime')
253
- if (!fs.existsSync(outRuntime)) { fs.mkdirSync(outRuntime) }
254
- // from ./src
255
- for (const mod of ['nako_version.mjs', 'plugin_node.mjs']) {
256
- fs.copyFileSync(path.join(nakoRuntime, mod), path.join(outRuntime, mod))
257
- }
258
- // from nadesiko3core/src
259
- const srcDir = path.join(__dirname, '..', 'node_modules', 'nadesiko3core', 'src')
260
- const baseFiles = ['nako_errors.mjs', 'nako_core_version.mjs',
261
- 'plugin_system.mjs', 'plugin_math.mjs', 'plugin_promise.mjs', 'plugin_test.mjs', 'plugin_csv.mjs', 'nako_csv.mjs']
262
- for (const mod of baseFiles) {
263
- fs.copyFileSync(path.join(srcDir, mod), path.join(outRuntime, mod))
264
- }
265
- // or 以下のコピーだと依存ファイルがコピーされない package.jsonを見てコピーする必要がある
266
- const orgModule = path.join(__dirname, '..', 'node_modules')
267
- const dirNodeModules = path.join(path.dirname(opt.output), 'node_modules')
268
- const modlist = ['fs-extra', 'iconv-lite', 'opener', 'node-fetch']
269
- const copied: { [key: string]: boolean } = {}
270
- // 再帰的に必要なモジュールをコピーする
271
- const copyModule = (mod: string) => {
272
- if (copied[mod]) { return }
273
- copied[mod] = true
274
- // ライブラリ自身をコピー
275
- fse.copySync(path.join(orgModule, mod), path.join(dirNodeModules, mod))
276
- // 依存ライブラリをコピー
277
- const packageFile = path.join(orgModule, mod, 'package.json')
278
- const jsonStr = fs.readFileSync(packageFile, 'utf-8')
279
- const jsonData = JSON.parse(jsonStr)
280
- // サブモジュールをコピー
281
- for (const smod in jsonData.dependencies) {
282
- copyModule(smod)
283
- }
284
- }
285
- for (const mod of modlist) {
286
- copyModule(mod)
287
- }
288
-
289
- if (opt.run) {
290
- exec(`node ${opt.output}`, function (err, stdout, stderr) {
291
- if (err) { console.log('[ERROR]', stderr) }
292
- console.log(stdout)
293
- })
294
- }
295
- }
296
-
297
- // ワンライナーの場合
298
- async cnakoOneLiner (opt: any) {
299
- const org = opt.source
300
- try {
301
- if (opt.source.indexOf('表示') < 0) {
302
- opt.source = '' + opt.source + 'を表示。'
303
- }
304
- await this.runAsync(opt.source, 'main.nako3')
305
- } catch (e) {
306
- // エラーになったら元のワンライナーで再挑戦
307
- try {
308
- if (opt.source !== org) {
309
- await this.runAsync(org, 'main.nako3')
310
- } else {
311
- throw e
312
- }
313
- } catch (e: any) {
314
- if (this.debug) {
315
- throw e
316
- } else {
317
- console.error(e.message)
318
- }
319
- }
320
- }
321
- }
322
-
323
- /**
324
- * ASTを出力
325
- * @param opt
326
- * @param {string} src
327
- */
328
- outputAST (opt: any, src: string) {
329
- const ast = this.parse(src, opt.mainfile)
330
- const makeIndent = (level: number) => {
331
- let s = ''
332
- for (let i = 0; i < level; i++) { s += ' ' }
333
- return s
334
- }
335
- const trim = (s: string) => { return s.replace(/(^\s+|\s+$)/g, '') }
336
- /**
337
- * AST文字列に変換して返す
338
- * @param {*} ast
339
- * @param {number} level
340
- * @return {string}
341
- */
342
- const outAST = (ast: Ast, level: number): string => {
343
- if (typeof (ast) === 'string') {
344
- return makeIndent(level) + '"' + ast + '"'
345
- }
346
- if (typeof (ast) === 'number') {
347
- return makeIndent(level) + ast
348
- }
349
- if (ast instanceof Array) {
350
- const s = makeIndent(level) + '[\n'
351
- const sa: string[] = []
352
- ast.forEach((a: Ast) => {
353
- sa.push(outAST(a, level + 1))
354
- })
355
- return s + sa.join(',\n') + '\n' + makeIndent(level) + ']'
356
- }
357
- if (ast instanceof Object) {
358
- const s = makeIndent(level) + '{\n'
359
- const sa = []
360
- for (const key in ast) {
361
- const sv = trim(outAST((ast as any)[key], level + 1))
362
- const so = makeIndent(level + 1) + '"' + key + '": ' + sv
363
- sa.push(so)
364
- }
365
- return s + sa.join(',\n') + '\n' + makeIndent(level) + '}'
366
- }
367
- return makeIndent(level) + ast
368
- }
369
- console.log(outAST(ast, 0))
370
- }
371
-
372
- // REPL(対話実行環境)の場合
373
- async cnakoRepl (_opt: any) {
374
- const fname = path.join(__dirname, 'repl.nako3')
375
- const src = fs.readFileSync(fname, 'utf-8')
376
- await this.runAsync(src, 'main.nako3')
377
- }
378
-
379
- // マニュアルを表示する
380
- cnakoMan (command: string) {
381
- try {
382
- const pathCommands = path.join(__dirname, '../release/command_cnako3.json')
383
- const commands = JSON.parse(fs.readFileSync(pathCommands, 'utf-8'))
384
- const data = commands[command]
385
- for (const key in data) {
386
- console.log(`${key}: ${data[key]}`)
387
- }
388
- } catch (e: any) {
389
- if (e.code === 'MODULE_NOT_FOUND') {
390
- console.log('コマンド一覧がないため、マニュアルを表示できません。以下のコマンドでコマンド一覧を生成してください。\n$ npm run build')
391
- } else {
392
- throw e
393
- }
394
- }
395
- }
396
-
397
- // 対応機器/Webブラウザを表示する
398
- cnakoBrowsers () {
399
- const fileMD = path.resolve(__dirname, '../doc', 'browsers.md')
400
- console.log(fs.readFileSync(fileMD, 'utf-8'))
401
- }
402
-
403
- // (js|nako3) loader
404
- getLoaderTools () {
405
- /** @type {string[]} */
406
- const log: string[] = []
407
- const tools: LoaderTool = {
408
- resolvePath: (name: string, token: any, fromFile: string): {filePath: string, type: string} => {
409
- // 最初に拡張子があるかどうかをチェック
410
- // JSプラグインか?
411
- if (/\.(js|mjs)(\.txt)?$/.test(name)) {
412
- const jspath = CNako3.findJSPluginFile(name, fromFile, __dirname, log)
413
- if (jspath === '') {
414
- throw new NakoImportError(`JSプラグイン『${name}』が見つかりません。以下のパスを検索しました。\n${log.join('\n')}`, token.file, token.line)
415
- }
416
- return { filePath: jspath, type: 'js' }
417
- }
418
- // なでしこプラグインか?
419
- if (/\.(nako3|nako)(\.txt)?$/.test(name)) {
420
- // ファイルかHTTPか
421
- if (name.startsWith('http://') || name.startsWith('https://')) {
422
- return { filePath: name, type: 'nako3' }
423
- }
424
- if (path.isAbsolute(name)) {
425
- return { filePath: path.resolve(name), type: 'nako3' }
426
- } else {
427
- // filename が undefined のとき token.file が undefined になる。
428
- if (token.file === undefined) { throw new Error('ファイル名を指定してください。') }
429
- const dir = path.dirname(fromFile)
430
- return { filePath: path.resolve(path.join(dir, name)), type: 'nako3' }
431
- }
432
- }
433
- // 拡張子がない、あるいは、(.js|.mjs|.nako3|.nako)以外はJSモジュールと見なす
434
- const jspath2 = CNako3.findJSPluginFile(name, fromFile, __dirname, log)
435
- if (jspath2 === '') {
436
- throw new NakoImportError(`JSプラグイン『${name}』が見つかりません。以下のパスを検索しました。\n${log.join('\n')}`, token.file, token.line)
437
- }
438
- return { filePath: jspath2, type: 'js' }
439
- },
440
- readNako3: (name, token) => {
441
- const loader:any = { task: null }
442
- // ファイルかHTTPか
443
- if (name.startsWith('http://') || name.startsWith('https://')) {
444
- // Webのファイルを非同期で読み込む
445
- loader.task = (async () => {
446
- const res = await fetch(name)
447
- if (!res.ok) {
448
- throw new NakoImportError(`『${name}』からのダウンロードに失敗しました: ${res.status} ${res.statusText}`, token.file, token.line)
449
- }
450
- return await res.text()
451
- })()
452
- } else {
453
- // ファイルを非同期で読み込む
454
- // ファイルチェックだけ先に実行
455
- if (!fs.existsSync(name)) {
456
- throw new NakoImportError(`ファイル ${name} が存在しません。`, token.file, token.line)
457
- }
458
- loader.task = (new Promise((resolve, reject) => {
459
- fs.readFile(name, { encoding: 'utf-8' }, (err, data) => {
460
- if (err) { return reject(err) }
461
- resolve(data)
462
- })
463
- }))
464
- }
465
- // 非同期で読み込む
466
- return loader
467
- },
468
- readJs: (filePath, token) => {
469
- const loader: any = { task: null }
470
- if (process.platform === 'win32') {
471
- if (filePath.substring(1, 3) === ':\\') {
472
- filePath = 'file://' + filePath
473
- }
474
- }
475
- // URLからの読み取り
476
- // ファイルかHTTPか
477
- if (filePath.startsWith('http://') || filePath.startsWith('https://')) {
478
- // 動的 import が http 未対応のため、一度、Webのファイルを非同期で読み込んで/tmpに保存してから動的importを行う
479
- loader.task = (
480
- new Promise((resolve, reject) => {
481
- // 一時フォルダを得る
482
- const osTmpDir = (process.platform === 'win32') ? process.env.TEMP : '/tmp'
483
- const osTmpDir2 = (osTmpDir) || path.join('./tmp')
484
- const tmpDir = path.join(osTmpDir2, 'com.nadesi.v3.cnako')
485
- const tmpFile = path.join(tmpDir, filePath.replace(/[^a-zA-Z0-9_.]/g, '_'))
486
- if (!fs.existsSync(tmpDir)) { fs.mkdirSync(tmpDir, { recursive: true }) }
487
- // WEBからダウンロード
488
- fetch(filePath)
489
- .then((res: any) => {
490
- return res.text()
491
- })
492
- .then((txt: string) => {
493
- // 一時ファイルに保存
494
- try {
495
- fs.writeFileSync(tmpFile, txt, 'utf-8')
496
- } catch (err) {
497
- const err2 = new NakoImportError(`URL『${filePath}』からダウンロードしたJSファイルがキャッシュに書き込めません。${err}`, token.file, token.line)
498
- reject(err2)
499
- }
500
- })
501
- .then(() => {
502
- // 一時ファイルから読み込む
503
- import(tmpFile).then((mod) => {
504
- // プラグインは export default で宣言
505
- const obj = Object.assign({}, mod)
506
- resolve(() => {
507
- return obj.default
508
- })
509
- }).catch((err) => {
510
- const err2 = new NakoImportError(`URL『${filePath}』からダウンロードしたはずのJSファイル読み込めません。${err}`, token.file, token.line)
511
- reject(err2)
512
- })
513
- })
514
- .catch((err: any) => {
515
- const err2 = new NakoImportError(`URL『${filePath}』からJSファイルが読み込めません。${err}`, token.file, token.line)
516
- reject(err2)
517
- })
518
- })
519
- )
520
- return loader
521
- }
522
- loader.task = (
523
- new Promise((resolve, reject) => {
524
- import(filePath).then((mod) => {
525
- // プラグインは export default で宣言
526
- const obj = Object.assign({}, mod)
527
- resolve(() => { return obj.default })
528
- }).catch((err) => {
529
- const err2 = new NakoImportError(`ファイル『${filePath}』が読み込めません。${err}`, token.file, token.line)
530
- reject(err2)
531
- })
532
- })
533
- )
534
- return loader
535
- }
536
- }
537
- return tools
538
- }
539
-
540
- /**
541
- * @param {string} code
542
- * @param {string} filename
543
- * @param {string} preCode
544
- * @returns {Promise<void>}
545
- */
546
- async loadDependencies (code: string, filename: string, preCode: string) {
547
- const tools = this.getLoaderTools()
548
- await super._loadDependencies(code, filename, preCode, tools)
549
- }
550
-
551
- /**
552
- * @param code
553
- * @param fname
554
- * @param [preCode]
555
- */
556
- async runAsync (code: string, fname: string, preCode = ''): Promise<NakoGlobal> {
557
- // 取り込む文の処理
558
- try {
559
- await this.loadDependencies(code, fname, preCode)
560
- } catch (err: any) {
561
- // 読み込みエラーは報告のみして続けて実行してみる
562
- this.getLogger().error(err)
563
- }
564
- // 実行
565
- return this._runEx(code, fname, {}, preCode)
566
- }
567
-
568
- /**
569
- * プラグインファイルの検索を行う
570
- * @param {string} pname プラグインの名前
571
- * @param {string} filename 取り込み元ファイル名
572
- * @param {string} srcDir このファイルが存在するディレクトリ
573
- * @param {string[]} [log]
574
- * @return {string} フルパス、失敗した時は、''を返す
575
- */
576
- static findJSPluginFile (pname: string, filename: string, srcDir: string, log: string[] = []): string {
577
- log.length = 0
578
- const cachePath: {[key: string]: boolean} = {}
579
- /** キャッシュ付きでファイルがあるか検索 */
580
- const exists = (f: string): boolean => {
581
- // 同じパスを何度も検索することがないように
582
- if (cachePath[f]) { return cachePath[f] }
583
- const stat = fs.statSync(f, { throwIfNoEntry: false })
584
- const b = !!(stat && stat.isFile())
585
- cachePath[f] = b
586
- return b
587
- }
588
- /** 普通にファイルをチェック
589
- * @param {string} pathTest
590
- * @param {string} desc
591
- * @returns {boolean}
592
- */
593
- const fCheck = (pathTest: string, desc: string): boolean => {
594
- // 素直に指定されたパスをチェック
595
- const bExists = exists(pathTest)
596
- log.push(`[${desc}] ${pathTest}, ${bExists}`)
597
- return bExists
598
- }
599
- /** 通常 + package.json のパスを調べる
600
- * @param {string} pathTest
601
- * @param {string} desc
602
- * @returns {string}
603
- */
604
- const fCheckEx = (pathTest: string, desc: string): string => {
605
- // 直接JSファイルが指定された?
606
- if (/\.(js|mjs)$/.test(pathTest)) {
607
- if (fCheck(pathTest, desc)) { return pathTest }
608
- }
609
- // 指定パスのpackage.jsonを調べる
610
- const json = path.join(pathTest, 'package.json')
611
- if (fCheck(json, desc + '/package.json')) {
612
- // package.jsonを見つけたので、メインファイルを調べて取り込む (CommonJSモジュール対策)
613
- const jsonText = fs.readFileSync(json, 'utf-8')
614
- const obj = JSON.parse(jsonText)
615
- if (!obj.main) { return '' }
616
- const mainFile = path.resolve(path.join(pathTest, obj.main))
617
- return mainFile
618
- }
619
- return ''
620
- }
621
-
622
- // URL指定か?
623
- if (pname.substring(0, 8) === 'https://') {
624
- return pname
625
- }
626
- // 各パスを検索していく
627
- const p1 = pname.substring(0, 1)
628
- // フルパス指定か?
629
- if (p1 === '/' || pname.substring(1, 3).toLowerCase() === ':\\' || pname.substring(0, 6) === 'file:/') {
630
- const fileFullpath = fCheckEx(pname, 'fullpath')
631
- if (fileFullpath) { return fileFullpath }
632
- return '' // フルパスの場合別のフォルダは調べない
633
- }
634
- // 相対パスか?
635
- if (p1 === '.' || pname.indexOf('/') >= 0) {
636
- // 相対パス指定なので、なでしこのプログラムからの相対指定を調べる
637
- const pathRelative = path.join(path.resolve(path.dirname(filename)), pname)
638
- const fileRelative = fCheckEx(pathRelative, 'relpath')
639
- if (fileRelative) { return fileRelative }
640
- return '' // 相対パスの場合も別のフォルダは調べない
641
- }
642
- // plugin_xxx.mjs のようにファイル名のみが指定された場合のみ、いくつかのパスを調べる
643
- // 母艦パス(元ファイルと同じフォルダ)か?
644
- const testScriptPath = path.join(path.resolve(path.dirname(filename)), pname)
645
- const fileScript = fCheckEx(testScriptPath, 'scriptPath')
646
- if (fileScript) { return fileScript }
647
-
648
- // ランタイムパス/src/<plugin>
649
- const pathRuntimeSrc = path.join(path.resolve(srcDir), pname) // cnako3mod.mjs は ランタイム/src に配置されていることが前提
650
- const fileRuntimeSrc = fCheckEx(pathRuntimeSrc, 'runtimeSrcPath')
651
- if (fileRuntimeSrc) { return fileRuntimeSrc }
652
-
653
- // 環境変数をチェック
654
- // 環境変数 NAKO_LIB か?
655
- if (process.env.NAKO_LIB) {
656
- const NAKO_LIB = path.join(path.resolve(process.env.NAKO_LIB), pname)
657
- const fileLib = fCheckEx(NAKO_LIB, 'NAKO_LIB')
658
- if (fileLib) { return fileLib }
659
- }
660
-
661
- // ランタイムパス/node_modules/<plugin>
662
- const pathRuntime = path.join(path.dirname(path.resolve(__dirname)))
663
- const pathRuntimePname = path.join(pathRuntime, 'node_modules', pname)
664
- const fileRuntime = fCheckEx(pathRuntimePname, 'runtime')
665
- if (fileRuntime) { return fileRuntime }
666
-
667
- // ランタイムと同じ配置 | ランタイムパス/../<plugin>
668
- const runtimeLib = path.join(pathRuntime, '..', pname)
669
- const fileLib = fCheckEx(runtimeLib, 'runtimeLib')
670
- if (fileLib) { return fileLib }
671
-
672
- // nadesiko3core | ランタイムパス/node_modules/nadesiko3core/src/<plugin>
673
- const pathRuntimeSrc2 = path.join(pathRuntime, 'node_modules', 'nadesiko3core', 'src', pname) // cnako3mod.mjs は ランタイム/src に配置されていることが前提
674
- const fileRuntimeSrc2 = fCheckEx(pathRuntimeSrc2, 'nadesiko3core')
675
- if (fileRuntimeSrc2) { return fileRuntimeSrc2 }
676
-
677
- // 環境変数 NAKO_HOMEか?
678
- if (process.env.NAKO_HOME) {
679
- const NAKO_HOME = path.join(path.resolve(process.env.NAKO_HOME), 'node_modules', pname)
680
- const fileHome = fCheckEx(NAKO_HOME, 'NAKO_HOME')
681
- if (fileHome) { return fileHome }
682
- // NAKO_HOME/src ?
683
- const pathNakoHomeSrc = path.join(NAKO_HOME, 'src', pname)
684
- const fileNakoHomeSrc = fCheckEx(pathNakoHomeSrc, 'NAKO_HOME/src')
685
- if (fileNakoHomeSrc) { return fileNakoHomeSrc }
686
- }
687
- // 環境変数 NODE_PATH (global) 以下にあるか?
688
- if (process.env.NODE_PATH) {
689
- const pathNode = path.join(path.resolve(process.env.NODE_PATH), pname)
690
- const fileNode = fCheckEx(pathNode, 'NODE_PATH')
691
- if (fileNode) { return fileNode }
692
- }
693
- // Nodeのパス検索には任せない(importで必ず失敗するので)
694
- return ''
695
- }
696
- }
1
+ /**
2
+ * コマンドライン版のなでしこ3をモジュールとして定義
3
+ * 実際には cnako3.mjs から読み込まれる
4
+ */
5
+ import fs from 'fs'
6
+ import fse from 'fs-extra'
7
+ import { exec } from 'child_process'
8
+ import path from 'path'
9
+
10
+ import { NakoCompiler, LoaderTool, LoaderToolTask } from '../core/src/nako3.mjs'
11
+ import { NakoImportError } from '../core/src/nako_errors.mjs'
12
+
13
+ import { Ast, CompilerOptions } from '../core/src/nako_types.mjs'
14
+ import { NakoGlobal } from '../core/src/nako_global.mjs'
15
+ import nakoVersion from './nako_version.mjs'
16
+
17
+ import PluginNode from './plugin_node.mjs'
18
+ import app from './commander_ja.mjs'
19
+ import fetch from 'node-fetch'
20
+
21
+ import { NakoGenOptions } from '../core/src/nako_gen.mjs'
22
+
23
+ // __dirname のために
24
+ import url from 'url'
25
+ const __filename = url.fileURLToPath(import.meta.url)
26
+ const __dirname = path.dirname(__filename)
27
+
28
+ /** コマンドラインアクション */
29
+ interface CNako3ArgOptions {
30
+ warn: boolean
31
+ debug: boolean
32
+ compile: any | boolean
33
+ test: any | boolean
34
+ one_liner: any | boolean
35
+ trace: any | boolean
36
+ run: any | boolean
37
+ repl: any | boolean
38
+ source: any | string
39
+ mainfile: any | string
40
+ man: string
41
+ browsers: boolean
42
+ ast: boolean
43
+ }
44
+
45
+ interface CNako3Options {
46
+ nostd: boolean
47
+ }
48
+
49
+ /** CNako3 */
50
+ export class CNako3 extends NakoCompiler {
51
+ debug: boolean
52
+ filename: string
53
+ version: string
54
+
55
+ constructor (opts:CNako3Options = { nostd: false }) {
56
+ super({ useBasicPlugin: !opts.nostd })
57
+ this.debug = false
58
+ this.filename = 'main.nako3'
59
+ this.version = nakoVersion.version
60
+ if (!opts.nostd) {
61
+ this.addPluginFile('PluginNode', path.join(__dirname, 'plugin_node.mjs'), PluginNode)
62
+ }
63
+ // 必要な定数を設定
64
+ this.addListener('beforeRun', (g: NakoGlobal) => {
65
+ g.__varslist[0]['ナデシコ種類'] = 'cnako3'
66
+ g.__varslist[0]['ナデシコバージョン'] = this.version
67
+ })
68
+ }
69
+
70
+ // CNAKO3で使えるコマンドを登録する
71
+ registerCommands () {
72
+ // コマンド引数がないならば、ヘルプを表示(-hはcommandarにデフォルト用意されている)
73
+ if (process.argv.length <= 2) { process.argv.push('-h') }
74
+
75
+ const verInfo = `v${nakoVersion.version}`
76
+ // commanderを使って引数を解析する
77
+ app
78
+ .title('日本語プログラミング言語「なでしこ」' + verInfo)
79
+ .version(verInfo, '-v, --version')
80
+ .usage('[オプション] 入力ファイル.nako3')
81
+ .option('-h, --help', 'コマンドの使い方を表示')
82
+ .option('-w, --warn', '警告を表示する')
83
+ .option('-d, --debug', 'デバッグモードの指定')
84
+ .option('-D, --trace', '詳細デバッグモードの指定')
85
+ .option('-c, --compile', 'コンパイルモードの指定')
86
+ .option('-t, --test', 'コンパイルモードの指定 (テスト用コードを出力)')
87
+ .option('-r, --run', 'コンパイルモードでも実行する')
88
+ .option('-e, --eval [src]', '直接プログラムを実行するワンライナーモード')
89
+ .option('-o, --output', '出力ファイル名の指定')
90
+ .option('-s, --silent', 'サイレントモードの指定')
91
+ .option('-l, --repl', '対話シェル(REPL)の実行')
92
+ .option('-b, --browsers', '対応機器/Webブラウザを表示する')
93
+ .option('-m, --man [command]', 'マニュアルを表示する')
94
+ .option('-p, --speed', 'スピード優先モードの指定')
95
+ .option('-A, --ast', 'パースした結果をASTで出力する')
96
+ // .option('-h, --help', '使い方を表示する')
97
+ // .option('-v, --version', 'バージョンを表示する')
98
+ .parse(process.argv)
99
+ return app
100
+ }
101
+
102
+ /** コマンドライン引数を解析 */
103
+ checkArguments (): CNako3ArgOptions {
104
+ const app: any = this.registerCommands()
105
+
106
+ let logLevel = 'error'
107
+ if (app.trace) {
108
+ logLevel = 'trace'
109
+ } else if (app.debug) {
110
+ logLevel = 'debug'
111
+ } else if (app.warn) {
112
+ logLevel = 'warn'
113
+ }
114
+ this.getLogger().addListener(logLevel, ({ level, nodeConsole }) => {
115
+ console.log(nodeConsole)
116
+ })
117
+
118
+ const args: any = {
119
+ compile: app.compile || false,
120
+ run: app.run || false,
121
+ source: app.eval || '',
122
+ man: app.man || '',
123
+ one_liner: app.eval || false,
124
+ debug: this.debug || false,
125
+ trace: app.trace,
126
+ warn: app.warn,
127
+ repl: app.repl || false,
128
+ test: app.test || false,
129
+ browsers: app.browsers || false,
130
+ speed: app.speed || false,
131
+ ast: app.ast || false
132
+ }
133
+ args.mainfile = app.args[0]
134
+ args.output = app.output
135
+
136
+ // todo: ESModule 対応の '.mjs' のコードを吐くように修正 #1217
137
+ const ext = '.mjs'
138
+ if (/\.(nako|nako3|txt|bak)$/.test(args.mainfile)) {
139
+ if (!args.output) {
140
+ if (args.test) {
141
+ args.output = args.mainfile.replace(/\.(nako|nako3)$/, '.spec' + ext)
142
+ } else {
143
+ args.output = args.mainfile.replace(/\.(nako|nako3)$/, ext)
144
+ }
145
+ }
146
+ } else {
147
+ if (!args.output) {
148
+ if (args.test) {
149
+ args.output = args.mainfile + '.spec' + ext
150
+ } else {
151
+ args.output = args.mainfile + ext
152
+ }
153
+ }
154
+ args.mainfile += '.nako3'
155
+ }
156
+ return args
157
+ }
158
+
159
+ // 実行する
160
+ async execCommand () {
161
+ // コマンドを解析
162
+ const opt = this.checkArguments()
163
+ // 使い方の表示か?
164
+ if (opt.man) {
165
+ this.cnakoMan(opt.man)
166
+ return
167
+ }
168
+ // 対応ブラウザを表示する
169
+ if (opt.browsers) {
170
+ this.cnakoBrowsers()
171
+ return
172
+ }
173
+ // REPLを実行する
174
+ if (opt.repl) {
175
+ this.cnakoRepl(opt)
176
+ return
177
+ }
178
+ // ワンライナーで実行する
179
+ if (opt.one_liner) {
180
+ this.cnakoOneLiner(opt)
181
+ return
182
+ }
183
+
184
+ // メインプログラムを読み込む
185
+ this.filename = opt.mainfile
186
+ const src = fs.readFileSync(opt.mainfile, 'utf-8')
187
+ if (opt.compile) {
188
+ await this.nakoCompile(opt, src, false)
189
+ return
190
+ }
191
+
192
+ // ASTを出力する
193
+ if (opt.ast) {
194
+ try {
195
+ await this.loadDependencies(src, opt.mainfile, '')
196
+ } catch (err: any) {
197
+ if (this.numFailures > 0) {
198
+ this.logger.error(err)
199
+ process.exit(1)
200
+ }
201
+ }
202
+ this.outputAST(opt, src)
203
+ return
204
+ }
205
+
206
+ // テストを実行する
207
+ if (opt.test) {
208
+ try {
209
+ await this.loadDependencies(src, opt.mainfile, '')
210
+ this.test(src, opt.mainfile)
211
+ return
212
+ } catch (e: any) {
213
+ if (this.numFailures > 0) {
214
+ this.logger.error(e)
215
+ process.exit(1)
216
+ }
217
+ }
218
+ }
219
+
220
+ // ファイルを読んで実行する
221
+ try {
222
+ // コンパイルと実行を行うメソッド
223
+ const g = await this.runAsync(src, opt.mainfile)
224
+ return g
225
+ } catch (e: any) {
226
+ this.logger.error(e)
227
+ // 文法エラーなどがあった場合
228
+ if (opt.debug || opt.trace) {
229
+ throw e
230
+ }
231
+ }
232
+ }
233
+
234
+ /**
235
+ * コンパイルモードの場合
236
+ * @param opt
237
+ * @param {string} src
238
+ * @param {boolean} isTest
239
+ */
240
+ async nakoCompile (opt: any, src: string, isTest: boolean) {
241
+ // 依存ライブラリなどを読み込む
242
+ await this.loadDependencies(src, this.filename, '')
243
+ // JSにコンパイル
244
+ const genOpt = new NakoGenOptions(
245
+ isTest,
246
+ ['plugin_node.mjs'],
247
+ 'self.__varslist[0][\'ナデシコ種類\']=\'cnako3\';'
248
+ )
249
+ const jscode = this.compileStandalone(src, this.filename, genOpt)
250
+ console.log(opt.output)
251
+ fs.writeFileSync(opt.output, jscode, 'utf-8')
252
+
253
+ // 実行に必要なファイルをコピー
254
+ const nakoRuntime = __dirname
255
+ const outRuntime = path.join(path.dirname(opt.output), 'nako3runtime')
256
+ if (!fs.existsSync(outRuntime)) { fs.mkdirSync(outRuntime) }
257
+ // from ./src
258
+ for (const mod of ['nako_version.mjs', 'plugin_node.mjs']) {
259
+ fs.copyFileSync(path.join(nakoRuntime, mod), path.join(outRuntime, mod))
260
+ }
261
+ // from nadesiko3core/src
262
+ const srcDir = path.join(__dirname, '..', 'node_modules', 'nadesiko3core', 'src')
263
+ const baseFiles = ['nako_errors.mjs', 'nako_core_version.mjs',
264
+ 'plugin_system.mjs', 'plugin_math.mjs', 'plugin_promise.mjs', 'plugin_test.mjs', 'plugin_csv.mjs', 'nako_csv.mjs']
265
+ for (const mod of baseFiles) {
266
+ fs.copyFileSync(path.join(srcDir, mod), path.join(outRuntime, mod))
267
+ }
268
+ // or 以下のコピーだと依存ファイルがコピーされない package.jsonを見てコピーする必要がある
269
+ const orgModule = path.join(__dirname, '..', 'node_modules')
270
+ const dirNodeModules = path.join(path.dirname(opt.output), 'node_modules')
271
+ const modlist = ['fs-extra', 'iconv-lite', 'opener', 'node-fetch']
272
+ const copied: { [key: string]: boolean } = {}
273
+ // 再帰的に必要なモジュールをコピーする
274
+ const copyModule = (mod: string) => {
275
+ if (copied[mod]) { return }
276
+ copied[mod] = true
277
+ // ライブラリ自身をコピー
278
+ fse.copySync(path.join(orgModule, mod), path.join(dirNodeModules, mod))
279
+ // 依存ライブラリをコピー
280
+ const packageFile = path.join(orgModule, mod, 'package.json')
281
+ const jsonStr = fs.readFileSync(packageFile, 'utf-8')
282
+ const jsonData = JSON.parse(jsonStr)
283
+ // サブモジュールをコピー
284
+ for (const smod in jsonData.dependencies) {
285
+ copyModule(smod)
286
+ }
287
+ }
288
+ for (const mod of modlist) {
289
+ copyModule(mod)
290
+ }
291
+
292
+ if (opt.run) {
293
+ exec(`node ${opt.output}`, function (err, stdout, stderr) {
294
+ if (err) { console.log('[ERROR]', stderr) }
295
+ console.log(stdout)
296
+ })
297
+ }
298
+ }
299
+
300
+ // ワンライナーの場合
301
+ async cnakoOneLiner (opt: any) {
302
+ const org = opt.source
303
+ try {
304
+ if (opt.source.indexOf('表示') < 0) {
305
+ opt.source = '' + opt.source + 'を表示。'
306
+ }
307
+ await this.runAsync(opt.source, 'main.nako3')
308
+ } catch (e) {
309
+ // エラーになったら元のワンライナーで再挑戦
310
+ try {
311
+ if (opt.source !== org) {
312
+ await this.runAsync(org, 'main.nako3')
313
+ } else {
314
+ throw e
315
+ }
316
+ } catch (e: any) {
317
+ if (this.debug) {
318
+ throw e
319
+ } else {
320
+ console.error(e.message)
321
+ }
322
+ }
323
+ }
324
+ }
325
+
326
+ /**
327
+ * ASTを出力
328
+ * @param opt
329
+ * @param {string} src
330
+ */
331
+ outputAST (opt: any, src: string) {
332
+ const ast = this.parse(src, opt.mainfile)
333
+ const makeIndent = (level: number) => {
334
+ let s = ''
335
+ for (let i = 0; i < level; i++) { s += ' ' }
336
+ return s
337
+ }
338
+ const trim = (s: string) => { return s.replace(/(^\s+|\s+$)/g, '') }
339
+ /**
340
+ * AST文字列に変換して返す
341
+ * @param {*} ast
342
+ * @param {number} level
343
+ * @return {string}
344
+ */
345
+ const outAST = (ast: Ast, level: number): string => {
346
+ if (typeof (ast) === 'string') {
347
+ return makeIndent(level) + '"' + ast + '"'
348
+ }
349
+ if (typeof (ast) === 'number') {
350
+ return makeIndent(level) + ast
351
+ }
352
+ if (ast instanceof Array) {
353
+ const s = makeIndent(level) + '[\n'
354
+ const sa: string[] = []
355
+ ast.forEach((a: Ast) => {
356
+ sa.push(outAST(a, level + 1))
357
+ })
358
+ return s + sa.join(',\n') + '\n' + makeIndent(level) + ']'
359
+ }
360
+ if (ast instanceof Object) {
361
+ const s = makeIndent(level) + '{\n'
362
+ const sa = []
363
+ for (const key in ast) {
364
+ const sv = trim(outAST((ast as any)[key], level + 1))
365
+ const so = makeIndent(level + 1) + '"' + key + '": ' + sv
366
+ sa.push(so)
367
+ }
368
+ return s + sa.join(',\n') + '\n' + makeIndent(level) + '}'
369
+ }
370
+ return makeIndent(level) + ast
371
+ }
372
+ console.log(outAST(ast, 0))
373
+ }
374
+
375
+ // REPL(対話実行環境)の場合
376
+ async cnakoRepl (_opt: any) {
377
+ const fname = path.join(__dirname, 'repl.nako3')
378
+ const src = fs.readFileSync(fname, 'utf-8')
379
+ await this.runAsync(src, 'main.nako3')
380
+ }
381
+
382
+ // マニュアルを表示する
383
+ cnakoMan (command: string) {
384
+ try {
385
+ const pathCommands = path.join(__dirname, '../release/command_cnako3.json')
386
+ const commands = JSON.parse(fs.readFileSync(pathCommands, 'utf-8'))
387
+ const data = commands[command]
388
+ for (const key in data) {
389
+ console.log(`${key}: ${data[key]}`)
390
+ }
391
+ } catch (e: any) {
392
+ if (e.code === 'MODULE_NOT_FOUND') {
393
+ console.log('コマンド一覧がないため、マニュアルを表示できません。以下のコマンドでコマンド一覧を生成してください。\n$ npm run build')
394
+ } else {
395
+ throw e
396
+ }
397
+ }
398
+ }
399
+
400
+ // 対応機器/Webブラウザを表示する
401
+ cnakoBrowsers () {
402
+ const fileMD = path.resolve(__dirname, '../doc', 'browsers.md')
403
+ console.log(fs.readFileSync(fileMD, 'utf-8'))
404
+ }
405
+
406
+ // (js|nako3) loader
407
+ getLoaderTools () {
408
+ /** @type {string[]} */
409
+ const log: string[] = []
410
+ const tools: LoaderTool = {
411
+ resolvePath: (name: string, token: any, fromFile: string): {filePath: string, type: string} => {
412
+ // 最初に拡張子があるかどうかをチェック
413
+ // JSプラグインか?
414
+ if (/\.(js|mjs)(\.txt)?$/.test(name)) {
415
+ const jspath = CNako3.findJSPluginFile(name, fromFile, __dirname, log)
416
+ if (jspath === '') {
417
+ throw new NakoImportError(`JSプラグイン『${name}』が見つかりません。以下のパスを検索しました。\n${log.join('\n')}`, token.file, token.line)
418
+ }
419
+ return { filePath: jspath, type: 'js' }
420
+ }
421
+ // なでしこプラグインか?
422
+ if (/\.(nako3|nako)(\.txt)?$/.test(name)) {
423
+ // ファイルかHTTPか
424
+ if (name.startsWith('http://') || name.startsWith('https://')) {
425
+ return { filePath: name, type: 'nako3' }
426
+ }
427
+ if (path.isAbsolute(name)) {
428
+ return { filePath: path.resolve(name), type: 'nako3' }
429
+ } else {
430
+ // filename undefined のとき token.file undefined になる。
431
+ if (token.file === undefined) { throw new Error('ファイル名を指定してください。') }
432
+ const dir = path.dirname(fromFile)
433
+ return { filePath: path.resolve(path.join(dir, name)), type: 'nako3' }
434
+ }
435
+ }
436
+ // 拡張子がない、あるいは、(.js|.mjs|.nako3|.nako)以外はJSモジュールと見なす
437
+ const jspath2 = CNako3.findJSPluginFile(name, fromFile, __dirname, log)
438
+ if (jspath2 === '') {
439
+ throw new NakoImportError(`JSプラグイン『${name}』が見つかりません。以下のパスを検索しました。\n${log.join('\n')}`, token.file, token.line)
440
+ }
441
+ return { filePath: jspath2, type: 'js' }
442
+ },
443
+ readNako3: (name, token) => {
444
+ const loader:any = { task: null }
445
+ // ファイルかHTTPか
446
+ if (name.startsWith('http://') || name.startsWith('https://')) {
447
+ // Webのファイルを非同期で読み込む
448
+ loader.task = (async () => {
449
+ const res = await fetch(name)
450
+ if (!res.ok) {
451
+ throw new NakoImportError(`『${name}』からのダウンロードに失敗しました: ${res.status} ${res.statusText}`, token.file, token.line)
452
+ }
453
+ return await res.text()
454
+ })()
455
+ } else {
456
+ // ファイルを非同期で読み込む
457
+ // ファイルチェックだけ先に実行
458
+ if (!fs.existsSync(name)) {
459
+ throw new NakoImportError(`ファイル ${name} が存在しません。`, token.file, token.line)
460
+ }
461
+ loader.task = (new Promise((resolve, reject) => {
462
+ fs.readFile(name, { encoding: 'utf-8' }, (err, data) => {
463
+ if (err) { return reject(err) }
464
+ resolve(data)
465
+ })
466
+ }))
467
+ }
468
+ // 非同期で読み込む
469
+ return loader
470
+ },
471
+ readJs: (filePath, token) => {
472
+ const loader: any = { task: null }
473
+ if (process.platform === 'win32') {
474
+ if (filePath.substring(1, 3) === ':\\') {
475
+ filePath = 'file://' + filePath
476
+ }
477
+ }
478
+ // URLからの読み取り
479
+ // ファイルかHTTPか
480
+ if (filePath.startsWith('http://') || filePath.startsWith('https://')) {
481
+ // 動的 import が http 未対応のため、一度、Webのファイルを非同期で読み込んで/tmpに保存してから動的importを行う
482
+ loader.task = (
483
+ new Promise((resolve, reject) => {
484
+ // 一時フォルダを得る
485
+ const osTmpDir = (process.platform === 'win32') ? process.env.TEMP : '/tmp'
486
+ const osTmpDir2 = (osTmpDir) || path.join('./tmp')
487
+ const tmpDir = path.join(osTmpDir2, 'com.nadesi.v3.cnako')
488
+ const tmpFile = path.join(tmpDir, filePath.replace(/[^a-zA-Z0-9_.]/g, '_'))
489
+ if (!fs.existsSync(tmpDir)) { fs.mkdirSync(tmpDir, { recursive: true }) }
490
+ // WEBからダウンロード
491
+ fetch(filePath)
492
+ .then((res: any) => {
493
+ return res.text()
494
+ })
495
+ .then((txt: string) => {
496
+ // 一時ファイルに保存
497
+ try {
498
+ fs.writeFileSync(tmpFile, txt, 'utf-8')
499
+ } catch (err) {
500
+ const err2 = new NakoImportError(`URL『${filePath}』からダウンロードしたJSファイルがキャッシュに書き込めません。${err}`, token.file, token.line)
501
+ reject(err2)
502
+ }
503
+ })
504
+ .then(() => {
505
+ // 一時ファイルから読み込む
506
+ import(tmpFile).then((mod) => {
507
+ // プラグインは export default で宣言
508
+ const obj = Object.assign({}, mod)
509
+ resolve(() => {
510
+ return obj.default
511
+ })
512
+ }).catch((err) => {
513
+ const err2 = new NakoImportError(`URL『${filePath}』からダウンロードしたはずのJSファイル読み込めません。${err}`, token.file, token.line)
514
+ reject(err2)
515
+ })
516
+ })
517
+ .catch((err: any) => {
518
+ const err2 = new NakoImportError(`URL『${filePath}』からJSファイルが読み込めません。${err}`, token.file, token.line)
519
+ reject(err2)
520
+ })
521
+ })
522
+ )
523
+ return loader
524
+ }
525
+ loader.task = (
526
+ new Promise((resolve, reject) => {
527
+ import(filePath).then((mod) => {
528
+ // プラグインは export default で宣言
529
+ const obj = Object.assign({}, mod)
530
+ resolve(() => { return obj.default })
531
+ }).catch((err) => {
532
+ const err2 = new NakoImportError(`ファイル『${filePath}』が読み込めません。${err}`, token.file, token.line)
533
+ reject(err2)
534
+ })
535
+ })
536
+ )
537
+ return loader
538
+ }
539
+ }
540
+ return tools
541
+ }
542
+
543
+ /**
544
+ * @param {string} code
545
+ * @param {string} filename
546
+ * @param {string} preCode
547
+ * @returns {Promise<void>}
548
+ */
549
+ async loadDependencies (code: string, filename: string, preCode: string) {
550
+ const tools = this.getLoaderTools()
551
+ await super._loadDependencies(code, filename, preCode, tools)
552
+ }
553
+
554
+ /**
555
+ * @param code
556
+ * @param fname
557
+ * @param [preCode]
558
+ */
559
+ async runAsync (code: string, fname: string, options: CompilerOptions = new CompilerOptions()): Promise<NakoGlobal> {
560
+ // 取り込む文の処理
561
+ try {
562
+ await this.loadDependencies(code, fname, options.preCode)
563
+ } catch (err: any) {
564
+ // 読み込みエラーは報告のみして続けて実行してみる
565
+ this.getLogger().error(err)
566
+ }
567
+ // 実行
568
+ return super.runAsync(code, fname, options)
569
+ }
570
+
571
+ /**
572
+ * プラグインファイルの検索を行う
573
+ * @param {string} pname プラグインの名前
574
+ * @param {string} filename 取り込み元ファイル名
575
+ * @param {string} srcDir このファイルが存在するディレクトリ
576
+ * @param {string[]} [log]
577
+ * @return {string} フルパス、失敗した時は、''を返す
578
+ */
579
+ static findJSPluginFile (pname: string, filename: string, srcDir: string, log: string[] = []): string {
580
+ log.length = 0
581
+ const cachePath: {[key: string]: boolean} = {}
582
+ /** キャッシュ付きでファイルがあるか検索 */
583
+ const exists = (f: string): boolean => {
584
+ // 同じパスを何度も検索することがないように
585
+ if (cachePath[f]) { return cachePath[f] }
586
+ try {
587
+ // ファイルがないと例外が出る
588
+ const stat = fs.statSync(f)
589
+ const b = !!(stat && stat.isFile())
590
+ cachePath[f] = b
591
+ return b
592
+ } catch (err: any) {
593
+ return false
594
+ }
595
+ }
596
+ /** 普通にファイルをチェック
597
+ * @param {string} pathTest
598
+ * @param {string} desc
599
+ * @returns {boolean}
600
+ */
601
+ const fCheck = (pathTest: string, desc: string): boolean => {
602
+ // 素直に指定されたパスをチェック
603
+ const bExists = exists(pathTest)
604
+ log.push(`- (${desc}) ${pathTest}, ${bExists}`)
605
+ return bExists
606
+ }
607
+ /** 通常 + package.json のパスを調べる
608
+ * @param {string} pathTest
609
+ * @param {string} desc
610
+ * @returns {string}
611
+ */
612
+ const fCheckEx = (pathTest: string, desc: string): string => {
613
+ // 直接JSファイルが指定された?
614
+ if (/\.(js|mjs)$/.test(pathTest)) {
615
+ if (fCheck(pathTest, desc)) { return pathTest }
616
+ }
617
+ // 指定パスのpackage.jsonを調べる
618
+ const json = path.join(pathTest, 'package.json')
619
+ if (fCheck(json, desc + '/package.json')) {
620
+ // package.jsonを見つけたので、メインファイルを調べて取り込む (CommonJSモジュール対策)
621
+ const jsonText = fs.readFileSync(json, 'utf-8')
622
+ const obj = JSON.parse(jsonText)
623
+ if (!obj.main) { return '' }
624
+ const mainFile = path.resolve(path.join(pathTest, obj.main))
625
+ return mainFile
626
+ }
627
+ return ''
628
+ }
629
+
630
+ // URL指定か?
631
+ if (pname.substring(0, 8) === 'https://') {
632
+ return pname
633
+ }
634
+ // 各パスを検索していく
635
+ const p1 = pname.substring(0, 1)
636
+ // フルパス指定か?
637
+ if (p1 === '/' || pname.substring(1, 3).toLowerCase() === ':\\' || pname.substring(0, 6) === 'file:/') {
638
+ const fileFullpath = fCheckEx(pname, 'フルパス')
639
+ if (fileFullpath) { return fileFullpath }
640
+ return '' // フルパスの場合別のフォルダは調べない
641
+ }
642
+ // 相対パスか?
643
+ if (p1 === '.' || pname.indexOf('/') >= 0) {
644
+ // 相対パス指定なので、なでしこのプログラムからの相対指定を調べる
645
+ const pathRelative = path.join(path.resolve(path.dirname(filename)), pname)
646
+ const fileRelative = fCheckEx(pathRelative, '相対パス')
647
+ if (fileRelative) { return fileRelative }
648
+ return '' // 相対パスの場合も別のフォルダは調べない
649
+ }
650
+ // plugin_xxx.mjs のようにファイル名のみが指定された場合のみ、いくつかのパスを調べる
651
+ // 母艦パス(元ファイルと同じフォルダ)か?
652
+ const testScriptPath = path.join(path.resolve(path.dirname(filename)), pname)
653
+ const fileScript = fCheckEx(testScriptPath, '母艦パス')
654
+ if (fileScript) { return fileScript }
655
+
656
+ // ランタイムパス/src/<plugin>
657
+ if (pname.match(/^plugin_[a-z0-9_]+\.mjs/)) {
658
+ // cnako3mod.mjs ランタイム/src に配置されていることが前提
659
+ const pathRoot = path.resolve(__dirname, '..')
660
+ const pathRuntimeSrc = path.join(pathRoot, 'src', pname)
661
+ const fileRuntimeSrc = fCheckEx(pathRuntimeSrc, 'CNAKO3パス')
662
+ if (fileRuntimeSrc) { return fileRuntimeSrc }
663
+ // ランタイム/core/src/<plugin>
664
+ const pathCore = path.join(pathRoot, 'core', 'src', pname)
665
+ const fileCore = fCheckEx(pathCore, 'CNAKO3パス')
666
+ if (fileCore) { return fileCore }
667
+ }
668
+
669
+ // 環境変数をチェック
670
+ // 環境変数 NAKO_LIB か?
671
+ if (process.env.NAKO_LIB) {
672
+ const NAKO_LIB = path.join(path.resolve(process.env.NAKO_LIB), pname)
673
+ const fileLib = fCheckEx(NAKO_LIB, 'NAKO_LIB')
674
+ if (fileLib) { return fileLib }
675
+ }
676
+
677
+ // ランタイムパス/node_modules/<plugin>
678
+ const pathRuntime = path.join(path.dirname(path.resolve(__dirname)))
679
+ const pathRuntimePname = path.join(pathRuntime, 'node_modules', pname)
680
+ const fileRuntime = fCheckEx(pathRuntimePname, 'runtime')
681
+ if (fileRuntime) { return fileRuntime }
682
+
683
+ // ランタイムと同じ配置 | ランタイムパス/../<plugin>
684
+ const runtimeLib = path.join(pathRuntime, '..', pname)
685
+ const fileLib = fCheckEx(runtimeLib, 'runtimeLib')
686
+ if (fileLib) { return fileLib }
687
+
688
+ // nadesiko3core | ランタイムパス/node_modules/nadesiko3core/src/<plugin>
689
+ const pathRuntimeSrc2 = path.join(pathRuntime, 'node_modules', 'nadesiko3core', 'src', pname) // cnako3mod.mjs は ランタイム/src に配置されていることが前提
690
+ const fileRuntimeSrc2 = fCheckEx(pathRuntimeSrc2, 'nadesiko3core')
691
+ if (fileRuntimeSrc2) { return fileRuntimeSrc2 }
692
+
693
+ // 環境変数 NAKO_HOMEか?
694
+ if (process.env.NAKO_HOME) {
695
+ const NAKO_HOME = path.join(path.resolve(process.env.NAKO_HOME), 'node_modules', pname)
696
+ const fileHome = fCheckEx(NAKO_HOME, 'NAKO_HOME')
697
+ if (fileHome) { return fileHome }
698
+ // NAKO_HOME/src ?
699
+ const pathNakoHomeSrc = path.join(NAKO_HOME, 'src', pname)
700
+ const fileNakoHomeSrc = fCheckEx(pathNakoHomeSrc, 'NAKO_HOME/src')
701
+ if (fileNakoHomeSrc) { return fileNakoHomeSrc }
702
+ }
703
+ // 環境変数 NODE_PATH (global) 以下にあるか?
704
+ if (process.env.NODE_PATH) {
705
+ const pathNode = path.join(path.resolve(process.env.NODE_PATH), pname)
706
+ const fileNode = fCheckEx(pathNode, 'NODE_PATH')
707
+ if (fileNode) { return fileNode }
708
+ }
709
+ // Nodeのパス検索には任せない(importで必ず失敗するので)
710
+ return ''
711
+ }
712
+ }