') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); GitHub - optiprune/cli · GitHub
Skip to content

Repository files navigation

OptiPrune analyzer animation

CLI npm versionCore npm versionCLI packageCore testsLicenseNode.js

OptiPrune

OptiPrune is a static dead-code analyzer for TypeScript and JavaScript projects. It combines parser-backed module graphs, export and member reachability, dependency and workspace inspection, dynamic-import analysis, semantic contracts, optional symbolic/concolic checks, and source-aware plugins.

The CLI package is @optiprune/cli. The analysis engine is available separately as the headless package @optiprune/core.

Features

AreaWhat is included
Project analysisEntry discovery, module graphs, export/member reachability, dependency edges, strongly connected components, and cycle reporting.
TypeScript and JavaScript.ts, .tsx, .js, .jsx, and .vue extensions by default, with custom extension lists available from the CLI or config.
Dynamic pathsLiteral and pattern-based dynamic imports, unresolved-path findings, recovery information, and isolated execution checks.
Logic analysisConstant conditions, contradictory guards, unreachable statements, and schema-impossible guards.
Dependenciespackage.json, scripts, dependency/devDependency usage, package exports, bins, workspace packages, and lockfile-aware context.
Contracts and entriesPublic API contracts, schema-aware protection, conventional entries, entry-file exports, test-file handling, and framework/plugin entry points.
FixesOpt-in fixes for unreachable files, unused exports and members, dependencies, development dependencies, verified conditions, and safely recoverable package.json JSON. Every fix is confidence-gated and supports dry runs.
OutputHuman-readable terminal output, JSON reports with optional structured debug diagnostics, and SARIF output for CI/code-scanning workflows.
Headless usageanalyze, shouldFail, cache helpers, fix helpers, reporters, and public TypeScript types from @optiprune/core.
PluginsSource-aware adapters for frameworks, build tools, test tools, runtimes, package managers, and workspace conventions.

Installation

Install the CLI as a development dependency:

npm install --save-dev @optiprune/cli
# or
pnpm add -D @optiprune/cli
# or
yarn add -D @optiprune/cli

The Core package currently requires Node.js 21 or newer.

Quick start

Run an analysis from the project root:

npx @optiprune/cli analyze

The default command is analyze, so this is equivalent:

npx @optiprune/cli

Select a machine-readable output format when integrating with tooling:

npx @optiprune/cli analyze --json
npx @optiprune/cli analyze --sarif > optiprune.sarif

Commands

CommandPurpose
analyze [options]Analyze the project. This is the default command.
export-cache <targetPath>Export the current analysis cache to a JSON file.
import-cache <sourcePath>Import an external cache JSON file into the local project cache.
optiprune --helpPrint command and option help.
optiprune --versionPrint the CLI and detected Core versions.

Analyze flags

FlagDescriptionDefault
-r, --rootDir <path>Root directory of the project.Current working directory
-e, --entry <patterns...>Entry-point patterns, globs, or file paths.[]
-x, --extensions <exts...>File extensions to analyze..ts .tsx .js .jsx .vue
-i, --ignore <patterns...>Glob patterns to ignore.[]
--no-report-unused-exportsDisable unused-export reporting.Enabled
--no-conventional-entriesExclude conventional entries such as src/index.ts.Included
--include-entry-exportsReport unused exports declared directly in entry files.Disabled
--include-entry-membersReport unused members declared in objects exported directly from entry files.Disabled
--cyclesPrint detected dependency cycles.Disabled
--ignore-testsIgnore test files such as test.ts, *.test.ts, and __tests__.Disabled
--fail-on <confidence>Exit non-zero when findings meet the selected confidence level: high, medium, low, or none.high
--jsonPrint the structured analysis report as JSON.Disabled
--sarifPrint SARIF output.Disabled
--skip-3Skip the SMT constraint-analysis layer.Disabled
--skip-4Skip the concolic execution-proof layer.Disabled
-v, --verbosePrint verbose output and internal graph state; with --json, include structured debug diagnostics in the report.Disabled
--fix <rules...>Select fix targets: files, exports, dependencies, devDependencies, conditions, or json.None
--fix-jsonSafely repair recoverable package.json JSON errors; shorthand for --fix json.Disabled
--node-llama-cppForce-enable the dedicated node-llama-cpp semantic analysis plugin.Disabled
--confidence <level>Minimum fix confidence: high, medium+, low+, or all.high
--forceAllow a selected fix when the source edit is otherwise considered unsafe.Disabled
--dry-runLog planned fixes without changing files.Disabled
--cache-from <path>Import a JSON cache before analysis.None
--cache-to <path>Export the resulting cache after analysis.None

