Production-grade infrastructure for Adobe ExtendScript.
|
ESON ESB64 ESARR ESSTR ESCHARS ESHTTP ESTIMER ESRAND ESUUID ESENV ESPATH ESFS ESHASH ESLOG |
ESPACK ESMIN ESABI VectorIPC ESTC ESDB COMTool ESsemble |
Also from the same team: ArcFit.dev, deterministic arc warp for Illustrator.
- Why ESMIN?
- Features
- Installation
- Quick Start
- API
- Validation
- Performance
- Security Model
- Compatibility
- Engine quirks that shaped the design
- Development
- Repository layout
- Known limitations
- Credits
- License
Illustrator 30.6.0 accepts ES3-era JavaScript plus Adobe-specific syntax that ordinary JavaScript minifiers do not model. #target and #include lines are not JavaScript tokens, E4X literals cannot be parsed by UglifyJS, and the engine has parser differences around nested ternaries and switch-case semicolon boundaries.
ESMIN keeps UglifyJS in the parts it can prove, and wraps it with the Adobe-specific steps that were verified by executing original/minified pairs inside Illustrator: UTF-8 reading, Adobe directive extraction/restoration, recursive include resolution, E4X and dynamic-reference risk scans, UglifyJS 3.19.3 with the conservative config, switch-case repair, Node parse guards, and the optional Illustrator differential harness.
- Conservative config with live evidence —
configs/conservative.jsonkeepsoutput.extendscript,quote_keys,keep_quoted_props, andsemicolonsenabled; the committed aggregate evidence inreferences/COMPATIBILITY_REPORT.mddocuments the live Illustrator harness, and the conservative corpus gate records 104 pass, 5 documented divergences, and 1 skip when regenerated. - Directive and include handling —
scripts/extendscript_preprocess.pyextracts Adobe header directives, resolves#includerecursively, detects circular includes, and restores valid directives above the minified body. - E4X risk handling — the pipeline detects E4X;
scripts/e4x_to_xml_string.pycan transform verified literal/accessor cases tonew XML(...), whiledefault xml namespaceremains an explicit non-minifiable case. - Switch-case repair — generated text runs through
fix_extendscript_switchfor Illustrator's verified switch-case ASI parser bug. - Fixture and matrix harness — 100+ JSON fixtures cover ES3 syntax, host objects, directives/includes, E4X, ScriptUI, BridgeTalk, eval, strings, properties, and parser edges; matrix configs isolate output, mangle, and compress options.
- Production CLI —
esminwraps the single-file minifier (scripts/minify-jsx.py) for npm-style invocation while preserving the Python harness for live Illustrator validation.
npm install es-minFrom another local repo while this is checked out as a sibling:
node ../esmin/bin/esmin.mjs --in Script.jsx --config ../esmin/configs/conservative.json --out Script.min.jsxThe npm package name is es-min; the installed CLI command is esmin.
esmin --in ArcFit_NativeWarp_FixedWidth.jsx \
--config configs/conservative.json \
--out ArcFit_NativeWarp_FixedWidth.min.jsxRun --check-only before shipping a new source shape:
esmin --in Script.jsx --config configs/conservative.json --out Script.min.jsx --check-only| Flag | Meaning |
|---|---|
--in <jsx> |
input .jsx / .jsxinc entry file |
--config <json> |
UglifyJS option file; use configs/conservative.json for distribution |
--out <jsx> |
output file |
--skip-includes |
do not resolve #include directives |
--check-only |
preprocess and risk-scan only; write no output |
| Script | Purpose |
|---|---|
scripts/test_extendscript_minification.py |
original/minified differential harness through Illustrator COM |
scripts/minify-jsx.py |
production single-file minifier used by the CLI |
scripts/e4x_to_xml_string.py |
opt-in E4X literal/accessor transform for verified cases |
scripts/report-generator.py |
compatibility report generator from JSONL harness outputs |
scripts/fuzz-generate.mjs |
generated fixture corpus |
| Config | Use it for | Live evidence |
|---|---|---|
configs/baseline.json |
identity/debug runs and option-matrix comparisons | baseline corpus evidence in references/COMPATIBILITY_REPORT.md |
configs/conservative.json |
production distribution default | 104 pass, 5 documented divergences, 1 skip on the curated corpus |
configs/aggressive.json |
extra reduction only after checking the documented prerequisites | 103 pass, 6 documented divergences, 1 skip on the curated corpus |
Aggressive mode is not a drop-in default: avoid it when scripts contain indirect eval, function-name-as-string usage, sparse-array hole checks, host-object reads in return expressions, or file-mode last-expression dependencies.
| Check | Command | Result |
|---|---|---|
| Static repository checks | npm test |
validates package metadata, configs, 110 fixtures, Python compilation, and Node parse guards |
| Conservative live corpus | python scripts/test_extendscript_minification.py --input fixtures --config configs/conservative.json --output reports/final-conservative |
regenerate gate; recorded conservative evidence is 104 pass, 5 documented divergences, 1 skip |
| Conservative fuzz corpus | node scripts/fuzz-generate.mjs --count 60 --seed 42 --out reports/fuzz then python scripts/test_extendscript_minification.py --input reports/fuzz --config configs/conservative.json --output reports/run-fuzz-conservative |
regenerate gate; recorded evidence is 60/60 pass |
| Full evidence report | python scripts/report-generator.py --output references/COMPATIBILITY_REPORT.md --results ... |
references/COMPATIBILITY_REPORT.md records 3350 original/minified executions |
The live oracle is Adobe Illustrator through ILLUSTRATOR_COM_TOOL.py; Node parsing is a static guard, not proof of ExtendScript compatibility.
The current measured performance claim is byte-size reduction, not runtime speed. references/COMPATIBILITY_REPORT.md records 3346 fixture variants with size data from Illustrator-executed runs: mean reduction 11.26%, median reduction 6.49%, min/max -35.51% / 100.0%.
Runtime minifier latency depends on UglifyJS, Python process startup, include depth, and input size; no shipped benchmark table is included until those timings are measured on a tagged commit.
ESMIN is a build-time transformer. It reads input source files, resolves local #include paths, invokes Node/UglifyJS, and writes a minified output file. It does not load an ExtendScript ExternalObject DLL and does not execute the target script during esmin CLI minification.
The live harness does execute fixture source and minified output inside Illustrator. Treat fixture code and input scripts as code with the privileges of the Illustrator process. Run the live harness only on trusted corpora or inside an isolated Illustrator profile.
| Target | Status |
|---|---|
| Adobe Illustrator 30.6.0 / ExtendScript 4.5.6 / Windows x86-64 | live evidence in references/COMPATIBILITY_REPORT.md |
| Node.js | >=18.0.0 for worker scripts; evidence report used Node v22.23.2 |
| Python | Python 3; evidence report used Python 3.12 / 3.14 with pywin32 for COM harness |
| UglifyJS | pinned to 3.19.3 |
| Non-Illustrator ExtendScript hosts | not claimed until live-tested in that host |
- Nested ternary output requires
output.extendscript: true— without it, Illustrator 30.6.0 reportsError 25: Expected: :.across nested conditional positions. - Switch-case boundaries require explicit semicolons — empty switches and
casebodies ending without;can fail withError 25; the repair pass exists for this bug. - Reserved-word object keys must be quoted — unquoted keys such as
{if: 2}fail withError 9;quote_keysandkeep_quoted_propsare mandatory. - E4X is not ordinary JavaScript — UglifyJS cannot parse XML literals or
default xml namespace; verified transforms exist for a subset only. - Eval and string-referenced identifiers constrain mangling — indirect eval and function names used as strings can break local mangling or
unusedremoval. - Host-object errors differ by expression context — host reads inside return expressions can bypass
try/catch; aggressive sequence transforms are therefore restricted.
npm install
npm test
# Production minify
npm run minify -- --in Script.jsx --config configs/conservative.json --out Script.min.jsx
# Live Illustrator corpus gate
npm run fixture:conservative
npm run fuzz:generate
npm run fuzz:conservative
npm run live-verifybin/ npm CLI wrapper
configs/ baseline, conservative, aggressive, and option-matrix configs
fixtures/ curated JSON fixtures and include trees
references/ compatibility report and evidence documents
scripts/ Python/Node minification, preprocessing, E4X, fuzz, report tools
tests/ static repository checks
docs/ release-note draft and release planning notes
SKILL.md agent-facing operating guide retained for compatibility
- No DLL or ESPACK accel bundle is generated by v0.1.0. A release that attaches such assets must first add a native component, source, build script, tests, and live validation.
default xml namespaceremains non-minifiable; there is no ES3-equivalent transform in this tool.- Static checks do not prove Illustrator compatibility; the differential harness is the release gate.
Built on UglifyJS 3.19.3 and Adobe ExtendScript engine behavior measured through Illustrator automation. ExtendScript host references: docsforadobe and the Illustrator COM/JSX probes in this workspace.
GPL-3.0-or-later. See LICENSE.