Skip to content

Commit 082cbbb

Browse files
authored
Merge pull request #259 from openzim/fix_js_import_rewrite
Add JS rewriting rule to ignore import function rewriting
2 parents d9f2086 + baad1c3 commit 082cbbb

File tree

3 files changed

+65
-1
lines changed

3 files changed

+65
-1
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Changed
1111

1212
- Upgrade to wombat 3.8.11 (#256)
13+
- Backport changes in wabac.js around JS rewriting rules (#259)
14+
15+
### Fixed
16+
17+
- JS rewriting abusively rewrite import function (#255)
1318

1419
## [5.1.1] - 2025-02-17
1520

src/zimscraperlib/rewriting/js.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -154,13 +154,15 @@ def create_js_rules() -> list[TransformationRule]:
154154
return [
155155
# rewriting `eval(...)` - invocation
156156
(re.compile(r"(?:^|\s)\beval\s*\("), replace_prefix_from(eval_str, "eval")),
157+
(re.compile(r"\([\w]+,\s*eval\)\("), m2str(lambda _: f" {eval_str}")),
157158
# rewriting `x = eval` - no invocation
158159
(re.compile(r"[=]\s*\beval\b(?![(:.$])"), replace("eval", "self.eval")),
160+
(re.compile(r"var\s+self"), replace("var", "let")),
159161
# rewriting `.postMessage` -> `__WB_pmw(self).postMessage`
160162
(re.compile(r"\.postMessage\b\("), add_prefix(".__WB_pmw(self)")),
161163
# rewriting `location = ` to custom expression `(...).href =` assignement
162164
(
163-
re.compile(r"[^$.]?\s?\blocation\b\s*[=]\s*(?![\s\d=])"),
165+
re.compile(r"(?:^|[^$.+*/%^-])\s?\blocation\b\s*[=]\s*(?![\s\d=])"),
164166
add_suffix_non_prop(check_loc),
165167
),
166168
# rewriting `return this`
@@ -186,6 +188,7 @@ def create_js_rules() -> list[TransformationRule]:
186188
# As the rule will match first, it will prevent next rule matching `import` to
187189
# be apply to `async import`.
188190
(re.compile(r"async\s+import\s*\("), m2str(lambda x: x)),
191+
(re.compile(r"[^$.]\bimport\s*\([^)]*\)\s*\{"), m2str(lambda x: x)),
189192
# esm dynamic import, if found, mark as module
190193
(
191194
re.compile(r"[^$.]\bimport\s*\("),

tests/rewriting/test_js_rewriting.py

+56
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,40 @@ def test_js_rewrite_post_message(simple_js_rewriter: JsRewriter):
101101
)
102102

103103

104+
@pytest.mark.parametrize(
105+
"raw_js,expected",
106+
[
107+
pytest.param("x = eval; x(a);", "x = self.eval; x(a);", id="case1"),
108+
pytest.param(
109+
" eval(a)",
110+
" WB_wombat_runEval2((_______eval_arg, isGlobal) => { var ge = eval; "
111+
"return isGlobal ? ge(_______eval_arg) : eval(_______eval_arg); })"
112+
".eval(this, (function() { return arguments })(),a)",
113+
id="case2",
114+
),
115+
pytest.param(
116+
"$eval = eval; $eval(a);", "$eval = self.eval; $eval(a);", id="case3"
117+
),
118+
pytest.param(
119+
"foo(a, eval(data));",
120+
"foo(a, WB_wombat_runEval2((_______eval_arg, isGlobal) => { var ge = eval; "
121+
"return isGlobal ? ge(_______eval_arg) : eval(_______eval_arg); })"
122+
".eval(this, (function() { return arguments })(),data));",
123+
id="case4",
124+
),
125+
pytest.param(
126+
"return(1, eval)(data);",
127+
"return WB_wombat_runEval2((_______eval_arg, isGlobal) => { var ge = eval; "
128+
"return isGlobal ? ge(_______eval_arg) : eval(_______eval_arg); })"
129+
".eval(this, (function() { return arguments })(),data);",
130+
id="case5",
131+
),
132+
],
133+
)
134+
def test_js_rewrite_evals(simple_js_rewriter: JsRewriter, raw_js: str, expected: str):
135+
assert simple_js_rewriter.rewrite(raw_js) == expected
136+
137+
104138
class WrappedTestContent(ContentForTests):
105139

106140
def __init__(
@@ -173,11 +207,20 @@ def wrap_script(text: str) -> str:
173207
input_="this. location = 'http://example.com/'",
174208
expected="this. location = 'http://example.com/'",
175209
),
210+
WrappedTestContent(
211+
input_="abc-location = http://example.com/",
212+
expected="abc-location = http://example.com/",
213+
),
214+
WrappedTestContent(
215+
input_="func(location = 0)",
216+
expected="func(location = 0)",
217+
),
176218
WrappedTestContent(
177219
input_="if (self.foo) { console.log('blah') }",
178220
expected="if (self.foo) { console.log('blah') }",
179221
),
180222
WrappedTestContent(input_="window.x = 5", expected="window.x = 5"),
223+
WrappedTestContent(input_=" var self ", expected=" let self "),
181224
]
182225
)
183226
def rewrite_wrapped_content(request: pytest.FixtureRequest):
@@ -271,6 +314,12 @@ def wrap_import(text: str) -> str:
271314
import { Z } from "../../../path.js";
272315
273316
B = await import(somefile);
317+
318+
class X {
319+
import(a, b, c) {
320+
await import (somefile);
321+
}
322+
}
274323
""",
275324
expected="""
276325
import * from "../../../example.com/file.js"
@@ -282,6 +331,12 @@ def wrap_import(text: str) -> str:
282331
import { Z } from "../../path.js";
283332
284333
B = await ____wb_rewrite_import__(import.meta.url, somefile);
334+
335+
class X {
336+
import(a, b, c) {
337+
await ____wb_rewrite_import__ (import.meta.url, somefile);
338+
}
339+
}
285340
""",
286341
),
287342
ImportTestContent(
@@ -341,6 +396,7 @@ def test_import_rewrite(rewrite_import_content: ImportTestContent):
341396
"a.window.x = 5",
342397
" postMessage({'a': 'b'})",
343398
"simport(5);",
399+
"import(e) {",
344400
"a.import(5);",
345401
"$import(5);",
346402
"async import(val) { ... }",

0 commit comments

Comments
 (0)