Browse Source

js: Add a command line argument to evaluate a string as a script

For example:

    $ js -c "console.log(42)"
    42
Timothy Flynn 3 years ago
parent
commit
19d4f52a9e
2 changed files with 32 additions and 13 deletions
  1. 10 2
      Base/usr/share/man/man1/js.md
  2. 22 11
      Userland/Utilities/js.cpp

+ 10 - 2
Base/usr/share/man/man1/js.md

@@ -28,18 +28,26 @@ Run `help()` in REPL mode to see its available built-in functions.
 * `-m`, `--as-module`: Treat as module
 * `-l`, `--print-last-result`: Print the result of the last statement executed.
 * `-g`, `--gc-on-every-allocation`: Run garbage collection on every allocation.
-* `-c`, `--disable-ansi-colors`: Disable ANSI colors
+* `-i`, `--disable-ansi-colors`: Disable ANSI colors
 * `-h`, `--disable-source-location-hints`: Disable source location hints
 * `-s`, `--no-syntax-highlight`: Disable live syntax highlighting in the REPL
+* `-c`, `--evaluate`: Evaluate the argument as a script
 
 ## Examples
 
-Here's how you execute a script:
+Here's how you execute a script from a file:
 
 ```sh
 $ js ~/Source/js/type-play.js
 ```
 
+Here's how you execute a script as a command line argument:
+
+```sh
+$ js -c "console.log(42)"
+42
+```
+
 And here's an example of an interactive REPL session:
 
 ```js

+ 22 - 11
Userland/Utilities/js.cpp

@@ -1345,6 +1345,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
 
     bool gc_on_every_allocation = false;
     bool disable_syntax_highlight = false;
+    StringView evaluate_script;
     Vector<StringView> script_paths;
 
     Core::ArgsParser args_parser;
@@ -1355,10 +1356,11 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
     args_parser.add_option(s_opt_bytecode, "Optimize the bytecode", "optimize-bytecode", 'p');
     args_parser.add_option(s_as_module, "Treat as module", "as-module", 'm');
     args_parser.add_option(s_print_last_result, "Print last result", "print-last-result", 'l');
-    args_parser.add_option(s_strip_ansi, "Disable ANSI colors", "disable-ansi-colors", 'c');
+    args_parser.add_option(s_strip_ansi, "Disable ANSI colors", "disable-ansi-colors", 'i');
     args_parser.add_option(s_disable_source_location_hints, "Disable source location hints", "disable-source-location-hints", 'h');
     args_parser.add_option(gc_on_every_allocation, "GC on every allocation", "gc-on-every-allocation", 'g');
     args_parser.add_option(disable_syntax_highlight, "Disable live syntax highlighting", "no-syntax-highlight", 's');
+    args_parser.add_option(evaluate_script, "Evaluate argument as a script", "evaluate", 'c', "script");
     args_parser.add_positional_argument(script_paths, "Path to script files", "scripts", Core::ArgsParser::Required::No);
     args_parser.parse(arguments);
 
@@ -1391,7 +1393,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
 
     // FIXME: Figure out some way to interrupt the interpreter now that vm.exception() is gone.
 
-    if (script_paths.is_empty()) {
+    if (evaluate_script.is_empty() && script_paths.is_empty()) {
         s_print_last_result = true;
         interpreter = JS::Interpreter::create<ReplObject>(*vm);
         ReplConsoleClient console_client(interpreter->global_object().console());
@@ -1613,20 +1615,29 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
             sigint_handler();
         });
 
-        if (script_paths.size() > 1)
-            warnln("Warning: Multiple files supplied, this will concatenate the sources and resolve modules as if it was the first file");
-
         StringBuilder builder;
-        for (auto& path : script_paths) {
-            auto file = TRY(Core::File::open(path, Core::OpenMode::ReadOnly));
-            auto file_contents = file->read_all();
-            auto source = StringView { file_contents };
-            builder.append(source);
+        StringView source_name;
+
+        if (evaluate_script.is_empty()) {
+            if (script_paths.size() > 1)
+                warnln("Warning: Multiple files supplied, this will concatenate the sources and resolve modules as if it was the first file");
+
+            for (auto& path : script_paths) {
+                auto file = TRY(Core::File::open(path, Core::OpenMode::ReadOnly));
+                auto file_contents = file->read_all();
+                auto source = StringView { file_contents };
+                builder.append(source);
+            }
+
+            source_name = script_paths[0];
+        } else {
+            builder.append(evaluate_script);
+            source_name = "eval"sv;
         }
 
         // We resolve modules as if it is the first file
 
-        if (!parse_and_run(*interpreter, builder.string_view(), script_paths[0]))
+        if (!parse_and_run(*interpreter, builder.string_view(), source_name))
             return 1;
     }