Skip to content

refactor: convert claycli to TypeScript (Phase 4)#238

Open
tkstang wants to merge 38 commits intoyolo-updatefrom
typescript-conversion
Open

refactor: convert claycli to TypeScript (Phase 4)#238
tkstang wants to merge 38 commits intoyolo-updatefrom
typescript-conversion

Conversation

@tkstang
Copy link

@tkstang tkstang commented Feb 26, 2026

PR: Progress — claycli modernization (Phase 4: TypeScript Conversion)

What

Converted the entire claycli codebase from JavaScript to TypeScript with strict mode. All source files are now .ts (except setup-jest.js and eslint.config.js). TypeScript compiles to CommonJS via tsc, with declarations and source maps. The npm package ships compiled JS from dist/. Review fixes addressed deprecated APIs, unused dependencies, type safety gaps, and build config cleanup.

Why

TypeScript conversion completes the modernization plan by adding static type safety, enabling IDE-driven refactoring, and producing .d.ts declarations for downstream consumers. This builds on the Node 20+ / Webpack 5 / async-await foundation established in Phases 0–3.

Scope

  • Project: .oat/projects/shared/claycli-modernization
  • Phase: p04 (TypeScript Conversion)
  • Tasks: 9 base tasks + 9 review fix tasks = 18 tasks total
  • Commits: 30
  • Base: yolo-update (Phases 0–3)

Base tasks (p04-t01 through p04-t09)

  • TypeScript infrastructure: typescript, ts-jest, typescript-eslint, strict tsconfig.json
  • Leaf modules converted: types, deep-reduce, config-file-helpers, composer
  • Utility modules converted: prefixes, compilation-helpers, formatting, 5 reporters
  • Core modules converted: rest, config, lint, export, import
  • Compile/pack modules converted: 14 files including scripts.ts (726 LOC)
  • CLI entry points converted: 8 files (cli-options, config, export, import, lint, log, pack, index)
  • Build config: tsconfig.build.json, entry points → dist/, npm run build / npm run type-check
  • AGENTS.md updated with TypeScript conventions
  • Integration checkpoint 3: nymag/sites compiled successfully (625 files, 4046 registry entries)

