Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 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
5 changes: 5 additions & 0 deletions .changeset/barrel-metric.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"debarrel": minor
---

Add `barrel-metric` event emitted per re-export in every barrel the codemod visits. Each event carries five cardinalities — `export_style`, `chaining`, `risk_amplifier`, `file`, and a derived `migration_complexity_score` (0–4) — so you can estimate migration effort before rolling the codemod out at scale.
19 changes: 19 additions & 0 deletions codemods/debarrel/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,25 @@ Pure barrel files (files that only re-export) are renamed to `index.barrel.bak.t
- Import-then-reexport patterns
- Mixed barrel files that contain their own declarations (only the re-exported imports are rewritten; the barrel is kept)

## Migration complexity metric

Alongside the rewrite, the codemod emits a `barrel-metric` event per re-export found in each barrel. Each event carries five cardinalities so you can estimate migration effort before rolling the codemod out at scale:

| Cardinality | Values |
| --- | --- |
| `export_style` | `explicit` \| `wildcard` |
| `chaining` | `single-level` \| `chained` |
| `risk_amplifier` | `none` \| `heavy-usage-or-public-api` \| `cycles-or-side-effects` |
| `file` | workspace-relative path of the affected barrel |
| `migration_complexity_score` | `0`–`4` (sum of the other dimensions) |

Scoring rules: `wildcard` adds 1, `chained` adds 1, `heavy-usage-or-public-api` adds 1, `cycles-or-side-effects` adds 2. Roughly: **0–1 = Low**, **2 = Medium**, **3–4 = High**.

Notes:

- `heavy-usage-or-public-api` fires only when the barrel matches the advertised entry point of its nearest `package.json` (`main`, `module`, `types`, or any leaf of `exports`). A random internal `index.ts` inside a repo is not flagged.
- `count` aggregates raw emission events, not unique re-export sites. Because every file in a barrel's directory emits the same metric tuple (a workaround for per-directory test snapshots), the value is inflated by directory density in proportion to the number of sibling files. To recover an approximate re-export count, divide `count` by the number of files in the barrel's directory.

## Usage

```bash
Expand Down
11 changes: 9 additions & 2 deletions codemods/debarrel/codemod.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
schema_version: "1.0"

name: "debarrel"
version: "0.5.0"
version: "0.6.0"
description: "Debarrel JS/TS codebases. Removing barrel files and replacing import statements."
author: "Mo Mohebifar <mo@codemod.com>"
license: "MIT"
Expand All @@ -11,7 +11,14 @@ repository: https://github.com/codemod/useful-codemods
targets:
languages: ["typescript"]

keywords: ["transformation", "migration"]
keywords:
[
"barrel-files",
"dependency-graph",
"build-performance",
"ci-performance",
"code-health",
]

registry:
access: "public"
Expand Down
3 changes: 3 additions & 0 deletions codemods/debarrel/scripts/codemod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ import {
rewriteMockCalls,
type BarrelMockInfo,
} from "./utils/mocks.ts";
import { emitMetricsForBarrelSibling } from "./utils/metrics.ts";

const codemod: Codemod<Language> = async (root) => {
const rootNode = root.root();
const filename = root.filename();
const edits: Edit[] = [];
const barrelRewrites = new Map<string, BarrelMockInfo>();

emitMetricsForBarrelSibling(filename);

for (const importStmt of rootNode.findAll({
rule: { kind: "import_statement" },
})) {
Expand Down
Loading
Loading