#!/usr/bin/env node /** * T5 motion codemod (spec 17.2, 17.4, 17.7, Task A11). Pure and idempotent: * * - `motion-safe:` only asks the system and skips the level chosen in the app. Movement behind it * (translate, scale, rotate, slide-, zoom-, animate-, transition-transform, also behind further * variants) moves to `motion-full:`. * - Colour and opacity transitions need no variant ("Aus" sets every duration to zero): * `motion-safe:transition-colors`/`-opacity` lose the variant. * - Pulsing and spinning are full motion: a bare `animate-pulse`/`animate-spin` gets * `motion-full:`, and `motion-reduce:animate-none` (the old opt-out) goes. * * Hover lifts, `transition-all` and overlay timings are changed by hand (they need a judgement). * * CLI: node scripts/codemod-t5-motion.mjs [--check] * --check lists the files that would change and exits 1 if there are any. */ import { readdirSync, readFileSync, statSync, writeFileSync } from "node:fs"; import { join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; /** Characters that belong to a class token (so a match never starts inside one). */ const TOKEN_CHAR = String.raw`[\w:/\[\]().%-]`; /** Further variants between the motion variant and the utility (`data-open:`, `group-hover:`). */ const VARIANTS = String.raw`(?:[^\s"'\`:]+:)*`; const MOVEMENT = String.raw`-?(?:translate|scale|rotate|slide-|zoom-|animate-|transition-transform)`; const SAFE_MOVEMENT = new RegExp(String.raw`(? filesOf(join(path, name))); } return /\.tsx?$/.test(path) && !/\.spec\./.test(path) ? [path] : []; } if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { const args = process.argv.slice(2); const check = args.includes("--check"); const changed = args .filter((arg) => arg !== "--check") .flatMap((arg) => filesOf(resolve(arg))) .filter((file) => { const before = readFileSync(file, "utf8"); const after = transform(before); if (after === before) return false; if (!check) writeFileSync(file, after); return true; }); for (const file of changed) console.log(file); if (check && changed.length > 0) process.exit(1); }