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
@@ -1,384 +1,384 @@
1
- /* eslint-disable @typescript-eslint/no-empty-function */
2
- // @ts-nocheck
3
- /* eslint-disable no-undef */
4
- import assert from 'assert'
5
- import fs from 'fs'
6
- import path from 'path'
7
- import { expect } from 'chai'
8
-
9
- import { NakoCompiler } from 'nadesiko3core/src/nako3.mjs'
10
- import { tokenize, LanguageFeatures, BackgroundTokenizer } from '../../src/wnako3_editor.mjs'
11
- import { CNako3 } from '../../src/cnako3mod.mjs'
12
- import { NakoLexerError } from 'nadesiko3core/src/nako_errors.mjs'
13
-
14
- // __dirname のために
15
- import url from 'url'
16
- // @ts-ignore
17
- const __filename = url.fileURLToPath(import.meta.url)
18
- const __dirname = path.dirname(__filename)
19
-
20
- describe('wnako3_editor_test', () => {
21
- class AceRange {
22
- constructor (/** @type {number} */startLine, /** @type {number} */startColumn, /** @type {number} */endLine, /** @type {number} */endColumn) {
23
- this.startLine = startLine
24
- this.startColumn = startColumn
25
- this.endLine = endLine
26
- this.endColumn = endColumn
27
- }
28
- }
29
- /** @implements {IAceDocument} */
30
- class AceDocument {
31
- constructor (/** @type {string} */text) {
32
- this.lines = text.split('\n')
33
- /** @type {any[]} */
34
- this.log = []
35
- }
36
-
37
- getLine (/** @type {number} */row) { return this.lines[row] }
38
- getLength () { return this.lines.length }
39
- getAllLines () { return [...this.lines] }
40
- insertInLine (/** @type {{ row: number, column: number }} */position, /** @type {string} */text) { this.log.push(['insertInLine', position, text]) }
41
- removeInLine (/** @type {number} */row, /** @type {number} */columnStart, /** @type {number} */columnEnd) { this.log.push(['removeInLine', row, columnStart, columnEnd]) }
42
- replace (/** @type {AceRange} */range, /** @type {string} */text) { this.log.push(['replace', range, text]) }
43
- /** @returns {ISession} */
44
- asSession () { // テスト用
45
- // @ts-ignore
46
- return { doc: this }
47
- }
48
- }
49
- /** @returns {Promise<BackgroundTokenizer>} */
50
- const createBackgroundTokenizer = (/** @type {string} */text, compiler = new NakoCompiler()) => {
51
- return new Promise((resolve, reject) => {
52
- const tokenizer = new BackgroundTokenizer(
53
- new AceDocument(text),
54
- compiler,
55
- () => { resolve(tokenizer) }, // ok
56
- (_, err) => { reject(err) }, // err
57
- true
58
- )
59
- })
60
- }
61
- describe('シンタックスハイライト', () => {
62
- it('コードを分割する', () => {
63
- const tokens = tokenize('A=1\nA+1を表示'.split('\n'), new NakoCompiler(), false).editorTokens
64
-
65
- // 1行目
66
- assert.strictEqual(tokens[0][0].value, 'A')
67
- assert.strictEqual(tokens[0][1].value, '=')
68
- assert.strictEqual(tokens[0][2].value, '1')
69
-
70
- // 2行目
71
- assert.strictEqual(tokens[1][0].value, 'A')
72
- assert.strictEqual(tokens[1][1].value, '+')
73
- assert.strictEqual(tokens[1][2].value, '1を')
74
- assert.strictEqual(tokens[1][3].value, '表示')
75
- })
76
- it('scopeを割り当てる', () => {
77
- const tokens = tokenize('A=1\nA+1を表示'.split('\n'), new NakoCompiler(), false).editorTokens
78
-
79
- // 1行目
80
- assert(tokens[0][0].type.includes('variable'))
81
- assert(tokens[0][1].type.includes('operator'))
82
- assert(tokens[0][2].type.includes('numeric'))
83
-
84
- // 2行目
85
- assert(tokens[1][0].type.includes('variable'))
86
- assert(tokens[1][1].type.includes('operator'))
87
- assert(tokens[1][2].type.includes('numeric'))
88
- assert(tokens[1][3].type.includes('function'))
89
- })
90
- it('取り込み文を無視する', () => {
91
- tokenize('!「http://www.example.com/non_existent_file.nako3」を取り込む。'.split('\n'), new NakoCompiler(), false)
92
- })
93
- it('助詞に下線を引く', () => {
94
- const tokens = tokenize('「\n」を表示'.split('\n'), new NakoCompiler(), true).editorTokens
95
- assert.strictEqual(tokens[1][0].value, '」')
96
- assert(tokens[1][0].type.includes('string'))
97
-
98
- assert.strictEqual(tokens[1][1].value, 'を')
99
- assert(tokens[1][1].type.includes('underline'))
100
-
101
- assert.strictEqual(tokens[1][2].value, '表示')
102
- assert(tokens[1][2].type.includes('function'))
103
- })
104
- // todo
105
- /*
106
- it('依存ファイルのキャッシュを利用する', () => {
107
- const nako3 = new CNako3()
108
- const code = '!「./requiretest_indirect.nako3」を取り込む\n1と2の痕跡演算'
109
- const file = path.join(__dirname, 'main.nako3')
110
- nako3.loadDependencies(code, file, '')
111
- const tokens = tokenize(code.split('\n'), nako3, true)
112
-
113
- // 「痕跡演算」が関数として認識されていることを確認する。
114
- const token = tokens.editorTokens[1].find((token) => token.value === '痕跡演算')
115
- expect(token).to.have.property('type').and.to.include('function')
116
- })
117
- it('シンタックスハイライトにかかる時間が依存ファイルの行数に依存しないことを確認', () => {
118
- // 一時的に大きいファイルを作成
119
- const largeFile = path.join(__dirname, 'large_file.nako3')
120
- assert(!fs.existsSync(largeFile))
121
- fs.writeFileSync(largeFile, '●(Aを)large_fileとは\nここまで\nA=1+2+3+4+5\n'.repeat(1000))
122
- try {
123
- // 大きいファイルを取り込むコードを実行
124
- const code = '!「./large_file.nako3」を取り込む\n1をlarge_file'
125
- const file = path.join(__dirname, 'main.nako3')
126
-
127
- const nako3 = new CNako3()
128
- console.time('loadDependencies')
129
- nako3.loadDependencies(code, file, '') // この行は遅いが、取り込み文に変更が合った時しか呼ばれない
130
- console.timeEnd('loadDependencies')
131
-
132
- const startTime = process.hrtime.bigint()
133
- console.time('tokenize')
134
- const tokens = tokenize(code.split('\n'), nako3, true) // この行は速い必要がある
135
- const delta = process.hrtime.bigint() - startTime
136
- console.timeEnd('tokenize')
137
-
138
- // 200ms以下で終わることを確認
139
- // GitHub Actions で10〜40msくらいかかる。
140
- assert(delta <= BigInt(200000000))
141
-
142
- // 取り込みが行われたことを確認する
143
- const token = tokens.editorTokens[1].find((token) => token.value === 'large_file')
144
- expect(token).to.have.property('type').and.to.include('function')
145
- } finally {
146
- fs.unlinkSync(largeFile)
147
- }
148
- })
149
- */
150
- it('明示的に取り込んだプラグインの関数', async () => {
151
- const compiler = new CNako3()
152
- const code = '!「plugin_csv.mjs」を取り込む\n「1」のCSV取得'
153
- await compiler.loadDependencies(code, '', '')
154
- const token = tokenize(code.split('\n'), compiler, false).editorTokens[1][1]
155
- expect(token.type).to.include('function')
156
- expect(token.docHTML).to.include('CSV取得')
157
- expect(token.value).to.equal('CSV取得')
158
- })
159
- })
160
- describe('ドキュメントのホバー', () => {
161
- it('プラグイン関数の助詞のドキュメントを表示する', () => {
162
- const nako3 = new NakoCompiler()
163
- nako3.addPluginObject('PluginEditorTest', {
164
- 'プラグイン関数テスト': {
165
- type: 'func',
166
- josi: [['を', 'と'], ['に', 'は']],
167
- fn: () => {}
168
- }
169
- })
170
-
171
- const token = tokenize('XをYにプラグイン関数テスト'.split('\n'), nako3, false)
172
- .editorTokens[0]
173
- .find((t) => t.value === 'プラグイン関数テスト')
174
- expect(token).to.have.property('docHTML').and.to.include('(Aを|Aと、Bに|Bは)')
175
- expect(token).to.have.property('docHTML').and.to.include('PluginEditorTest')
176
- })
177
- it('ユーザー定義関数の助詞のドキュメントを表示する', () => {
178
- const token = tokenize('●(Aを)Fとは\nここまで\n1をF'.split('\n'), new NakoCompiler(), false)
179
- .editorTokens[2]
180
- .find((t) => t.value === 'F')
181
- expect(token).to.have.property('docHTML').and.to.include('(Aを)')
182
- })
183
- it('前回の実行結果の影響を受けない', () => {
184
- const nako3 = new NakoCompiler()
185
- tokenize('●(Aを)Fとは\nここまで\n1をF'.split('\n'), nako3, false)
186
- const token = tokenize('1をF'.split('\n'), nako3, false)
187
- .editorTokens[0]
188
- .find((t) => t.value === 'F')
189
- // eslint-disable-next-line no-unused-expressions
190
- expect(token).to.have.property('docHTML').and.is.null
191
- })
192
- })
193
- describe('行コメントのトグル', () => {
194
- it('コメントアウト', () => {
195
- const doc = new AceDocument('abc\n')
196
- LanguageFeatures.toggleCommentLines('', doc.asSession(), 0, 1)
197
- assert.deepStrictEqual(doc.log, [
198
- ['insertInLine', { row: 0, column: 0 }, '// '],
199
- ['insertInLine', { row: 1, column: 0 }, '// ']
200
- ])
201
- })
202
- it('アンコメント', () => {
203
- const doc = new AceDocument('// abc\n\n※def')
204
- LanguageFeatures.toggleCommentLines('', doc.asSession(), 0, 2)
205
- assert.deepStrictEqual(doc.log, [
206
- ['removeInLine', 0, 0, 3], // '// ' を削除
207
- ['removeInLine', 2, 0, 1] // '※' を削除
208
- ])
209
- })
210
- it('中黒のある場合', () => {
211
- const doc = new AceDocument('・・abc')
212
- LanguageFeatures.toggleCommentLines('', doc.asSession(), 0, 0)
213
- assert.deepStrictEqual(doc.log, [
214
- ['insertInLine', { row: 0, column: 2 }, '// '] // 'abc' の直前に挿入
215
- ])
216
- })
217
- })
218
- describe('auto outdent', () => {
219
- it('「ここまで」を入力し終わった瞬間に発火する', () => {
220
- assert(!LanguageFeatures.checkOutdent('start', ' ここ', 'ま'))
221
- assert(LanguageFeatures.checkOutdent('start', ' ここま', 'で'))
222
- assert(!LanguageFeatures.checkOutdent('start', ' ここまで', '\n'))
223
-
224
- assert(!LanguageFeatures.checkOutdent('start', '・ここ', 'ま'))
225
- assert(LanguageFeatures.checkOutdent('start', '・ここま', 'で'))
226
- assert(!LanguageFeatures.checkOutdent('start', '・ここまで', '\n'))
227
- })
228
- it('1つ前の行がブロックの開始行なら、その行に合わせる', () => {
229
- const doc = new AceDocument(' もしはいならば\n ここまで')
230
- // 2行目にauto outdentを実行
231
- new LanguageFeatures(AceRange, new NakoCompiler()).autoOutdent('start', doc.asSession(), 1)
232
- // 2行目の0-8文字目が ' ' で置換される
233
- assert.deepStrictEqual(doc.log, [['replace', new AceRange(1, 0, 1, 8), ' ']])
234
- })
235
- it('1つ前の行がブロックの開始行でなければ、1段階インデントを下げる', () => {
236
- const doc = new AceDocument('もしはいならば\n もしはいならば\n 1を表示\n ここまで')
237
- // 4行目にauto outdentを実行
238
- new LanguageFeatures(AceRange, new NakoCompiler()).autoOutdent('start', doc.asSession(), 3)
239
- // 2行目の0-8文字目が ' ' で置換される
240
- assert.deepStrictEqual(doc.log, [['replace', new AceRange(3, 0, 3, 8), ' ']])
241
- })
242
- })
243
- describe('auto indent', () => {
244
- it('0列目の場合', () => {
245
- // 1段階インデントする
246
- assert.strictEqual(
247
- LanguageFeatures.getNextLineIndent('start', 'もしはいならば', ' '),
248
- ' '
249
- )
250
- })
251
- it('4列目の場合', () => {
252
- // 1段階インデントする
253
- assert.strictEqual(
254
- LanguageFeatures.getNextLineIndent('start', ' もしはいならば', ' '),
255
- ' '
256
- )
257
- })
258
- it('ブロックの開始行ではない場合', () => {
259
- // 1つ前の行と同じインデント幅を返す
260
- assert.strictEqual(
261
- LanguageFeatures.getNextLineIndent('start', ' もしはい', ' '),
262
- ' '
263
- )
264
- })
265
- })
266
- describe('バックグラウンドでコードをトークン化する', () => {
267
- it('成功時', async () => {
268
- const t = await createBackgroundTokenizer('1を表示')
269
- // 0行目の0、1、2個目のトークン
270
- expect(t.lines[0][0]).to.include({ type: 'constant.numeric', docHTML: null, value: '1' })
271
- expect(t.lines[0][1]).to.include({ type: 'constant.numeric.markup.underline', value: 'を' })
272
- expect(t.lines[0][2]).to.include({ type: 'entity.name.function', value: '表示' })
273
- })
274
- it('失敗時', async () => {
275
- let ok = false
276
- try {
277
- await createBackgroundTokenizer('「{」')
278
- } catch (err) {
279
- expect(err).to.be.instanceOf(NakoLexerError)
280
- ok = true
281
- }
282
- if (!ok) { throw new Error() }
283
- })
284
- })
285
- describe('オートコンプリート', () => {
286
- // todo
287
- /*
288
- it('同一ファイル内の関数', async () => {
289
- const compiler = new NakoCompiler()
290
- const tokenizer = await createBackgroundTokenizer('●(Aを)テスト用関数とは\nここまで\n', compiler)
291
- expect(LanguageFeatures.getCompletionItems(2, '', compiler, tokenizer)).to.deep.include({
292
- caption: "(Aを)テスト用関数",
293
- value: "テスト用関数",
294
- meta: "関数",
295
- score: 0,
296
- })
297
- })
298
- */
299
- it('同一ファイルの変数', async () => {
300
- const compiler = new NakoCompiler()
301
- const tokenizer = await createBackgroundTokenizer('テスト用変数=10\nここまで\n', compiler)
302
- expect(LanguageFeatures.getCompletionItems(2, '', compiler, tokenizer)).to.deep.include({
303
- caption: 'テスト用変数',
304
- value: 'テスト用変数',
305
- meta: '変数',
306
- score: 0
307
- })
308
- })
309
- it('組み込みのプラグイン関数', async () => {
310
- const compiler = new NakoCompiler()
311
- compiler.addPluginObject('PluginEditorTest', { 'テスト用プラグイン関数': { type: 'func', josi: [['を'], ['に']], pure: true, fn: () => {} } })
312
- const tokenizer = await createBackgroundTokenizer('', compiler)
313
- expect(LanguageFeatures.getCompletionItems(0, '', compiler, tokenizer)).to.deep.include({
314
- caption: '(Aを、Bに)テスト用プラグイン関数',
315
- value: 'テスト用プラグイン関数',
316
- meta: 'PluginEditorTest',
317
- score: 0
318
- })
319
- })
320
- it('組み込みのプラグイン変数', async () => {
321
- const compiler = new NakoCompiler()
322
- compiler.addPluginObject('PluginEditorTest', { 'テスト用プラグイン変数': { type: 'var', value: 0 } })
323
- const tokenizer = await createBackgroundTokenizer('', compiler)
324
- expect(LanguageFeatures.getCompletionItems(0, '', compiler, tokenizer)).to.deep.include({
325
- caption: 'テスト用プラグイン変数',
326
- value: 'テスト用プラグイン変数',
327
- meta: 'PluginEditorTest',
328
- score: 0
329
- })
330
- })
331
- // todo
332
- /*
333
- it('別ファイルの関数', async () => {
334
- const compiler = new CNako3()
335
- const code = `!「${__dirname}/requiretest.nako3」を取り込む\n`
336
- compiler.loadDependencies(code, '', '')
337
- const tokenizer = await createBackgroundTokenizer(code, compiler)
338
- const result = LanguageFeatures.getCompletionItems(0, '', compiler, tokenizer)
339
- assert(result.some((v) => v.caption === '(Aと、Bを)痕跡演算'))
340
- })
341
- */
342
- it('関数の呼び出しはmetaの値に影響を与えない', async () => {
343
- const compiler = new NakoCompiler()
344
- compiler.addPluginObject('PluginEditorTest', { 'テスト用プラグイン関数': { type: 'func', josi: [['を'], ['に']], pure: true, fn: () => {} } })
345
- const tokenizer = await createBackgroundTokenizer('テスト用プラグイン関数\n', compiler)
346
- const result = LanguageFeatures.getCompletionItems(1, '', compiler, tokenizer)
347
- assert.deepStrictEqual(result.filter((v) => v.value === 'テスト用プラグイン関数'), [
348
- {
349
- caption: '(Aを、Bに)テスト用プラグイン関数',
350
- value: 'テスト用プラグイン関数',
351
- meta: 'PluginEditorTest', // ここに `関数` が表示されないことを確認する
352
- score: 0
353
- }
354
- ])
355
- })
356
- // todo
357
- /*
358
- it('同一名の関数の定義が複数あるとき、候補には1つしか表示しない', async () => {
359
- const compiler = new NakoCompiler()
360
- const tokenizer = await createBackgroundTokenizer('●(Aを)テスト用関数とは\nここまで\n●(Aを)テスト用関数とは\nここまで\n', compiler)
361
- expect(LanguageFeatures.getCompletionItems(2, '', compiler, tokenizer)).to.deep.include({
362
- caption: "(Aを)テスト用関数",
363
- value: "テスト用関数",
364
- meta: "関数", // `関数, 関数` にならないことを確認する
365
- score: 0,
366
- })
367
- })
368
- */
369
- })
370
- it('テスト定義に実行ボタンを表示する', () => {
371
- const out = LanguageFeatures.getCodeLens(new AceDocument(
372
- '●テスト:足すとは\n' +
373
- 'ここまで\n' +
374
- '●(AとBを)足すとは\n' +
375
- 'ここまで\n' +
376
- '●テスト:引くとは\n' +
377
- 'ここまで\n'
378
- ))
379
- assert.deepStrictEqual(out, [
380
- { start: { row: 0 }, command: { title: 'テストを実行', id: 'runTest', arguments: ['足す'] } },
381
- { start: { row: 4 }, command: { title: 'テストを実行', id: 'runTest', arguments: ['引く'] } }
382
- ])
383
- })
384
- })
1
+ /* eslint-disable @typescript-eslint/no-empty-function */
2
+ // @ts-nocheck
3
+ /* eslint-disable no-undef */
4
+ import assert from 'assert'
5
+ import fs from 'fs'
6
+ import path from 'path'
7
+ import { expect } from 'chai'
8
+
9
+ import { NakoCompiler } from '../../core/src/nako3.mjs'
10
+ import { tokenize, LanguageFeatures, BackgroundTokenizer } from '../../src/wnako3_editor.mjs'
11
+ import { CNako3 } from '../../src/cnako3mod.mjs'
12
+ import { NakoLexerError } from '../../core/src/nako_errors.mjs'
13
+
14
+ // __dirname のために
15
+ import url from 'url'
16
+ // @ts-ignore
17
+ const __filename = url.fileURLToPath(import.meta.url)
18
+ const __dirname = path.dirname(__filename)
19
+
20
+ describe('wnako3_editor_test', () => {
21
+ class AceRange {
22
+ constructor (/** @type {number} */startLine, /** @type {number} */startColumn, /** @type {number} */endLine, /** @type {number} */endColumn) {
23
+ this.startLine = startLine
24
+ this.startColumn = startColumn
25
+ this.endLine = endLine
26
+ this.endColumn = endColumn
27
+ }
28
+ }
29
+ /** @implements {IAceDocument} */
30
+ class AceDocument {
31
+ constructor (/** @type {string} */text) {
32
+ this.lines = text.split('\n')
33
+ /** @type {any[]} */
34
+ this.log = []
35
+ }
36
+
37
+ getLine (/** @type {number} */row) { return this.lines[row] }
38
+ getLength () { return this.lines.length }
39
+ getAllLines () { return [...this.lines] }
40
+ insertInLine (/** @type {{ row: number, column: number }} */position, /** @type {string} */text) { this.log.push(['insertInLine', position, text]) }
41
+ removeInLine (/** @type {number} */row, /** @type {number} */columnStart, /** @type {number} */columnEnd) { this.log.push(['removeInLine', row, columnStart, columnEnd]) }
42
+ replace (/** @type {AceRange} */range, /** @type {string} */text) { this.log.push(['replace', range, text]) }
43
+ /** @returns {ISession} */
44
+ asSession () { // テスト用
45
+ // @ts-ignore
46
+ return { doc: this }
47
+ }
48
+ }
49
+ /** @returns {Promise<BackgroundTokenizer>} */
50
+ const createBackgroundTokenizer = (/** @type {string} */text, compiler = new NakoCompiler()) => {
51
+ return new Promise((resolve, reject) => {
52
+ const tokenizer = new BackgroundTokenizer(
53
+ new AceDocument(text),
54
+ compiler,
55
+ () => { resolve(tokenizer) }, // ok
56
+ (_, err) => { reject(err) }, // err
57
+ true
58
+ )
59
+ })
60
+ }
61
+ describe('シンタックスハイライト', () => {
62
+ it('コードを分割する', () => {
63
+ const tokens = tokenize('A=1\nA+1を表示'.split('\n'), new NakoCompiler(), false).editorTokens
64
+
65
+ // 1行目
66
+ assert.strictEqual(tokens[0][0].value, 'A')
67
+ assert.strictEqual(tokens[0][1].value, '=')
68
+ assert.strictEqual(tokens[0][2].value, '1')
69
+
70
+ // 2行目
71
+ assert.strictEqual(tokens[1][0].value, 'A')
72
+ assert.strictEqual(tokens[1][1].value, '+')
73
+ assert.strictEqual(tokens[1][2].value, '1を')
74
+ assert.strictEqual(tokens[1][3].value, '表示')
75
+ })
76
+ it('scopeを割り当てる', () => {
77
+ const tokens = tokenize('A=1\nA+1を表示'.split('\n'), new NakoCompiler(), false).editorTokens
78
+
79
+ // 1行目
80
+ assert(tokens[0][0].type.includes('variable'))
81
+ assert(tokens[0][1].type.includes('operator'))
82
+ assert(tokens[0][2].type.includes('numeric'))
83
+
84
+ // 2行目
85
+ assert(tokens[1][0].type.includes('variable'))
86
+ assert(tokens[1][1].type.includes('operator'))
87
+ assert(tokens[1][2].type.includes('numeric'))
88
+ assert(tokens[1][3].type.includes('function'))
89
+ })
90
+ it('取り込み文を無視する', () => {
91
+ tokenize('!「http://www.example.com/non_existent_file.nako3」を取り込む。'.split('\n'), new NakoCompiler(), false)
92
+ })
93
+ it('助詞に下線を引く', () => {
94
+ const tokens = tokenize('「\n」を表示'.split('\n'), new NakoCompiler(), true).editorTokens
95
+ assert.strictEqual(tokens[1][0].value, '」')
96
+ assert(tokens[1][0].type.includes('string'))
97
+
98
+ assert.strictEqual(tokens[1][1].value, 'を')
99
+ assert(tokens[1][1].type.includes('underline'))
100
+
101
+ assert.strictEqual(tokens[1][2].value, '表示')
102
+ assert(tokens[1][2].type.includes('function'))
103
+ })
104
+ // todo
105
+ /*
106
+ it('依存ファイルのキャッシュを利用する', () => {
107
+ const nako3 = new CNako3()
108
+ const code = '!「./requiretest_indirect.nako3」を取り込む\n1と2の痕跡演算'
109
+ const file = path.join(__dirname, 'main.nako3')
110
+ nako3.loadDependencies(code, file, '')
111
+ const tokens = tokenize(code.split('\n'), nako3, true)
112
+
113
+ // 「痕跡演算」が関数として認識されていることを確認する。
114
+ const token = tokens.editorTokens[1].find((token) => token.value === '痕跡演算')
115
+ expect(token).to.have.property('type').and.to.include('function')
116
+ })
117
+ it('シンタックスハイライトにかかる時間が依存ファイルの行数に依存しないことを確認', () => {
118
+ // 一時的に大きいファイルを作成
119
+ const largeFile = path.join(__dirname, 'large_file.nako3')
120
+ assert(!fs.existsSync(largeFile))
121
+ fs.writeFileSync(largeFile, '●(Aを)large_fileとは\nここまで\nA=1+2+3+4+5\n'.repeat(1000))
122
+ try {
123
+ // 大きいファイルを取り込むコードを実行
124
+ const code = '!「./large_file.nako3」を取り込む\n1をlarge_file'
125
+ const file = path.join(__dirname, 'main.nako3')
126
+
127
+ const nako3 = new CNako3()
128
+ console.time('loadDependencies')
129
+ nako3.loadDependencies(code, file, '') // この行は遅いが、取り込み文に変更が合った時しか呼ばれない
130
+ console.timeEnd('loadDependencies')
131
+
132
+ const startTime = process.hrtime.bigint()
133
+ console.time('tokenize')
134
+ const tokens = tokenize(code.split('\n'), nako3, true) // この行は速い必要がある
135
+ const delta = process.hrtime.bigint() - startTime
136
+ console.timeEnd('tokenize')
137
+
138
+ // 200ms以下で終わることを確認
139
+ // GitHub Actions で10〜40msくらいかかる。
140
+ assert(delta <= BigInt(200000000))
141
+
142
+ // 取り込みが行われたことを確認する
143
+ const token = tokens.editorTokens[1].find((token) => token.value === 'large_file')
144
+ expect(token).to.have.property('type').and.to.include('function')
145
+ } finally {
146
+ fs.unlinkSync(largeFile)
147
+ }
148
+ })
149
+ */
150
+ it('明示的に取り込んだプラグインの関数', async () => {
151
+ const compiler = new CNako3()
152
+ const code = '!「plugin_csv.mjs」を取り込む\n「1」のCSV取得'
153
+ await compiler.loadDependencies(code, '', '')
154
+ const token = tokenize(code.split('\n'), compiler, false).editorTokens[1][1]
155
+ expect(token.type).to.include('function')
156
+ expect(token.docHTML).to.include('CSV取得')
157
+ expect(token.value).to.equal('CSV取得')
158
+ })
159
+ })
160
+ describe('ドキュメントのホバー', () => {
161
+ it('プラグイン関数の助詞のドキュメントを表示する', () => {
162
+ const nako3 = new NakoCompiler()
163
+ nako3.addPluginObject('PluginEditorTest', {
164
+ 'プラグイン関数テスト': {
165
+ type: 'func',
166
+ josi: [['を', 'と'], ['に', 'は']],
167
+ fn: () => {}
168
+ }
169
+ })
170
+
171
+ const token = tokenize('XをYにプラグイン関数テスト'.split('\n'), nako3, false)
172
+ .editorTokens[0]
173
+ .find((t) => t.value === 'プラグイン関数テスト')
174
+ expect(token).to.have.property('docHTML').and.to.include('(Aを|Aと、Bに|Bは)')
175
+ expect(token).to.have.property('docHTML').and.to.include('PluginEditorTest')
176
+ })
177
+ it('ユーザー定義関数の助詞のドキュメントを表示する', () => {
178
+ const token = tokenize('●(Aを)Fとは\nここまで\n1をF'.split('\n'), new NakoCompiler(), false)
179
+ .editorTokens[2]
180
+ .find((t) => t.value === 'F')
181
+ expect(token).to.have.property('docHTML').and.to.include('(Aを)')
182
+ })
183
+ it('前回の実行結果の影響を受けない', () => {
184
+ const nako3 = new NakoCompiler()
185
+ tokenize('●(Aを)Fとは\nここまで\n1をF'.split('\n'), nako3, false)
186
+ const token = tokenize('1をF'.split('\n'), nako3, false)
187
+ .editorTokens[0]
188
+ .find((t) => t.value === 'F')
189
+ // eslint-disable-next-line no-unused-expressions
190
+ expect(token).to.have.property('docHTML').and.is.null
191
+ })
192
+ })
193
+ describe('行コメントのトグル', () => {
194
+ it('コメントアウト', () => {
195
+ const doc = new AceDocument('abc\n')
196
+ LanguageFeatures.toggleCommentLines('', doc.asSession(), 0, 1)
197
+ assert.deepStrictEqual(doc.log, [
198
+ ['insertInLine', { row: 0, column: 0 }, '// '],
199
+ ['insertInLine', { row: 1, column: 0 }, '// ']
200
+ ])
201
+ })
202
+ it('アンコメント', () => {
203
+ const doc = new AceDocument('// abc\n\n※def')
204
+ LanguageFeatures.toggleCommentLines('', doc.asSession(), 0, 2)
205
+ assert.deepStrictEqual(doc.log, [
206
+ ['removeInLine', 0, 0, 3], // '// ' を削除
207
+ ['removeInLine', 2, 0, 1] // '※' を削除
208
+ ])
209
+ })
210
+ it('中黒のある場合', () => {
211
+ const doc = new AceDocument('・・abc')
212
+ LanguageFeatures.toggleCommentLines('', doc.asSession(), 0, 0)
213
+ assert.deepStrictEqual(doc.log, [
214
+ ['insertInLine', { row: 0, column: 2 }, '// '] // 'abc' の直前に挿入
215
+ ])
216
+ })
217
+ })
218
+ describe('auto outdent', () => {
219
+ it('「ここまで」を入力し終わった瞬間に発火する', () => {
220
+ assert(!LanguageFeatures.checkOutdent('start', ' ここ', 'ま'))
221
+ assert(LanguageFeatures.checkOutdent('start', ' ここま', 'で'))
222
+ assert(!LanguageFeatures.checkOutdent('start', ' ここまで', '\n'))
223
+
224
+ assert(!LanguageFeatures.checkOutdent('start', '・ここ', 'ま'))
225
+ assert(LanguageFeatures.checkOutdent('start', '・ここま', 'で'))
226
+ assert(!LanguageFeatures.checkOutdent('start', '・ここまで', '\n'))
227
+ })
228
+ it('1つ前の行がブロックの開始行なら、その行に合わせる', () => {
229
+ const doc = new AceDocument(' もしはいならば\n ここまで')
230
+ // 2行目にauto outdentを実行
231
+ new LanguageFeatures(AceRange, new NakoCompiler()).autoOutdent('start', doc.asSession(), 1)
232
+ // 2行目の0-8文字目が ' ' で置換される
233
+ assert.deepStrictEqual(doc.log, [['replace', new AceRange(1, 0, 1, 8), ' ']])
234
+ })
235
+ it('1つ前の行がブロックの開始行でなければ、1段階インデントを下げる', () => {
236
+ const doc = new AceDocument('もしはいならば\n もしはいならば\n 1を表示\n ここまで')
237
+ // 4行目にauto outdentを実行
238
+ new LanguageFeatures(AceRange, new NakoCompiler()).autoOutdent('start', doc.asSession(), 3)
239
+ // 2行目の0-8文字目が ' ' で置換される
240
+ assert.deepStrictEqual(doc.log, [['replace', new AceRange(3, 0, 3, 8), ' ']])
241
+ })
242
+ })
243
+ describe('auto indent', () => {
244
+ it('0列目の場合', () => {
245
+ // 1段階インデントする
246
+ assert.strictEqual(
247
+ LanguageFeatures.getNextLineIndent('start', 'もしはいならば', ' '),
248
+ ' '
249
+ )
250
+ })
251
+ it('4列目の場合', () => {
252
+ // 1段階インデントする
253
+ assert.strictEqual(
254
+ LanguageFeatures.getNextLineIndent('start', ' もしはいならば', ' '),
255
+ ' '
256
+ )
257
+ })
258
+ it('ブロックの開始行ではない場合', () => {
259
+ // 1つ前の行と同じインデント幅を返す
260
+ assert.strictEqual(
261
+ LanguageFeatures.getNextLineIndent('start', ' もしはい', ' '),
262
+ ' '
263
+ )
264
+ })
265
+ })
266
+ describe('バックグラウンドでコードをトークン化する', () => {
267
+ it('成功時', async () => {
268
+ const t = await createBackgroundTokenizer('1を表示')
269
+ // 0行目の0、1、2個目のトークン
270
+ expect(t.lines[0][0]).to.include({ type: 'constant.numeric', docHTML: null, value: '1' })
271
+ expect(t.lines[0][1]).to.include({ type: 'constant.numeric.markup.underline', value: 'を' })
272
+ expect(t.lines[0][2]).to.include({ type: 'entity.name.function', value: '表示' })
273
+ })
274
+ it('失敗時', async () => {
275
+ let ok = false
276
+ try {
277
+ await createBackgroundTokenizer('「{」')
278
+ } catch (err) {
279
+ expect(err).to.be.instanceOf(NakoLexerError)
280
+ ok = true
281
+ }
282
+ if (!ok) { throw new Error() }
283
+ })
284
+ })
285
+ describe('オートコンプリート', () => {
286
+ // todo
287
+ /*
288
+ it('同一ファイル内の関数', async () => {
289
+ const compiler = new NakoCompiler()
290
+ const tokenizer = await createBackgroundTokenizer('●(Aを)テスト用関数とは\nここまで\n', compiler)
291
+ expect(LanguageFeatures.getCompletionItems(2, '', compiler, tokenizer)).to.deep.include({
292
+ caption: "(Aを)テスト用関数",
293
+ value: "テスト用関数",
294
+ meta: "関数",
295
+ score: 0,
296
+ })
297
+ })
298
+ */
299
+ it('同一ファイルの変数', async () => {
300
+ const compiler = new NakoCompiler()
301
+ const tokenizer = await createBackgroundTokenizer('テスト用変数=10\nここまで\n', compiler)
302
+ expect(LanguageFeatures.getCompletionItems(2, '', compiler, tokenizer)).to.deep.include({
303
+ caption: 'テスト用変数',
304
+ value: 'テスト用変数',
305
+ meta: '変数',
306
+ score: 0
307
+ })
308
+ })
309
+ it('組み込みのプラグイン関数', async () => {
310
+ const compiler = new NakoCompiler()
311
+ compiler.addPluginObject('PluginEditorTest', { 'テスト用プラグイン関数': { type: 'func', josi: [['を'], ['に']], pure: true, fn: () => {} } })
312
+ const tokenizer = await createBackgroundTokenizer('', compiler)
313
+ expect(LanguageFeatures.getCompletionItems(0, '', compiler, tokenizer)).to.deep.include({
314
+ caption: '(Aを、Bに)テスト用プラグイン関数',
315
+ value: 'テスト用プラグイン関数',
316
+ meta: 'PluginEditorTest',
317
+ score: 0
318
+ })
319
+ })
320
+ it('組み込みのプラグイン変数', async () => {
321
+ const compiler = new NakoCompiler()
322
+ compiler.addPluginObject('PluginEditorTest', { 'テスト用プラグイン変数': { type: 'var', value: 0 } })
323
+ const tokenizer = await createBackgroundTokenizer('', compiler)
324
+ expect(LanguageFeatures.getCompletionItems(0, '', compiler, tokenizer)).to.deep.include({
325
+ caption: 'テスト用プラグイン変数',
326
+ value: 'テスト用プラグイン変数',
327
+ meta: 'PluginEditorTest',
328
+ score: 0
329
+ })
330
+ })
331
+ // todo
332
+ /*
333
+ it('別ファイルの関数', async () => {
334
+ const compiler = new CNako3()
335
+ const code = `!「${__dirname}/requiretest.nako3」を取り込む\n`
336
+ compiler.loadDependencies(code, '', '')
337
+ const tokenizer = await createBackgroundTokenizer(code, compiler)
338
+ const result = LanguageFeatures.getCompletionItems(0, '', compiler, tokenizer)
339
+ assert(result.some((v) => v.caption === '(Aと、Bを)痕跡演算'))
340
+ })
341
+ */
342
+ it('関数の呼び出しはmetaの値に影響を与えない', async () => {
343
+ const compiler = new NakoCompiler()
344
+ compiler.addPluginObject('PluginEditorTest', { 'テスト用プラグイン関数': { type: 'func', josi: [['を'], ['に']], pure: true, fn: () => {} } })
345
+ const tokenizer = await createBackgroundTokenizer('テスト用プラグイン関数\n', compiler)
346
+ const result = LanguageFeatures.getCompletionItems(1, '', compiler, tokenizer)
347
+ assert.deepStrictEqual(result.filter((v) => v.value === 'テスト用プラグイン関数'), [
348
+ {
349
+ caption: '(Aを、Bに)テスト用プラグイン関数',
350
+ value: 'テスト用プラグイン関数',
351
+ meta: 'PluginEditorTest', // ここに `関数` が表示されないことを確認する
352
+ score: 0
353
+ }
354
+ ])
355
+ })
356
+ // todo
357
+ /*
358
+ it('同一名の関数の定義が複数あるとき、候補には1つしか表示しない', async () => {
359
+ const compiler = new NakoCompiler()
360
+ const tokenizer = await createBackgroundTokenizer('●(Aを)テスト用関数とは\nここまで\n●(Aを)テスト用関数とは\nここまで\n', compiler)
361
+ expect(LanguageFeatures.getCompletionItems(2, '', compiler, tokenizer)).to.deep.include({
362
+ caption: "(Aを)テスト用関数",
363
+ value: "テスト用関数",
364
+ meta: "関数", // `関数, 関数` にならないことを確認する
365
+ score: 0,
366
+ })
367
+ })
368
+ */
369
+ })
370
+ it('テスト定義に実行ボタンを表示する', () => {
371
+ const out = LanguageFeatures.getCodeLens(new AceDocument(
372
+ '●テスト:足すとは\n' +
373
+ 'ここまで\n' +
374
+ '●(AとBを)足すとは\n' +
375
+ 'ここまで\n' +
376
+ '●テスト:引くとは\n' +
377
+ 'ここまで\n'
378
+ ))
379
+ assert.deepStrictEqual(out, [
380
+ { start: { row: 0 }, command: { title: 'テストを実行', id: 'runTest', arguments: ['足す'] } },
381
+ { start: { row: 4 }, command: { title: 'テストを実行', id: 'runTest', arguments: ['引く'] } }
382
+ ])
383
+ })
384
+ })