You can directly create a PR if the change is small. Otherwise, please open an issue first to discuss the change.
This project uses pnpm for package management. Please make sure you have it installed before proceeding.
- Fork and clone the repo
- Check out a new branch:
git checkout -b some-feature
- Install dependencies:
pnpm install
- Test your changes in the playground:
pnpm dev
Press F5
in VSCode to build the project and launch the debugger.
Choose any of these launch configurations:
-
Launch playground
: runs a dev server in the background and opens the playground in your browser.debug-playground.mp4
-
Deobfuscate tmp file
: runs the CLI locally.- Create the file
packages/webcrack/tmp/test.js
and paste your code - The output will be saved in
tmp/webcrack-out
- Create the file
Run the tests with pnpm test
.
.toMatchInlineSnapshot()
for new tests will automatically generate the expected output when saved, no need to write it manually.
If the snapshots are outdated, make sure the changes are correct and update them:
The tests can also be debugged by installing the Vitest extension and right-clicking on the play icon:
pnpm lint:fix && pnpm format
The easiest way to create a new transform is to copy an existing one and modify it.
{
- exit(path) { if (path.isIdentifier()) { ... } }
+ Identifier: { exit(path) { ... } }
}
May not work in some cases (accessing path.scope
when the scope hasn't been crawled before).
{
Identifier(path) { ... },
+ noScope: true,
}
To only traverse the AST once and avoid missing nodes based on the order of visitors.
- applyTransform(ast, transformA);
- applyTransform(ast, transformB);
+ applyTransforms(ast, [transformA, transformB]);
This also avoids conflicts by first renaming bindings with the name b
to something else.
- path.scope.rename('a', 'b');
+ const binding = path.scope.getBinding('a')!;
+ renameFast(binding, 'b');
For example finding calls to a function foo
(provided that you already have foo's NodePath):
const matcher = m.callExpression(m.identifier('foo'));
- traverse(ast, {
- CallExpression(path) {
- if (matcher.match(path.node)) { ... }
- }
- });
+ const binding = fooPath.scope.getBinding('foo')!;
+ for (const reference of binding.referencePaths) {
+ if (matcher.match(reference.parent)) { ... }
+ }
- Babel Handbook - general overview of AST and code transformations
- AST Explorer - visualize the AST and test transforms
- @codemod/matchers - a much cleaner way of finding AST structures
- ReverseJS - blog posts about creating deobfuscators with Babel
- Bubbl.es - scope visualizer
- Vitest - for tests