rapydscript-ng 0.7.23 → 0.8.0

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 (114) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +72 -26
  3. package/bin/package.json +1 -0
  4. package/bin/rapydscript +65 -62
  5. package/editor-plugins/nvim/rapydscript/README.md +184 -0
  6. package/editor-plugins/nvim/rapydscript/bin/rapydscript.so +0 -0
  7. package/editor-plugins/nvim/rapydscript/ftdetect/rapydscript.lua +10 -0
  8. package/editor-plugins/nvim/rapydscript/lua/rapydscript/health.lua +88 -0
  9. package/editor-plugins/nvim/rapydscript/lua/rapydscript/init.lua +279 -0
  10. package/local-agent.md +28 -0
  11. package/package.json +4 -5
  12. package/release/baselib-plain-pretty.js +448 -326
  13. package/release/baselib-plain-ugly.js +3 -3
  14. package/release/compiler.js +2528 -1672
  15. package/release/signatures.json +17 -17
  16. package/src/ast.pyj +73 -25
  17. package/src/baselib-builtins.pyj +2 -2
  18. package/src/baselib-containers.pyj +153 -151
  19. package/src/baselib-internal.pyj +3 -3
  20. package/src/baselib-str.pyj +5 -5
  21. package/src/lib/aes.pyj +1 -1
  22. package/src/lib/encodings.pyj +1 -1
  23. package/src/lib/pythonize.pyj +1 -1
  24. package/src/lib/re.pyj +2 -2
  25. package/src/lib/traceback.pyj +165 -28
  26. package/src/lib/uuid.pyj +1 -1
  27. package/src/output/codegen.pyj +10 -3
  28. package/src/output/functions.pyj +31 -40
  29. package/src/output/literals.pyj +11 -14
  30. package/src/output/loops.pyj +25 -87
  31. package/src/output/modules.pyj +5 -47
  32. package/src/output/statements.pyj +1 -1
  33. package/src/output/stream.pyj +58 -31
  34. package/src/parse.pyj +777 -427
  35. package/src/tokenizer.pyj +16 -4
  36. package/src/utils.pyj +1 -1
  37. package/test/_treeshake_mod.pyj +30 -0
  38. package/test/_treeshake_side_effect.pyj +9 -0
  39. package/test/ast_serialization.pyj +392 -0
  40. package/test/async.pyj +95 -0
  41. package/test/baselib.pyj +1 -2
  42. package/test/embedded_compiler.pyj +57 -0
  43. package/test/fmt.pyj +201 -0
  44. package/test/generic.pyj +7 -3
  45. package/test/imports.pyj +8 -6
  46. package/test/internationalization.pyj +38 -37
  47. package/test/lint.pyj +120 -115
  48. package/test/lsp.pyj +222 -0
  49. package/test/repl.pyj +70 -65
  50. package/test/sourcemaps.pyj +315 -0
  51. package/test/starargs.pyj +46 -39
  52. package/test/traceback.pyj +263 -0
  53. package/test/treeshaking.pyj +181 -0
  54. package/test/web_repl_export.pyj +88 -0
  55. package/tools/ast_serialize.mjs +557 -0
  56. package/tools/cli.mjs +510 -0
  57. package/tools/compile.mjs +201 -0
  58. package/tools/compiler.mjs +127 -0
  59. package/tools/{completer.js → completer.mjs} +6 -6
  60. package/tools/{embedded_compiler.js → embedded_compiler.mjs} +17 -13
  61. package/tools/export.js +109 -56
  62. package/tools/fmt.mjs +735 -0
  63. package/tools/{gettext.js → gettext.mjs} +46 -53
  64. package/tools/{ini.js → ini.mjs} +9 -10
  65. package/tools/{lint.js → lint.mjs} +107 -56
  66. package/tools/lsp.mjs +914 -0
  67. package/tools/lsp_protocol.mjs +259 -0
  68. package/tools/lsp_symbols.mjs +418 -0
  69. package/tools/{msgfmt.js → msgfmt.mjs} +18 -18
  70. package/tools/{repl.js → repl.mjs} +52 -41
  71. package/tools/{self.js → self.mjs} +56 -46
  72. package/tools/sourcemap.mjs +123 -0
  73. package/tools/test.mjs +152 -0
  74. package/tools/treeshake.mjs +400 -0
  75. package/tools/{utils.js → utils.mjs} +26 -23
  76. package/tools/{web_repl.js → web_repl.mjs} +15 -13
  77. package/tools/web_repl_export.mjs +93 -0
  78. package/tree-sitter/README.md +101 -0
  79. package/tree-sitter/grammar.js +992 -0
  80. package/tree-sitter/package.json +43 -0
  81. package/tree-sitter/queries/rapydscript/highlights.scm +232 -0
  82. package/tree-sitter/queries/rapydscript/indents.scm +64 -0
  83. package/tree-sitter/queries/rapydscript/injections.scm +14 -0
  84. package/tree-sitter/queries/rapydscript/locals.scm +108 -0
  85. package/tree-sitter/src/grammar.json +4976 -0
  86. package/tree-sitter/src/node-types.json +2901 -0
  87. package/tree-sitter/src/parser.c +196465 -0
  88. package/tree-sitter/src/scanner.c +294 -0
  89. package/tree-sitter/src/tree_sitter/alloc.h +54 -0
  90. package/tree-sitter/src/tree_sitter/array.h +330 -0
  91. package/tree-sitter/src/tree_sitter/parser.h +286 -0
  92. package/tree-sitter/test/corpus/chaining.txt +99 -0
  93. package/tree-sitter/test/corpus/classes.txt +147 -0
  94. package/tree-sitter/test/corpus/comprehensions.txt +155 -0
  95. package/tree-sitter/test/corpus/containers.txt +242 -0
  96. package/tree-sitter/test/corpus/control_flow.txt +361 -0
  97. package/tree-sitter/test/corpus/decorators.txt +64 -0
  98. package/tree-sitter/test/corpus/existential.txt +102 -0
  99. package/tree-sitter/test/corpus/functions.txt +293 -0
  100. package/tree-sitter/test/corpus/imports.txt +117 -0
  101. package/tree-sitter/test/corpus/literals.txt +135 -0
  102. package/tree-sitter/test/corpus/operators.txt +296 -0
  103. package/tree-sitter/test/corpus/statements.txt +189 -0
  104. package/tree-sitter/test/corpus/strings.txt +90 -0
  105. package/tree-sitter/test/corpus/subscripts.txt +227 -0
  106. package/tree-sitter/tree-sitter.json +36 -0
  107. package/web-repl/env.js +35 -23
  108. package/web-repl/main.js +8 -8
  109. package/bin/export +0 -75
  110. package/bin/web-repl-export +0 -102
  111. package/tools/cli.js +0 -523
  112. package/tools/compile.js +0 -184
  113. package/tools/compiler.js +0 -84
  114. package/tools/test.js +0 -110
