import { readFileSync } from 'node:fs' import { join, relative } from 'node:path' import { fileURLToPath } from 'node:url' import { walkFiles } from './lib/fs-walk.mjs' // Every control-UI surface must move with the shared motion vocabulary defined in // src/assets/base.css: durations --dur-fast/base/enter/pulse and easings // --ease-standard/out/in/spring. Raw millisecond/second literals and the bare // `ease`/`ease-in`/`ease-out`/`ease-in-out` keywords inside transition/animation // declarations are violations — route them through the tokens so timing and feel // stay consistent (and so "exits one tier faster" can be enforced in one place). // // Allowed: var(--token), cubic-bezier(...)/steps(...) custom curves, `linear` // and `infinite` continuous loops (spinners/pulses keep their own cadence), the // zero value (0s/0ms), and the token definitions in base.css. Any genuinely // intentional one-off can opt out with a trailing `/* motion-allow: why */`. const root = fileURLToPath(new URL('..', import.meta.url)) const srcDir = join(root, 'src') const customProp = /^\s*--[\w-]+\s*:/ const easingKeyword = /\b(?:ease-in-out|ease-in|ease-out|ease)\b/ // A time value; we exclude the literal zero (0s / 0ms / 0.0s) separately. const durationLiteral = /\b\d*\.?\d+m?s\b/g const isZero = (v) => /^0(?:\.0+)?m?s$/.test(v) const files = walkFiles(srcDir, /\.(vue|css)$/) const failures = [] // In .vue files only