feat(bindings): add prebuildify to node
Co-Authored-By: Amaan Qureshi <amaanq12@gmail.com>
This commit is contained in:
parent
69cf13bc05
commit
072865e450
4 changed files with 106 additions and 88 deletions
|
|
@ -3,7 +3,7 @@ use anyhow::{anyhow, Context, Result};
|
|||
use filetime::FileTime;
|
||||
use heck::{ToKebabCase, ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase};
|
||||
use serde::Deserialize;
|
||||
use serde_json::{Map, Value};
|
||||
use serde_json::{json, Map, Value};
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
|
@ -83,8 +83,8 @@ pub fn path_in_ignore(repo_path: &Path) -> bool {
|
|||
|
||||
fn insert_after(
|
||||
map: Map<String, Value>,
|
||||
key: &str,
|
||||
after: &str,
|
||||
key: &str,
|
||||
value: Value,
|
||||
) -> Map<String, Value> {
|
||||
let mut entries = map.into_iter().collect::<Vec<_>>();
|
||||
|
|
@ -104,6 +104,8 @@ pub fn generate_grammar_files(
|
|||
) -> Result<()> {
|
||||
let dashed_language_name = language_name.to_kebab_case();
|
||||
|
||||
// TODO: remove legacy code updates in v0.24.0
|
||||
|
||||
// Create or update package.json
|
||||
let package_json_path_state = missing_path_else(
|
||||
repo_path.join("package.json"),
|
||||
|
|
@ -113,82 +115,115 @@ pub fn generate_grammar_files(
|
|||
fs::read_to_string(path).with_context(|| "Failed to read package.json")?;
|
||||
let mut package_json = serde_json::from_str::<Map<String, Value>>(&package_json_str)
|
||||
.with_context(|| "Failed to parse package.json")?;
|
||||
let package_json_needs_update = generate_bindings
|
||||
&& (package_json
|
||||
.get("dependencies")
|
||||
.map_or(false, |d| d.get("nan").is_some())
|
||||
|| !package_json.contains_key("peerDependencies")
|
||||
|| !package_json.contains_key("types")
|
||||
|| !package_json.contains_key("files"));
|
||||
if package_json_needs_update {
|
||||
if generate_bindings {
|
||||
let mut updated = false;
|
||||
|
||||
let dependencies = package_json
|
||||
.entry("dependencies".to_string())
|
||||
.or_insert_with(|| Value::Object(Map::new()));
|
||||
let dependencies = dependencies.as_object_mut().unwrap();
|
||||
.or_insert_with(|| Value::Object(Map::new()))
|
||||
.as_object_mut()
|
||||
.unwrap();
|
||||
if dependencies.remove("nan").is_some() {
|
||||
eprintln!("Replacing package.json's nan dependency with node-addon-api");
|
||||
dependencies.insert(
|
||||
"node-addon-api".to_string(),
|
||||
Value::String("^7.1.0".to_string()),
|
||||
eprintln!("Replacing nan dependency with node-addon-api in package.json");
|
||||
dependencies.insert("node-addon-api".to_string(), "^7.1.0".into());
|
||||
updated = true;
|
||||
}
|
||||
if !dependencies.contains_key("node-gyp-build") {
|
||||
eprintln!("Adding node-gyp-build dependency to package.json");
|
||||
dependencies.insert("node-gyp-build".to_string(), "^4.8.0".into());
|
||||
updated = true;
|
||||
}
|
||||
|
||||
let dev_dependencies = package_json
|
||||
.entry("devDependencies".to_string())
|
||||
.or_insert_with(|| Value::Object(Map::new()))
|
||||
.as_object_mut()
|
||||
.unwrap();
|
||||
if !dev_dependencies.contains_key("prebuildify") {
|
||||
eprintln!("Adding prebuildify devDependency to package.json");
|
||||
dev_dependencies.insert("prebuildify".to_string(), "^6.0.0".into());
|
||||
updated = true;
|
||||
}
|
||||
|
||||
let scripts = package_json
|
||||
.entry("scripts".to_string())
|
||||
.or_insert_with(|| Value::Object(Map::new()))
|
||||
.as_object_mut()
|
||||
.unwrap();
|
||||
match scripts.get("install") {
|
||||
None => {
|
||||
eprintln!("Adding an install script to package.json");
|
||||
scripts.insert("install".to_string(), "node-gyp-build".into());
|
||||
updated = true;
|
||||
}
|
||||
Some(Value::String(v)) if v != "node-gyp-build" => {
|
||||
eprintln!("Updating the install script in package.json");
|
||||
scripts.insert("install".to_string(), "node-gyp-build".into());
|
||||
updated = true;
|
||||
}
|
||||
Some(_) => {}
|
||||
}
|
||||
if !scripts.contains_key("prebuildify") {
|
||||
eprintln!("Adding a prebuildify script to package.json");
|
||||
scripts.insert(
|
||||
"prebuildify".to_string(),
|
||||
"prebuildify --napi --strip".into(),
|
||||
);
|
||||
updated = true;
|
||||
}
|
||||
|
||||
// insert `peerDependencies` after `dependencies`
|
||||
if !package_json.contains_key("peerDependencies") {
|
||||
eprintln!("Adding peerDependencies to package.json");
|
||||
let mut peer_dependencies = Map::new();
|
||||
peer_dependencies.insert(
|
||||
"tree-sitter".to_string(),
|
||||
Value::String("^0.21.0".to_string()),
|
||||
);
|
||||
package_json = insert_after(
|
||||
package_json,
|
||||
"peerDependencies",
|
||||
"dependencies",
|
||||
Value::Object(peer_dependencies),
|
||||
"peerDependencies",
|
||||
json!({"tree-sitter": "^0.21.0"}),
|
||||
);
|
||||
|
||||
let mut tree_sitter_meta = Map::new();
|
||||
tree_sitter_meta.insert("optional".to_string(), Value::Bool(true));
|
||||
let mut peer_dependencies_meta = Map::new();
|
||||
peer_dependencies_meta
|
||||
.insert("tree_sitter".to_string(), Value::Object(tree_sitter_meta));
|
||||
package_json = insert_after(
|
||||
package_json,
|
||||
"peerDependencies",
|
||||
"dependencies",
|
||||
Value::Object(peer_dependencies_meta),
|
||||
"peerDependenciesMeta",
|
||||
json!({"tree_sitter": {"optional": true}}),
|
||||
);
|
||||
updated = true;
|
||||
}
|
||||
|
||||
// insert `types` right after `main`
|
||||
if !package_json.contains_key("types") {
|
||||
eprintln!("Adding types to package.json");
|
||||
package_json = insert_after(
|
||||
package_json,
|
||||
"types",
|
||||
"main",
|
||||
Value::String("bindings/node".to_string()),
|
||||
);
|
||||
package_json =
|
||||
insert_after(package_json, "main", "types", "bindings/node".into());
|
||||
updated = true;
|
||||
}
|
||||
|
||||
// insert `files` right after `keywords`
|
||||
if !package_json.contains_key("files") {
|
||||
eprintln!("Adding files to package.json");
|
||||
let files = Value::Array(vec![
|
||||
Value::String("grammar.js".to_string()),
|
||||
Value::String("binding.gyp".to_string()),
|
||||
Value::String("types/dsl.d.ts".to_string()),
|
||||
Value::String("bindings/node/*".to_string()),
|
||||
Value::String("queries/*".to_string()),
|
||||
Value::String("src/**".to_string()),
|
||||
]);
|
||||
package_json = insert_after(package_json, "files", "keywords", files);
|
||||
package_json = insert_after(
|
||||
package_json,
|
||||
"keywords",
|
||||
"files",
|
||||
json!([
|
||||
"grammar.js",
|
||||
"binding.gyp",
|
||||
"types/dsl.d.ts",
|
||||
"prebuilds/**",
|
||||
"bindings/node/*",
|
||||
"queries/*",
|
||||
"src/**",
|
||||
]),
|
||||
);
|
||||
updated = true;
|
||||
}
|
||||
|
||||
let mut package_json_str = serde_json::to_string_pretty(&package_json)?;
|
||||
package_json_str.push('\n');
|
||||
write_file(path, package_json_str)?;
|
||||
if updated {
|
||||
let mut package_json_str = serde_json::to_string_pretty(&package_json)?;
|
||||
package_json_str.push('\n');
|
||||
write_file(path, package_json_str)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
@ -272,9 +307,19 @@ pub fn generate_grammar_files(
|
|||
|
||||
// Generate Node bindings
|
||||
missing_path(bindings_dir.join("node"), create_dir)?.apply(|path| {
|
||||
missing_path(path.join("index.js"), |path| {
|
||||
generate_file(path, INDEX_JS_TEMPLATE, language_name)
|
||||
})?;
|
||||
missing_path_else(
|
||||
path.join("index.js"),
|
||||
|path| generate_file(path, INDEX_JS_TEMPLATE, language_name),
|
||||
|path| {
|
||||
let index_js =
|
||||
fs::read_to_string(path).with_context(|| "Failed to read index.js")?;
|
||||
if index_js.contains("../../build/Release") {
|
||||
eprintln!("Replacing index.js with new binding API");
|
||||
generate_file(path, INDEX_JS_TEMPLATE, language_name)?;
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
)?;
|
||||
|
||||
missing_path(path.join("index.d.ts"), |path| {
|
||||
generate_file(path, INDEX_D_TS_TEMPLATE, language_name)
|
||||
|
|
@ -309,10 +354,6 @@ pub fn generate_grammar_files(
|
|||
},
|
||||
)?;
|
||||
|
||||
// Remove files from old node binding paths.
|
||||
existing_path(repo_path.join("index.js"), remove_file)?;
|
||||
existing_path(repo_path.join("src").join("binding.cc"), remove_file)?;
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
|
|
@ -464,11 +505,6 @@ fn create_dir(path: &Path) -> Result<()> {
|
|||
.with_context(|| format!("Failed to create {:?}", path.to_string_lossy()))
|
||||
}
|
||||
|
||||
fn remove_file(path: &Path) -> Result<()> {
|
||||
fs::remove_file(path).ok();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
enum PathState {
|
||||
Exists(PathBuf),
|
||||
|
|
@ -508,18 +544,6 @@ impl PathState {
|
|||
}
|
||||
}
|
||||
|
||||
fn existing_path<F>(path: PathBuf, mut action: F) -> Result<PathState>
|
||||
where
|
||||
F: FnMut(&Path) -> Result<()>,
|
||||
{
|
||||
if path.exists() {
|
||||
action(path.as_path())?;
|
||||
Ok(PathState::Exists(path))
|
||||
} else {
|
||||
Ok(PathState::Missing(path))
|
||||
}
|
||||
}
|
||||
|
||||
fn missing_path<F>(path: PathBuf, mut action: F) -> Result<PathState>
|
||||
where
|
||||
F: FnMut(&Path) -> Result<()>,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ target/
|
|||
|
||||
# Node artifacts
|
||||
build/
|
||||
prebuilds/
|
||||
node_modules/
|
||||
*.tgz
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,6 @@
|
|||
try {
|
||||
module.exports = require("../../build/Release/tree_sitter_PARSER_NAME_binding");
|
||||
} catch (error1) {
|
||||
if (error1.code !== "MODULE_NOT_FOUND") {
|
||||
throw error1;
|
||||
}
|
||||
try {
|
||||
module.exports = require("../../build/Debug/tree_sitter_PARSER_NAME_binding");
|
||||
} catch (error2) {
|
||||
if (error2.code !== "MODULE_NOT_FOUND") {
|
||||
throw error2;
|
||||
}
|
||||
throw error1
|
||||
}
|
||||
}
|
||||
const root = require("path").join(__dirname, "..", "..");
|
||||
|
||||
module.exports = require("node-gyp-build")(root);
|
||||
|
||||
try {
|
||||
module.exports.nodeTypeInfo = require("../../src/node-types.json");
|
||||
|
|
|
|||
|
|
@ -16,14 +16,17 @@
|
|||
"grammar.js",
|
||||
"binding.gyp",
|
||||
"types/dsl.d.ts",
|
||||
"prebuilds/**",
|
||||
"bindings/node/*",
|
||||
"queries/*",
|
||||
"src/**"
|
||||
],
|
||||
"dependencies": {
|
||||
"node-addon-api": "^7.1.0"
|
||||
"node-addon-api": "^7.1.0",
|
||||
"node-gyp-build": "^4.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prebuildify": "^6.0.0",
|
||||
"tree-sitter-cli": "^CLI_VERSION"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
|
@ -35,6 +38,8 @@
|
|||
}
|
||||
},
|
||||
"scripts": {
|
||||
"install": "node-gyp-build",
|
||||
"prebuildify": "prebuildify --napi --strip",
|
||||
"build": "tree-sitter generate --no-bindings",
|
||||
"build-wasm": "tree-sitter build-wasm",
|
||||
"test": "tree-sitter test",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue