From 8899211c6221b858543e351764b4920df72bc3a3 Mon Sep 17 00:00:00 2001 From: Chris Modzelewski Date: Fri, 3 Nov 2023 13:04:20 -0400 Subject: [PATCH 1/2] Fixed bug in JS literal serialization that accidentally serialized strings as dicts. Closes #130 --- highcharts_core/js_literal_functions.py | 26 ++++++++++++++++++------- tests/fixtures.py | 1 + tests/options/test_tooltips.py | 19 +++++++++++++++++- tests/test_js_literal_functions.py | 18 +++++++++++++++++ 4 files changed, 56 insertions(+), 8 deletions(-) diff --git a/highcharts_core/js_literal_functions.py b/highcharts_core/js_literal_functions.py index 628592e4..0ff27d48 100644 --- a/highcharts_core/js_literal_functions.py +++ b/highcharts_core/js_literal_functions.py @@ -159,15 +159,25 @@ def is_js_object(as_str, careful_validation = False): is_empty = as_str[1:-1].strip() == '' if is_empty: return True - has_colon = ':' in as_str - if has_colon: - return True - if 'new ' in as_str: + colon_count = as_str.count(':') + open_brace_count = as_str.count('{') + close_brace_count = as_str.count('}') + brace_set_count = (open_brace_count + close_brace_count) / 2 + if colon_count > 0: + if brace_set_count == 1: + return True + elif brace_set_count > 1 and colon_count >= brace_set_count: + return True + else: + careful_validation = True + elif 'new ' in as_str: return True - if 'Object.create(' in as_str: + elif 'Object.create(' in as_str: return True - return False - else: + else: + return False + + if careful_validation: expression_item = f'const testName = {as_str}' try: parsed = esprima.parseScript(expression_item) @@ -192,6 +202,8 @@ def is_js_object(as_str, careful_validation = False): return True return False + + return False def attempt_variable_declaration(as_str): diff --git a/tests/fixtures.py b/tests/fixtures.py index 3dfdc265..8c87f01e 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -796,6 +796,7 @@ def Class_from_js_literal(cls, input_files, filename, as_file, error): assert isinstance(result, cls) is True as_js_literal = result.to_js_literal() + print(as_js_literal) #print('-----------------') #print('RESULT VALIDATION') if 'pattern:' in as_js_literal: diff --git a/tests/options/test_tooltips.py b/tests/options/test_tooltips.py index f983258b..95a35819 100644 --- a/tests/options/test_tooltips.py +++ b/tests/options/test_tooltips.py @@ -9,7 +9,7 @@ from highcharts_core import errors from tests.fixtures import input_files, check_input_file, to_camelCase, to_js_dict, \ Class__init__, Class__to_untrimmed_dict, Class_from_dict, Class_to_dict, \ - Class_from_js_literal + Class_from_js_literal, compare_js_literals STANDARD_PARAMS = [ ({}, None), @@ -86,6 +86,9 @@ }""", 'split': True }, None), + ({ + 'format': '{point.name} {point.y}' + }, None), ({ 'border_width': 'not-a-number' @@ -128,3 +131,17 @@ def test_to_dict(kwargs, error): ]) def test_from_js_literal(input_files, filename, as_file, error): Class_from_js_literal(cls, input_files, filename, as_file, error) + + +def test_bug130_tooltip_serialization(): + as_js_literal = """{ + format: '{point.name}: {point.y}' + }""" + + obj = cls.from_js_literal(as_js_literal) + assert obj is not None + assert isinstance(obj, cls) is True + assert obj.format == '{point.name}: {point.y}' + + result = obj.to_js_literal() + assert "'{point.name}: {point.y}'" in result or '"{point.name}: {point.y}"' in result \ No newline at end of file diff --git a/tests/test_js_literal_functions.py b/tests/test_js_literal_functions.py index 00b52c79..7d39ca9f 100644 --- a/tests/test_js_literal_functions.py +++ b/tests/test_js_literal_functions.py @@ -190,3 +190,21 @@ def test_convert_js_property_to_python(original_str, override, expected, error): else: with pytest.raises(error): result = js.convert_js_property_to_python(item, original_str) + + +@pytest.mark.parametrize('original_str, expected, error', [ + ("Object.create({item1:true})", True, None), + ("new Date()", True, None), + ("test string", False, None), + ("{item1: 456}", True, None), + ("'{point.name}: {point.y}'", False, None), + ("{item: {subitem: 123}}", True, None), + ("{item: 123, item2: 456, item3: {subitem: 789}}", True, None), +]) +def test_is_js_object(original_str, expected, error): + if not error: + result = js.is_js_object(original_str) + assert result is expected + else: + with pytest.raises(error): + result = js.is_js_object(original_str) \ No newline at end of file From a9b2806e3d1e55a51e5a6c148edfbe53c720fbad Mon Sep 17 00:00:00 2001 From: Chris Modzelewski Date: Fri, 3 Nov 2023 13:06:11 -0400 Subject: [PATCH 2/2] Bumped version number and updated changelog. --- CHANGES.rst | 9 +++++++++ highcharts_core/__version__.py | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 138570db..761b3d1f 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,4 +1,13 @@ +Release 1.5.1 +========================================= + +* **BUGFIX:** Fixed bug in JS literal serialization that would misinterpret strings that + start with ``{``, end with ``}``, and contain a colon (``:``) as an object literal rather + than as a string. (#130) + +-------------------- + Release 1.5.0 ========================================= diff --git a/highcharts_core/__version__.py b/highcharts_core/__version__.py index 618528c7..1b37c690 100644 --- a/highcharts_core/__version__.py +++ b/highcharts_core/__version__.py @@ -1 +1 @@ -__version__ = '1.5.0' \ No newline at end of file +__version__ = '1.5.1' \ No newline at end of file