diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8f70b7d4..85624cbf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -101,9 +101,9 @@ jobs: echo "image = \"$image\"" >> Cross.toml echo "CROSS_CONFIG=$PWD/Cross.toml" >> $GITHUB_ENV - echo "FROM ghcr.io/cross-rs/$target:edge" >> Dockerfile - echo "ENV DEBIAN_FRONTEND=noninteractive" >> Dockerfile - echo "RUN apt-get update && apt-get install -y nodejs" >> Dockerfile + echo "FROM ghcr.io/cross-rs/$target:edge" >> Dockerfile + echo "RUN curl -fsSL https://deb.nodesource.com/setup_16.x | bash -" >> Dockerfile + echo "RUN apt-get update && apt-get -y install nodejs" >> Dockerfile docker build -t $image . - name: Setup env extras diff --git a/Cargo.lock b/Cargo.lock index 166633c2..e43ea184 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1432,6 +1432,7 @@ dependencies = [ "tree-sitter-tags", "tree-sitter-tests-proc-macro", "unindent", + "url", "walkdir", "wasmparser 0.206.0", "webbrowser", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index fd2136ae..977caad0 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -60,6 +60,9 @@ tree-sitter-highlight.workspace = true tree-sitter-loader.workspace = true tree-sitter-tags.workspace = true +[target."cfg(windows)".dependencies] +url = "2.5.0" + [dev-dependencies] tree_sitter_proc_macro = { path = "src/tests/proc_macro", package = "tree-sitter-tests-proc-macro" } diff --git a/cli/npm/package.json b/cli/npm/package.json index b072c899..5b17bcaf 100644 --- a/cli/npm/package.json +++ b/cli/npm/package.json @@ -13,6 +13,9 @@ "lexer" ], "main": "lib/api/index.js", + "engines": { + "node": ">=12.0.0" + }, "scripts": { "install": "node install.js", "prepack": "cp ../../LICENSE ../README.md .", diff --git a/cli/src/generate/dsl.js b/cli/src/generate/dsl.js index 3b9b1824..371153c7 100644 --- a/cli/src/generate/dsl.js +++ b/cli/src/generate/dsl.js @@ -223,7 +223,7 @@ function RuleBuilder(ruleMap) { } function grammar(baseGrammar, options) { - let inherits = null; + let inherits = undefined; if (!options) { options = baseGrammar; @@ -421,7 +421,7 @@ function grammar(baseGrammar, options) { return { grammar: { name, - ...(inherits ? ( inherits ) : {}), + inherits, word, rules, extras, @@ -456,18 +456,32 @@ function checkPrecedence(value) { } } -global.alias = alias; -global.blank = blank; -global.choice = choice; -global.optional = optional; -global.prec = prec; -global.repeat = repeat; -global.repeat1 = repeat1; -global.seq = seq; -global.sym = sym; -global.token = token; -global.grammar = grammar; -global.field = field; +function getEnv(name) { + if (globalThis.process) return process.env[name]; // Node/Bun + if (globalThis.Deno) return Deno.env.get(name); // Deno + throw Error("Unsupported JS runtime"); +} -const result = require(process.env.TREE_SITTER_GRAMMAR_PATH); -process.stdout.write(JSON.stringify(result.grammar, null, null)); +globalThis.alias = alias; +globalThis.blank = blank; +globalThis.choice = choice; +globalThis.optional = optional; +globalThis.prec = prec; +globalThis.repeat = repeat; +globalThis.repeat1 = repeat1; +globalThis.seq = seq; +globalThis.sym = sym; +globalThis.token = token; +globalThis.grammar = grammar; +globalThis.field = field; + +const result = await import(getEnv("TREE_SITTER_GRAMMAR_PATH")); +const output = JSON.stringify(result.default?.grammar ?? result.grammar); + +if (globalThis.process) { // Node/Bun + process.stdout.write(output); +} else if (globalThis.Deno) { // Deno + Deno.stdout.writeSync(new TextEncoder().encode(output)); +} else { + throw Error("Unsupported JS runtime"); +} diff --git a/cli/src/generate/mod.rs b/cli/src/generate/mod.rs index 1d3b9e40..fdba98d6 100644 --- a/cli/src/generate/mod.rs +++ b/cli/src/generate/mod.rs @@ -189,35 +189,54 @@ pub fn load_grammar_file(grammar_path: &Path, js_runtime: Option<&str>) -> Resul fn load_js_grammar_file(grammar_path: &Path, js_runtime: Option<&str>) -> Result { let grammar_path = fs::canonicalize(grammar_path)?; + #[cfg(windows)] + let grammar_path = url::Url::from_file_path(grammar_path) + .expect("Failed to convert path to URL") + .to_string(); + let js_runtime = js_runtime.unwrap_or("node"); - let mut node_process = Command::new(js_runtime) + let mut js_command = Command::new(js_runtime); + match js_runtime { + "node" => { + js_command.args(["--input-type=module", "-"]); + } + "bun" => { + js_command.arg("-"); + } + "deno" => { + js_command.args(["run", "--allow-all", "-"]); + } + _ => {} + } + + let mut js_process = js_command .env("TREE_SITTER_GRAMMAR_PATH", grammar_path) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn() .with_context(|| format!("Failed to run `{js_runtime}`"))?; - let mut node_stdin = node_process + let mut js_stdin = js_process .stdin .take() .with_context(|| format!("Failed to open stdin for {js_runtime}"))?; let cli_version = Version::parse(env!("CARGO_PKG_VERSION")) .with_context(|| "Could not parse this package's version as semver.")?; write!( - node_stdin, - "global.TREE_SITTER_CLI_VERSION_MAJOR = {}; - global.TREE_SITTER_CLI_VERSION_MINOR = {}; - global.TREE_SITTER_CLI_VERSION_PATCH = {};", + js_stdin, + "globalThis.TREE_SITTER_CLI_VERSION_MAJOR = {}; + globalThis.TREE_SITTER_CLI_VERSION_MINOR = {}; + globalThis.TREE_SITTER_CLI_VERSION_PATCH = {};", cli_version.major, cli_version.minor, cli_version.patch, ) .with_context(|| format!("Failed to write tree-sitter version to {js_runtime}'s stdin"))?; - let javascript_code = include_bytes!("./dsl.js"); - node_stdin - .write(javascript_code) + js_stdin + .write(include_bytes!("./dsl.js")) .with_context(|| format!("Failed to write grammar dsl to {js_runtime}'s stdin"))?; - drop(node_stdin); - let output = node_process + drop(js_stdin); + + let output = js_process .wait_with_output() .with_context(|| format!("Failed to read output from {js_runtime}"))?; match output.status.code() { diff --git a/cli/src/main.rs b/cli/src/main.rs index 8315b341..5aad818b 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -92,7 +92,8 @@ struct Generate { long, value_name = "EXECUTABLE", env = "TREE_SITTER_JS_RUNTIME", - help = "The path to the JavaScript runtime to use for generating parsers" + default_value = "node", + help = "The name or path of the JavaScript runtime to use for generating parsers" )] pub js_runtime: Option, }