Files
kucherenko__jscpd/rust/crates/basta/Cargo.toml
apk 2baf2890d4 feat(dead-code): read components, bundler aliases, globs and workspaces
basta reported most of a real Vue, Svelte or Astro project as dead: on
thirty GitHub-trending projects in those three ecosystems it flagged 1572
unused files, and some import in the tree contradicted 78% of them. The
misses were almost never in the analysis itself; they were imports only the
project's own build knows how to resolve. This reads them the way the build
does.

- Single-file components are read whole. The script of a .vue, .svelte or
  .astro file is masked in place so positions stay real, and the markup is
  scanned for the names it reads: <Foo />, kebab-case spellings, {{ }}
  interpolations, Svelte actions, attribute expressions, and a literal
  import() written in markup.
- Aliases come from vite.config.* resolve.alias and svelte.config.* kit.alias
  as well as tsconfig paths, and SvelteKit's $lib is known without the
  generated .svelte-kit/tsconfig.json no repository commits. The project's
  own declaration now wins over the ~/ @/ project-root fallback.
- A computed import whose static head names a directory,
  import(`./pages/${name}.vue`), and import.meta.glob('./locales/*.js') are
  expanded into one namespace edge per file there, the way a bundler hands
  back whole module objects. Such an import no longer marks its module as
  dynamic access, so the module's own findings keep their confidence.
- In a monorepo a package name resolves through that package's package.json,
  exports subpath by subpath with source conditions preferred over ./dist,
  anywhere in the workspace pnpm-workspace.yaml, lerna.json, turbo.json or a
  workspaces field marks out.
- A path literal in a build config resolves against the project root, and
  Nitro's api/, routes/ and middleware/ are file-system routes.

On the same thirty projects reported unused files fell from 1572 to 468.

fixtures/dead-code-demo gains components/, bundler/ and monorepo/. On master
the bundler demo reports five files as certainly dead, four of them wrongly;
the monorepo demo reports badge.ts, which the app imports by package name.
Both now report only what is dead. The quote-aware byte scanning the markup
and config readers share lives in one place, lang::Quotes and
lang::outside_strings, so rust/crates keeps master's 25 clones.
2026-09-17 12:36:34 +02:00

49 lines
1.3 KiB
TOML

[package]
name = "basta"
version = "0.1.1"
edition.workspace = true
publish = false
rust-version.workspace = true
description = "Dead code detection — unused files, exports, symbols and imports across JavaScript, TypeScript, Vue, Svelte, Astro and Python"
homepage.workspace = true
license.workspace = true
repository.workspace = true
documentation = "https://jscpd.dev"
keywords = ["dead-code", "unused-code", "static-analysis", "unused-exports", "basta"]
categories = ["command-line-utilities", "development-tools"]
[lib]
name = "basta"
path = "src/lib.rs"
[[bin]]
name = "basta"
path = "src/main.rs"
[dependencies]
globset = "0.4"
ignore = "0.4"
cpd-core = { version = "0.1.14", path = "../cpd-core" }
cpd-finder = { version = "0.1.16", path = "../cpd-finder" }
cpd-reporter = { version = "0.1.15", path = "../cpd-reporter" }
cpd-tokenizer = { version = "0.1.16", path = "../cpd-tokenizer" }
oxc_allocator = "0.147"
oxc_ast = "0.147"
oxc_ast_visit = "0.147"
oxc_parser = "0.147"
oxc_semantic = "0.147"
oxc_span = "0.147"
oxc_syntax = "0.147"
ruff_python_ast = "0.0.13"
ruff_python_parser = "0.0.13"
rustc-hash = "2"
chrono = "0.4"
rayon = "1"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
clap = { version = "4", features = ["derive"] }
env_logger = "0.11"
[dev-dependencies]
serde_json = "1"