M+Minify++

Evaluation · evidence, not a slogan

Battle tested at the syntax boundaries that break minifiers.

Minify++'s test strategy grew out of adversarial Nift minifier testing. Now that Minify++ is independent, that evidence belongs here: direct C++ format tests, executable JavaScript differential testing, generated semantic matrices, JSX/TSX parser-and-idempotence gates, CLI tests and Nift integration tests.

15,459

generated JavaScript programs executed before and after minification.

180

generated JSX/TSX programs parsed before/after and checked for idempotence.

7 formats

HTML, CSS, JS, JSX, JSON, XML and SVG families under focused tests.

Memory evidence has its own living record.

The dedicated Memory & resource safety page now records the completed standalone sanitizer/RSS/Valgrind lifetime gate and remains the living home for future reruns, rather than freezing detailed memory numbers here.

What “battle tested” means here

It does not mean bug-free. No finite suite proves that. It means Minify++ is tested specifically against grammar boundaries where text minification tends to alter meaning, and discovered bugs are converted into permanent regressions. The suite is intended to become harder over time, not merely larger.

Layer 1: direct format smoke tests

The C++ smoke suite calls the library API directly. It covers whitespace/comment removal, strings, malformed input, Unicode and format-specific preservation rules without involving Nift or the standalone CLI. This keeps a failing transformation close to the implementation that caused it.

HTML

Tests distinguish removable formatting whitespace from meaningful inline/mixed-content whitespace, and protect raw-text contexts such as <script>, <style> and <textarea>. Templates, doctypes, entities and module-script content are included.

CSS

Coverage includes comments, strings, custom properties, data URLs, calc()/clamp(), container queries, layers, :has(), native nesting, modern color syntax and unknown/future at-rule shapes. Minify++ deliberately avoids an allowlist that would make a future @something fail merely because Minify++ predates it.

JSON

JSON is parsed structurally rather than treated as arbitrary whitespace. Malformed JSON is rejected instead of emitting a smaller invalid file. Strings, escapes, Unicode and nested values are exercised.

XML and SVG

Namespaces, entities, CDATA, mixed text, SVG path attributes and preserved text spacing are tested. XML-like syntax is not assumed to have HTML's whitespace semantics.

Non-JavaScript generated/idempotence gate

Minify++ has a dedicated 115-document generated corpus across HTML, CSS, JSON, XML and SVG. Each document must be stable under a second minification pass. JSON additionally receives a structural semantic-equivalence check and malformed-input rejection. XML/SVG are intentionally treated as conservative lexical minifiers rather than validating XML parsers, so the test contract reflects that boundary instead of overstating validation.

Independent CSS semantic comparison

Idempotence cannot detect output that is consistently wrong. A separate PostCSS-backed gate now parses original and minified representative modern stylesheets, normalizes irrelevant formatting, and compares their meaningful rule, selector, at-rule and declaration trees. Focused cases cover the exact boundary families that broke the project website.

Layer 2: executable JavaScript differential testing

Representative JavaScript is run under Node before and after Minify++. Stdout, stderr and behavior must agree. This directly catches the class of bug that matters most: output that still looks like JavaScript but means something different.

Named cases cover regex-versus-division, automatic semicolon insertion, empty loop bodies such as while(condition);, numeric member access, Unicode identifiers, nested/tagged templates, optional chaining/calls, private/static fields, BigInt, control headers, labels, object literals, generators, async functions and class boundaries.

Layer 3: 15,459 generated semantic combinations

The generated matrix combines many legal statement endings with many regex literal shapes and following contexts. Each source is minified independently; original and minified forms are then executed in aggregate with per-case isolation to avoid paying thousands of Node startup costs.

The latest expansion adds more async/generator/object/class forms, destructuring in loops and catches, static/private fields, lookbehind, named backreferences, Unicode property escapes and comment/markup-looking regex bodies. The important property is combinatorial pressure: a regex that works after a variable declaration might still fail after a labelled block, class, loop or control statement.

Layer 4: JSX/TSX syntax + idempotence

JSX cannot be meaningfully executed without choosing a framework transform, so Minify++ uses a different oracle. Every generated fixture must first be accepted by tsc --noCheck --jsx preserve. Minify++ minifies it; TypeScript must accept the result; Minify++ minifies it again; the second output must be byte-for-byte identical.

The current 180-program corpus covers fragments, custom/member tags, spread attributes, ternaries, templates, object literals, optional/nullish expressions, nested JSX returned from functions/classes/generators, SVG/MathML, generic component type arguments, regex-heavy children and TSX generic arrows.

Bugs the adversarial suites actually found

Regex after labelled/control blocks

A scanner can interpret / as division after the wrong kind of statement boundary. Generated combinations found cases where labels nested beneath control statements were not recognized as regex-prefix contexts. Counter-tests protect genuine division expressions so the fix cannot simply classify every slash as regex.

Regex character classes that look like JSX

const x = <div>{/[{}<>]/.test(s) ? <A/> : <B/>}</div>;

The <> inside the regex character class is visually identical to JSX fragment punctuation. JSX-root discovery now skips JavaScript regex literals before interpreting markup.

Generic JSX component arguments

<Comp<Map<string, number>> value={m} />

Nested generic angle brackets cannot be treated as the outer JSX tag boundary. Permanent regressions cover increasingly deep type arguments.

Function types inside JSX generics

<Comp<(x: number) => string> value={fn} />

The > in => is not a generic closer. This subtle ambiguity was found by generated testing and fixed in both root and nested tag scanners.

TSX generic arrows inside JSX expressions

<div>{(<T,>(x: T) => <A value={x} />)(1)}</div>

The scanner initially interpreted <T,> as nested markup. TSX-safe generic-arrow forms are now recognized before markup discovery.

Layer 5: standalone CLI behavior

The CLI suite verifies normal output, in-place behavior, malformed input, unknown options, failure safety and version output. A library can be correct while a file-replacement path is destructive, so CLI behavior is tested separately.

Layer 6: sanitizer-backed mutation testing

A deterministic mutation gate attacks valid seeds from all seven formats. Any first-pass output accepted by Minify++ must remain acceptable on a second pass. The enlarged reopened campaign passed 7,000,000 mutations under both the ordinary build and AddressSanitizer/UndefinedBehaviorSanitizer. It exposed JavaScript comment-delimiter synthesis and JSX comment/root confusion beyond the first production audit; both are minimized permanent regressions.

Layer 7: embedded Nift integration

Nift uses the same public Minify++ API. Its integration tests verify config-driven minification, per-file overrides, incremental builds and the safe standalone nift minify behavior. These tests belong to Nift because they test Nift's policy and project state; the transformation correctness belongs to Minify++.

Why the old Nift battle-testing history matters

Minify++ did not start with a clean-room marketing test suite. Its scanner was repeatedly attacked while embedded in Nift, and the failures drove the independent architecture. Moving that detailed minifier evidence to this site makes the ownership clearer: Nift should document that it integrates Minify++ correctly; Minify++ should document why its output transformations deserve confidence.

What is still not proven

The suite cannot prove equivalence for every JavaScript program, every future CSS feature or every malformed browser input. It also does not claim maximum compression. The defensible statement is narrower: Minify++ has multiple independent correctness oracles, a growing adversarial corpus, and a policy of retaining every confirmed bug as a regression.

Current readiness: pass with known limitations, revalidated.

The repaired implementation is green across the stronger evidence wall, clean committed-package check, synchronized Nift integration and fresh-browser website validation. macOS and Windows remain explicit validation gaps; XML/SVG remain lexical rather than validating modes; and benchmark figures are host-specific evidence.