--confidence, --force, and --dry-run require --fix or --fix-json. Unknown fix targets are rejected before analysis begins.

Fixes

Fixes are explicit rather than implicit. Start with a dry run, inspect the output, then omit --dry-run when the proposed changes are acceptable.

npx @optiprune/cli analyze \
--fix files exports dependencies devDependencies conditions json \
--confidence medium+ \
--dry-run
# Or repair only safe package.json syntax issues
npx @optiprune/cli analyze --fix-json
TargetApplies to
filesVerified unreachable files.
exportsVerified unused exports and members.
dependenciesUnused runtime dependencies.
devDependenciesUnused development dependencies.
conditionsVerified constant conditions.
jsonSafe recovery of malformed package.json syntax, including comments, trailing commas, missing commas, and missing closing delimiters. Unsafe forms such as unquoted keys remain unchanged.

--force changes the safety decision for the selected fix operation; it does not make an unverified finding correct. Use it only when the source edit has been reviewed.

Cache

Use cache files to reuse analysis state in local workflows or CI:

npx @optiprune/cli analyze \
--cache-from .optiprune/cache.json \
--cache-to .optiprune/cache.json
npx @optiprune/cli export-cache .optiprune/cache.json
npx @optiprune/cli import-cache .optiprune/cache.json

export-cache and import-cache accept -r, --rootDir <path> when the cache belongs to a directory other than the current working directory.

Configuration

OptiPrune reads configuration through the Core loader. Supported sources include:

SourceNotes
optiprune.jsonStandard JSON configuration.
optiprune.jsoncJSON with comments and trailing commas.
optiprune.config.tsTypeScript configuration with a default export.
optiprune.config.jsJavaScript ESM configuration with a default export.
optiprune.config.mjsJavaScript ESM configuration with a default export.
package.json#optiprunePackage field configuration.

See config.md for the configuration reference and schema.json for the authoritative schema.

Headless Core API

Use @optiprune/core directly when the CLI is not the right integration boundary:

npm install @optiprune/core
import { analyze, shouldFail } from "@optiprune/core";
const report = await analyze({
rootDir: process.cwd(),
entry: ["src/index.ts"],
output: "json",
});
console.log(report.summary);
if (shouldFail(report, "high")) {
process.exitCode = 1;
}

The Core package also exposes cache helpers, applyFixes, reporters, and public types:

import { applyFixes, exportCache, importCache } from "@optiprune/core";
import { formatSarif, formatTerminal } from "@optiprune/core/reporters";
import type { AnalysisReport, AnalyzerOptions, Finding } from "@optiprune/core/types";

An AnalysisReport contains summary counts, findings, entry points, module records, exports, dependency edges, and strongly connected components.

Plugin model

Plugins provide source-aware context for frameworks, build tools, test runners, runtimes, package managers, and workspace conventions. They can contribute entry patterns, mark files or packages as used, interpret project metadata, and participate in analysis lifecycle hooks.

Browse the Core plugin directory to inspect the current source-backed set and the AnalyzerPlugin/PluginAdapter contracts.

Development

Build the package from this repository:

npm run build
npm test

The Core repository uses Vitest for its test suite. The workflow badges above reflect the status reported by GitHub Actions rather than a hard-coded claim in this README.

Links

ResourceLink
CLI repositorygithub.com/optiprune/cli
Core repositorygithub.com/optiprune/core
CLI packagenpmjs.com/package/@optiprune/cli
Core packagenpmjs.com/package/@optiprune/core
Documentation siteopti.drml.int.yt
LicenseMIT

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages