Add a function to append value to a JavaScript array
- ID
84a8f91- date
2024-08-17 07:04:46+00:00- author
Alex Chan <alex@alexwlchan.net>- parent
815cb70- message
Add a function to append value to a JavaScript array- changed files
3 files, 69 additions, 1 deletion
Changed files
README.md (573) → README.md (664)
diff --git a/README.md b/README.md
index 530f4d8..c16bab5 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@ Think of this module as the JSON module, but for JavaScript files.
* You can read a JavaScript file with `read_js(path, varname)`
* You can write a JavaScript file with `write_js(path, value, varname)`
+* You can append an item to a JavaScript array with `append_js_array_value(path, value)`
## Installation
src/javascript/__init__.py (1442) → src/javascript/__init__.py (2393)
diff --git a/src/javascript/__init__.py b/src/javascript/__init__.py
index aa95ed5..9e41dd6 100644
--- a/src/javascript/__init__.py
+++ b/src/javascript/__init__.py
@@ -1,4 +1,5 @@
import json
+import os
import pathlib
import typing
@@ -52,3 +53,32 @@ def write_js(p: pathlib.Path | str, *, value: typing.Any, varname: str) -> None:
with open(p, "w") as out_file:
out_file.write(js_string)
+
+
+def append_to_js_array(p: pathlib.Path | str, *, value: typing.Any) -> None:
+ """
+ Append a single value to an array in a JavaScript "data file".
+
+ Example:
+
+ >>> write_js('food.js', value=['apple', 'banana', 'coconut'], varname='fruit')
+ >>> append_to_js_array('food.js', value='damson')
+ >>> read_js('food.js', varname='fruit')
+ ['apple', 'banana', 'coconut', 'damson']
+
+ If you have a large file, this is usually faster than reading,
+ appending, and re-writing the entire file.
+
+ """
+ file_size = os.stat(p).st_size
+
+ json_to_append = b",\n" + json.dumps(value).encode("utf8") + b"\n];\n"
+
+ with open(p, "rb+") as out_file:
+ out_file.seek(file_size - 4)
+
+ if out_file.read(4) == b"\n];\n":
+ out_file.seek(file_size - 4)
+ out_file.write(json_to_append)
+ else:
+ raise ValueError(f"End of file {p!r} does not look like an array")
tests/test_javascript.py (2546) → tests/test_javascript.py (3796)
diff --git a/tests/test_javascript.py b/tests/test_javascript.py
index 97a6d93..d9b35cf 100644
--- a/tests/test_javascript.py
+++ b/tests/test_javascript.py
@@ -2,7 +2,7 @@ import pathlib
import pytest
-from javascript import read_js, write_js
+from javascript import append_to_js_array, read_js, write_js
class TestReadJs:
@@ -72,3 +72,40 @@ class TestWriteJs:
js_path.read_text()
== 'const redPentagon = {\n "sides": 5,\n "colour": "red"\n};\n'
)
+
+
+class TestAppendToArray:
+ def test_can_mix_types(self, tmp_path: pathlib.Path) -> None:
+ js_path = tmp_path / "food.js"
+
+ write_js(js_path, value=["apple", "banana", "coconut"], varname="fruit")
+ append_to_js_array(js_path, value=["damson"])
+ assert read_js(js_path, varname="fruit") == [
+ "apple",
+ "banana",
+ "coconut",
+ ["damson"],
+ ]
+
+ def test_error_if_file_doesnt_look_like_array(self, tmp_path: pathlib.Path) -> None:
+ js_path = tmp_path / "shape.js"
+ red_pentagon = {"sides": 5, "colour": "red"}
+
+ write_js(js_path, value=red_pentagon, varname="redPentagon")
+
+ with pytest.raises(ValueError, match="does not look like an array"):
+ append_to_js_array(js_path, value=["yellow"])
+
+
+class TestRoundTrip:
+ def test_can_append_to_file(self, tmp_path: pathlib.Path) -> None:
+ js_path = tmp_path / "food.js"
+
+ write_js(js_path, value=["apple", "banana", "coconut"], varname="fruit")
+ append_to_js_array(js_path, value="damson")
+ assert read_js(js_path, varname="fruit") == [
+ "apple",
+ "banana",
+ "coconut",
+ "damson",
+ ]