Skip to content

feat: Complete TypeScript migration of all source files#535

Draft
kvz wants to merge 174 commits intomainfrom
feat/typescript-migration
Draft

feat: Complete TypeScript migration of all source files#535
kvz wants to merge 174 commits intomainfrom
feat/typescript-migration

Conversation

@kvz
Copy link
Collaborator

@kvz kvz commented Feb 16, 2026

Kicking the tires on opus 4.6 to see if it can port this project to TypeScript (addresses #532) with some handholding. I'll timebox it. If it's nothing I'll just throw this PR away.

Summary

  • Replace esprima with TypeScript compiler API (ts.createSourceFile) in the build utility, enabling incremental .js.ts migration of source files
  • The parser now handles both CJS (module.exports = function) and ESM (export default function) patterns natively
  • Convert 7 source functions in-place: ceil, str_repeat, strlen, str_replace, parse_str, array_pop, json_encode
  • All 494 test suites pass, yarn check clean, build:dist produces valid CJS output

Infrastructure changes

  • src/_util/util.ts: Replaced esprima parser with ts.createSourceFile(), updated globs to *.{js,ts}, extension-aware index/test generation with .default handling for ESM exports
  • tsconfig.build.json: New config for CJS dist compilation (module: "CommonJS")
  • scripts/fix-cjs-exports.mjs: Post-processes tsc output to add module.exports = exports.default and fix index.js requires for dist
  • tsconfig.json: Extended include to src/**/*.ts, added DOM lib
  • package.json: Updated build:dist to compile TS, fix CJS exports, clean up
  • src/_util/headerFormatter.ts: Updated glob patterns for .ts files

Design decisions

  • ini_get kept as .js for now — 17 JS source files require() it internally, and CJS require() doesn't resolve .ts extensions
  • Index files use require('./foo.ts').default for TS files in dev; fix-cjs-exports.mjs strips .ts and .default for dist
  • Generated test files use require(...).default for TS source files

Test plan

  • yarn build (indices + tests) succeeds
  • yarn test — 494 passed, 1 skipped
  • yarn check — lint, tsc, headers all clean
  • yarn test:module — CJS require chain works
  • yarn build:dist — produces valid CJS output, all converted functions work via require('./dist/php')

Addresses #532

🤖 Generated with Claude Code

kvz and others added 8 commits February 16, 2026 10:08
…sions

Replace esprima with TypeScript compiler API (ts.createSourceFile) in the
build utility, enabling incremental .js → .ts migration of source files.
The parser now handles both CJS (module.exports) and ESM (export default)
patterns natively.

Infrastructure changes:
- Build utility: TS parser, extension-aware globs, .default handling for
  ESM requires in generated tests and index files
- New tsconfig.build.json for CJS dist compilation
- New fix-cjs-exports.mjs to post-process tsc output for CJS compat
- Updated headerFormatter globs for .ts files

Converted functions (in-place .js → .ts):
- ceil, str_repeat, strlen, str_replace, parse_str, array_pop, json_encode

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Convert ini_get.ts and all 17 files that depend on it from JavaScript
to TypeScript, eliminating CJS require() resolution issues with .ts files.

Converted files: ini_get, assert_options, shuffle, uasort, uksort, usort,
arsort, asort, krsort, ksort, natcasesort, natsort, rsort, sort, substr,
strtr, parse_url, is_array.

Also adds docs/MIGRATE-TO-TS.md migration guide and enables
rewriteRelativeImportExtensions in tsconfig.build.json for CJS dist output.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove ini_get import from all 17 dependent files, reading the ini
value inline via optional chaining on globalThis.$locutus instead.
Functions now work standalone without the ini_get dependency.

Replace unsafe as-casts with runtime conversions (Number(), String()),
type guards, null guards, and properly narrowed local variables.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Change all 25 TS files from `export default function` to `export function`
- Update build tooling (util.ts parser, reindex, writetests) for named exports
- Update fix-cjs-exports.mjs to handle named exports with legacy default fallback
- Fix custom test import to use named import from .ts
- Rewrite docs/MIGRATE-TO-TS.md with all learnings from migration so far
- Add .changeset/typescript-migration.md for major version bump

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…cript

Batch migration of 5 more functions using the updated MIGRATE-TO-TS guide:
- floor (math), is_int (var), gmdate (datetime), number_format (strings), wordwrap (strings)
- Fix require paths in is_integer.js, array_slice.js, array_splice.js for is_int.ts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
TypeScript functions now show both the original TypeScript source and a
clean JavaScript transpilation in switchable tabs. Tab preference is
persisted via localStorage. JS-only functions render as before.

- Use ts.transpileModule() to generate JS version with halved indentation
- Add tab UI with TS blue/JS yellow brand colors and animated underlines
- Update "How to use" section to show ESM imports for TS functions
- Fix GitHub links to use dynamic .ts/.js extension

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the over-styled dark <pre> block with syntax-colored spans with
a simple inline <code> element, matching the CommonJS line below it and
the rest of the site's code styling.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Complete the full TypeScript migration of all source files:
- 462 function files converted from .js to .ts (module.exports → export)
- 51 index barrel files converted to ES module re-exports
- 70 require() calls converted to import statements
- 98 files with @ts-nocheck for incremental strict typing later
- Node built-in imports (fs, path, crypto) kept without .ts extension
- Parent barrel files use export * as namespace pattern
- Dead golang/strings/Index.ts removed (Index2.ts is canonical)
- Reindex function updated to generate TypeScript barrel files
- biome.json updated for _bc.ts exclusion

Zero JS source files remain. All 494 test suites pass (1154 tests).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@kvz kvz changed the title feat: TypeScript migration infrastructure + first 7 conversions feat: Complete TypeScript migration of all source files Feb 17, 2026
Convert CJS require() chain to ESM dynamic import() since source files
now use export syntax. CJS require() can't resolve .ts index files or
load ESM modules without extra flags.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@kvz kvz marked this pull request as draft February 17, 2026 09:10
kvz and others added 19 commits February 17, 2026 10:11
Delete convert-to-ts.mjs and fix-default-imports.mjs (one-time migration
scripts, no longer needed). Keep fix-cjs-exports.mjs (used by build:dist).

Rename MIGRATE-TO-TS.md to typescript.md and rewrite as project
documentation covering architecture decisions, contribution guidelines,
and the path toward full type coverage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add parameter and return type annotations to 344 function files by
inferring types from example comments and parameter name heuristics.
Fix dynamic object indexing with Record<string, any> in 27 files.
Enable noImplicitAny: true in tsconfig.json.

191 files retain @ts-nocheck for complex type issues (dynamic indexing,
runtime coercions, union returns). All new code now requires explicit
type annotations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
kvz added 30 commits February 19, 2026 09:18
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

Comments