From 9762ee97ab3b664c2ecc249e6498be4b713c3883 Mon Sep 17 00:00:00 2001 From: Andrew Yim Date: Tue, 16 Jun 2026 19:35:13 +0900 Subject: [PATCH] feat(okf): add okf_common frontmatter/link parser with tests Co-Authored-By: Claude Opus 4.8 (1M context) --- .../code/scripts/okf_common.py | 78 +++++++++++++++++++ .../code/scripts/tests/test_okf_common.py | 47 +++++++++++ 2 files changed, 125 insertions(+) create mode 100644 custom-skills/97-ourdigital-okf/code/scripts/okf_common.py create mode 100644 custom-skills/97-ourdigital-okf/code/scripts/tests/test_okf_common.py diff --git a/custom-skills/97-ourdigital-okf/code/scripts/okf_common.py b/custom-skills/97-ourdigital-okf/code/scripts/okf_common.py new file mode 100644 index 0000000..21ca2f7 --- /dev/null +++ b/custom-skills/97-ourdigital-okf/code/scripts/okf_common.py @@ -0,0 +1,78 @@ +"""Shared OKF v0.1 parsing utilities (Python standard library only).""" +from __future__ import annotations + +import re +from pathlib import Path + +RESERVED = {"index.md", "log.md"} +_LINK_RE = re.compile(r"\[[^\]]*\]\(([^)]+)\)") + + +class FrontmatterError(ValueError): + """Raised when a frontmatter block is present but cannot be parsed.""" + + +def split_frontmatter(text): + """Return (raw_frontmatter, body). raw is None if there is no leading '---' block.""" + if not text.startswith("---"): + return None, text + lines = text.splitlines() + if lines[0].strip() != "---": + return None, text + for i in range(1, len(lines)): + if lines[i].strip() == "---": + return "\n".join(lines[1:i]), "\n".join(lines[i + 1:]) + raise FrontmatterError("opening '---' without a closing '---'") + + +def _scalar(value): + value = value.strip() + if len(value) >= 2 and value[0] == value[-1] and value[0] in "\"'": + return value[1:-1] + return value + + +def parse_yaml_subset(raw): + """Parse the small YAML subset OKF uses: `key: value` and `key: [a, b]`.""" + meta = {} + for line in raw.splitlines(): + stripped = line.strip() + if not stripped or stripped.startswith("#"): + continue + if ":" not in line: + raise FrontmatterError("unparseable frontmatter line: %r" % line) + key, _, value = line.partition(":") + key, value = key.strip(), value.strip() + if value.startswith("[") and value.endswith("]"): + inner = value[1:-1].strip() + meta[key] = [s for s in (_scalar(x) for x in inner.split(",")) if s] if inner else [] + else: + meta[key] = _scalar(value) + return meta + + +def parse_frontmatter(text): + """Return (meta, body). meta is None when no frontmatter block is present.""" + raw, body = split_frontmatter(text) + if raw is None: + return None, text + return parse_yaml_subset(raw), body + + +def iter_concepts(bundle_dir): + """Yield Path for every non-reserved .md file under bundle_dir, sorted.""" + root = Path(bundle_dir) + for path in sorted(root.rglob("*.md")): + if path.name not in RESERVED: + yield path + + +def concept_id(bundle_dir, path): + """Concept ID = bundle-relative path with the .md suffix removed.""" + rel = Path(path).relative_to(Path(bundle_dir)).as_posix() + return rel[:-3] if rel.endswith(".md") else rel + + +def extract_links(body): + """Return the list of link targets from markdown links in body.""" + return _LINK_RE.findall(body) diff --git a/custom-skills/97-ourdigital-okf/code/scripts/tests/test_okf_common.py b/custom-skills/97-ourdigital-okf/code/scripts/tests/test_okf_common.py new file mode 100644 index 0000000..c0db8fd --- /dev/null +++ b/custom-skills/97-ourdigital-okf/code/scripts/tests/test_okf_common.py @@ -0,0 +1,47 @@ +import sys, unittest +from pathlib import Path +sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) +from okf_common import (parse_frontmatter, parse_yaml_subset, + extract_links, concept_id, FrontmatterError) + + +class TestFrontmatter(unittest.TestCase): + def test_parse_basic(self): + text = "---\ntype: BigQuery Table\ntitle: Orders\ntags: [sales, revenue]\n---\n\n# Body\n" + meta, body = parse_frontmatter(text) + self.assertEqual(meta["type"], "BigQuery Table") + self.assertEqual(meta["title"], "Orders") + self.assertEqual(meta["tags"], ["sales", "revenue"]) + self.assertIn("# Body", body) + + def test_url_value_with_colons(self): + meta, _ = parse_frontmatter("---\ntype: X\nresource: https://e.com/a?b=c\n---\nbody") + self.assertEqual(meta["resource"], "https://e.com/a?b=c") + + def test_quoted_value(self): + self.assertEqual(parse_yaml_subset('okf_version: "0.1"')["okf_version"], "0.1") + + def test_empty_list(self): + self.assertEqual(parse_yaml_subset("tags: []")["tags"], []) + + def test_no_frontmatter(self): + meta, body = parse_frontmatter("# Just markdown\n") + self.assertIsNone(meta) + self.assertEqual(body, "# Just markdown\n") + + def test_unclosed_raises(self): + with self.assertRaises(FrontmatterError): + parse_frontmatter("---\ntype: X\n\nbody without close") + + +class TestLinksAndIds(unittest.TestCase): + def test_extract_links(self): + body = "See [a](/tables/a.md) and [b](./b.md) and [ext](https://x.com)." + self.assertEqual(extract_links(body), ["/tables/a.md", "./b.md", "https://x.com"]) + + def test_concept_id(self): + self.assertEqual(concept_id("/bundle", "/bundle/tables/users.md"), "tables/users") + + +if __name__ == "__main__": + unittest.main()