Skip to main content

CHANGELOG.md

1# CHANGELOG
3## v1.4.1 - 2025-08-15
5Fix the yanked v1.4.0 release, and make sure it includes the correct code.
7## v1.4.0 - 2025-08-15
9Add an `ensure_ascii` parameter to `write_js`.
10If `True`, all incoming ASCII characters will be escaped, otherwise they will be left as-is.
11Default is `False`.
13This changes the default output of `write_js`.
14Before, it would escape any incoming ASCII characters, for example `“hello world”` would be encoded as:
16```json
17"\u201chello world\u201d"
18```
20With the new behaviour, it will be encoded as:
22```json
23“hello world”
24```
26unless you explicitly pass `ensure_ascii=True`.
28This mirrors the parameter on the builtin `json.dumps()`, but with a different default.
30## v1.3.0 - 2025-05-05
32Add a `sort_keys` parameter to `write_js`.
33If `True`, dictionaries with be serialised to JSON sorted by key.
34Default `False`.
36This mirrors the parameter on the builtin `json.dumps()`.
38## v1.2.3 - 2025-05-04
40Tweak the error message introduced in v1.2.2 -- JSON objects are **name**/value pairs, not key/value pairs.
42## v1.2.2 - 2025-05-03
44Duplicate keys in JSON objects are now rejected as an error.
46For example, consider the following JavaScript:
48```javascript
49const shape = {"sides": "5", "colour": "red", "sides": 4};
50```
52These duplicate keys are technically allowed by the JSON specification, but are always a mistake when I encounter them.
53Many JSON parsers will silently drop the first instance of `sides`, including both Python's and web browsers.
55Previously `read_js` would read this file and silently drop the first key, but now it throws a `ValueError` and prompts you to de-duplicate the key.
57## v1.2.1 - 2025-04-13
59Fix a bug in the validation of `typing.Union[A, B]` where both types are a `TypedDict`.
61The validation is stricter, and will require an exact match to either `A` or `B` -- previously it was possible for data to validate that was only a "partial" match, and this could cause data to be lost.
62This was only possible in cases where the fields of `A` were a strict subset of the fields of `B`, and you passed a value which used more fields than `A` but less than `B`.
64For example, consider the following type:
66```python
67BasicShape = typing.TypedDict("Shape", {"sides": int, })
68NamedShape = typing.TypedDict("Shape", {"sides": int, "colour": str, "name": str })
70Shape = BasicShape | NamedShape
71```
73if you passed the data:
75```javascript
76const shape = {"sides": "5", "colour": "red"};
77```
79this isn't a strict match for `BasicShape` or `NamedShape`, but would be incorrectly validated and returned as `{'sides': 5}`.
81Now this throws a `pydantic.ValidationError`.
83## v1.2.0 - 2025-03-07
85This adds a new function `read_typed_js`, which is like `read_js` but will additionally validate the data against a type you specify.
87* `read_js()` returns `typing.Any`, and will always return something if the file contains valid JSON
88* `read_typed_js` returns `T`, where `T` is the type you specify as `model`.
89 This will only return if the file contains JSON that matches the type, and otherwise it will throw a `pydantic.ValidationError`.
91This is useful if you want to check your data or you write typed Python.
93You need to install the typed extra to get this function, i.e. `pip install javascript-data-files[typed]`.
95## v1.1.1 - 2025-01-10
97Tweak the way the JavaScript is encoded to make it slightly more compact and readable -- in particular, short lists will now be encoded as a single line, rather than split across multiple lines.
99Before:
101```json
103 1,
104 2,
105 3
107```
109After:
111```json
112[1, 2, 3]
113```
115The value is the same but should be more readable.
116This opens the door to more readability improvements in the future.
118## v1.1.0 - 2025-01-10
120You can now call `write_js()` with a file-like object.
121This can be text I/O or as binary I/O.
123This gives you more control over how the file is written -- for example, you can open the file in "exclusive creation" mode to prevent overwriting an existing file:
125```python
126with open("shape.js", "x") as out_file:
127 write_js(
128 out_file,
129 value={"sides": 5, "colour": "red"},
130 varname="redPentagon"
131 )
132```
134## v1.0.1 - 2024-08-26
136When you call `append_to_js_array()` or `append_to_js_object()`, previously the new value would all be smushed onto one line.
137Now it's written with 2 spaces of indentation, to match `write_js()`.
139## v1.0.0 - 2024-08-24
141Initial release. This includes four functions:
143* Read a JavaScript file with `read_js(path, varname)`
144* Write a JavaScript file with `write_js(path, value, varname)`
145* Append an item to a JavaScript array with `append_to_js_array(path, value)`
146* Append a key-value pair to a JavaScript object with `append_to_js_object(path, key, value)`
148## v0.0.1 - 2024-08-24
150Initial release on PyPI, to test the release mechanism.