Skip to content

Commit 1c853ed

Browse files
fix: quote strings containing [N]: patterns, reorder decoder (v2.1.1)
Same fix as gcf-typescript v2.1.2. Encoder quotes inline array patterns in string values. Decoder checks key=value before inline array detection. 213 tests pass, 0 failures.
1 parent 62a6e0b commit 1c853ed

3 files changed

Lines changed: 22 additions & 10 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "gcf-python"
7-
version = "2.1.0"
7+
version = "2.1.1"
88
description = "Drop-in JSON replacement for AI pipelines. 79% fewer tokens. 90.7% comprehension across 10 models. Zero dependencies."
99
readme = "README.md"
1010
license = {text = "MIT"}

src/gcf/decode_generic.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,17 @@ def _parse_object_body(
151151
i += consumed
152152
continue
153153

154+
# Key=value. Check before inline array so bracket patterns in quoted
155+
# values (e.g. text="ERR[404]: Not Found") are not misinterpreted.
156+
eq_idx = _find_kv_split(content)
157+
if eq_idx > 0:
158+
name = _parse_key_from_header(content[:eq_idx])
159+
_check_dup(out, name)
160+
out[name] = parse_scalar(content[eq_idx + 1:])
161+
i += 1
162+
continue
163+
164+
# Inline array (e.g. items[3]: a,b,c). Only reached if no = found.
154165
if not content.startswith("@") and not content.startswith("##"):
155166
bracket_idx = content.find("[")
156167
if bracket_idx > 0:
@@ -166,14 +177,6 @@ def _parse_object_body(
166177
i += 1
167178
continue
168179

169-
eq_idx = _find_kv_split(content)
170-
if eq_idx > 0:
171-
name = _parse_key_from_header(content[:eq_idx])
172-
_check_dup(out, name)
173-
out[name] = parse_scalar(content[eq_idx + 1:])
174-
i += 1
175-
continue
176-
177180
i += 1
178181
return i - start
179182

@@ -191,7 +194,13 @@ def _find_kv_split(s: str) -> int:
191194
return i + 1 if i + 1 < len(s) and s[i + 1] == "=" else -1
192195
i += 1
193196
return -1
194-
return s.find("=")
197+
eq_idx = s.find("=")
198+
if eq_idx < 0:
199+
return -1
200+
bracket_idx = s.find("[")
201+
if bracket_idx >= 0 and bracket_idx < eq_idx:
202+
return -1
203+
return eq_idx
195204

196205

197206
def _parse_key_from_header(s: str) -> str:

src/gcf/scalar.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
_JSON_NUMBER_RE = re.compile(r"^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$")
1010
_NUMERIC_LIKE_RE = re.compile(r"^[+-]\.?\d|^\.\d|^0\d")
11+
_INLINE_ARRAY_RE = re.compile(r"\[[^\]]*\]\s*:")
1112
_BARE_KEY_RE = re.compile(r"^[a-zA-Z_][a-zA-Z0-9_]*$")
1213

1314

@@ -36,6 +37,8 @@ def needs_quote(s: str) -> bool:
3637
return True
3738
if s[0] in ("#", "@", "."):
3839
return True
40+
if _INLINE_ARRAY_RE.search(s):
41+
return True
3942
for c in s:
4043
o = ord(c)
4144
if c in ('"', "\\", "|", ",") or o < 0x20 or c in ("\n", "\r"):

0 commit comments

Comments
 (0)