|
17 | 17 | import jsonref |
18 | 18 | from pydantic import BaseModel |
19 | 19 | import click |
| 20 | +import re |
20 | 21 |
|
21 | 22 |
|
22 | 23 | def run_command(cmd: str): |
@@ -51,9 +52,43 @@ def generate_typescript_interfaces(schema_dir: Path): |
51 | 52 | run_command( |
52 | 53 | f"npx -y json-schema-to-typescript@15.0.4 -i '{schema_dir / '*.json'}' -o {schema_dir}" |
53 | 54 | ) |
| 55 | + post_process_typescript_declarations(schema_dir) |
54 | 56 | run_command(f"npx -y prettier@3.5.1 --write {schema_dir}") |
55 | 57 |
|
56 | 58 |
|
| 59 | +def post_process_typescript_declarations(schema_dir: Path) -> None: |
| 60 | + """Replace index signature value type with JSONObject and insert import. |
| 61 | +
|
| 62 | + - Turns `[k: string]: unknown;` and `[k: string]: any;` into `[k: string]: JSONObject;` |
| 63 | + - Adds `import type { JSONObject } from '@llamaindex/ui';` if needed |
| 64 | + """ |
| 65 | + index_signature_unknown_pattern = re.compile(r"\[k:\s*string\]:\s*unknown;?") |
| 66 | + index_signature_any_pattern = re.compile(r"\[k:\s*string\]:\s*any;?") |
| 67 | + import_statement = "import type { JSONObject } from '@llamaindex/ui';\n" |
| 68 | + import_regex = re.compile(r"import\s+type\s+\{\s*JSONObject\s*\}\s+from\s+'@llamaindex/ui';") |
| 69 | + |
| 70 | + for dts_path in schema_dir.glob("*.d.ts"): |
| 71 | + content = dts_path.read_text(encoding="utf-8") |
| 72 | + |
| 73 | + # Replace index signature value types |
| 74 | + new_content = index_signature_unknown_pattern.sub("[k: string]: JSONObject;", content) |
| 75 | + new_content = index_signature_any_pattern.sub("[k: string]: JSONObject;", new_content) |
| 76 | + |
| 77 | + # Insert import if JSONObject is used and import not present |
| 78 | + if "JSONObject" in new_content and not import_regex.search(new_content): |
| 79 | + # Try to place after the generator banner if present, else at file start |
| 80 | + insertion_index = 0 |
| 81 | + banner_end = new_content.find("*/") |
| 82 | + if banner_end != -1: |
| 83 | + # Move to the next newline after banner |
| 84 | + next_newline = new_content.find("\n", banner_end + 2) |
| 85 | + insertion_index = next_newline + 1 if next_newline != -1 else banner_end + 2 |
| 86 | + new_content = new_content[:insertion_index] + import_statement + new_content[insertion_index:] |
| 87 | + |
| 88 | + if new_content != content: |
| 89 | + dts_path.write_text(new_content, encoding="utf-8") |
| 90 | + |
| 91 | + |
57 | 92 | def load_module_from_path(module_name: str, file_path: Path) -> ModuleType: |
58 | 93 | spec = importlib.util.spec_from_file_location(module_name, file_path) |
59 | 94 | if spec is None or spec.loader is None: |
|
0 commit comments