Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions detect/detect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,125 @@ func TestNodeProject(t *testing.T) {
}
}

func TestNodeRustNativeExtensions(t *testing.T) {
t.Run("projects", func(t *testing.T) {
tests := []struct {
name string
fixture string
tool string
}{
{name: "napi-rs", fixture: "../testdata/napi-rs-project", tool: "napi-rs"},
{name: "Neon", fixture: "../testdata/neon-project", tool: "Neon"},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := runOn(t, tt.fixture)
assertToolDetectedWithConfidence(t, r, "native_extension", tt.tool, brief.ConfidenceHigh)
})
}
})

t.Run("signals", func(t *testing.T) {
tests := []struct {
name string
files map[string]string
tool string
}{
{
name: "napi-rs npm dependency",
files: map[string]string{
"package.json": `{"name":"example","devDependencies":{"@napi-rs/cli":"^3.0.0"}}`,
},
tool: "napi-rs",
},
{
name: "napi-rs build script",
files: map[string]string{
"package.json": `{"name":"example","scripts":{"build":"napi build --platform --release"}}`,
},
tool: "napi-rs",
},
{
name: "napi crate",
files: map[string]string{
"package.json": `{"name":"example"}`,
"Cargo.toml": "[package]\nname = \"example\"\nversion = \"0.1.0\"\n[dependencies]\nnapi = \"3\"\n",
},
tool: "napi-rs",
},
{
name: "napi-derive crate",
files: map[string]string{
"package.json": `{"name":"example"}`,
"Cargo.toml": "[package]\nname = \"example\"\nversion = \"0.1.0\"\n[dependencies]\nnapi-derive = \"3\"\n",
},
tool: "napi-rs",
},
{
name: "napi-build crate",
files: map[string]string{
"package.json": `{"name":"example"}`,
"Cargo.toml": "[package]\nname = \"example\"\nversion = \"0.1.0\"\n[build-dependencies]\nnapi-build = \"2\"\n",
},
tool: "napi-rs",
},
{
name: "Neon npm dependency",
files: map[string]string{
"package.json": `{"name":"example","devDependencies":{"@neon-rs/cli":"^0.1.82"}}`,
},
tool: "Neon",
},
{
name: "Neon Cargo dependency",
files: map[string]string{
"package.json": `{"name":"example"}`,
"Cargo.toml": "[package]\nname = \"example\"\nversion = \"0.1.0\"\n[dependencies.neon]\nversion = \"1.1\"\n",
},
tool: "Neon",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dir := t.TempDir()
for path, content := range tt.files {
writeProjectFile(t, dir, path, content)
}
r := runOn(t, dir)
assertToolDetectedWithConfidence(t, r, "native_extension", tt.tool, brief.ConfidenceHigh)
})
}
})

t.Run("near miss", func(t *testing.T) {
dir := t.TempDir()
writeProjectFile(
t,
dir,
"package.json",
`{"name":"near-miss","dependencies":{"napi":"1","neon":"1"},"scripts":{"palette":"echo neon"}}`,
)
writeProjectFile(
t,
dir,
"Cargo.toml",
"[package]\nname = \"near-miss\"\nversion = \"0.1.0\"\n[dependencies]\nother-napi = \"1\"\nultraviolet-neon = \"1\"\n",
)
writeProjectFile(t, dir, "README.md", "napi-rs uses the napi build command.\n")

r := runOn(t, dir)
for _, name := range []string{"napi-rs", "Neon"} {
if slices.ContainsFunc(r.Tools["native_extension"], func(d brief.Detection) bool {
return d.Name == name
}) {
t.Errorf("prose mention should not detect %s", name)
}
}
})
}

func TestPythonProject(t *testing.T) {
engine := New(loadKB(t), "../testdata/python-project")
r, err := engine.Run()
Expand Down
37 changes: 37 additions & 0 deletions knowledge/node/napi-rs.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
[tool]
name = "napi-rs"
category = "native_extension"
homepage = "https://napi.rs/"
docs = "https://napi.rs/docs/introduction/getting-started"
repo = "https://github.com/napi-rs/napi-rs"
description = "Builds Node-API addons written in Rust"

# Match the Cargo crates in Cargo.toml rather than through the global dependency
# cache so same-named npm packages do not trigger this definition.
[detect]
dependencies = ["@napi-rs/cli"]
ecosystems = ["node"]

[detect.file_contains]
"package.json" = ["napi build"]
"Cargo.toml" = [
"\nnapi =",
"\nnapi=",
"\nnapi-derive =",
"\nnapi-derive=",
"\nnapi-build =",
"\nnapi-build=",
"[dependencies.napi]",
"[dependencies.napi-derive]",
"[build-dependencies.napi-build]",
]

[commands]
run = "npx napi build --platform --release"
alternatives = ["npx napi build"]

[config]
files = ["package.json", "Cargo.toml", "build.rs"]

[taxonomy]
role = ["native-extension"]
26 changes: 26 additions & 0 deletions knowledge/node/neon.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[tool]
name = "Neon"
category = "native_extension"
homepage = "https://neon-rs.dev/"
docs = "https://neon-rs.dev/docs/hello-world/"
repo = "https://github.com/neon-bindings/neon"
description = "Builds Node.js native addons written in Rust"

# Match the Cargo crate in Cargo.toml rather than through the global dependency
# cache so a same-named npm package does not trigger this definition.
[detect]
dependencies = ["@neon-rs/cli"]
ecosystems = ["node"]

[detect.file_contains]
"Cargo.toml" = ["\nneon =", "\nneon=", "[dependencies.neon]"]

[commands]
run = "npm run build"
alternatives = ["npm run build -- --release"]

[config]
files = ["package.json", "Cargo.toml"]

[taxonomy]
role = ["native-extension"]
14 changes: 14 additions & 0 deletions testdata/napi-rs-project/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "napi-rs-project"
version = "0.1.0"
edition = "2024"

[lib]
crate-type = ["cdylib"]

[dependencies]
napi = { version = "3", features = ["napi8"] }
napi-derive = "3"

[build-dependencies]
napi-build = "2"
10 changes: 10 additions & 0 deletions testdata/napi-rs-project/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "napi-rs-project",
"version": "0.1.0",
"scripts": {
"build": "napi build --platform --release"
},
"devDependencies": {
"@napi-rs/cli": "^3.0.0"
}
}
1 change: 1 addition & 0 deletions testdata/napi-rs-project/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub fn fixture() {}
11 changes: 11 additions & 0 deletions testdata/neon-project/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "neon-project"
version = "0.1.0"
edition = "2024"

[lib]
crate-type = ["cdylib"]

[dependencies.neon]
version = "1.1"
features = ["napi-8"]
12 changes: 12 additions & 0 deletions testdata/neon-project/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "neon-project",
"version": "0.1.0",
"scripts": {
"cargo-build": "cargo build --message-format=json-render-diagnostics > cargo.log",
"postcargo-build": "neon dist < cargo.log",
"build": "npm run cargo-build -- --release"
},
"devDependencies": {
"@neon-rs/cli": "^0.1.82"
}
}
1 change: 1 addition & 0 deletions testdata/neon-project/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub fn fixture() {}