Break out the decoder logic in a separate file
- ID
283ea11- date
2025-05-03 07:45:47+00:00- author
Alex Chan <alex@alexwlchan.net>- parent
0634780- message
Break out the decoder logic in a separate file- changed files
3 files, 31 additions, 14 deletions
Changed files
src/javascript_data_files/__init__.py (6907) → src/javascript_data_files/__init__.py (6664)
diff --git a/src/javascript_data_files/__init__.py b/src/javascript_data_files/__init__.py
index f4079f1..96467dc 100644
--- a/src/javascript_data_files/__init__.py
+++ b/src/javascript_data_files/__init__.py
@@ -14,11 +14,11 @@ Think of this like the JSON module, but for JavaScript files.
import io
import json
import pathlib
-import re
import textwrap
import typing
import uuid
+from .decoder import decode_from_js
from .encoder import encode_as_js, encode_as_json
@@ -44,18 +44,7 @@ def read_js(p: pathlib.Path | str, *, varname: str) -> typing.Any:
"""
p = pathlib.Path(p)
- contents = p.read_text()
-
- m = re.compile(r"^(?:const |var )?%s = " % varname)
-
- if not m.match(contents):
- raise ValueError(
- f"File {p} does not start with JavaScript `const` declaration!"
- )
-
- json_string = m.sub(repl="", string=contents).rstrip().rstrip(";")
-
- return json.loads(json_string)
+ return decode_from_js(js_string=p.read_text(), varname=varname)
def read_typed_js[T](p: pathlib.Path | str, *, varname: str, model: type[T]) -> T:
src/javascript_data_files/decoder.py (0) → src/javascript_data_files/decoder.py (760)
diff --git a/src/javascript_data_files/decoder.py b/src/javascript_data_files/decoder.py
new file mode 100644
index 0000000..5c9eb70
--- /dev/null
+++ b/src/javascript_data_files/decoder.py
@@ -0,0 +1,28 @@
+"""
+This file contains pure functions for converting JSON strings
+to Python values.
+
+Because I expect some of this JSON to be written by me, and I can
+make copy-paste mistakes, there are a couple of ways it tries
+to catch errors.
+"""
+
+import json
+import re
+import typing
+
+
+def decode_from_js(js_string: str, *, varname: str) -> typing.Any:
+ """
+ Parse a string as a JavaScript value.
+ """
+ # Matches 'const varname = ' or 'var varname = ' at the start
+ # of a string.
+ m = re.compile(r"^(?:const |var )?%s = " % varname)
+
+ if not m.match(js_string):
+ raise ValueError("Does not start with JavaScript `const` declaration!")
+
+ json_string = m.sub(repl="", string=js_string).rstrip().rstrip(";")
+
+ return json.loads(json_string)
tests/test_javascript_data_files.py (17712) → tests/test_javascript_data_files.py (17712)
diff --git a/tests/test_javascript_data_files.py b/tests/test_javascript_data_files.py
index 34eecd3..3446a02 100644
--- a/tests/test_javascript_data_files.py
+++ b/tests/test_javascript_data_files.py
@@ -92,7 +92,7 @@ class TestReadJs:
)
with pytest.raises(
- ValueError, match="does not start with JavaScript `const` declaration"
+ ValueError, match="Does not start with JavaScript `const` declaration"
):
read_js(js_path, varname="blueTriangle")