#include // IWYU pragma: keep #include #include #include #include #include #include #include #include "ant.h" #include "gc.h" #include "crash.h" #include "repl.h" #include "debug.h" #include "utils.h" #include "watch.h" #include "reactor.h" #include "runtime.h" #include "snapshot.h" #include "esm/loader.h" #include "esm/library.h" #include "esm/remote.h" #include "internal.h" #include "silver/vm.h" #include "messages.h" #include "cli/pkg.h" #include "cli/misc.h" #include "cli/version.h" #include "modules/builtin.h" #include "modules/buffer.h" #include "modules/atomics.h" #include "modules/os.h" #include "modules/io.h" #include "modules/fs.h" #include "modules/crypto.h" #include "modules/server.h" #include "modules/timer.h" #include "modules/json.h" #include "modules/fetch.h" #include "modules/request.h" #include "modules/response.h" #include "modules/shell.h" #include "modules/process.h" #include "modules/tty.h" #include "modules/path.h" #include "modules/ffi.h" #include "modules/events.h" #include "modules/lmdb.h" #include "modules/performance.h" #include "modules/uri.h" #include "modules/url.h" #include "modules/reflect.h" #include "modules/symbol.h" #include "modules/date.h" #include "modules/math.h" #include "modules/bigint.h" #include "modules/regex.h" #include "modules/textcodec.h" #include "modules/sessionstorage.h" #include "modules/localstorage.h" #include "modules/navigator.h" #include "modules/child_process.h" #include "modules/readline.h" #include "modules/observable.h" #include "modules/collections.h" #include "modules/iterator.h" #include "modules/generator.h" #include "modules/module.h" #include "modules/util.h" #include "modules/async_hooks.h" #include "modules/net.h" #include "modules/tls.h" #include "modules/http_metadata.h" #include "modules/http_parser.h" #include "modules/http_writer.h" #include "modules/dns.h" #include "modules/assert.h" #include "modules/domexception.h" #include "modules/abort.h" #include "modules/globals.h" #include "modules/intl.h" #include "modules/wasm.h" #include "modules/string_decoder.h" #include "modules/stream.h" #include "modules/structured-clone.h" #include "modules/v8.h" #include "modules/worker_threads.h" #include "modules/headers.h" #include "modules/blob.h" #include "modules/formdata.h" #include "modules/zlib.h" #include "streams/queuing.h" #include "streams/readable.h" #include "streams/writable.h" #include "streams/transform.h" #include "streams/codec.h" #include "streams/compression.h" int js_result = EXIT_SUCCESS; typedef int (*cmd_fn)(int argc, char **argv); typedef struct { const char *name; const char *alias; const char *desc; cmd_fn fn; } subcommand_t; static const subcommand_t subcommands[] = { {"init", NULL, "Create a new package.json", pkg_cmd_init}, {"install", "i", "Install dependencies from lockfile", pkg_cmd_install}, {"update", "up", "Re-resolve dependencies and refresh lockfile", pkg_cmd_update}, {"add", "a", "Add a package to dependencies", pkg_cmd_add}, {"remove", "rm", "Remove a package from dependencies", pkg_cmd_remove}, {"trust", NULL, "Run lifecycle scripts for packages", pkg_cmd_trust}, {"run", NULL, "Run a script from package.json", pkg_cmd_run}, {"exec", "x", "Run a command from node_modules/.bin", pkg_cmd_exec}, {"why", "explain", "Show why a package is installed", pkg_cmd_why}, {"info", NULL, "Show package information from registry", pkg_cmd_info}, {"ls", "list", "List installed packages", pkg_cmd_ls}, {"cache", NULL, "Manage the package cache", pkg_cmd_cache}, {"create", NULL, "Scaffold a project from a template", pkg_cmd_create}, {NULL, NULL, NULL, NULL} }; static void ant_debug_apply(const char *key, const char *val) { if (strcmp(key, "gc") == 0) { if (strcmp(val, "disable") == 0) gc_disabled = true; } else if (strcmp(key, "dump/parse") == 0) { if (strcmp(val, "trace") == 0) sv_debug_enable(SV_DEBUG_PARSE); } else if (strcmp(key, "dump/compile") == 0) { if (strcmp(val, "trace") == 0) sv_debug_enable(SV_DEBUG_COMPILE); } else if (strcmp(key, "dump/crprintf") == 0) { if (strcmp(val, "bytecode") == 0 || strcmp(val, "all") == 0) crprintf_set_debug(true); if (strcmp(val, "hex") == 0 || strcmp(val, "all") == 0) crprintf_set_debug_hex(true); } else if (strcmp(key, "dump/vm") == 0) { if (strcmp(val, "bytecode") == 0 || strcmp(val, "all") == 0) sv_debug_enable(SV_DEBUG_DUMP_BYTECODE); if (strcmp(val, "jit") == 0 || strcmp(val, "all") == 0) sv_debug_enable(SV_DEBUG_DUMP_JIT); if (strcmp(val, "op-warn") == 0 || strcmp(val, "all") == 0) sv_debug_enable(SV_DEBUG_JIT_WARN); } } static inline void setup_console_colors(void) { crprintf_var("version", ANT_VERSION); crprintf_var("fatal", "FATAL"); crprintf_var("error", "Error"); crprintf_var("warn", "Warning"); } static void parse_ant_debug_flags(void) { const char *env = getenv("ANT_DEBUG"); if (!env || !*env) return; char *buf = strdup(env); if (!buf) return; char *sp = NULL, *vp = NULL; for (char *e = strtok_r(buf, " ", &sp); e; e = strtok_r(NULL, " ", &sp)) { char *sep = strchr(e, ':'); if (!sep) { crfprintf(stderr, msg.unknown_flag_warn, e); continue; } *sep++ = '\0'; for (char *v = strtok_r(sep, ",", &vp); v; v = strtok_r(NULL, ",", &vp)) ant_debug_apply(e, v); } free(buf); } static const subcommand_t *find_subcommand(const char *name) { for (const subcommand_t *cmd = subcommands; cmd->name; cmd++) { if (strcmp(name, cmd->name) == 0) return cmd; if (cmd->alias && strcmp(name, cmd->alias) == 0) return cmd; } return NULL; } static void print_subcommands(void) { crprintf("Commands:\n"); for (const subcommand_t *cmd = subcommands; cmd->name; cmd++) { crprintf(" %s %s\n", cmd->name, cmd->desc); } crprintf(msg.ant_command_extra); printf("\n"); } static void print_commands(void **argtable) { crprintf(msg.ant_help_header); print_subcommands(); crprintf(msg.ant_help_flags); print_flags_help(stdout, argtable); print_flag(stdout, (flag_help_t){ .l = "verbose", .g = "enable verbose output" }); print_flag(stdout, (flag_help_t){ .l = "no-color", .g = "disable colored output" }); } typedef struct { int argc; char **argv; } argv_split_t; static bool is_valued_flag(const char *arg) { return strcmp(arg, "-e") == 0 || strcmp(arg, "--eval") == 0 || strcmp(arg, "--localstorage-file") == 0; } static int find_argv_token_index(int argc, char **argv, const char *token) { if (!token) return -1; for (int i = 1; i < argc; i++) if (argv[i] == token) return i; return -1; } static argv_split_t split_script_args(int *argc, char **argv) { for (int i = 1; i < *argc; i++) { if (strcmp(argv[i], "--") == 0) { argv_split_t tail = { *argc - i - 1, argv + i + 1 }; *argc = i; return tail; } if (argv[i][0] == '-') { if (is_valued_flag(argv[i]) && i + 1 < *argc) i++; continue; } argv_split_t tail = { *argc - i - 1, argv + i + 1 }; *argc = i + 1; return tail; } return (argv_split_t){ 0, NULL }; } static argv_split_t build_process_argv(int argc, char **argv, const char *module, argv_split_t script) { if (!module || script.argc == 0) return (argv_split_t){ argc, argv }; int total = 2 + script.argc; char **out = try_oom(sizeof(char*) * (total + 1)); out[0] = argv[0]; out[1] = (char *)module; for (int i = 0; i < script.argc; i++) out[2 + i] = script.argv[i]; out[total] = NULL; return (argv_split_t){ total, out }; } static char *read_stdin(size_t *len) { size_t cap = 4096; *len = 0; char *buf = malloc(cap); if (!buf) return NULL; size_t n; while ((n = fread(buf + *len, 1, cap - *len, stdin)) > 0) { *len += n; if (*len == cap) { cap *= 2; char *next = realloc(buf, cap); if (!next) { free(buf); return NULL; } buf = next; } } buf[*len] = '\0'; return buf; } static char *read_file(const char *filename, size_t *len) { FILE *fp = fopen(filename, "rb"); if (!fp) return NULL; fseek(fp, 0, SEEK_END); long size = ftell(fp); fseek(fp, 0, SEEK_SET); char *buffer = malloc(size + 1); if (!buffer) { fclose(fp); return NULL; } *len = fread(buffer, 1, size, fp); fclose(fp); buffer[*len] = '\0'; return buffer; } static void eval_code(ant_t *js, const char *script, size_t len, const char *tag, bool should_print) { js_set_filename(js, tag); js_setup_import_meta(js, tag); js_set(js, js_glob(js), "__dirname", js_mkstr(js, ".", 1)); js_set(js, js_glob(js), "__filename", js_mkstr(js, tag, strlen(tag))); ant_value_t result = js_eval_bytecode_eval(js, script, len); js_run_event_loop(js); if (print_uncaught_throw(js)) { js_result = EXIT_FAILURE; return; } char cbuf_stack[512]; js_cstr_t cstr = js_to_cstr( js, result, cbuf_stack, sizeof(cbuf_stack) ); if (vtype(result) == T_ERR) { fprintf(stderr, "%s\n", cstr.ptr); js_result = EXIT_FAILURE; } else if (should_print) { if (vtype(result) == T_STR) printf("%s\n", cstr.ptr ? cstr.ptr : ""); else if (cstr.ptr && strcmp(cstr.ptr, "undefined") != 0) { print_value_colored(cstr.ptr, stdout); printf("\n"); } } if (cstr.needs_free) free((void *)cstr.ptr); } static int execute_module(ant_t *js, const char *filename) { char *use_path_owned = NULL; const char *use_path = filename; const char *stable_use_path = filename; ant_value_t ns = 0; ant_value_t specifier = 0; ant_value_t default_export = 0; if (esm_is_url(filename)) { js_set(js, js_glob(js), "__dirname", js_mkundef()); specifier = js_mkstr(js, filename, strlen(filename)); } else { char *file_path = strdup(filename); char *dir = dirname(file_path); js_set(js, js_glob(js), "__dirname", js_mkstr(js, dir, strlen(dir))); free(file_path); use_path_owned = realpath(filename, NULL); if (use_path_owned) use_path = use_path_owned; specifier = js_esm_make_file_url(js, use_path); } const char *interned = intern_string(use_path, strlen(use_path)); if (interned) stable_use_path = interned; else stable_use_path = use_path; js_set(js, js_glob(js), "__filename", js_mkstr(js, filename, strlen(filename)) ); js_set_filename(js, stable_use_path); js_setup_import_meta(js, stable_use_path); ns = js_esm_import_sync(js, specifier); free(use_path_owned); if (print_uncaught_throw(js)) return EXIT_FAILURE; if (vtype(ns) == T_ERR) { fprintf(stderr, "%s\n", js_str(js, ns)); return EXIT_FAILURE; } default_export = js_get(js, ns, "default"); return server_maybe_start_from_export(js, default_export); } int main(int argc, char *argv[]) { bool internal_crash_report_mode = ant_crash_is_internal_report(argc, argv); if (internal_crash_report_mode) argc = 1; if (!internal_crash_report_mode && !getenv("ANT_NO_CRASH_HANDLER")) ant_crash_init(argc, argv); setup_console_colors(); parse_ant_debug_flags(); int filtered_argc = 0; int original_argc = argc; char **original_argv = argv; const char *binary_name = strrchr(argv[0], '/'); binary_name = binary_name ? binary_name + 1 : argv[0]; if (strcmp(binary_name, "antx") == 0) { char **exec_argv = try_oom(sizeof(char*) * (argc + 2)); exec_argv[0] = argv[0]; exec_argv[1] = "x"; for (int i = 1; i < argc; i++) exec_argv[i + 1] = argv[i]; exec_argv[argc + 1] = NULL; int exitcode = pkg_cmd_exec(argc, exec_argv + 1); free(exec_argv); return exitcode; } char **filtered_argv = try_oom(sizeof(char*) * argc); for (int i = 0; i < argc; i++) { if (strcmp(argv[i], "--verbose") == 0) pkg_verbose = true; else if (strcmp(argv[i], "--no-color") == 0) { crprintf_set_color(false); io_no_color = true; } else if (strncmp(argv[i], "--stack-size=", 13) == 0) sv_user_stack_size_kb = atoi(argv[i] + 13); else filtered_argv[filtered_argc++] = argv[i]; } argc = filtered_argc; argv = filtered_argv; argv_split_t script_tail = split_script_args(&argc, argv); argv_split_t proc_argv = { 0, NULL }; #define ARG_ITEMS(X) \ X(struct arg_str *, eval, arg_str0("e", "eval", "