nadesiko3 3.3.13 → 3.3.16

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.
package/src/cnako3mod.mjs CHANGED
@@ -1,11 +1,10 @@
1
- // @ts-nocheck
2
1
  /**
3
2
  * コマンドライン版のなでしこ3をモジュールとして定義
4
3
  * 実際には cnako3.js から読み込まれる
5
4
  */
6
5
  import fs from 'fs'
7
6
  import { exec } from 'child_process'
8
- import path from 'path'
7
+ import path, { resolve } from 'path'
9
8
  import { NakoCompiler } from './nako3.mjs'
10
9
  import PluginNode from './plugin_node.mjs'
11
10
  import { NakoImportError } from './nako_errors.mjs'
@@ -23,7 +22,7 @@ export class CNako3 extends NakoCompiler {
23
22
  super({ useBasicPlugin: true })
24
23
  this.silent = false
25
24
  if (!opts.nostd) {
26
- this.addPluginFile('PluginNode', path.join(__dirname, 'plugin_node.js'), PluginNode)
25
+ this.addPluginFile('PluginNode', path.join(__dirname, 'plugin_node.mjs'), PluginNode)
27
26
  }
28
27
  this.__varslist[0]['ナデシコ種類'] = 'cnako3'
29
28
  }
@@ -61,12 +60,23 @@ export class CNako3 extends NakoCompiler {
61
60
 
62
61
  /**
63
62
  * コマンドライン引数を解析
64
- * @returns {{warn: boolean, debug: boolean, compile: any | boolean, test: any | boolean, one_liner: any | boolean, trace: any, run: any | boolean, repl: any | boolean, source: any | string}}
63
+ * @returns {{
64
+ * warn: boolean,
65
+ * debug: boolean,
66
+ * compile: any | boolean,
67
+ * test: any | boolean,
68
+ * one_liner: any | boolean,
69
+ * trace: any | boolean,
70
+ * run: any | boolean,
71
+ * repl: any | boolean,
72
+ * source: any | string,
73
+ * mainfile: any | string,
74
+ * }}
65
75
  */
66
76
  checkArguments () {
67
77
  const app = this.registerCommands()
68
78
 
69
- /** @type {import('./nako_logger').LogLevel} */
79
+ /** @type {import('./nako_logger.mjs').LogLevel} */
70
80
  let logLevel = 'error'
71
81
  if (app.trace) {
72
82
  logLevel = 'trace'
@@ -99,21 +109,23 @@ export class CNako3 extends NakoCompiler {
99
109
  }
100
110
  args.mainfile = app.args[0]
101
111
  args.output = app.output
112
+
113
+ // todo: ESModule 対応の '.mjs' のコードを履く #1217
114
+ const ext = '.js'
102
115
  if (/\.(nako|nako3|txt|bak)$/.test(args.mainfile)) {
103
116
  if (!args.output) {
104
117
  if (args.test) {
105
- args.output = args.mainfile.replace(/\.(nako|nako3)$/, '.spec.js')
118
+ args.output = args.mainfile.replace(/\.(nako|nako3)$/, '.spec' + ext)
106
119
  } else {
107
- // todo: 将来的に mjs のコードを履くように修正する↓ '.mjs'
108
- args.output = args.mainfile.replace(/\.(nako|nako3)$/, '.js')
120
+ args.output = args.mainfile.replace(/\.(nako|nako3)$/, ext)
109
121
  }
110
122
  }
111
123
  } else {
112
124
  if (!args.output) {
113
125
  if (args.test) {
114
- args.output = args.mainfile + '.spec.js'
126
+ args.output = args.mainfile + '.spec' + ext
115
127
  } else {
116
- args.output = args.mainfile + '.js'
128
+ args.output = args.mainfile + ext
117
129
  }
118
130
  }
119
131
  args.mainfile += '.nako3'
@@ -201,6 +213,28 @@ export class CNako3 extends NakoCompiler {
201
213
  const jscode = this.compileStandalone(src, this.filename, isTest)
202
214
  console.log(opt.output)
203
215
  fs.writeFileSync(opt.output, jscode, 'utf-8')
216
+
217
+ /*
218
+ // 実行に必要なファイルをコピー
219
+ const nakoRuntime = __dirname
220
+ const outRuntime = path.join(path.dirname(opt.output), 'nako3runtime')
221
+ if (!fs.existsSync(outRuntime)) { fs.mkdirSync(outRuntime) }
222
+ for (let mod of ['nako_version.mjs', 'nako_errors.mjs', 'plugin_node.mjs']) {
223
+ fs.copyFileSync(path.join(nakoRuntime, mod), path.join(outRuntime, mod))
224
+ }
225
+ // todo: 必要に応じてnode_modulesをコピー (時間が掛かりすぎるのでコピーしない)
226
+ const dstModule = path.join(path.dirname(opt.output), 'node_modules')
227
+ const orgModule = path.join(__dirname, '..', 'node_modules')
228
+ if (!fs.existsSync(dstModule)) {
229
+ fs.mkdirSync(dstModule)
230
+ fse.copySync(path.join(orgModule), path.join(dstModule))
231
+ }
232
+ // or 以下のコピーだと依存ファイルがコピーされない package.jsonを見てコピーする必要がある
233
+ for (let mod of ['fs-extra', 'iconv-lite', 'opener', 'clipboardy', 'sendkeys-js']) {
234
+ fse.copySync(path.join(orgModule, mod), path.join(dstModule, mod))
235
+ }
236
+ */
237
+
204
238
  if (opt.run) {
205
239
  exec(`node ${opt.output}`, function (err, stdout, stderr) {
206
240
  if (err) { console.log('[ERROR]', stderr) }
@@ -321,43 +355,57 @@ export class CNako3 extends NakoCompiler {
321
355
  /** @type {string[]} */
322
356
  const log = []
323
357
  const tools = {}
324
- tools.resolvePath = (name, token) => {
325
- // JSプラグインのパスを解決する
326
- if (/\.(js|mjs)(\.txt)?$/.test(name) || /^[^.]*$/.test(name)) {
327
- const jspath = CNako3.findJSPluginFile(name, this.filename, __dirname, log)
358
+ tools.resolvePath = (name, token, fromFile) => {
359
+ // 最初に拡張子があるかどうかをチェック
360
+ // JSプラグインか?
361
+ if (/\.(js|mjs)(\.txt)?$/.test(name)) {
362
+ const jspath = CNako3.findJSPluginFile(name, fromFile, __dirname, log)
328
363
  if (jspath === '') {
329
- throw new NakoImportError(`ファイル『${name}』が見つかりません。以下のパスを検索しました。\n${log.join('\n')}`, token.file, token.line)
364
+ throw new NakoImportError(`JSプラグイン『${name}』が見つかりません。以下のパスを検索しました。\n${log.join('\n')}`, token.file, token.line)
330
365
  }
331
366
  return { filePath: jspath, type: 'js' }
332
367
  }
333
- // なでしこプラグインのパスを解決する
334
- if (/\.nako3?(\.txt)?$/.test(name)) {
368
+ // なでしこプラグインか?
369
+ if (/\.(nako3|nako)(\.txt)?$/.test(name)) {
335
370
  if (path.isAbsolute(name)) {
336
371
  return { filePath: path.resolve(name), type: 'nako3' }
337
372
  } else {
338
373
  // filename が undefined のとき token.file が undefined になる。
339
- if (token.file === undefined) {
340
- throw new Error('ファイル名を指定してください。')
341
- }
342
- return { filePath: path.resolve(path.join(path.dirname(token.file), name)), type: 'nako3' }
374
+ if (token.file === undefined) { throw new Error('ファイル名を指定してください。') }
375
+ const dir = path.dirname(fromFile)
376
+ return { filePath: path.resolve(path.join(dir, name)), type: 'nako3' }
343
377
  }
344
378
  }
345
- return { filePath: name, type: 'invalid' }
379
+ // 拡張子がない、あるいは、(.js|.mjs|.nako3|.nako)以外はJSモジュールと見なす
380
+ const jspath2 = CNako3.findJSPluginFile(name, fromFile, __dirname, log)
381
+ if (jspath2 === '') {
382
+ throw new NakoImportError(`JSプラグイン『${name}』が見つかりません。以下のパスを検索しました。\n${log.join('\n')}`, token.file, token.line)
383
+ }
384
+ return { filePath: jspath2, type: 'js' }
346
385
  }
347
386
  tools.readNako3 = (name, token) => {
348
- if (!fs.existsSync(name)) {
349
- throw new NakoImportError(`ファイル ${name} が存在しません。`, token.file, token.line)
350
- }
351
- return { sync: true, value: fs.readFileSync(name).toString() }
387
+ // ファイルチェックだけ先に実行
388
+ if (!fs.existsSync(name)) {
389
+ throw new NakoImportError(`ファイル ${name} が存在しません。`, token.file, token.line)
390
+ }
391
+ // 非同期で読み込む
392
+ const loader = {task: null}
393
+ loader.task = (new Promise((resolve, reject) => {
394
+ fs.readFile(name, {encoding: 'utf-8'}, (err, data) => {
395
+ if (err) { return reject(err) }
396
+ resolve(data)
397
+ })
398
+ }))
399
+ return loader
352
400
  }
353
401
  tools.readJs = (filePath, token) => {
354
- const content = {sync: false, value: null}
402
+ const loader = {task: null}
355
403
  if (process.platform === 'win32') {
356
404
  if (filePath.substring(1, 3) === ':\\') {
357
405
  filePath = 'file://' + filePath
358
406
  }
359
407
  }
360
- content.value = (
408
+ loader.task = (
361
409
  new Promise((resolve, reject) => {
362
410
  import(filePath).then((mod) => {
363
411
  // プラグインは export default で宣言されている? (moduleプラグインの場合)
@@ -369,7 +417,7 @@ export class CNako3 extends NakoCompiler {
369
417
  })
370
418
  })
371
419
  )
372
- return content
420
+ return loader
373
421
  }
374
422
  return tools
375
423
  }
@@ -412,87 +460,111 @@ export class CNako3 extends NakoCompiler {
412
460
  */
413
461
  static findJSPluginFile (pname, filename, srcDir, log = []) {
414
462
  log.length = 0
463
+ /** @type {Object<string,boolean>} */
415
464
  const cachePath = {}
416
- /** @type {string[]} */
417
- const exists = (f, _desc) => {
465
+ /** キャッシュ付きでファイルがあるか検索
466
+ * @param {string} f
467
+ * @returns {boolean}
468
+ */
469
+ const exists = (f) => {
418
470
  // 同じパスを何度も検索することがないように
419
- if (cachePath[f]) { return false }
420
- cachePath[f] = true
421
- log.push(f)
471
+ if (cachePath[f]) { return cachePath[f] }
422
472
  const stat = fs.statSync(f, {throwIfNoEntry: false})
423
- if (!stat) { return false }
424
- return stat.isFile()
473
+ const b = !!(stat && stat.isFile())
474
+ return cachePath[f] = b
425
475
  }
426
- // 普通にファイルをチェック
427
- const fCheck = (pathTest) => {
476
+ /** 普通にファイルをチェック
477
+ * @param {string} pathTest
478
+ * @param {string} desc
479
+ * @returns {boolean}
480
+ */
481
+ const fCheck = (pathTest, desc) => {
428
482
  // 素直に指定されたパスをチェック
429
- let fpath = path.join(pathTest, pname)
430
- if (exists(fpath, 'direct')) { return fpath }
431
- return false
432
- }
433
- // ファイル および node_modules 以下を調べる
434
- const fCheckEx = (pathTest) => {
435
- const defPath = fCheck(pathTest)
436
- if (defPath) { return defPath }
437
- const fpath = path.join(pathTest, 'node_modules', pname)
438
- const json = path.join(fpath, 'package.json')
439
- if (exists(json)) {
483
+ const bExists = exists(pathTest)
484
+ log.push(`[${desc}] ${pathTest}, ${bExists}`)
485
+ return bExists
486
+ }
487
+ /** 通常 + package.json のパスを調べる
488
+ * @param {string} pathTest
489
+ * @param {string} desc
490
+ * @returns {string}
491
+ */
492
+ const fCheckEx = (pathTest, desc) => {
493
+ // 直接JSファイルが指定された?
494
+ if (/\.(js|mjs)$/.test(pathTest)) {
495
+ if (fCheck(pathTest, desc)) { return pathTest }
496
+ }
497
+ // 指定パスのpackage.jsonを調べる
498
+ const json = path.join(pathTest, 'package.json')
499
+ if (fCheck(json, desc+'/package.json')) {
440
500
  // package.jsonを見つけたので、メインファイルを調べて取り込む (CommonJSモジュール対策)
441
501
  const json_txt = fs.readFileSync(json, 'utf-8')
442
502
  const obj = JSON.parse(json_txt)
443
- if (!obj['main']) { return false }
444
- const mainFile = path.join(pathTest, 'node_modules', pname, obj['main'])
503
+ if (!obj['main']) { return '' }
504
+ const mainFile = path.resolve(path.join(pathTest, obj['main']))
445
505
  return mainFile
446
506
  }
447
- return false
507
+ return ''
508
+ }
509
+
510
+ // URL指定か?
511
+ if (pname.substring(0, 8) === 'https://') {
512
+ return pname
448
513
  }
449
514
  // 各パスを検索していく
450
515
  const p1 = pname.substring(0, 1)
451
516
  // フルパス指定か?
452
- if (p1 === '/' || pname.substring(1, 3).toLowerCase() === ':\\') {
453
- if (exists(pname)) { return pname }
454
- const fileFullpath = fCheckEx(pname)
517
+ if (p1 === '/' || pname.substring(1, 3).toLowerCase() === ':\\' || pname.substring(0, 6) === 'file:/') {
518
+ const fileFullpath = fCheckEx(pname, 'fullpath')
455
519
  if (fileFullpath) { return fileFullpath }
456
520
  return '' // フルパスの場合別のフォルダは調べない
457
521
  }
458
522
  // 相対パスか?
459
523
  if (p1 === '.' || pname.indexOf('/') >= 0) {
460
524
  // 相対パス指定なので、なでしこのプログラムからの相対指定を調べる
461
- const pathRelative = path.resolve(path.dirname(filename))
462
- const fileRelative = fCheckEx(pathRelative)
525
+ const pathRelative = path.join(path.resolve(path.dirname(filename)), pname)
526
+ const fileRelative = fCheckEx(pathRelative, 'relpath')
463
527
  if (fileRelative) { return fileRelative }
464
528
  return '' // 相対パスの場合も別のフォルダは調べない
465
529
  }
466
530
  // plugin_xxx.mjs のようにファイル名のみが指定された場合のみ、いくつかのパスを調べる
467
531
  // 母艦パス(元ファイルと同じフォルダ)か?
468
- const pathScript = path.resolve(path.dirname(filename))
469
- const fileScript = fCheckEx(pathScript)
532
+ const testScriptPath = path.join(path.resolve(path.dirname(filename)), pname)
533
+ const fileScript = fCheckEx(testScriptPath, 'scriptPath')
470
534
  if (fileScript) { return fileScript }
471
535
 
472
- // ランタイムパス/src
473
- const pathRuntimeSrc = path.resolve(srcDir) // cnako3mod.mjs は ランタイム/src に配置されていることが前提
474
- const fileRuntimeSrc = fCheck(pathRuntimeSrc)
536
+ // ランタイムパス/src/<plugin>
537
+ const pathRuntimeSrc = path.join(path.resolve(srcDir), pname) // cnako3mod.mjs は ランタイム/src に配置されていることが前提
538
+ const fileRuntimeSrc = fCheckEx(pathRuntimeSrc, 'runtimeSrcPath')
475
539
  if (fileRuntimeSrc) { return fileRuntimeSrc }
476
540
 
477
- // ランタイムパス
478
- const pathRuntime = path.resolve(path.dirname(srcDir))
479
- const fileRuntime = fCheckEx(pathRuntime)
541
+ // 環境変数をチェック
542
+ // 環境変数 NAKO_LIB か?
543
+ if (process.env.NAKO_LIB) {
544
+ const NAKO_LIB = path.join(path.resolve(process.env.NAKO_LIB), pname)
545
+ const fileLib = fCheckEx(NAKO_LIB, 'NAKO_LIB')
546
+ if (fileLib) { return fileLib }
547
+ }
548
+
549
+ // ランタイムパス/node_modules/<plugin>
550
+ const pathRuntime = path.join(path.resolve(__dirname), 'node_modules', pname)
551
+ const fileRuntime = fCheckEx(pathRuntime, 'runtime')
480
552
  if (fileRuntime) { return fileRuntime }
481
553
 
482
554
  // 環境変数 NAKO_HOMEか?
483
555
  if (process.env.NAKO_HOME) {
484
- const NAKO_HOME = path.resolve(process.env.NAKO_HOME)
485
- const fileHome = fCheckEx(NAKO_HOME)
556
+ const NAKO_HOME = path.join(path.resolve(process.env.NAKO_HOME), 'node_modules', pname)
557
+ const fileHome = fCheckEx(NAKO_HOME, 'NAKO_HOME')
486
558
  if (fileHome) { return fileHome }
487
559
  // NAKO_HOME/src ?
488
- const pathNakoHomeSrc = path.join(NAKO_HOME, 'src')
489
- const fileNakoHomeSrc = fCheck(pathNakoHomeSrc)
560
+ const pathNakoHomeSrc = path.join(NAKO_HOME, 'src', pname)
561
+ const fileNakoHomeSrc = fCheckEx(pathNakoHomeSrc, 'NAKO_HOME/src')
490
562
  if (fileNakoHomeSrc) { return fileNakoHomeSrc }
491
563
  }
492
564
  // 環境変数 NODE_PATH (global) 以下にあるか?
493
565
  if (process.env.NODE_PATH) {
494
- const pathNode = path.resolve(process.env.NODE_PATH)
495
- const fileNode = fCheckEx(pathNode)
566
+ const pathNode = path.join(path.resolve(process.env.NODE_PATH), pname)
567
+ const fileNode = fCheckEx(pathNode, 'NODE_PATH')
496
568
  if (fileNode) { return fileNode }
497
569
  }
498
570
  // Nodeのパス検索には任せない(importで必ず失敗するので)
package/src/nako3.mjs CHANGED
@@ -1,4 +1,3 @@
1
- // @ts-nocheck
2
1
  /**
3
2
  * nadesiko v3
4
3
  */
@@ -177,18 +176,20 @@ export class NakoCompiler {
177
176
 
178
177
  /**
179
178
  * プログラムが依存するファイルを再帰的に取得する。
180
- * - .jsであれば評価してthis.addPluginFileを呼び出し、.nako3であればファイルをfetchしてdependenciesに保存し再帰する。
181
- * - resolvePathはファイルを検索して正規化する必要がある。
182
- * - readNako3やreadJsのsyncを確認してfalseならPromiseを返すので並列処理し、そうでなければ同期的に処理する。
183
- * - readNako3はソースコードを返す。readJsはrequireあるいはevalする関数を返す。
179
+ * - 依存するファイルがJavaScriptファイルの場合、そのファイルを実行して評価結果をthis.addPluginFileに渡す。
180
+ * - 依存するファイルがなでしこ言語の場合、ファイルの中身を取得して変数に保存し、再帰する。
181
+ *
184
182
  * @param {string} code
185
183
  * @param {string} filename
186
184
  * @param {string} preCode
187
185
  * @param {{
188
- * resolvePath: (name: string, token: TokenWithSourceMap) => { type: 'nako3' | 'js' | 'invalid', filePath: string }
189
- * readNako3: (filePath: string, token: TokenWithSourceMap) => { sync: true, value: string } | { sync: false, value: Promise<string> }
190
- * readJs: (filePath: string, token: TokenWithSourceMap) => { sync: true, value: () => object } | { sync: false, value: Promise<() => object> }
191
- * }} tools
186
+ * resolvePath: (name: string, token: TokenWithSourceMap, fromFile: string) => { type: 'nako3' | 'js' | 'invalid', filePath: string }
187
+ * readNako3: (filePath: string, token: TokenWithSourceMap) => { task: Promise<string> }
188
+ * readJs: (filePath: string, token: TokenWithSourceMap) => { task: Promise<() => object> }
189
+ * }} tools - 実行環境 (ブラウザ or Node.js) によって外部ファイルの取得・実行方法は異なるため、引数でそれらを行う関数を受け取る。
190
+ * - resolvePath は指定した名前をもつファイルを検索し、正規化されたファイル名を返す関数。返されたファイル名はreadNako3かreadJsの引数になる。
191
+ * - readNako3は指定されたファイルの中身を返す関数。
192
+ * - readJsは指定したファイルをJavaScriptのプログラムとして実行し、`export default` でエクスポートされた値を返す関数。
192
193
  * @returns {Promise<unknown> | void}
193
194
  * @protected
194
195
  */
@@ -200,10 +201,12 @@ export class NakoCompiler {
200
201
  const loadJS = (item, tasks) => {
201
202
  // jsならプラグインとして読み込む。(ESMでは必ず動的に読む)
202
203
  const obj = tools.readJs(item.filePath, item.firstToken)
203
- tasks.push(obj.value.then((res) => {
204
- dependencies[item.filePath].addPluginFile = () => {
205
- this.addPluginFile(item.value, item.filePath, dependencies[item.filePath].funclist = res(), false)
206
- }}))
204
+ tasks.push(obj.task.then((res) => {
205
+ const pluginFuncs = res()
206
+ this.addPluginFile(item.value, item.filePath, pluginFuncs, false)
207
+ dependencies[item.filePath].funclist = pluginFuncs
208
+ dependencies[item.filePath].addPluginFile = () => { this.addPluginFile(item.value, item.filePath, pluginFuncs, false) }
209
+ }))
207
210
  }
208
211
  const loadNako3 = (item, tasks) => {
209
212
  // nako3ならファイルを読んでdependenciesに保存する。
@@ -221,15 +224,11 @@ export class NakoCompiler {
221
224
  const funclist = {}
222
225
  NakoLexer.preDefineFunc(cloneAsJSON(tokens), this.logger, funclist)
223
226
  dependencies[item.filePath].funclist = funclist
224
-
225
227
  // 再帰
226
228
  return loadRec(code, item.filePath, '')
227
229
  }
228
- if (content.sync) {
229
- registerFile(content.value)
230
- } else {
231
- tasks.push(content.value.then((res) => registerFile(res)))
232
- }
230
+ // 取り込み構文における問題を減らすため、必ず非同期でプログラムを読み込む仕様とした #1219
231
+ tasks.push(content.task.then((res) => registerFile(res)))
233
232
  }
234
233
  /** @param {string} code @param {string} filename @param {string} preCode @returns {Promise<unknown> | void} */
235
234
  const loadRec = (code, filename, preCode) => {
@@ -238,7 +237,7 @@ export class NakoCompiler {
238
237
  // 取り込みが必要な情報一覧を調べる(トークン分割して、取り込みタグを得る)
239
238
  const tags = NakoCompiler.listRequireStatements(compiler.rawtokenize(code, 0, filename, preCode))
240
239
  // パスを解決する
241
- const tagsResolvePath = tags.map((v) => ({ ...v, ...tools.resolvePath(v.value, v.firstToken) }))
240
+ const tagsResolvePath = tags.map((v) => ({ ...v, ...tools.resolvePath(v.value, v.firstToken, filename) }))
242
241
  // 取り込み開始
243
242
  for (const item of tagsResolvePath) {
244
243
  // 2回目以降の読み込み
package/src/nako_gen.mjs CHANGED
@@ -1,5 +1,4 @@
1
1
  /**
2
- * file: nako_gen.js
3
2
  * パーサーが生成した中間オブジェクトを実際のJavaScriptのコードに変換する。
4
3
  * なお速度優先で忠実にJavaScriptのコードを生成する。
5
4
  */
@@ -7,12 +6,6 @@
7
6
  import { NakoSyntaxError, NakoError, NakoRuntimeError } from './nako_errors.mjs'
8
7
  import { NakoLexer } from './nako_lexer.mjs'
9
8
  import nakoVersion from './nako_version.mjs'
10
- const isIE11 = () => {
11
- if (typeof(window) == 'object' && window.navigator && window.navigator.userAgent) {
12
- return (window.navigator.userAgent.indexOf('MSIE') >= 0)
13
- }
14
- return false
15
- }
16
9
 
17
10
  // なでしこで定義した関数の開始コードと終了コード
18
11
  const topOfFunction = '(function(){\n'
@@ -1546,7 +1539,7 @@ export class NakoGen {
1546
1539
 
1547
1540
 
1548
1541
  /**
1549
- * @param {import('./nako3')} com
1542
+ * @param {import('./nako3.mjs').NakoCompiler} com
1550
1543
  * @param {Ast} ast
1551
1544
  * @param {boolean | string} isTest 文字列なら1つのテストだけを実行する
1552
1545
  */
@@ -1573,21 +1566,19 @@ export function generateJS (com, ast, isTest) {
1573
1566
  }
1574
1567
  // async method
1575
1568
  if (gen.numAsyncFn > 0) {
1576
- let canAsync = !isIE11()
1577
- if (canAsync) {
1578
- js = `
1569
+ js = `
1579
1570
  // <nadesiko3::gen::async>
1580
1571
  (async () => { // async::main
1581
1572
  ${js}
1582
1573
  }).call(this).catch(err => {
1583
- if (!(err instanceof this.NakoRuntimeError)) {
1584
- err = new this.NakoRuntimeError(err, this.__varslist[0].line);
1585
- }
1586
- this.logger.error(err);
1587
- throw err;
1574
+ if (typeof(NakoRuntimeError) === 'undefined') { NakoRuntimeError = this.NakoRuntimeError }
1575
+ if (!(err instanceof NakoRuntimeError)) {
1576
+ err = new NakoRuntimeError(err, this.__varslist[0].line);
1577
+ }
1578
+ this.logger.error(err);
1579
+ throw err;
1588
1580
  }); // async::main
1589
1581
  // <nadesiko3::gen::async>\n`
1590
- }
1591
1582
  }
1592
1583
 
1593
1584
  // デバッグメッセージ
@@ -1595,36 +1586,37 @@ throw err;
1595
1586
  // todo: 将来的に mjs のコードを履くように修正する
1596
1587
  const standaloneJSCode = `\
1597
1588
  // <standaloneCode>
1589
+ // 将来的に ESModule に対応する #1217
1590
+ // import path from 'path'
1591
+ // import PluginNode from './nako3runtime/plugin_node.mjs'
1592
+ // import {NakoRuntimeError} from './nako3runtime/nako_errors.mjs'
1593
+
1598
1594
  const path = require('path')
1599
- const nakoVersion = ${JSON.stringify(nakoVersion)};
1600
1595
  ${NakoError.toString()}
1601
- ${NakoRuntimeError.toString()}
1602
- function __nako3safunc() {
1603
- this.logger = {
1596
+ ${NakoRuntimeError.toString()}
1597
+ const nakoVersion = ${JSON.stringify(nakoVersion)};
1598
+ const self = this
1599
+ self.logger = {
1604
1600
  error: (message) => { console.error(message) },
1605
1601
  send: (level, message) => { console.log(message) },
1606
1602
  };
1607
- this.__varslist = [{}, {}, {}];
1608
- this.__vars = this.__varslist[2];
1609
- this.__module = {};
1610
- this.__locals = {};
1611
- this.__genMode = 'sync';
1603
+ self.__varslist = [{}, {}, {}];
1604
+ self.__vars = self.__varslist[2];
1605
+ self.__module = {};
1606
+ self.__locals = {};
1607
+ self.__genMode = 'sync';
1612
1608
  try {
1613
1609
  ${gen.getVarsCode()}
1614
1610
  ${js}
1615
1611
  } catch (err) {
1616
1612
  if (!(err instanceof NakoRuntimeError)) {
1617
- err = new NakoRuntimeError(err, __varslist[0].line);
1613
+ err = new NakoRuntimeError(err, self.__varslist[0].line);
1618
1614
  }
1619
- this.logger.error(err);
1615
+ self.logger.error(err);
1620
1616
  throw err;
1621
1617
  }
1622
- //
1623
- } // end of __nako3safunc function
1624
- __nako3safunc();
1625
1618
  // </standaloneCode>
1626
- `
1627
-
1619
+ `
1628
1620
  return {
1629
1621
  // なでしこの実行環境ありの場合
1630
1622
  runtimeEnv: js,
@@ -1,7 +1,7 @@
1
1
  // なでしこバージョン
2
2
  export default {
3
- version: '3.3.13',
3
+ version: '3.3.16',
4
4
  major: 3,
5
5
  minor: 3,
6
- patch: 13
6
+ patch: 16
7
7
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * file: plugin_node.js
2
+ * file: plugin_node.mjs
3
3
  * node.js のためのプラグイン
4
4
  */
5
5
  import fs from 'fs'
@@ -11,9 +11,8 @@ import iconv from 'iconv-lite'
11
11
  import opener from 'opener'
12
12
  import clipboardy from 'clipboardy'
13
13
  import assert from 'assert'
14
- // 「標準入力取得時」で利用
15
- import * as readline from 'readline'
16
- import { stdin as input, stdout as output } from 'process'
14
+ // 「標準入力取得時」「尋」で利用
15
+ import readline from 'readline'
17
16
  // ハッシュ関数で利用
18
17
  import crypto from 'crypto'
19
18
  import os from 'os'
@@ -585,11 +584,15 @@ export default {
585
584
  josi: [['と', 'を']],
586
585
  pure: true,
587
586
  asyncFn: true,
588
- fn: async function (msg, sys) {
589
- const rl = readline.createInterface({ input, output });
590
- const res = await rl.question(msg)
591
- if (res.match(/^[0-9.]+$/)) { return parseFloat(res) }
592
- return res
587
+ fn: function (msg, sys) {
588
+ return new Promise((resolve, _reject) => {
589
+ const rl = readline.createInterface(process.stdin, process.stdout)
590
+ rl.question(msg, (buf) => {
591
+ rl.close()
592
+ if (buf && buf.match(/^[0-9.]+$/)) { buf = parseFloat(buf) }
593
+ resolve(buf)
594
+ })
595
+ })
593
596
  }
594
597
  },
595
598
  // @テスト
@@ -598,7 +601,6 @@ export default {
598
601
  josi: [['と'], ['が']],
599
602
  pure: true,
600
603
  fn: function (a, b, sys) {
601
-
602
604
  assert.strictEqual(a, b)
603
605
  }
604
606
  },