Review fix tasks (p04-t10 through p04-t18)

  • p04-t10: Convert cli/compile/*.js to TypeScript (7 remaining files)
  • p04-t11: Replace deprecated new Buffer() with Buffer.from() (5 instances)
  • p04-t12: Remove 3 unused production dependencies (dependency-tree, exports-loader, imports-loader)
  • p04-t13: Add proper types to getDependencies() API contract (hard contract with nymag/sites)
  • p04-t14: Replace deprecated nodeUrl.parse() with new URL() (4 instances)
  • p04-t15: Add FetchOptions interface to eliminate as RequestInit assertions
  • p04-t16: Clean up tsconfig.build.json include/exclude contradiction
  • p04-t17: Remove unused path-browserify dependency
  • p04-t18: Fix WHATWG URL migration for schemeless CLI inputs (safeParseUrl helper)

Commits

  • 76f27dd chore(p04-t01): set up TypeScript infrastructure
  • faf498a refactor(p04-t02): convert leaf modules to TypeScript
  • a781064 refactor(p04-t03): convert utility modules to TypeScript
  • f1e3d9b refactor(p04-t04): convert core modules to TypeScript
  • 7edc0da refactor(p04-t05): convert compile and pack modules to TypeScript
  • cff9783 refactor(p04-t06): convert CLI entry points to TypeScript
  • 66b35e6 chore(p04-t07): configure TypeScript build for npm publishing
  • f60db1e docs(p04-t08): update AGENTS.md for TypeScript codebase
  • 77d372f fix(p04-t09): fix resolveLoader paths for dist/ execution
  • 6918c38 refactor(p04-t10): convert cli/compile files to TypeScript
  • 8896d86 fix(p04-t11): replace deprecated new Buffer() with Buffer.from()
  • 0040032 chore(p04-t12): remove unused production dependencies
  • 7e9c825 refactor(p04-t13): add proper types to getDependencies API contract
  • f4cb5e4 fix(p04-t14): replace deprecated nodeUrl.parse with new URL()
  • a2013d7 fix(p04-t15): replace RequestInit type assertion with proper FetchOptions type
  • 5f25e00 fix(p04-t16): clean up tsconfig.build.json include/exclude
  • 1dc132c chore(p04-t17): remove unused path-browserify dependency
  • bbf4bab fix(p04-t18): handle schemeless URLs in prefixes urlToUri/getExt
  • 5ad2b0b fix: restore stream detection in import.ts after rebase
  • Plus OAT artifact commits

Validation

  • Tests: 384 passing (Jest 29 + ts-jest)
  • Lint: ESLint 9 flat config with typescript-eslint — clean
  • Types: tsc --noEmit (strict mode) — clean
  • Build: tsc -p tsconfig.build.json — 191 files in dist/
  • Integration: nymag/sites checkpoint 3 — 625 files compiled, 4571 JS outputs, 4046 registry entries (matches checkpoints 1 and 2)
  • Review: p04 code review completed, 1 Important finding fixed (p04-t18), status fixes_completed (re-review pending)

References

Note: Spec-driven requirements/design artifacts are absent — this project used import workflow mode with an imported plan.

Add typescript, @types/node, ts-jest, and typescript-eslint as
devDependencies. Create tsconfig.json with strict settings and
noEmit for type checking. Configure Jest transform for .ts files
via ts-jest. Add TypeScript-aware ESLint config block for .ts files
with @typescript-eslint/no-unused-vars replacing the base rule.
Convert four leaf modules (no internal dependencies) from JS to TS:
- lib/types.ts: readonly string array of Clay data types
- lib/deep-reduce.ts: recursive component tree reducer with typed fn callback
- lib/config-file-helpers.ts: config file reader with typed ConfigFile
- lib/composer.ts: component normalize/denormalize with Bootstrap/ComponentRef interfaces

Add @types/lodash for lodash type definitions. All modules use typed
function signatures while keeping require() for untyped external deps.
Convert utility modules with typed function signatures:
- lib/prefixes.ts: prefix add/remove with typed dispatch and string params
- lib/compilation-helpers.ts: bucket, time, watcher with BrowserslistConfig
- lib/formatting.ts: toDispatch/toBootstrap with Dispatch, Page, User interfaces
- lib/reporters/*.ts: all 5 reporter modules with Action/Summary interfaces

Uses import from 'lodash' for typed lodash calls, require() for untyped
external deps (chalk, clay-log, terminal-logger, etc).
Convert rest, config, lint, export, import modules from JS to TS with
full type annotations. Add caughtErrorsIgnorePattern to TS eslint rule
for underscore-prefixed catch variables.
Rename all .js files in lib/cmd/compile/ and lib/cmd/pack/ to .ts
(except _client-init.js which is a client-side script read by gulp).
Add explicit type annotations for function parameters and callback
args. Install @types/jest for test file type checking. Update
eslint.config.js browser globals glob for renamed file. Add export {}
to test files so TypeScript treats them as modules.
Rename cli/*.js to .ts (except cli/index.js which is the bin entry
point with shebang). Convert module.exports to export =, remove
'use strict', add type annotations to function params and callbacks.
Keep cli/index.js and index.js as .js — they are package entry points
that need a build step (p04-t07) before they can be converted.
Add tsconfig.build.json for compilation to dist/, update package.json
entry points (main, types, bin) to point to dist/, add build/type-check
scripts, and add dist/ to .gitignore. The published package now ships
compiled JS with declaration files and source maps.
Document TypeScript conventions (export =, const require, tsconfig split),
update tech stack (TypeScript 5, ts-jest, typescript-eslint), update file
extensions (.ts), add build/type-check to commands and definition of done.
…kage.json copy to build

Integration test revealed two issues when running from dist/:
1. resolveLoader only had 3-level __dirname traversal (works from source but not
   dist/lib/cmd/compile/). Added 4-level path for dist/ execution.
2. cli/index.ts requires ../package.json which resolves to dist/package.json
   when running from dist/. Added cp package.json dist/ to build script.

Integration checkpoint 3 passes: 625 files compiled, 4571 JS outputs,
4046 registry entries (matches checkpoints 1 and 2).
All 5 phases complete. 3 integration checkpoints passed.
Awaiting final review before PR.
Final review: 0 critical, 3 important, 5 medium, 6 minor.
Converted 8 findings to fix tasks (p04-t10 through p04-t17).
Deferred 2 with rationale: Highland retention (M1), babel-plugin-lodash warning (m4).
4 minor findings are non-issues requiring no action.
Remove dependency-tree, exports-loader, and imports-loader — none are
imported anywhere in the codebase.
Replace any types with proper TypeScript types for the hard API contract
with nymag/sites. Add GetDependenciesOptions interface, type all public
and internal functions with string/boolean/Record types.
Migrate 4 occurrences of the deprecated url.parse() API to the modern
WHATWG URL API (new URL()). Remove unused nodeUrl imports from both files.
…ions type

Add FetchOptions interface extending RequestInit with optional agent
property (supported by Node's undici fetch). Remove all 5 'as RequestInit'
assertions from callers.
Remove setup-jest.js from both include and exclude arrays in the build
config. It was confusing to have it in both. The base tsconfig.json
retains it for type-checking; the build config doesn't need it.
path-browserify was a leftover from the Browserify era. Webpack 5 uses
resolve.fallback with `path: false`, so the polyfill is never loaded.
All 8 review fix tasks (p04-t10 through p04-t17) completed.
48/48 tasks done. Reviews table updated to fixes_completed.
Awaiting final re-review before PR.
Re-review passed with 0 findings. All 48 tasks done.
Updated plan.md Reviews table to passed, state.md to complete,
implementation.md Final Summary with review fixes and deferred items.
The p03-t10 stream detection fix was lost when resolving rebase conflicts
between the p03 .js fixes and the p04 .ts conversion. Re-apply the check.
When rebasing typescript-conversion onto yolo-update, taking --theirs for
OAT artifacts dropped the p03 review entries. Restore:
- plan.md: p03-t09/t10/t11 task definitions, p03 review row, updated totals (51 tasks)
- implementation.md: review notes, fix task entries, progress table (11/11 p03)
- state.md: updated totals and last commit
…ndling

p04 review found 1 Important finding: WHATWG URL migration breaks
schemeless CLI inputs (domain.com/...). Added p04-t18 to fix
urlToUri/getExt with fallback base URL parsing.
Add safeParseUrl helper that prepends http:// for schemeless inputs like
domain.com/_pages/foo.html, restoring the behavior that url.parse()
provided before the WHATWG URL migration. Add 4 regression tests.
All p04 review fix tasks implemented. 52/52 tasks complete.
Awaiting p03/p04 re-reviews and final review before PR.
Restored mapConcurrent usage in export.ts, import.ts, lint.ts, and
cli/lint.ts that was lost during TypeScript conversion. Thread
concurrency through options objects to comply with max-params rule.
Add null guard for destFileStats in the extra-file comparison path.
Prevents TypeError on first-run builds when dest directory is missing
and options.extra is set.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant