✨ feat(tsl-codegen): add decoupled documentation toolkit
Generate TSL API Markdown from YAML or JSON into a configurable project scope.\nAdd file and directory lint modes, tags-aware indexing, and keyword search across tags and descriptions.\nBundle the toolkit through the playbook build and sync workflows.
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
import importlib.util
|
||||
import io
|
||||
import tempfile
|
||||
import unittest
|
||||
from contextlib import redirect_stderr, redirect_stdout
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
SCRIPT_PATH = (
|
||||
Path(__file__).resolve().parents[1]
|
||||
/ "scripts"
|
||||
/ "build_index.py"
|
||||
)
|
||||
|
||||
|
||||
def load_script():
|
||||
spec = importlib.util.spec_from_file_location(
|
||||
"tsl_codegen_function_index", SCRIPT_PATH
|
||||
)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
class FunctionIndexTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.temp_dir = tempfile.TemporaryDirectory()
|
||||
self.skill_dir = Path(self.temp_dir.name) / "tsl-api-reference"
|
||||
self.codegen_root = self.skill_dir / "references" / "codegen"
|
||||
self.data_dir = self.skill_dir / "data"
|
||||
leaf = self.codegen_root / "builtin" / "base" / "array.md"
|
||||
leaf.parent.mkdir(parents=True)
|
||||
leaf.write_text(
|
||||
"# Builtin - 基础 / 数组\n\n"
|
||||
"## `demo()`\n\n"
|
||||
"<!-- tags: 数组 列表 -->\n\n"
|
||||
"返回示例值。\n\n"
|
||||
"返回:integer\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
self.module = load_script()
|
||||
|
||||
def tearDown(self):
|
||||
self.temp_dir.cleanup()
|
||||
|
||||
def run_main(self, *args):
|
||||
stdout = io.StringIO()
|
||||
stderr = io.StringIO()
|
||||
with redirect_stdout(stdout), redirect_stderr(stderr):
|
||||
result = self.module.main(["--skill-dir", str(self.skill_dir), *args])
|
||||
return result, stdout.getvalue(), stderr.getvalue()
|
||||
|
||||
def test_rebuild_writes_only_tsv(self):
|
||||
result, _, _ = self.run_main()
|
||||
|
||||
self.assertEqual(0, result)
|
||||
self.assertTrue((self.data_dir / "function_index.tsv").is_file())
|
||||
self.assertEqual([], list(self.codegen_root.rglob("index.md")))
|
||||
|
||||
def test_tags_and_summary_are_stored_separately(self):
|
||||
rows = self.module.build_rows(self.codegen_root)
|
||||
row = dict(zip(self.module.HEADER, rows[0]))
|
||||
|
||||
self.assertEqual("数组 列表", row["tags"])
|
||||
self.assertEqual("返回示例值。", row["summary"])
|
||||
|
||||
def test_check_does_not_require_index_pages(self):
|
||||
self.data_dir.mkdir(parents=True)
|
||||
rows = self.module.build_rows(self.codegen_root)
|
||||
(self.data_dir / "function_index.tsv").write_text(
|
||||
self.module.render_tsv(rows),
|
||||
encoding="utf-8",
|
||||
newline="\n",
|
||||
)
|
||||
|
||||
result, stdout, _ = self.run_main("--check")
|
||||
|
||||
self.assertEqual(0, result)
|
||||
self.assertIn("matches md tree", stdout)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user