From 271bb1b1bc435a9c4f79f4fa9733b9046f4f9e72 Mon Sep 17 00:00:00 2001 From: Krishan Kant Sharma Date: Wed, 1 Jul 2026 09:26:40 -0500 Subject: [PATCH] =?UTF-8?q?docs:=20deeper=20structural=20improvements=20?= =?UTF-8?q?=E2=80=94=20how-it-works,=20troubleshooting,=20report=20formats?= =?UTF-8?q?,=20exit=20codes,=20OF=20bindings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Merge reference/exit-codes.md into cli/exit-codes.md: full table, per-command matrix, why-exit-1 explanation, CI YAML example, stability guarantee. Deleted the redundant reference page (sidebar update needed separately). - Expand how-flaglint-works.md: import-verified concept with false-positive example, three-phase pipeline explanation, what FlagLint does not do. - Expand troubleshooting.md: 4 items → 8 items covering 0-flags-detected, config-not-found, React-not-automigrated, apply-0-transformed, validate-CI-gap. - Rewrite report-formats.md: format comparison table, when-to-use prose for each format, GitHub Code Scanning SARIF upload example. - Expand configuration.md openFeatureClientBindings: what it does, example, multiple bindings, difference from wrappers. Signed-off-by: Krishan Kant Sharma --- src/content/docs/docs/cli/audit.md | 2 +- src/content/docs/docs/cli/completion.md | 1 + src/content/docs/docs/cli/configuration.md | 70 ++++++++-- src/content/docs/docs/cli/exit-codes.md | 112 ++++++++++++---- src/content/docs/docs/cli/migrate.md | 2 +- src/content/docs/docs/cli/report-formats.md | 102 +++++++++++--- src/content/docs/docs/cli/scan.md | 12 +- src/content/docs/docs/cli/validate.md | 2 +- .../docs/docs/concepts/how-flaglint-works.md | 89 +++++++++++-- .../docs/concepts/openfeature-boundary.md | 2 +- .../docs/docs/concepts/safety-model.md | 2 +- .../concepts/source-level-debt-signals.md | 2 +- src/content/docs/docs/enterprise-demo.md | 2 +- src/content/docs/docs/guides/express.md | 2 +- .../docs/guides/manual-review-patterns.md | 2 +- src/content/docs/docs/guides/monorepos.md | 2 +- src/content/docs/docs/guides/nestjs.md | 2 +- .../docs/docs/guides/troubleshooting.md | 124 ++++++++++++++++-- src/content/docs/docs/index.md | 4 +- .../docs/docs/integrations/github-actions.md | 15 ++- .../docs/integrations/openfeature-provider.md | 2 +- .../docs/docs/integrations/opentelemetry.md | 2 +- src/content/docs/docs/product-contract.md | 2 +- src/content/docs/docs/quickstart.md | 16 +-- src/content/docs/docs/reference/changelog.md | 2 +- src/content/docs/docs/reference/exit-codes.md | 88 ------------- src/content/docs/docs/reference/faq.md | 2 +- .../docs/docs/reference/limitations.md | 6 +- .../docs/docs/reference/supported-scope.md | 2 +- src/content/docs/docs/trust/security.md | 2 +- .../tutorials/add-openfeature-provider.md | 2 +- .../tutorials/enforce-in-github-actions.md | 2 +- .../docs/tutorials/migrate-a-node-service.md | 2 +- .../tutorials/shared-client-architecture.md | 2 +- src/content/docs/docs/why-flaglint.md | 2 +- 35 files changed, 483 insertions(+), 202 deletions(-) delete mode 100644 src/content/docs/docs/reference/exit-codes.md diff --git a/src/content/docs/docs/cli/audit.md b/src/content/docs/docs/cli/audit.md index 09f190b..6cd6e81 100644 --- a/src/content/docs/docs/cli/audit.md +++ b/src/content/docs/docs/cli/audit.md @@ -165,6 +165,6 @@ npx flaglint validate ./src --no-direct-launchdarkly ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/cli/audit.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/cli/audit.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [Configuration](/docs/cli/configuration/) diff --git a/src/content/docs/docs/cli/completion.md b/src/content/docs/docs/cli/completion.md index 818807c..c245aca 100644 --- a/src/content/docs/docs/cli/completion.md +++ b/src/content/docs/docs/cli/completion.md @@ -94,3 +94,4 @@ flaglint completion fish > ~/.config/fish/completions/flaglint.fish - [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/cli/completion.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) +- Next: [GitHub Actions](/docs/integrations/github-actions/) diff --git a/src/content/docs/docs/cli/configuration.md b/src/content/docs/docs/cli/configuration.md index 1a130b9..d444302 100644 --- a/src/content/docs/docs/cli/configuration.md +++ b/src/content/docs/docs/cli/configuration.md @@ -34,16 +34,16 @@ Use `--config ` to pass a specific file. ## Fields -| Field | Default | Purpose | -| --- | --- | --- | -| `include` | `["**/*.{ts,tsx,js,jsx}"]` | Files to scan. | -| `exclude` | common build/test output | Files to skip. | -| `provider` | `launchdarkly` | Current implemented provider scope. | -| `minFileCount` | `0` | Optional local source review heuristic. | -| `wrappers` | `[]` | Wrapper functions to detect as flag evaluations. Accepts string names or object form (see below). | -| `openFeatureClientBindings` | `[]` | Imported shared client allowlist for `migrate --apply`. | -| `reportTitle` | unset | Optional report title. | -| `outputDir` | `.` | Directory for generated report files. | +| Field | Type | Default | Purpose | +| --- | --- | --- | --- | +| `include` | `string[]` | `["**/*.{ts,tsx,js,jsx}"]` | Files to scan. | +| `exclude` | `string[]` | common build/test output | Files to skip. | +| `provider` | `"launchdarkly"` | `"launchdarkly"` | Provider scope. Currently only `"launchdarkly"` is supported — other values exit 2. | +| `minFileCount` | `number` | `0` | Optional local source review heuristic. | +| `wrappers` | `(string \| WrapperObject)[]` | `[]` | Wrapper functions to detect as flag evaluations. Accepts string names or object form (see below). | +| `openFeatureClientBindings` | `string[]` | `[]` | Imported shared client allowlist for `migrate --apply`. | +| `reportTitle` | `string` (optional) | unset | Optional report title injected into HTML and Markdown reports. | +| `outputDir` | `string` | `"."` | Directory for generated report files. | ## Wrappers — String and Object Form @@ -84,6 +84,54 @@ With the example above, `getFlag("my-flag-key", ctx)` is detected only when `get ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/cli/configuration.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/cli/configuration.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [Report Formats](/docs/cli/report-formats/) + +## OpenFeature Client Bindings + +`openFeatureClientBindings` tells `flaglint migrate --apply` which variables in your code hold +an OpenFeature client. When applying transformations, FlagLint substitutes LD SDK evaluation +calls with the corresponding OpenFeature client method calls — but only when it can identify +the client variable to substitute. + +Each entry is a **variable name** (not a package name, not a file path) that FlagLint should +treat as an OpenFeature client. + +### Example + +Your application code: + +```typescript +import openFeatureClient from './platform/of-client' + +const value = openFeatureClient.getBooleanValue('my-flag', false) +``` + +Your config: + +```json +{ + "openFeatureClientBindings": ["openFeatureClient"] +} +``` + +With this configured, `migrate --apply` can generate the correct OpenFeature replacement call. +Without it, files that use an imported client are listed in the "skipped" output. + +### Multiple bindings + +If different parts of your codebase use different variable names for the OpenFeature client, +list all of them: + +```json +{ + "openFeatureClientBindings": ["openFeatureClient", "featureClient", "ofClient"] +} +``` + +### Difference from wrappers + +`openFeatureClientBindings` is for the **OpenFeature client** used in migration output — it +tells FlagLint what to generate, not what to detect. `wrappers` is for **existing LD-compatible +wrappers** — it tells FlagLint what to detect as flag evaluations in your current code. diff --git a/src/content/docs/docs/cli/exit-codes.md b/src/content/docs/docs/cli/exit-codes.md index 3f9daa3..b383d81 100644 --- a/src/content/docs/docs/cli/exit-codes.md +++ b/src/content/docs/docs/cli/exit-codes.md @@ -1,34 +1,102 @@ --- title: Exit Codes -description: Stable exit code contract for FlagLint v1.x — 0=success, 1=policy failure, 2=invalid input, 3=internal error. -lastUpdated: 2026-06-22 +description: Stable exit code contract for FlagLint v1.x — 0=success, 1=policy failure, 2=invalid input, 3=internal error, 130=interrupted. +lastUpdated: 2026-07-01 --- -FlagLint uses a stable, machine-readable exit code contract guaranteed across all v1.x releases. -See the [full Exit Codes reference](/docs/reference/exit-codes/) for CI examples and rationale. +FlagLint uses a stable, machine-readable exit code contract. Codes `0`, `1`, `2`, and `130` are +guaranteed stable across all v1.x releases and safe to use in CI pipelines and scripts. ## Exit Code Table | Code | Meaning | When it occurs | -| --- | --- | --- | -| `0` | Success — no blocking failures. | Scan completed; no policy violations found. | -| `1` | Policy or validation failure. | `validate --no-direct-launchdarkly` found direct LD calls; new findings beyond baseline (`--fail-on-new`); dirty working tree without `--allow-dirty`. | -| `2` | Invalid input. | Bad `--format` value; missing or malformed baseline or config file. | -| `3` | Internal FlagLint error. | Unexpected runtime exception in FlagLint itself. | -| `130` | Interrupted with `SIGINT` (Ctrl-C). | | - -## Command Notes - -- `audit` always exits `0` — it is informational only. -- `scan` exits `1` when configured stale/review signals produce blocking candidates. -- `migrate --dry-run` exits `0` after printing a plan. -- `migrate --apply` exits `1` on a dirty working tree unless `--allow-dirty` is used. -- `validate --no-direct-launchdarkly` exits `1` when direct LaunchDarkly evaluation calls are found. -- `validate --baseline --fail-on-new` exits `1` when any finding fingerprint is absent from the baseline. +|------|---------|----------------| +| `0` | Success — no blocking failures | Scan or audit completed; no policy violations found; no new findings beyond baseline | +| `1` | Policy or validation failure | `validate --no-direct-launchdarkly` found direct LD calls; new findings beyond baseline (`--fail-on-new`); dirty working tree without `--allow-dirty` | +| `2` | Invalid input | Bad `--format` value; directory not found or not a directory; missing or malformed baseline file; unsupported provider in config | +| `3` | Internal FlagLint error | Unexpected runtime exception in FlagLint itself — please [report as a bug](https://github.com/flaglint/flaglint/issues/new) | +| `130` | Interrupted (SIGINT) | User pressed Ctrl-C | + +## Per-Command Notes + +| Command | Exit `0` | Exit `1` | Exit `2` | +|---------|----------|----------|----------| +| `scan` | Always on completion (scan is inventory, not enforcement) | — | Invalid `--format`; directory not found; bad config | +| `audit` | Always on completion (audit is informational only) | — | Invalid `--format`; directory not found; bad config | +| `migrate` (default) | Plan written successfully | — | Directory not found; bad config | +| `migrate --dry-run` | Diffs printed | — | Directory not found | +| `migrate --apply` | Transformations applied | Dirty working tree (without `--allow-dirty`) | Directory not found | +| `validate` | No policy violations | Direct LD calls found; new findings beyond baseline | Invalid `--format`; bad baseline; bad config | + +## Why exit 1 does not mean the tool crashed + +Exit code `1` means **FlagLint ran successfully and found a policy violation** — not that the +tool failed. This distinction matters in CI logs: + +- `exit 0` → Clean. No violations found. +- `exit 1` → FlagLint worked correctly; your code has a flag debt issue to address. +- `exit 2` → You passed a bad argument or your config is invalid; fix the command invocation. +- `exit 3` → FlagLint itself hit an unexpected error; please [file a bug report](https://github.com/flaglint/flaglint/issues/new). +- `exit 130` → Interrupted by the user (Ctrl-C). + +This matches the POSIX convention used by linters such as ESLint (`exit 1` = lint errors found) +and allows CI steps to distinguish tool failure from policy failure without parsing stdout. + +## CI YAML example + +The following GitHub Actions workflow runs `flaglint validate` as a policy gate. It expects +`exit 0` (clean) or `exit 1` (violations found), and treats any other exit code as a +misconfiguration or internal error. + +```yaml +name: FlagLint Policy Gate + +on: + pull_request: + push: + branches: [main] + +jobs: + flaglint-validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: "22" + + # Exit 0 → no direct LD calls (clean). + # Exit 1 → direct LD calls found (policy violation — fail the build). + # Exit 2 → bad --format or config error (fix the workflow invocation). + - name: Validate no direct LaunchDarkly calls + run: npx flaglint@latest validate ./src --no-direct-launchdarkly + + # Optional: emit SARIF for GitHub Code Scanning annotations + - name: Validate (SARIF output) + if: always() + run: npx flaglint@latest validate ./src --no-direct-launchdarkly --format sarif --output flaglint.sarif + continue-on-error: true + + - name: Upload SARIF to GitHub Code Scanning + if: always() + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: flaglint.sarif +``` + +See the [GitHub Actions integration guide](/docs/integrations/github-actions/) and +the [`validate` command reference](/docs/cli/validate/) for the full set of options +including `--bootstrap-exclude` for allowing provider setup files. + +## Stability guarantee + +Codes `0`, `1`, `2`, and `130` are stable across all FlagLint v1.x releases. +Code `3` (internal error) may be refined in future releases but will always indicate +an unexpected tool failure (not a policy result). ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/cli/exit-codes.md) -- [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) -- See also: [Exit Codes reference](/docs/reference/exit-codes/) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/cli/exit-codes.md) +- [Report an issue](https://github.com/flaglint/flaglint/issues/new) - Next: [Express Guide](/docs/guides/express/) diff --git a/src/content/docs/docs/cli/migrate.md b/src/content/docs/docs/cli/migrate.md index ad7f432..4e9613d 100644 --- a/src/content/docs/docs/cli/migrate.md +++ b/src/content/docs/docs/cli/migrate.md @@ -68,6 +68,6 @@ Provider/bootstrap setup is never inserted automatically. ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/cli/migrate.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/cli/migrate.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [validate CLI](/docs/cli/validate/) diff --git a/src/content/docs/docs/cli/report-formats.md b/src/content/docs/docs/cli/report-formats.md index 8b008eb..f20e639 100644 --- a/src/content/docs/docs/cli/report-formats.md +++ b/src/content/docs/docs/cli/report-formats.md @@ -1,44 +1,112 @@ --- title: Report Formats -description: JSON, Markdown, HTML, and SARIF outputs. -lastUpdated: 2026-05-28 +description: When to use JSON, Markdown, HTML, SARIF, and text output — comparison table, usage examples, and GitHub Code Scanning integration. +lastUpdated: 2026-07-01 --- -## Scan Formats +FlagLint supports multiple output formats. Choose based on who consumes the output and how. + +## Format comparison + +| Format | Commands | Best for | +|--------|----------|----------| +| `markdown` | `scan`, `audit` | Human review, GitHub PR comments, Slack sharing | +| `json` | `scan`, `audit` | Automation, CI pipelines, custom dashboards, `jq` filtering | +| `html` | `scan`, `audit` | Sharing with non-technical stakeholders, archiving audit results | +| `sarif` | `scan`, `validate` | GitHub Code Scanning, IDE integrations, VS Code SARIF Viewer | +| `text` | `validate` | Terminal output, CI logs where markdown rendering is not available | + +## When to use each format + +**`markdown` (default for scan and audit)** + +Readable in GitHub PR comments and any Markdown renderer. Use this when you want engineers +to read findings directly — in a PR review, a Slack post, or a shared Notion doc. This is the +default when `--format` is omitted. + +**`json`** + +Machine-readable structured output. Use with `jq` for filtering, in custom dashboards, or when +building integrations on top of FlagLint output. The full schema is documented at +[JSON Output Reference](/docs/reference/json-output/). ```bash -npx flaglint scan ./src --format json -npx flaglint scan ./src --format markdown -npx flaglint scan ./src --format html --output flaglint-inventory.html -npx flaglint scan ./src --format sarif --output flaglint-inventory.sarif +npx flaglint@latest scan ./src --format json | jq '.usages[] | select(.isStale == true)' ``` -Use scan formats for inventory and review. +**`html`** + +Self-contained single-file report. Use for sharing audit results with engineering managers or +stakeholders who do not have CLI access. The HTML file embeds all styles — no server needed, +just open in a browser. + +```bash +npx flaglint@latest audit ./src --format html --output flaglint-audit.html +``` + +**`sarif`** + +[SARIF 2.1.0](https://sarifweb.azurewebsites.net/) compliant output. Use with: +- **GitHub Code Scanning** — upload via `github/codeql-action/upload-sarif` to get inline PR annotations +- **VS Code SARIF Viewer** extension — view findings inline in your editor +- **Azure DevOps** SARIF integration -## Validation SARIF +**`text`** -Use `validate --format sarif` for direct-SDK policy enforcement: +Plain-text output for `validate`. Use in CI logs where markdown rendering is not available and +you want a human-readable summary without table syntax. + +## Usage examples + +### Scan formats + +```bash +npx flaglint@latest scan ./src --format json +npx flaglint@latest scan ./src --format markdown +npx flaglint@latest scan ./src --format html --output flaglint-inventory.html +npx flaglint@latest scan ./src --format sarif --output flaglint-inventory.sarif +``` + +### Validation SARIF + +Use `validate --format sarif` for direct-SDK policy enforcement with GitHub Code Scanning: ```bash -npx flaglint validate ./src \ +npx flaglint@latest validate ./src \ --no-direct-launchdarkly \ --format sarif \ --output flaglint-validation.sarif ``` -This is the SARIF output intended for GitHub Code Scanning annotations. +### GitHub Code Scanning integration + +Upload SARIF output to get inline annotations on pull requests: + +```yaml +- name: Run FlagLint validate + run: npx flaglint@latest validate ./src --no-direct-launchdarkly --format sarif --output flaglint.sarif + continue-on-error: true + +- name: Upload SARIF to GitHub Code Scanning + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: flaglint.sarif +``` + +Findings appear as inline annotations on the Files Changed tab of your pull request. -## Migration Reports +### Migration reports ```bash -npx flaglint migrate ./src --output MIGRATION.md -npx flaglint migrate ./src --dry-run +npx flaglint@latest migrate ./src --output MIGRATION.md +npx flaglint@latest migrate ./src --dry-run ``` -The default migration report summarizes evidence. Dry-run prints diffs. +The default migration report summarizes evidence and migration readiness. `--dry-run` prints +reviewable diffs to stdout without writing any files. ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/cli/report-formats.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/cli/report-formats.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [Exit Codes](/docs/cli/exit-codes/) diff --git a/src/content/docs/docs/cli/scan.md b/src/content/docs/docs/cli/scan.md index d605ac1..57abfbe 100644 --- a/src/content/docs/docs/cli/scan.md +++ b/src/content/docs/docs/cli/scan.md @@ -47,12 +47,18 @@ Generated from `examples/enterprise-checkout-service/src`: - Line 67: `checkout-currency` (stringVariation) ``` -## Exit Behavior +## Exit Codes -`scan` exits `1` only when configured review signals mark non-dynamic, non-bulk flags as stale candidates. A one-file flag is not stale by default because `minFileCount` defaults to `0`. +`scan` is an inventory command — it never exits `1` due to findings. Use `validate` for CI enforcement. + +| Code | Meaning | +| --- | --- | +| `0` | Scan completed. | +| `2` | Invalid input — bad `--format` value, directory not found, or invalid config. | +| `130` | Interrupted (Ctrl+C / SIGINT). | ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/cli/scan.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/cli/scan.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [migrate CLI](/docs/cli/migrate/) diff --git a/src/content/docs/docs/cli/validate.md b/src/content/docs/docs/cli/validate.md index 1f5eebe..29dda31 100644 --- a/src/content/docs/docs/cli/validate.md +++ b/src/content/docs/docs/cli/validate.md @@ -104,6 +104,6 @@ npx flaglint validate ./src \ ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/cli/validate.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/cli/validate.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [Configuration](/docs/cli/configuration/) diff --git a/src/content/docs/docs/concepts/how-flaglint-works.md b/src/content/docs/docs/concepts/how-flaglint-works.md index fea29ae..36ee784 100644 --- a/src/content/docs/docs/concepts/how-flaglint-works.md +++ b/src/content/docs/docs/concepts/how-flaglint-works.md @@ -1,10 +1,52 @@ --- title: How FlagLint Works -description: The source-analysis model behind inventory, migration previews, and validation. -lastUpdated: 2026-05-28 +description: The import-verified static analysis model behind FlagLint's inventory, migration previews, and validation — and why it produces zero false positives on flag detection. +lastUpdated: 2026-07-01 --- -FlagLint performs local static analysis. It parses JavaScript and TypeScript source files, tracks LaunchDarkly client provenance from supported Node.js server SDK imports, and records evaluation call sites. +FlagLint performs local static analysis. It parses JavaScript and TypeScript source files, +tracks LaunchDarkly client provenance from supported Node.js server SDK imports, and records +evaluation call sites. It never executes application code and never calls LaunchDarkly APIs. + +## The import-verified approach + +Most flag scanners work by searching for function names like `variation`, `getFlag`, or `ldClient` +across your codebase. This produces false positives whenever an unrelated library happens to use +the same names — breaking CI and eroding trust in the tool. + +FlagLint uses **import-verified** detection. A call site is only flagged as a LaunchDarkly +evaluation if the tool can trace a complete provenance chain: + +1. A known LD SDK package is imported (`launchdarkly-node-server-sdk` or `@launchdarkly/node-server-sdk`) +2. The SDK's `init()` return value is bound to a variable +3. A `.variation()`, `.boolVariation()`, or equivalent method is called on that specific variable + +No import proof → no flag. A function coincidentally named `variation()` from an animation library +is never flagged. + +### Concrete example + +```typescript +// ❌ grep for "variation" would match this — FlagLint does NOT +import { variation } from 'some-animation-library' +const opacity = variation('fade', 0, 1) + +// ✅ FlagLint correctly identifies only this: +import { init } from 'launchdarkly-node-server-sdk' +const client = init(sdkKey, config) +const value = client.variation('my-flag', ctx, false) // ← flagged +``` + +The variable name does not matter. If `client` is renamed to `ldClient`, `ld`, or `featureFlags`, +FlagLint tracks the binding and still identifies the call. Conversely, a variable named `ldClient` +that was never assigned an LD `init()` return value is ignored. + +### Why this matters for migration + +Name-heuristic scanners produce false positives that fail CI for code that has nothing to do +with feature flags. Teams either disable the rule or accept noise — both outcomes break the +migration workflow. Import-verified scanning means the inventory is trustworthy: every finding +is a real LaunchDarkly SDK call, and the count is accurate enough to drive engineering planning. ## Analysis Pipeline @@ -17,23 +59,44 @@ flowchart LR E --> F["Report /\ndiff / SARIF"] -FlagLint does not execute application code and does not call LaunchDarkly APIs. +### Phase 1 — Collect + +FlagLint uses a TypeScript AST parser (`@typescript-eslint/typescript-estree`) to parse every +file matched by your `include`/`exclude` config. For each file it: + +- Resolves all import and require statements +- Identifies LD SDK imports and traces `init()` call bindings +- Identifies custom wrapper functions listed in your `wrappers` config +- Records every evaluation call site with its file, line, flag key, and call type + +### Phase 2 — Analyze + +Against the collected inventory, FlagLint: + +- Detects staleness signals (flags referenced in only one place, single-variant patterns, commented-out removal notes) +- Scores migration readiness (safely automatable vs. requires manual review) +- Identifies dynamic flag keys (runtime-computed strings that can't be statically resolved) -## Provenance Rules +### Phase 3 — Report -Supported LaunchDarkly clients come from `@launchdarkly/node-server-sdk` or legacy `launchdarkly-node-server-sdk` imports and require initialization through supported SDK patterns. +FlagLint generates stable fingerprints for each finding +(`launchdarkly:callType:flagKey:normalizedPath`) and produces: -Unrelated identifiers named `client`, `flag`, `feature`, `gate`, `init`, or `ldInit` are not treated as LaunchDarkly clients unless import provenance is proven. +- Structured inventory reports (`scan` — JSON, Markdown, HTML, SARIF) +- Reviewable migration diffs (`migrate --dry-run`) +- Guarded source edits (`migrate --apply`) +- Policy enforcement reports (`validate` — text, SARIF) +- Baseline files for tracking new findings over time -## Output Types +## What FlagLint does not do -- Inventory reports from `scan`. -- Reviewable migration diffs from `migrate --dry-run`. -- Guarded source edits from `migrate --apply`. -- Policy reports and SARIF from `validate`. +- Execute application code or make network calls +- Evaluate flag values at runtime +- Modify files without `migrate --apply` being explicitly passed +- Detect usage of browser SDKs (`launchdarkly-js-client-sdk`) — only the Node.js server SDKs ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/concepts/how-flaglint-works.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/concepts/how-flaglint-works.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [Safety Model](/docs/concepts/safety-model/) diff --git a/src/content/docs/docs/concepts/openfeature-boundary.md b/src/content/docs/docs/concepts/openfeature-boundary.md index 902ca7c..8d750dd 100644 --- a/src/content/docs/docs/concepts/openfeature-boundary.md +++ b/src/content/docs/docs/concepts/openfeature-boundary.md @@ -35,6 +35,6 @@ Once application code evaluates through OpenFeature, teams can enforce a single ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/concepts/openfeature-boundary.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/concepts/openfeature-boundary.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [Source-Level Debt Signals](/docs/concepts/source-level-debt-signals/) diff --git a/src/content/docs/docs/concepts/safety-model.md b/src/content/docs/docs/concepts/safety-model.md index 2a5b2d8..2602cb1 100644 --- a/src/content/docs/docs/concepts/safety-model.md +++ b/src/content/docs/docs/concepts/safety-model.md @@ -108,6 +108,6 @@ Generated diffs are reviewable migration assistance, not a guarantee of producti ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/concepts/safety-model.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/concepts/safety-model.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [OpenFeature Boundary](/docs/concepts/openfeature-boundary/) diff --git a/src/content/docs/docs/concepts/source-level-debt-signals.md b/src/content/docs/docs/concepts/source-level-debt-signals.md index 8a59b9c..a02c4da 100644 --- a/src/content/docs/docs/concepts/source-level-debt-signals.md +++ b/src/content/docs/docs/concepts/source-level-debt-signals.md @@ -25,6 +25,6 @@ The default `minFileCount` is `0`, so a legitimate one-file flag is not marked s ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/concepts/source-level-debt-signals.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/concepts/source-level-debt-signals.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [scan CLI](/docs/cli/scan/) diff --git a/src/content/docs/docs/enterprise-demo.md b/src/content/docs/docs/enterprise-demo.md index f2dc4fb..d46f47a 100644 --- a/src/content/docs/docs/enterprise-demo.md +++ b/src/content/docs/docs/enterprise-demo.md @@ -74,6 +74,6 @@ npx flaglint validate ./src --no-direct-launchdarkly ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/enterprise-demo.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/enterprise-demo.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [Migrate a Node Service](/docs/tutorials/migrate-a-node-service/) diff --git a/src/content/docs/docs/guides/express.md b/src/content/docs/docs/guides/express.md index 2ff5f80..6063da4 100644 --- a/src/content/docs/docs/guides/express.md +++ b/src/content/docs/docs/guides/express.md @@ -113,4 +113,4 @@ const value = await ldClient.boolVariation(getFlagKey(user), ctx, false); FlagLint reports this as high-risk and skips it. Replace with a static key or use a wrapper that evaluates per known key. -[Edit this page](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/guides/express.md) · [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) · Next: [NestJS Guide](/docs/guides/nestjs/) +[Edit this page](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/guides/express.md) · [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) · Next: [NestJS Guide](/docs/guides/nestjs/) diff --git a/src/content/docs/docs/guides/manual-review-patterns.md b/src/content/docs/docs/guides/manual-review-patterns.md index a9ac76c..c786d57 100644 --- a/src/content/docs/docs/guides/manual-review-patterns.md +++ b/src/content/docs/docs/guides/manual-review-patterns.md @@ -36,6 +36,6 @@ Generic `variation(...)` calls are automatable only when the fallback literal pr ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/guides/manual-review-patterns.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/guides/manual-review-patterns.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [Troubleshooting](/docs/guides/troubleshooting/) diff --git a/src/content/docs/docs/guides/monorepos.md b/src/content/docs/docs/guides/monorepos.md index a3315ce..bd0ba9b 100644 --- a/src/content/docs/docs/guides/monorepos.md +++ b/src/content/docs/docs/guides/monorepos.md @@ -107,4 +107,4 @@ steps: Browser SDKs, React SDKs, and non-Node packages in the monorepo are not detected. Run FlagLint only against Node.js server-side source directories. Non-Node packages will show zero results, not errors. -[Edit this page](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/guides/monorepos.md) · [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) · Next: [Manual Review Patterns](/docs/guides/manual-review-patterns/) +[Edit this page](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/guides/monorepos.md) · [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) · Next: [Manual Review Patterns](/docs/guides/manual-review-patterns/) diff --git a/src/content/docs/docs/guides/nestjs.md b/src/content/docs/docs/guides/nestjs.md index a3bf2a4..3a6edc8 100644 --- a/src/content/docs/docs/guides/nestjs.md +++ b/src/content/docs/docs/guides/nestjs.md @@ -119,4 +119,4 @@ If your team uses a shared evaluation wrapper that accepts dynamic flag keys, co Wrappers are reported but never auto-rewritten. -[Edit this page](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/guides/nestjs.md) · [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) · Next: [Monorepos](/docs/guides/monorepos/) +[Edit this page](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/guides/nestjs.md) · [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) · Next: [Monorepos](/docs/guides/monorepos/) diff --git a/src/content/docs/docs/guides/troubleshooting.md b/src/content/docs/docs/guides/troubleshooting.md index 7935626..8fcf1f4 100644 --- a/src/content/docs/docs/guides/troubleshooting.md +++ b/src/content/docs/docs/guides/troubleshooting.md @@ -1,32 +1,134 @@ --- title: Troubleshooting -description: Common FlagLint setup and migration issues. -lastUpdated: 2026-05-28 +description: Common FlagLint setup and migration issues — 0 flags detected, config not found, React SDK, apply skipping files, and CI failures. +lastUpdated: 2026-07-01 --- -## No LaunchDarkly Usage Detected +## No LaunchDarkly SDK usage detected -Confirm the code uses one of the supported Node.js server SDK packages: +FlagLint scans but reports 0 flag usages. -- `@launchdarkly/node-server-sdk` +**Most common causes:** + +**Wrong directory.** FlagLint scans the directory you pass (defaulting to `.`). If your SDK usage +is under `./src`, run: +```bash +npx flaglint@latest scan ./src +``` + +**SDK import not recognized.** FlagLint only detects Node.js server SDK imports: - `launchdarkly-node-server-sdk` +- `@launchdarkly/node-server-sdk` + +To verify files are being scanned at all, check `scannedFiles` in JSON output: +```bash +npx flaglint@latest scan ./src --format json | jq '.scannedFiles' +``` +If `0`, your `include` patterns aren't matching. Check your `flaglint.config.json`. + +**Using a custom wrapper.** If your team wraps the LD SDK in a shared utility, FlagLint won't +detect the wrapper calls unless you declare them. Add to your config: +```json +{ "wrappers": ["myGetFlag", "evaluateFeature"] } +``` + +--- + +## Config file not found + +FlagLint runs with defaults even though you have a config file. + +FlagLint searches for `.flaglintrc`, `.flaglintrc.json`, and `flaglint.config.json` in the +**current working directory** (first match wins). If you run from a different directory than +where your config file lives, it won't be found. + +**Fix:** Use `-c` to pin the config path explicitly: +```bash +npx flaglint@latest scan ./src -c ./path/to/flaglint.config.json +``` +Or always run FlagLint from the project root where your config file lives. + +--- + +## React SDK patterns not auto-migrated + +FlagLint detects React SDK hooks (`useFlags`, `useLDClient`, `useVariation`) in `scan` output, +but `flaglint migrate --apply` doesn't transform them. + +This is intentional. React SDK → OpenFeature React SDK migration requires changes to component +trees, context providers, and hook call sites that involve UI judgment calls FlagLint cannot +safely automate. Auto-migration is scoped to the Node.js server SDK only. + +React SDK usages appear in the inventory and migration plan as **manual review items**. Use +the plan as a checklist and migrate those call sites by hand. + +--- + +## `--apply` shows 0 transformed files + +`flaglint migrate --apply` runs but reports "0 call-sites transformed" or "0 file(s) affected." + +The migrator only transforms calls where it can identify the OpenFeature client to substitute. +If `openFeatureClientBindings` is not configured, it cannot generate the replacement call and +skips those files. + +**Fix:** Add your OpenFeature client variable name to `flaglint.config.json`: +```json +{ + "openFeatureClientBindings": ["openFeatureClient"] +} +``` -Browser SDKs, React SDKs, non-Node SDKs, and non-LaunchDarkly providers are outside current detection coverage. +Run `flaglint migrate --dry-run` first to preview what would be transformed. + +--- ## `--apply` Skips Files -`--apply` needs a proven OpenFeature client binding. Add a local `OpenFeature.getClient()` binding or configure imported shared clients with `openFeatureClientBindings`. +`migrate --apply` requires a proven OpenFeature client binding per file. Add a local +`OpenFeature.getClient()` binding or configure imported shared clients with +`openFeatureClientBindings` in your config. Files without a resolvable binding are listed in +the "skipped" output with the reason. + +--- ## Dirty Working Tree -`migrate --apply` refuses to edit a dirty git working tree by default. Commit, stash, use a temporary copy, or pass `--allow-dirty` only when you intentionally accept the risk. +`migrate --apply` refuses to edit a dirty git working tree by default. Commit or stash your +changes first, or pass `--allow-dirty` only when you intentionally accept the risk of applying +on uncommitted work. -## CI Validation Fails +--- -Use `validate --no-direct-launchdarkly` only after the relevant source path has migrated. Provider/bootstrap files can be excluded with `--bootstrap-exclude`. +## validate passes locally but fails in CI + +`flaglint validate` exits 0 locally but exits 1 in CI with the same code. + +**Likely cause:** Different working directories or config files. CI may run from the repo root +while local runs from a subdirectory, picking up different configs or different `include` patterns +that match different files. + +**Fix:** Pin the directory and config explicitly in both environments: +```bash +npx flaglint@latest validate ./src --no-direct-launchdarkly -c ./flaglint.config.json +``` + +--- + +## CI Validation Fails After Partial Migration + +Use `validate --no-direct-launchdarkly` only after the relevant source path has migrated. +Provider and bootstrap files that legitimately call the LD SDK directly can be excluded: +```bash +npx flaglint@latest validate ./src --no-direct-launchdarkly \ + --bootstrap-exclude "src/provider/**" \ + --bootstrap-exclude "src/bootstrap/ld-init.ts" +``` + +--- ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/guides/troubleshooting.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/guides/troubleshooting.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [OpenFeature Provider](/docs/integrations/openfeature-provider/) diff --git a/src/content/docs/docs/index.md b/src/content/docs/docs/index.md index dc8346b..b0b6c99 100644 --- a/src/content/docs/docs/index.md +++ b/src/content/docs/docs/index.md @@ -58,10 +58,10 @@ No API key. No source upload. Runs locally against your checkout. LaunchDarkly s - It does not replace LaunchDarkly. LaunchDarkly remains the provider. - It does not generate provider/bootstrap files automatically. - It does not query LaunchDarkly for flag age, owner, evaluation history, environment configuration, or production usage. -- It does not detect browser SDKs, React SDKs, non-Node SDKs, or non-LaunchDarkly providers. +- It does not detect browser SDKs (`launchdarkly-js-client-sdk`), non-Node SDKs, or non-LaunchDarkly providers. React SDK hooks, HOC, and provider are detected for manual review but not auto-migrated. ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/index.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/index.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [Quickstart](/docs/quickstart/) diff --git a/src/content/docs/docs/integrations/github-actions.md b/src/content/docs/docs/integrations/github-actions.md index 67cf68a..867d50c 100644 --- a/src/content/docs/docs/integrations/github-actions.md +++ b/src/content/docs/docs/integrations/github-actions.md @@ -26,6 +26,19 @@ This runs `flaglint validate ./src --no-direct-launchdarkly` and fails the job i | `command` | `validate` | FlagLint command: `validate`, `scan`, or `audit` | | `extra-args` | `""` | Additional CLI flags passed verbatim to flaglint | | `node-version` | `'20'` | Node.js version used by `actions/setup-node@v4` | +| `version` | `''` (latest) | Pin to a specific FlagLint release, e.g. `'1.1.0'`. Defaults to `@latest` when empty. | + +## Example: Pinning to a Specific Version + +```yaml +- uses: flaglint/flaglint-js@v1 + with: + version: '1.1.0' + command: validate + directory: ./src +``` + +Use `version` when you need reproducible CI output regardless of new FlagLint releases. ## Example: Blocking Enforcement @@ -89,7 +102,7 @@ flaglint.direct-launchdarkly ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/integrations/github-actions.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/integrations/github-actions.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - See also: [validate command](/docs/cli/validate/) - Next: [OpenTelemetry](/docs/integrations/opentelemetry/) diff --git a/src/content/docs/docs/integrations/openfeature-provider.md b/src/content/docs/docs/integrations/openfeature-provider.md index 29b3b60..c780e7a 100644 --- a/src/content/docs/docs/integrations/openfeature-provider.md +++ b/src/content/docs/docs/integrations/openfeature-provider.md @@ -68,6 +68,6 @@ Provider/bootstrap setup is not generated by FlagLint. ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/integrations/openfeature-provider.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/integrations/openfeature-provider.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [GitHub Actions](/docs/integrations/github-actions/) diff --git a/src/content/docs/docs/integrations/opentelemetry.md b/src/content/docs/docs/integrations/opentelemetry.md index 51965d5..f44c194 100644 --- a/src/content/docs/docs/integrations/opentelemetry.md +++ b/src/content/docs/docs/integrations/opentelemetry.md @@ -45,6 +45,6 @@ Prefer an approved variant identifier where available. Avoid exporting sensitive ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/integrations/opentelemetry.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/integrations/opentelemetry.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [Supported Scope](/docs/reference/supported-scope/) diff --git a/src/content/docs/docs/product-contract.md b/src/content/docs/docs/product-contract.md index e43cf43..b1246a8 100644 --- a/src/content/docs/docs/product-contract.md +++ b/src/content/docs/docs/product-contract.md @@ -57,6 +57,6 @@ If any version of FlagLint violates these promises, please open an issue on GitH ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/product-contract.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/product-contract.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [Security](/docs/trust/security/) diff --git a/src/content/docs/docs/quickstart.md b/src/content/docs/docs/quickstart.md index 1e132cb..7de5a02 100644 --- a/src/content/docs/docs/quickstart.md +++ b/src/content/docs/docs/quickstart.md @@ -9,14 +9,14 @@ lastUpdated: 2026-07-01 - Node.js 20 or newer. - A JavaScript or TypeScript project using LaunchDarkly Node.js server-side SDK evaluation calls from `@launchdarkly/node-server-sdk` or `launchdarkly-node-server-sdk`. -Browser SDKs, React SDKs, non-Node SDKs, and non-LaunchDarkly providers are outside current detection coverage. +Browser SDKs (`launchdarkly-js-client-sdk`), non-Node SDKs, and non-LaunchDarkly providers are outside auto-migration coverage. React SDK hooks, HOC, and provider are detected for manual review. ## 0. Scaffold a Config (Optional) If you don't have a `flaglint.config.json` yet, scaffold one with all fields set to their defaults: ```bash -npx flaglint init +npx flaglint@latest init ``` This writes `flaglint.config.json` to the current directory and prints a short explanation of every field to stderr. You can skip this step — FlagLint works with sensible defaults out of the box — but it's useful when you need to customize `include`/`exclude` patterns or configure `wrappers`. @@ -26,7 +26,7 @@ See the [`flaglint init` reference](/docs/cli/init/) and [Configuration referenc ## 1. Run an Audit ```bash -npx flaglint audit ./src +npx flaglint@latest audit ./src ``` The enterprise checkout demo in this repository contains this real TypeScript call site: @@ -72,7 +72,7 @@ The audit gives engineers a risk-ranked overview before any migration work: Use `scan` when you need file-level structured inventory for automation or deeper review: ```bash -npx flaglint scan ./src +npx flaglint@latest scan ./src ``` Generated from the same demo: @@ -99,7 +99,7 @@ The Markdown report inventory includes the detected static and manual-review cal ## 3. Preview Migration ```bash frame="none" -npx flaglint migrate ./src --dry-run +npx flaglint@latest migrate ./src --dry-run ``` Generated from the same demo: @@ -159,7 +159,7 @@ Next: [add the LaunchDarkly OpenFeature provider](/docs/tutorials/add-openfeatur After provider setup and review, apply proven rewrites on a branch: ```bash frame="none" -npx flaglint migrate ./src --apply +npx flaglint@latest migrate ./src --apply ``` ## 7. Enforce in CI @@ -167,7 +167,7 @@ npx flaglint migrate ./src --apply After migration, block new direct LaunchDarkly evaluation calls: ```bash frame="none" -npx flaglint validate ./src --no-direct-launchdarkly +npx flaglint@latest validate ./src --no-direct-launchdarkly ``` Completed-state demo output: @@ -182,4 +182,4 @@ Completed-state demo output: **Further reading:** [LaunchDarkly-to-OpenFeature Node.js migration guide](/docs/guides/launchdarkly-to-openfeature-nodejs/) · [Why migrations break in production](/blog/launchdarkly-openfeature-argument-order-bug/) · [Vendor-neutral abstraction without a full migration](/blog/after-launchdarkly-outage-vendor-neutral-abstraction/) -[Edit this page](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/quickstart.md) · [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) · Next: [Why FlagLint](/docs/why-flaglint/) +[Edit this page](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/quickstart.md) · [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) · Next: [Why FlagLint](/docs/why-flaglint/) diff --git a/src/content/docs/docs/reference/changelog.md b/src/content/docs/docs/reference/changelog.md index 99eba5d..180bbe3 100644 --- a/src/content/docs/docs/reference/changelog.md +++ b/src/content/docs/docs/reference/changelog.md @@ -222,5 +222,5 @@ v1.0.0 is the CI-readiness release. The core scanner and migrator are stable. Th ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/reference/changelog.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/reference/changelog.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) diff --git a/src/content/docs/docs/reference/exit-codes.md b/src/content/docs/docs/reference/exit-codes.md deleted file mode 100644 index 0340242..0000000 --- a/src/content/docs/docs/reference/exit-codes.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: Exit Codes -description: Stable exit code contract for FlagLint v1.x — use these codes in CI to distinguish policy failures from tool errors. -lastUpdated: 2026-06-22 ---- - -FlagLint follows a stable, machine-readable exit code contract. These codes are -guaranteed stable across v1.x and are safe to use in CI pipelines. - -## Exit Code Table - -| Code | Meaning | When it occurs | -|------|---------|----------------| -| `0` | Success — no blocking failures | Scan completed; no policy violations found; no stale flags detected (or stale flags found but no policy gate triggered) | -| `1` | Policy or validation failure | `flaglint validate --no-direct-launchdarkly` found direct LD calls; stale flags detected by `flaglint scan`; directory not found | -| `2` | Invalid input | Bad `--format` value; missing or malformed baseline; bad or unparseable config file (`.flaglintrc`) | -| `3` | Internal FlagLint error | Unexpected runtime exception in FlagLint itself; not expected in normal use | - -**SIGINT (Ctrl-C):** FlagLint exits with code `130` when interrupted. - -## Why exit 1 does not mean the tool crashed - -Exit code `1` means **FlagLint ran successfully and found a policy violation** — not -that the tool failed. This distinction matters in CI logs: - -- `exit 1` → FlagLint worked correctly; your code has a flag debt issue to fix. -- `exit 2` → You passed a bad argument; fix the command invocation. -- `exit 3` → FlagLint itself hit an unexpected error; please file a bug report. - -This matches the POSIX convention used by linters such as ESLint (exit 1 = lint -errors found) and allows CI steps to distinguish tool failure from policy failure -without parsing stdout. - -## CI YAML example - -The following GitHub Actions workflow runs `flaglint validate` as a policy gate. -It expects exit 0 (clean) or exit 1 (violations found), and treats any other exit -code as a tool misconfiguration or internal error. - -```yaml -name: FlagLint Policy Gate - -on: - pull_request: - push: - branches: [main] - -jobs: - flaglint-validate: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-node@v4 - with: - node-version: "20" - - - name: Install FlagLint - run: npm install -g flaglint - - # Exit 0 → no direct LD calls (clean). - # Exit 1 → direct LD calls found (policy violation — fail the build). - # Exit 2 → bad --format or config error (fix the workflow invocation). - - name: Validate no direct LaunchDarkly calls - run: flaglint validate ./src --no-direct-launchdarkly - - # Optional: emit SARIF for GitHub Code Scanning annotations - - name: Validate (SARIF output) - if: always() - run: flaglint validate ./src --no-direct-launchdarkly --format sarif --output flaglint.sarif - continue-on-error: true - - - name: Upload SARIF to GitHub Code Scanning - if: always() - uses: github/codeql-action/upload-sarif@v3 - with: - sarif_file: flaglint.sarif -``` - -See the [GitHub Actions integration guide](/docs/integrations/github-actions/) and -the [`validate` command reference](/docs/cli/validate/) for the full set of options -including `--bootstrap-exclude` for allowing provider setup files. - -## Feedback - -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/reference/exit-codes.md) -- [Report an issue](https://github.com/flaglint/flaglint/issues/new) -- Next: [FAQ](/docs/reference/faq/) diff --git a/src/content/docs/docs/reference/faq.md b/src/content/docs/docs/reference/faq.md index a90ad49..c5ac9d9 100644 --- a/src/content/docs/docs/reference/faq.md +++ b/src/content/docs/docs/reference/faq.md @@ -96,6 +96,6 @@ Node.js 20 or newer. FlagLint uses ESM and requires Node.js 20+. ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/reference/faq.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/reference/faq.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [Changelog](/docs/reference/changelog/) diff --git a/src/content/docs/docs/reference/limitations.md b/src/content/docs/docs/reference/limitations.md index de4d568..b09c973 100644 --- a/src/content/docs/docs/reference/limitations.md +++ b/src/content/docs/docs/reference/limitations.md @@ -8,8 +8,8 @@ FlagLint is intentionally narrow. ## Outside Detection Coverage -- Browser SDKs. -- React SDKs, hooks, and HOCs. +- Browser SDKs (`launchdarkly-js-client-sdk`). +- React SDK patterns (hooks, HOC, provider) are detected for manual review but are outside auto-migration scope — the migrator only transforms Node server SDK calls. - Non-Node SDKs. - Non-LaunchDarkly providers. - Runtime-only flag key construction that cannot be resolved statically. @@ -24,6 +24,6 @@ FlagLint does not insert provider setup files or remove LaunchDarkly dependencie ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/reference/limitations.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/reference/limitations.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [Security](/docs/reference/security/) diff --git a/src/content/docs/docs/reference/supported-scope.md b/src/content/docs/docs/reference/supported-scope.md index c845dc3..f905014 100644 --- a/src/content/docs/docs/reference/supported-scope.md +++ b/src/content/docs/docs/reference/supported-scope.md @@ -77,6 +77,6 @@ React SDK patterns are reported for manual review and are not auto-migrated. The ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/reference/supported-scope.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/reference/supported-scope.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [Limitations](/docs/reference/limitations/) diff --git a/src/content/docs/docs/trust/security.md b/src/content/docs/docs/trust/security.md index 7dee5d5..5baf818 100644 --- a/src/content/docs/docs/trust/security.md +++ b/src/content/docs/docs/trust/security.md @@ -36,5 +36,5 @@ FlagLint collects no telemetry. The CLI does not phone home. See [Privacy](/docs ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/trust/security.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/trust/security.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) diff --git a/src/content/docs/docs/tutorials/add-openfeature-provider.md b/src/content/docs/docs/tutorials/add-openfeature-provider.md index f772c08..a6028c5 100644 --- a/src/content/docs/docs/tutorials/add-openfeature-provider.md +++ b/src/content/docs/docs/tutorials/add-openfeature-provider.md @@ -47,6 +47,6 @@ For TypeScript ESM projects, configured module patterns without `.js` also recog ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/tutorials/add-openfeature-provider.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/tutorials/add-openfeature-provider.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [Enforce in GitHub Actions](/docs/tutorials/enforce-in-github-actions/) diff --git a/src/content/docs/docs/tutorials/enforce-in-github-actions.md b/src/content/docs/docs/tutorials/enforce-in-github-actions.md index 0838d5f..ff454ec 100644 --- a/src/content/docs/docs/tutorials/enforce-in-github-actions.md +++ b/src/content/docs/docs/tutorials/enforce-in-github-actions.md @@ -48,6 +48,6 @@ SARIF findings use rule id `flaglint.direct-launchdarkly`. ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/tutorials/enforce-in-github-actions.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/tutorials/enforce-in-github-actions.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [Shared Client Architecture](/docs/tutorials/shared-client-architecture/) diff --git a/src/content/docs/docs/tutorials/migrate-a-node-service.md b/src/content/docs/docs/tutorials/migrate-a-node-service.md index de17403..fc6a7e6 100644 --- a/src/content/docs/docs/tutorials/migrate-a-node-service.md +++ b/src/content/docs/docs/tutorials/migrate-a-node-service.md @@ -78,6 +78,6 @@ Generated output: ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/tutorials/migrate-a-node-service.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/tutorials/migrate-a-node-service.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [Add OpenFeature Provider](/docs/tutorials/add-openfeature-provider/) diff --git a/src/content/docs/docs/tutorials/shared-client-architecture.md b/src/content/docs/docs/tutorials/shared-client-architecture.md index d0fdbe0..1a84f77 100644 --- a/src/content/docs/docs/tutorials/shared-client-architecture.md +++ b/src/content/docs/docs/tutorials/shared-client-architecture.md @@ -48,6 +48,6 @@ Ambiguous or unconfigured bindings are skipped. FlagLint does not guess that an ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/tutorials/shared-client-architecture.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/tutorials/shared-client-architecture.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [How FlagLint Works](/docs/concepts/how-flaglint-works/) diff --git a/src/content/docs/docs/why-flaglint.md b/src/content/docs/docs/why-flaglint.md index 63d4c71..2724a13 100644 --- a/src/content/docs/docs/why-flaglint.md +++ b/src/content/docs/docs/why-flaglint.md @@ -93,6 +93,6 @@ Before you do — read [what FlagLint commits to you, in writing →](/docs/prod ## Feedback -- [Edit this page on GitHub](https://github.com/flaglint/flaglint/edit/main/docs-src/content/docs/docs/why-flaglint.md) +- [Edit this page on GitHub](https://github.com/flaglint/flaglint.dev/edit/main/src/content/docs/docs/why-flaglint.md) - [Report an unsupported pattern](https://github.com/flaglint/flaglint/issues/new?template=unsupported_pattern.yml) - Next: [Enterprise Demo](/docs/enterprise-demo/)