May 27, 2026 · v0.2.3

Ten New Deterministic Transforms

Six Python and four TypeScript transforms, roughly doubling coverage, plus a pythonVersion key so version-gated rewrites can be opted in safely.

Added: Python

  • super_no_args. super(ClassName, self).method(...) becomes super().method(...). Refuses sibling and parent class names and nested-class shadows to preserve MRO.
  • lru_cache_to_cache. @functools.lru_cache(maxsize=None) becomes @functools.cache on 3.9+; also rewrites the from functools import line.
  • pep585_generics. typing.List, Dict, Tuple, Iterable and friends become list, dict, tuple, collections.abc.Iterable on 3.9+, or with from __future__ import annotations. Refuses files with Pydantic v1 or get_type_hints to avoid runtime-eval crashes.
  • pep604_optional_union. Optional[X] becomes X | None; Union[A, B] becomes A | B on 3.10+, or with from __future__ import annotations.
  • datetime_utc_alias. datetime.timezone.utc becomes datetime.UTC on 3.11+. No __future__ override: UTC is a runtime attribute.
  • yield_from_for_loop. for x in y: yield x becomes yield from y. Refuses inside async def, a CPython compile-stage SyntaxError that LibCST's parser does not catch.

Added: TypeScript

  • indexof_to_includes. arr.indexOf(x) !== -1 and friends become arr.includes(x). Type-aware via ts-morph for String, Array, and ReadonlyArray receivers. Gated on tsconfig target ES2016+.
  • object_assign_to_spread. Object.assign({}, a, b) becomes { ...a, ...b }. The first argument must be an object literal; refuses spread-element sources. Gated on target ES2018+.
  • string_concat_to_template_literal. String concatenation chains become template literals. Refuses any, unknown, and non-primitive operands. Gated on target ES2015+.
  • vue_set_delete_to_assignment. Vue.set and this.$set become direct assignment; Vue.delete and this.$delete become delete obj.k. Plain .js and .ts only: .vue SFC parsing is deferred to v0.4. Refuses delete in expression context, and on Vue 2 codebases this is a semantic change.

Configuration

  • pythonVersion. Pin the Python target version, 3.9, 3.11 and so on, for the four version-gated transforms. Auto-detected from pyproject.toml's requires-python when unset; falls back to refusing version-gated transforms rather than guessing.

Changed

  • Engine composition. Multi-transform composition is now order-stable: when several transforms touch the same file, each emits its own FileChange carrying the cumulative content, and the last one per path is what is written to disk. Fixes a silent-data-loss bug where only the last transform's rewrite survived under run --apply.