Skip to content
thelabcornerPublic

About

ESMIN — UglifyJS-based, Illustrator-verified ExtendScript minification pipeline for .jsx/.jsxinc bundles.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

ESMIN: ExtendScript Minification for Adobe ExtendScript (ES3)

ExtendScript MINification = E.S.MIN

A UglifyJS-based .jsx / .jsxinc minification pipeline for Adobe Illustrator scripts, with directive preservation, include bundling, E4X risk handling, and live-engine differential validation

Differential: Illustrator corpus Fuzz: generated Engine parity: corpus Adobe: Creative Suite Engine Size License: GPL-3.0-or-later


Part Of The Same Toolkit

Production-grade infrastructure for Adobe ExtendScript.

Runtime Primitives

ESON
Strict RFC 8259 JSON for ExtendScript.

ESB64
Base64 and UTF-8 utilities.

ESARR
ES5+ Array compatibility methods.

ESSTR
String whitespace and trim methods.

ESCHARS
Native bulk byte operations.

ESHTTP
HTTP transport for ExtendScript automation.

ESTIMER
Microsecond timing for ExtendScript automation.

ESRAND
Deterministic random streams and sampling for ExtendScript.

ESUUID
RFC 9562 UUID generation, parsing, and conversion for ExtendScript.

ESENV
Environment and capability detection for ExtendScript.

ESPATH
Deterministic Windows/POSIX path and RFC 8089 file-URI transformations.

ESFS
Synchronous ExtendScript File/Folder I/O with explicit text, BINARY, and replacement semantics.

ESHASH
CRC-32/ISO-HDLC and SHA-256 for byte strings and UTF-8 text.

ESLOG
Structured logging with bounded text and JSONL sinks.

Build & Integration Tools

ESPACK
Self-extracting ExternalObject bundles.

ESMIN
Minification for shipped JSX bundles.

ESABI
Modern ExternalObject ABI declarations for native integrations.

VectorIPC
Bounded local IPC for scripting hosts and native plug-ins.

ESTC
TypeScript-to-ExtendScript build, compatibility, and live-parse tooling.

ESDB
Native state and durable storage for Adobe tooling.

COMTool
Guarded COM, ExtendScript, plug-in, and debugger automation for Adobe desktop apps.

ESsemble
Typed framework, resolver, and composition layer for the ExtendScript toolkit.

Also from the same team: ArcFit.dev, deterministic arc warp for Illustrator.


Table of Contents


Why ESMIN?

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.


Features

  • Conservative config with live evidence — configs/conservative.json keeps output.extendscript, quote_keys, keep_quoted_props, and semicolons enabled; the committed aggregate evidence in references/COMPATIBILITY_REPORT.md documents 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.py extracts Adobe header directives, resolves #include recursively, detects circular includes, and restores valid directives above the minified body.
  • E4X risk handling — the pipeline detects E4X; scripts/e4x_to_xml_string.py can transform verified literal/accessor cases to new XML(...), while default xml namespace remains an explicit non-minifiable case.
  • Switch-case repair — generated text runs through fix_extendscript_switch for 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 — esmin wraps the single-file minifier (scripts/minify-jsx.py) for npm-style invocation while preserving the Python harness for live Illustrator validation.

Installation

npm install es-min

From 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.jsx

The npm package name is es-min; the installed CLI command is esmin.


Quick Start

esmin --in ArcFit_NativeWarp_FixedWidth.jsx \
  --config configs/conservative.json \
  --out ArcFit_NativeWarp_FixedWidth.min.jsx

Run --check-only before shipping a new source shape:

esmin --in Script.jsx --config configs/conservative.json --out Script.min.jsx --check-only

API

CLI: esmin

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

Harness scripts

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 selection

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.


Validation

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.


Performance

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.


Security Model

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.


Compatibility

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

Engine quirks that shaped the design

  • Nested ternary output requires output.extendscript: true — without it, Illustrator 30.6.0 reports Error 25: Expected: :. across nested conditional positions.
  • Switch-case boundaries require explicit semicolons — empty switches and case bodies ending without ; can fail with Error 25; the repair pass exists for this bug.
  • Reserved-word object keys must be quoted — unquoted keys such as {if: 2} fail with Error 9; quote_keys and keep_quoted_props are 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 unused removal.
  • Host-object errors differ by expression context — host reads inside return expressions can bypass try/catch; aggressive sequence transforms are therefore restricted.

Development

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-verify

Repository layout

bin/          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

Known limitations

  • 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 namespace remains 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.

Credits

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.


License

GPL-3.0-or-later. See LICENSE.

About

ESMIN — UglifyJS-based, Illustrator-verified ExtendScript minification pipeline for .jsx/.jsxinc bundles.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages