Loading...
Thirteen languages, syntax-aware detection: tree-sitter AST for TypeScript, JavaScript, Go, Python, Java, C#, PHP, and Rust, precise regex patterns for the rest. Eight flag providers with SDK-aware detection. Custom flag patterns via .flagshark.yaml for anything we haven't pre-tuned.
TypeScript, JavaScript, Go, Python, Java, C#, PHP, and Rust parse to a full tree-sitter AST; the other five use precise regex patterns. Either way we match flag SDK calls by structure, so you get far fewer false positives from comments or strings.
All 13 are detected and tracked. Automated cleanup PRs are available today for 7 — Go, TypeScript, JavaScript, Java, Kotlin, Python, and Ruby; the rest are detection-only for now.
Every removal lands as a small, reviewable pull request — folded to the surviving branch and formatter-clean. Pick a language and see exactly what the diff looks like.
@@ func Charge(client Client, ctx Context, order Order) error {- useNew, err := client.BoolVariation("new-billing-engine", ctx, false)- if err != nil {- return err- }- if useNew {- return chargeV2(order)- }- return chargeLegacy(order)+ return chargeV2(order) }
.flagshark.yaml@@ export function Nav({ items }: NavProps) {- const compact = client.variation("compact-nav", ctx, false);- return compact ? <CompactNav items={items} /> : <FullNav items={items} />;+ return <CompactNav items={items} />; }
.flagshark.yaml@@ function renderHeader(user) {- if (client.variation("beta-banner", user, false) && user.isBeta) {+ if (user.isBeta) { showBanner(); } renderNav(); }
.flagshark.yaml@@ String resolveTheme(LDClient client, LDContext ctx) {- String theme = client.stringVariation("checkout-theme", ctx, "midnight");- return theme;+ return "midnight"; }
.flagshark.yaml@@ fun request(client: LDClient, ctx: LDContext): Response {- val smart = client.boolVariation("smart-retry", ctx, false)- return if (smart) retryingRequest() else plainRequest()+ return retryingRequest() }
.flagshark.yaml@@ def run(client, ctx):- for _ in range(client.variation("max-retries", ctx, 3)):+ for _ in range(3): attempt()
.flagshark.yaml@@ def upload(client, user, file)- return enqueue_upload(file) if client.variation("async-upload", user, false)- upload_now(file)+ enqueue_upload(file) end
.flagshark.yamlLaunchDarkly, PostHog, Unleash, OpenFeature, ConfigCat, GrowthBook, Flagsmith, and Statsig work out of the box (coverage varies by language). For anything else — Split, or your own in-house wrapper — name the SDK call in .flagshark.yaml and tell FlagShark which argument holds the flag key. Detection and cleanup then work exactly like the built-ins.
# .flagshark.yamlproviders: - name: Acme Flags language: typescript importPattern: "@acme/flags" methods: - name: isEnabled flagKeyIndex: 0
Same setup in every language: connect the repo, FlagShark scans on every push.
BoolVariation, StringVariation, AllFlags, TrackgetTreatment, getTreatments, trackisEnabled, getVariant, getAllTogglesisOn, getFeatureValue, evalFeatureisFeatureEnabled, getFeatureFlag, getAllFlagsgetValue, getValueDetails, getAllKeyshas_feature, get_value, get_traitcheckGate, getConfig, getExperimentNeed a provider we don't list? Define custom flag patterns in .flagshark.yaml (regex or AST patterns both work).