Code Transposition moves global code into a generated wrapper so functions and statements no longer appear in the same straightforward structure as the original source. It is also the transform that makes several other options possible, because it creates the private scope they need.
How it works
The option collects global statements and functions into a generated scope, then rewrites references so the output relies on local indirection. Names that must stay reachable from outside are declared at the top and assigned from inside the wrapper, which keeps the external contract intact while everything internal becomes local.
Without Code Transposition:
function logit() {
}
function mylogic() {
logit();
}
With Code Transposition enabled:
var logit, mylogic;
(function () {
function a() {
}
function b() {
a();
}
logit = a;
mylogic = b;
})();
Why the wrapper matters
Two things change, and the second is the more important one.
First, top-level structure stops being a readable index. An unwrapped file lets a reader scroll the global scope and get a table of contents for free. After transposition the top of the file is a declaration list and the bodies are inside an anonymous scope, in an order that no longer has to match how you wrote them.
Second — and this is why the option sits underneath so much else — identifiers that were global become local. A global name is part of the page's shared namespace and generally cannot be renamed safely, because anything on the page might reference it. Once it is local to a wrapper, it is renameable like any other local. Transposition is what lets name mangling reach code that would otherwise have to be left alone.
Configuration
{
"options": {
"ReorderCode": true,
"ReplaceNames": true
}
}
These options build on the wrapper this one creates:
- Code Transposition Eval (
ReorderCodeEval) packs the wrapper into an evaluated string. Requires unsafe-eval in your CSP.
- Protect Object Declaration (
ReorderCodeObjectDeclare) puts its object-builder helper in the wrapper scope.
- Flat Transform rewrites control flow into dispatch inside it.
- Dead-code injection also needs the wrapper to have somewhere to put unreachable branches.
Enabling any of those causes the wrapper to be generated even for a file that would not otherwise need one.
When the wrapper is skipped
If a file has nothing to hoist — no functions, classes, variables, imports, or exports at global scope — the wrapper is not added, because an extra scope level would be pure cost. That case is real: a file that is already one big IIFE, as many distributed libraries are, has no global declarations to collect. Adding another scope around it once caused variable-resolution breakage in IIFE-wrapped libraries, so the engine now leaves those files alone unless one of the options above specifically needs the wrapper.
The practical consequence: if you enable this option and the output looks unchanged at the top level, the file probably had nothing at global scope. That is correct behavior, not a failure.
What to test
- Runtime function replacement. Code that reassigns a top-level function after load — monkey-patching, test doubles, feature toggles that swap an implementation — interacts with this transform, because the declaration is now an assignment from inside a closure. Assigning a function to a variable is more predictable here than relying on a top-level declaration.
- Hoisting expectations. Function declarations hoist within their scope; moving them into a wrapper changes which scope that is. Code that calls a function before its declaration point still works, but code that reads a
var before assignment may see a different moment of initialisation.
- Anything reached by string. A global your HTML references in an
onclick attribute, or that another script looks up as window["name"], must be in your exclusion list. The wrapper preserves the declared names it knows about; it cannot know about a reference that only exists as text in your markup.
- Module files. ES module semantics differ from script semantics at the top level. If you ship
.mjs, read obfuscating ES modules for what an obfuscator can and cannot restructure there.
Compatibility note: test code that depends on replacing function declarations at runtime. In those cases, assigning a function to a variable can be more predictable than relying on a top-level declaration.