Skip to content

Commit 149947d

Browse files
committed
Wrap JS functions with parenthesis before eval on the JS side
1 parent a8ea92e commit 149947d

File tree

5 files changed

+17
-9
lines changed

5 files changed

+17
-9
lines changed

docs/changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ ITables ChangeLog
1010
**Changed**
1111
- The `warn_on_undocumented_option` option now defaults to `True` and only check the option names
1212
- We have added a new option `warn_on_unexpected_option_type` that defaults to `warn_on_undocumented_option` when `typeguard>=4.4.1` is installed (`False` otherwise)
13+
- Wrapping JS function definitions in parentheses prior to JS eval is now done on the JS side.
1314

1415
**Fixed**
1516
- We have added type hints to `itable.options` even for the options that don't have a default value ([#224](https://github.com/mwouts/itables/issues/224))

packages/dt_for_itables/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# 2.3.2+dev
22

33
- We have made sure that the ordering icons on empty headers do not reappear when ordering a column
4+
- Wrapping Javascript functions definitions within parentheses before evaluating is now done on the Javascript side.
45

56
# 2.3.2 (2025-05-17)
67

packages/dt_for_itables/src/index.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,17 @@ function evalNestedKeys(obj, keys, context) {
5959
}
6060
if (rest.length === 0) {
6161
try {
62-
obj[first] = window.eval(obj[first]);
62+
let code = obj[first];
63+
if (typeof code !== 'string') {
64+
throw new Error(`Expected a string to evaluate in context '${context}', but got ${typeof code}.`);
65+
}
66+
if (/^\s*function\s*\(/.test(code)) {
67+
// If the code matches the regular expression for a function definition,
68+
// we wrap it in parentheses to proceed with the evaluation.
69+
code = `(${code})`;
70+
}
71+
72+
obj[first] = window.eval(code);
6373
}
6474
catch (e) {
6575
console.error(`Error evaluating ${context}='${obj[first]}'": ${e.message}`);

src/itables/javascript.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -277,11 +277,6 @@ def get_keys_to_be_evaluated(data) -> list[list[Union[int, str]]]:
277277
data = dict(enumerate(data))
278278
if isinstance(data, dict):
279279
for key, value in data.items():
280-
if isinstance(value, JavascriptFunction):
281-
# eval can't evaluate a function,
282-
# but it can evaluate an expression that contains a function
283-
# e.g. eval('(function() {return 5;})') does returns the function
284-
data[key] = f"({value})"
285280
if isinstance(value, (JavascriptCode, JavascriptFunction)):
286281
keys_to_be_evaluated.append([key])
287282
else:

src/itables/typing.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import re
12
import warnings
23
from importlib.metadata import PackageNotFoundError, version
34
from pathlib import Path
@@ -17,9 +18,9 @@ class JavascriptFunction(str):
1718
"""
1819

1920
def __init__(self, value):
20-
assert value.lstrip().startswith(
21-
"function"
22-
), "A Javascript function is expected to start with 'function'"
21+
assert re.compile(r"^\s*function\s*\(").match(
22+
value
23+
), "A Javascript function is expected to start with 'function('"
2324

2425

2526
class JavascriptCode(str):

0 commit comments

Comments
 (0)