@@ -1,17 +1,19 @@
1
1
  /* vim:fileencoding=utf-8
2
- *
2
+ *
3
3
  * Copyright (C) 2015 Kovid Goyal <kovid at kovidgoyal.net>
4
4
  *
5
5
  * Distributed under terms of the BSD license
6
6
  */
7
- "use strict"; /*jshint node:true */
7
+ "use strict";
8
+
9
+ import fs from 'fs';
10
+ import path from 'path';
8
11
 
9
- var fs = require('fs');
10
- var RapydScript = (typeof create_rapydscript_compiler === 'function') ? create_rapydscript_compiler() : require('./compiler').create_compiler();
11
- var path = require('path');
12
+ var _rapydscript_compiler = typeof create_rapydscript_compiler !== 'undefined' ? create_rapydscript_compiler : globalThis.create_rapydscript_compiler;
13
+ var RapydScript = _rapydscript_compiler();
12
14
 
13
- function parse_file(code, filename) {
14
- return RapydScript.parse(code, {
15
+ async function parse_file(code, filename) {
16
+ return await RapydScript.parse(code, {
15
17
  filename: filename,
16
18
  basedir: path.dirname(filename),
17
19
  libdir: path.dirname(filename),
@@ -27,18 +29,19 @@ function detect_format(msgid) {
27
29
 
28
30
  function Gettext(catalog, filename) {
29
31
  this._visit = function (node, cont) {
30
- if (node instanceof RapydScript.AST_Call && node.args && node.args.length && node.expression instanceof RapydScript.AST_Symbol) {
32
+ if (node instanceof RapydScript.AST_Call && node.args && node.args.args && node.args.args.length && node.expression instanceof RapydScript.AST_Symbol) {
31
33
  var name = node.expression.name;
32
34
  if (name === '_' || name === 'gettext' || name === 'ngettext') {
33
35
  var nargs = (name === 'ngettext') ? 2 : 1;
34
36
  var line = node.start.line;
37
+ var pargs = node.args.args;
35
38
  for (var i = 0; i < nargs; i++) {
36
- if (!(node.args[i] instanceof RapydScript.AST_String)) {
39
+ if (!(pargs[i].value instanceof RapydScript.AST_String)) {
37
40
  console.error('Translation function: ' + name + ' does not have a string literal argument at line: ' + line + ' of ' + filename);
38
41
  process.exit(1);
39
42
  }
40
43
  }
41
- var msgid = node.args[0].value;
44
+ var msgid = pargs[0].value.value;
42
45
  if (!Object.prototype.hasOwnProperty.call(catalog, msgid)) {
43
46
  catalog[msgid] = {
44
47
  'locations': [],
@@ -46,20 +49,20 @@ function Gettext(catalog, filename) {
46
49
  'format': detect_format(msgid),
47
50
  };
48
51
  }
49
- if (name === 'ngettext') catalog[msgid].plural = node.args[1].value;
52
+ if (name === 'ngettext') catalog[msgid].plural = pargs[1].value.value;
50
53
  if (filename) catalog[msgid].locations.push(filename + ':' + line);
51
54
  }
52
-
55
+
53
56
  }
54
57
  if (cont !== undefined) cont();
55
58
  };
56
59
  }
57
60
 
58
- function gettext(catalog, code, filename) {
61
+ async function gettext(catalog, code, filename) {
59
62
  var toplevel;
60
63
 
61
64
  try {
62
- toplevel = parse_file(code, filename);
65
+ toplevel = await parse_file(code, filename);
63
66
  } catch(e) {
64
67
  if (e instanceof RapydScript.SyntaxError) {
65
68
  console.error('Failed to parse: ' + filename + ' with error: ' + e.line + ':' + e.col + ':' + e.message);
@@ -125,61 +128,51 @@ function write_output(catalog, options, write) {
125
128
 
126
129
  // CLI {{{
127
130
 
128
- function read_whole_file(filename, cb) {
131
+ async function read_whole_file(filename) {
129
132
  if (!filename) {
130
133
  var chunks = [];
131
134
  process.stdin.setEncoding('utf-8');
132
- process.stdin.on('data', function (chunk) {
133
- chunks.push(chunk);
134
- }).on('end', function () {
135
- cb(null, chunks.join(""));
135
+ await new Promise((resolve, reject) => {
136
+ process.stdin.on('data', chunk => chunks.push(chunk));
137
+ process.stdin.on('end', resolve);
138
+ process.stdin.on('error', reject);
136
139
  });
137
140
  process.openStdin();
141
+ return chunks.join('');
138
142
  } else {
139
- fs.readFile(filename, "utf-8", cb);
143
+ return await fs.promises.readFile(filename, 'utf-8');
140
144
  }
141
145
  }
142
146
 
143
- module.exports.cli = function(argv, base_path, src_path, lib_path) {
147
+ export async function cli(argv, base_path, src_path, lib_path) {
144
148
  var files = [];
145
- var num_of_files = files.length || 1;
146
149
  var catalog = {};
147
150
 
148
- function read_files(src) {
149
- src.forEach(function(f) {
150
- if (fs.lstatSync(f).isDirectory()) {
151
- var children = [];
152
- fs.readdirSync(f).forEach(function(x) { children.push(path.join(f, x)); });
153
- read_files(children);
154
- }
155
- else files.push(f);
156
- });
151
+ async function read_files(src) {
152
+ for (const f of src) {
153
+ var stat = await fs.promises.lstat(f);
154
+ if (stat.isDirectory()) {
155
+ var children = (await fs.promises.readdir(f)).map(x => path.join(f, x));
156
+ await read_files(children);
157
+ } else files.push(f);
158
+ }
157
159
  }
158
- read_files(argv.files);
159
-
160
- function process_single_file(err, code) {
161
- if (err) {
162
- console.error("ERROR: can't read file: " + files[0]);
160
+ await read_files(argv.files);
161
+
162
+ for (const f of (files.length ? files : [null])) {
163
+ var code;
164
+ try {
165
+ code = await read_whole_file(f);
166
+ } catch(e) {
167
+ console.error("ERROR: can't read file: " + f);
163
168
  process.exit(1);
164
169
  }
165
-
166
- gettext(catalog, code, files[0]);
167
-
168
- files = files.slice(1);
169
- if (files.length) {
170
- setImmediate(read_whole_file, files[0], process_single_file);
171
- return;
172
- } else {
173
- write_output(catalog, argv);
174
- process.exit(0);
175
- }
170
+ await gettext(catalog, code, f);
176
171
  }
177
-
178
- setImmediate(read_whole_file, files[0], process_single_file);
179
172
 
180
- };
173
+ write_output(catalog, argv);
174
+ process.exit(0);
175
+ }
181
176
 
182
- module.exports.gettext = gettext;
183
- module.exports.entry_to_string = entry_to_string;
184
- module.exports.write_output = write_output;
177
+ export { gettext, entry_to_string, write_output };
185
178
  // }}}
@@ -1,16 +1,15 @@
1
1
  /* vim:fileencoding=utf-8
2
- *
2
+ *
3
3
  * Copyright (C) 2015 Kovid Goyal <kovid at kovidgoyal.net>
4
4
  *
5
5
  * Distributed under terms of the BSD license
6
6
  */
7
- "use strict"; /*jshint node:true */
8
7
 
9
- var fs = require('fs');
10
- var path = require('path');
8
+ import fs from 'fs';
9
+ import path from 'path';
11
10
 
12
11
  function parse_ini_data(data) {
13
- // Based on MIT licensed code from:
12
+ // Based on MIT licensed code from:
14
13
  // https://github.com/shockie/node-iniparser/blob/master/lib/node-iniparser.js
15
14
  var ans = {}, match;
16
15
  var lines = data.split(/\r\n|\r|\n/);
@@ -40,11 +39,11 @@ function parse_ini_data(data) {
40
39
  return ans;
41
40
  }
42
41
 
43
- function find_cfg_file(toplevel_dir) {
42
+ async function find_cfg_file(toplevel_dir) {
44
43
  var current_dir = toplevel_dir, previous_dir = toplevel_dir;
45
44
  do {
46
45
  try {
47
- return fs.readFileSync(path.join(current_dir, 'setup.cfg'), 'utf-8');
46
+ return await fs.promises.readFile(path.join(current_dir, 'setup.cfg'), 'utf-8');
48
47
  } catch (e) {
49
48
  if (e.code !== 'ENOENT') throw e;
50
49
  }
@@ -55,11 +54,11 @@ function find_cfg_file(toplevel_dir) {
55
54
  return null;
56
55
  }
57
56
 
58
- function read_config(toplevel_dir) {
59
- var data = find_cfg_file(toplevel_dir);
57
+ async function read_config(toplevel_dir) {
58
+ var data = await find_cfg_file(toplevel_dir);
60
59
  if (!data) return {};
61
60
  return parse_ini_data(data);
62
61
  }
63
62
 
64
63
 
65
- exports.read_config = read_config;
64
+ export { read_config };
@@ -1,19 +1,23 @@
1
1
  /* vim:fileencoding=utf-8
2
- *
2
+ *
3
3
  * Copyright (C) 2015 Kovid Goyal <kovid at kovidgoyal.net>
4
4
  *
5
5
  * Distributed under terms of the BSD license
6
6
  */
7
- "use strict"; /*jshint node:true */
8
7
 
9
- var fs = require('fs');
10
- var RapydScript = require("./compiler").create_compiler();
11
- var path = require('path');
12
- var utils = require('./utils');
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+ import { read_config } from './ini.mjs';
11
+ import * as utils from './utils.mjs';
12
+
13
+ // Use the compiler instance pre-created by bin/rapydscript. It is set as a
14
+ // synchronous global before any dynamic imports, so this module can be
15
+ // require()'d without top-level await.
16
+ const RapydScript = globalThis.create_rapydscript_compiler();
13
17
  var colored = utils.safe_colored;
14
18
 
15
- var WARN = 1, ERROR = 2;
16
- var MESSAGES = {
19
+ export var WARN = 1, ERROR = 2;
20
+ export var MESSAGES = {
17
21
  'undef': 'undefined symbol: "{name}"',
18
22
  'unused-import': '"{name}" is imported but not used',
19
23
  'unused-local' : '"{name}" is defined but not used',
@@ -29,8 +33,8 @@ var MESSAGES = {
29
33
  };
30
34
 
31
35
  var BUILTINS = Object.create(null);
32
- ('this self window document chr ord iterator_symbol print len range dir' +
33
- ' eval undefined arguments abs max min enumerate pow callable reversed sum' +
36
+ ('this self window document chr ord iterator_symbol print len range dir' +
37
+ ' eval undefined arguments abs max min enumerate pow callable reversed sum' +
34
38
  ' getattr isFinite setattr hasattr parseInt parseFloat options_object' +
35
39
  ' isNaN JSON Math list set list_wrap ρσ_modules require bool int bin' +
36
40
  ' float iter Error EvalError set_wrap RangeError ReferenceError SyntaxError' +
@@ -39,7 +43,7 @@ var BUILTINS = Object.create(null);
39
43
  ' NodeList alert console Node Symbol NamedNodeMap ρσ_eslice ρσ_delslice Number' +
40
44
  ' Boolean encodeURIComponent decodeURIComponent setTimeout setInterval' +
41
45
  ' setImmediate clearTimeout clearInterval clearImmediate requestAnimationFrame' +
42
- ' id repr sorted __name__ equals get_module ρσ_str jstype divmod NaN'
46
+ ' id repr sorted __name__ equals get_module ρσ_str jstype divmod NaN no_prune'
43
47
  ).split(' ').forEach(function(x) { BUILTINS[x] = true; });
44
48
 
45
49
  Object.keys(RapydScript.NATIVE_CLASSES).forEach(function (name) { BUILTINS[name] = true; });
@@ -56,8 +60,8 @@ function cmp(a, b) {
56
60
  return (a < b) ? -1 : ((a > b) ? 1 : 0);
57
61
  }
58
62
 
59
- function parse_file(code, filename) {
60
- return RapydScript.parse(code, {
63
+ async function parse_file(code, filename) {
64
+ return await RapydScript.parse(code, {
61
65
  filename: filename,
62
66
  basedir: path.dirname(filename),
63
67
  libdir: path.dirname(filename),
@@ -70,7 +74,7 @@ function msg_from_node(filename, ident, name, node, level, line) {
70
74
  if (node instanceof RapydScript.AST_Lambda && node.name) name = node.name.name;
71
75
  var msg = MESSAGES[ident].replace('{name}', name || '').replace('{line}', line || '');
72
76
  return {
73
- filename: filename,
77
+ filename: filename,
74
78
  start_line: (node.start) ? node.start.line : undefined,
75
79
  start_col: (node.start) ? node.start.col : undefined,
76
80
  end_line: (node.end) ? node.end.line : undefined,
@@ -157,7 +161,7 @@ function Scope(is_toplevel, parent_scope, filename, is_class) {
157
161
  this.for_descendants(function (scope) {
158
162
  if (has_prop(scope.undefined_references, name)) {
159
163
  found = true;
160
- // Remove from childs' undefined references
164
+ // Remove from childs' undefined references
161
165
  delete scope.undefined_references[name];
162
166
  } else if (has_prop(scope.nonlocals, name) && has_prop(scope.bindings, name)) found = true;
163
167
  });
@@ -295,7 +299,7 @@ function Linter(toplevel, filename, code, options) {
295
299
  if (node.left instanceof RapydScript.AST_SymbolRef) {
296
300
  node.left.lint_visited = node.operator === '='; // Could be compound assignment like: +=
297
301
  if (node.operator === '=') {
298
- // Only create a binding if the operator is not
302
+ // Only create a binding if the operator is not
299
303
  // a compound assignment operator
300
304
  this.current_node = node.left;
301
305
  this.add_binding(node.left.name);
@@ -374,7 +378,7 @@ function Linter(toplevel, filename, code, options) {
374
378
  }
375
379
  }
376
380
  }
377
-
381
+
378
382
  }
379
383
  };
380
384
 
@@ -419,7 +423,7 @@ function Linter(toplevel, filename, code, options) {
419
423
  (node.properties || []).forEach(function (prop) {
420
424
  if (prop.key instanceof RapydScript.AST_Constant) {
421
425
  var val = prop.key.value;
422
- if (has_prop(seen, val))
426
+ if (has_prop(seen, val))
423
427
  this.messages.push(msg_from_node(filename, 'dup-key', val, prop));
424
428
  seen[val] = true;
425
429
  }
@@ -483,7 +487,7 @@ function Linter(toplevel, filename, code, options) {
483
487
 
484
488
  if (node instanceof RapydScript.AST_Scope) {
485
489
  this.handle_scope();
486
- }
490
+ }
487
491
 
488
492
  if (cont !== undefined) cont();
489
493
 
@@ -498,11 +502,39 @@ function Linter(toplevel, filename, code, options) {
498
502
  this.resolve = function() {
499
503
  var messages = this.messages;
500
504
  var line_filters = {};
505
+ var in_multiline_str = false;
506
+ var ml_quote = null;
501
507
 
502
508
  code.split('\n').forEach(function(line, num) {
503
509
  line = line.trimRight();
504
510
  num++;
505
- if (line[line.length - 1] === ';') {
511
+
512
+ // Track triple-quoted multiline string state so we can skip
513
+ // eol-semicolon checks for lines that are inside string literals.
514
+ var line_starts_in_multiline = in_multiline_str;
515
+ var pos = 0, close_pos;
516
+ while (pos < line.length) {
517
+ if (!in_multiline_str) {
518
+ var dq = line.indexOf('"""', pos);
519
+ var sq = line.indexOf("'''", pos);
520
+ var first, quote;
521
+ if (dq !== -1 && (sq === -1 || dq < sq)) { first = dq; quote = '"""'; }
522
+ else if (sq !== -1) { first = sq; quote = "'''"; }
523
+ else break;
524
+ in_multiline_str = true;
525
+ ml_quote = quote;
526
+ pos = first + 3;
527
+ close_pos = line.indexOf(ml_quote, pos);
528
+ if (close_pos !== -1) { in_multiline_str = false; ml_quote = null; pos = close_pos + 3; }
529
+ else break;
530
+ } else {
531
+ close_pos = line.indexOf(ml_quote, pos);
532
+ if (close_pos !== -1) { in_multiline_str = false; ml_quote = null; pos = close_pos + 3; }
533
+ else break;
534
+ }
535
+ }
536
+
537
+ if (!line_starts_in_multiline && !in_multiline_str && line[line.length - 1] === ';') {
506
538
  var ident = 'eol-semicolon';
507
539
  messages.push({filename:filename, ident:ident, message:MESSAGES[ident],
508
540
  level:WARN, name:';', start_line:num, start_col:line.lastIndexOf(';')});
@@ -535,7 +567,18 @@ function Linter(toplevel, filename, code, options) {
535
567
 
536
568
  }
537
569
 
538
- function lint_code(code, options) {
570
+ // Run only the linter analysis over an already parsed toplevel. Used by both
571
+ // lint_code and the LSP (which parses once, in error-recovery mode, and reuses
572
+ // the resulting AST for all of its services).
573
+ export function lint_parsed(toplevel, code, options) {
574
+ options = options || {};
575
+ var filename = options.filename || '<eval>';
576
+ var linter = new Linter(toplevel, filename, code, options);
577
+ toplevel.walk(linter);
578
+ return linter.resolve();
579
+ }
580
+
581
+ export async function lint_code(code, options) {
539
582
  options = options || {};
540
583
  var reportcb = {'json':cli_json_report, 'vim': cli_vim_report, 'undef': cli_undef_report}[options.errorformat] || (options.report || cli_report);
541
584
  var filename = options.filename || '<eval>';
@@ -543,7 +586,7 @@ function lint_code(code, options) {
543
586
  var lines = code.split('\n'); // Can be used (in the future) to display extract from code corresponding to error location
544
587
 
545
588
  try {
546
- toplevel = parse_file(code, filename);
589
+ toplevel = await parse_file(code, filename);
547
590
  } catch(e) {
548
591
  if (e instanceof RapydScript.ImportError) {
549
592
  messages = [{filename:filename, start_line:e.line, start_col:e.col, level:ERROR, ident:'import-err', message:e.message}];
@@ -553,28 +596,29 @@ function lint_code(code, options) {
553
596
  }
554
597
 
555
598
  if (toplevel) {
556
- var linter = new Linter(toplevel, filename, code, options);
557
- toplevel.walk(linter);
558
- messages = linter.resolve();
599
+ messages = lint_parsed(toplevel, code, options);
559
600
  }
560
601
  messages.forEach(function(msg, i) { msg.code_lines = lines; reportcb(msg, i, messages); });
561
602
  return messages;
562
603
  }
563
604
 
605
+ export { BUILTINS };
606
+
564
607
  // CLI {{{
565
608
 
566
- function read_whole_file(filename, cb) {
609
+ async function read_whole_file(filename) {
567
610
  if (!filename || filename === '-') {
568
611
  var chunks = [];
569
612
  process.stdin.setEncoding('utf-8');
570
- process.stdin.on('data', function (chunk) {
571
- chunks.push(chunk);
572
- }).on('end', function () {
573
- cb(null, chunks.join(""));
613
+ await new Promise((resolve, reject) => {
614
+ process.stdin.on('data', chunk => chunks.push(chunk));
615
+ process.stdin.on('end', resolve);
616
+ process.stdin.on('error', reject);
574
617
  });
575
618
  process.openStdin();
619
+ return chunks.join('');
576
620
  } else {
577
- fs.readFile(filename, "utf-8", cb);
621
+ return await fs.promises.readFile(filename, 'utf-8');
578
622
  }
579
623
  }
580
624
 
@@ -619,17 +663,15 @@ function cli_vim_report(r) {
619
663
 
620
664
  var ini_cache = {};
621
665
 
622
- function get_ini(toplevel_dir) {
666
+ async function get_ini(toplevel_dir) {
623
667
  if (has_prop(ini_cache, toplevel_dir)) return ini_cache[toplevel_dir];
624
- var rl = require('./ini').read_config(toplevel_dir).rapydscript || {};
668
+ var rl = (await read_config(toplevel_dir)).rapydscript || {};
625
669
  ini_cache[toplevel_dir] = rl;
626
670
  return rl;
627
671
  }
628
672
 
629
- module.exports.cli = function(argv, base_path, src_path, lib_path) {
673
+ export async function cli(argv, base_path, src_path, lib_path) {
630
674
  var files = argv.files.slice();
631
- var num_of_files = files.length || 1;
632
- var read_config = require('./ini');
633
675
 
634
676
  if (argv.noqa_list) {
635
677
  Object.keys(MESSAGES).forEach(function(ident) {
@@ -642,6 +684,23 @@ module.exports.cli = function(argv, base_path, src_path, lib_path) {
642
684
  process.exit(0);
643
685
  }
644
686
 
687
+ if (argv.input_list) {
688
+ // Check for conflict: --input-list=- and - as an input file
689
+ if (argv.input_list === '-' && files.indexOf('-') !== -1) {
690
+ console.error("ERROR: Cannot use - as both --input-list source and an input file");
691
+ process.exit(1);
692
+ }
693
+ var list_data;
694
+ try {
695
+ list_data = await read_whole_file(argv.input_list === '-' ? null : argv.input_list);
696
+ } catch(e) {
697
+ console.error("ERROR: can't read input list file: " + argv.input_list);
698
+ process.exit(1);
699
+ }
700
+ var list_files = list_data.split('\n').map(function(l) { return l.trim(); }).filter(function(l) { return l.length > 0; });
701
+ files = files.concat(list_files);
702
+ }
703
+
645
704
  if (files.filter(function(el){ return el === "-"; }).length > 1) {
646
705
  console.error("ERROR: Can read a single file from STDIN (two or more dashes specified)");
647
706
  process.exit(1);
@@ -657,15 +716,19 @@ module.exports.cli = function(argv, base_path, src_path, lib_path) {
657
716
  return x === '-' ? argv.stdin_filename : x;
658
717
  }
659
718
 
660
- function lint_single_file(err, code) {
661
- var output, final_builtins = merge(builtins), final_noqa = merge(noqa), rl;
662
- if (err) {
663
- console.error("ERROR: can't read file: " + files[0]);
719
+ for (const filename of (files.length ? files : [null])) {
720
+ var code;
721
+ try {
722
+ code = await read_whole_file(filename === '-' ? null : filename);
723
+ } catch(e) {
724
+ console.error("ERROR: can't read file: " + filename);
664
725
  process.exit(1);
665
726
  }
666
727
 
728
+ var final_builtins = merge(builtins), final_noqa = merge(noqa);
729
+
667
730
  // Read setup.cfg
668
- rl = get_ini(path.dirname(path_for_filename(files[0])));
731
+ var rl = await get_ini(path.dirname(path_for_filename(filename || '-')));
669
732
  var g = {};
670
733
  (rl.globals || rl.builtins || '').split(',').forEach(function (x) { g[x.trim()] = true; });
671
734
  final_builtins = merge(final_builtins, g);
@@ -685,21 +748,9 @@ module.exports.cli = function(argv, base_path, src_path, lib_path) {
685
748
  });
686
749
 
687
750
  // Lint!
688
- if (lint_code(code, {filename:path_for_filename(files[0]), builtins:final_builtins, noqa:final_noqa, errorformat:argv.errorformat || false}).length) all_ok = false;
689
-
690
- files = files.slice(1);
691
- if (files.length) {
692
- setImmediate(read_whole_file, files[0], lint_single_file);
693
- return;
694
- } else process.exit((all_ok) ? 0 : 1);
751
+ if ((await lint_code(code, {filename:path_for_filename(filename || '-'), builtins:final_builtins, noqa:final_noqa, errorformat:argv.errorformat || false})).length) all_ok = false;
695
752
  }
696
-
697
- setImmediate(read_whole_file, files[0], lint_single_file);
698
753
 
699
- };
700
-
701
- module.exports.lint_code = lint_code;
702
- module.exports.WARN = WARN;
703
- module.exports.ERROR = ERROR;
704
- module.exports.MESSAGES = MESSAGES;
754
+ process.exit((all_ok) ? 0 : 1);
755
+ }
705
756
  // }}}