MetaMask / MetaMask/metamask-extension

[Epic] `ui/helpers/utils/util.js` decomposition (relocate helpers by subject)

Open
#44,552 1 comment 0 reactions 0 assignees View on GitHub
for-migration INVALID-ISSUE-TEMPLATE mig-epic-55-child mig-epic-70 ta-triaged team-extension-platform
Dominant language
TypeScript
Stars
13.2k
Forks
5.6k
Avg merge
2d 5h
Merged PRs (30d)
451

Description

**Parent Epic:** [MetaMask-planning#5284 — [EPIC|P2] Typescript](https://github.com/MetaMask/MetaMask-planning/issues/5284) → area sub-epic [#7383 — TypeScript conversion of `ui/contexts`, `ui/helpers`, `ui/selectors`, `ui/ducks`, `ui/hooks`](https://github.com/MetaMask/metamask-extension/issues/7383)
**Labels:** `Epic`, `team-extension-platform`

---

## 🎯 Goal

Empty and delete `ui/helpers/utils/util.js` (1,021 lines, 54 exports) by **relocating each helper to its domain-appropriate module** — improving modularity, maintainability, and reviewability, and unblocking incremental JS→TS migration (most helpers land in modules that are already TypeScript). Decompose by subject; this is relocation, not arbitrary splitting.

## Motivation

`util.js` is a grab-bag catch-all: address display, ENS/URL parsing, chain/contract helpers, date formatting, snap helpers, account/keyring predicates, and dead code all share one file with no unifying subject. It is imported by **140 files**, so it is a hub whose churn touches the whole app, and it cannot be converted to TypeScript coherently in one pass. Moving each helper to a module that already owns its subject (most already `.ts`) shrinks the hub, advances those modules' own migrations, and — because several helpers are near-duplicates of existing ones — removes duplication (`getAssetImageURL`↔`asset-utils`, `getURL`↔`getValidUrl`, `sanitizeMessage`↔`sanitizeMessageRecursively`). Applies the #41735 decomposition model to a utils hub.

## Context

- `ui/helpers/utils/util.js` — 1,021 lines, 54 exports + 8 private helpers.
- **Blast radius: 140 importing files** across `ui/`, `shared/`, `app/`. **Three are namespace imports** (`import * as util`) that any import-rewrite codemod must special-case (two `dapp-swap-comparison` hook tests + one `confirm-add-suggested-nft` test).
- **Size is dominated by import-rewrite fan-out, not LOC** — the code per helper is tiny; the cost is rewiring call sites. High-fan-out relocations (`shortenAddress` 50, `getAccountByAddress` 21, `getSnapName` 20, the `getURL*` cluster) warrant a `jscodeshift`/`ts-morph` codemod, not manual edits.

## Scope

Each ticket is self-contained: move the helper(s) to the target module, move/keep their tests, codemod the import sites, delete the originals. Ordered lowest-fan-out / clearest-home first; the high-fan-out moves and the file deletion come last.

| Order | Ticket | Target | Size | Pri |
|---|---|---|---|---|
| 1 | Delete dead / test-only exports (10) | — | S | P1 |
| 2 | Numeric + typed-data helpers | `conversion.utils`/`number-utils`/`typed-signature` | S | P2 |
| 3 | Browser + clipboard | `browser-runtime.utils` / ui `browser.ts` | S | P2 |
| 4 | Token / contract / price | `token-util` | M | P2 |
| 5 | Asset image (+ dedupe) | `asset-utils` | M | P2 |
| 6 | String helpers | `string-utils` | M | P2 |
| 7 | Date / time formatters | new `ui/helpers/utils/date.ts` | M | P2 |
| 8 | URL / origin (+ dedupe) | `url-utils` | L | P1 |
| 9 | Snap helpers | `shared/lib/snaps` / ui `snaps.ts` | L | P2 |
| 10 | Account / keyring | `shared/lib/accounts` | L | P1 |
| 11 | Address display (`shortenAddress`) | new `ui/helpers/utils/address.ts` | XL | P1 |
| 12 | Close out: replace `isNullish`, inline `valuesFor`, delete `util.js` + test | — | S | P1 |

**Order rationale:** dead-code deletion first (zero rewrites, shrinks the file); low-fan-out moves to existing homes next; `shortenString` moves before the address group so `shortenAddress` can re-point; the three highest-fan-out moves (URL, account, address) are codemod-driven and land late; the file is deleted only once empty.

## ✅ Success Criteria

- All 54 exports relocated to subject-appropriate modules (existing where one owns the subject; new `date.ts`/`address.ts` only where none exists); near-duplicates reconciled.
- Import sites codemod-rewritten (incl. the 3 namespace-import tests); no behavior change.
- `ui/helpers/utils/util.js` and `util.test.js` **deleted** — the file does not survive as a near-empty catch-all.
- Tests pass; no new Sentry signatures.

Contributor guide

Open the contributing guide

Research direction

Start with ui/helpers/utils/util.js and ui/helpers/utils/util.test.js, then inspect their 140 importing files and the ticket order in this issue. Begin with the dead or test-only exports, run the relevant utility tests, and proceed through the listed relocations; done means all exports and imports are moved, tests pass, and util.js plus util.test.js are deleted.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, typescript
Domain
frontend, tooling
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.