diff --git a/docker/create_meta.py b/docker/create_meta.py new file mode 100644 index 0000000..a2078bd --- /dev/null +++ b/docker/create_meta.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python3 +""" +This code is generate by ChatGPT 5.1, as test automatic script to generate _meta.js file + +Generate _meta.js with Math/CSE link entries and labeled sections +from the original _meta.js. + +Usage: + python generate_meta.py [path/to/_meta.js] + +If no path is given, it assumes _meta.js is next to this script. +""" + +import sys +from pathlib import Path +import re + + +COMMENT_BLOCK = [ + " /**\n", + ' * Do not remove the labels "Math Courses Start"\n', + ' * and "Math Courses End" and "CSE Courses Start" and "CSE Courses End"\n', + " * or the separated builds will not work.\n", + " * \n", + " * WE USE THESE LABELS TO BUILD THE SEPARATED WEBSITES FOR MATH AND CSE COURSES.\n", + " */\n", +] + + +def parse_properties(lines): + """ + Parse top-level properties (indented 4 spaces) of the export default object. + Returns: + header_lines: lines up to and including 'export default {' + footer_lines: closing '}' (and anything after) + props: dict name -> list of lines for that property + order: order of property names as they appeared + """ + # find 'export default {' line + export_idx = None + for i, line in enumerate(lines): + if "export default" in line: + export_idx = i + break + if export_idx is None: + raise ValueError("No 'export default' found in file.") + + header = lines[: export_idx + 1] + body = lines[export_idx + 1 :] + + # last non-empty line is closing brace of the object + last_non_empty = len(lines) - 1 + while last_non_empty >= 0 and lines[last_non_empty].strip() == "": + last_non_empty -= 1 + footer = lines[last_non_empty:] + + body_until_footer = body[: len(body) - len(footer) + 1] # include blank before footer if any + + prop_re = re.compile(r"^ {4}(\w+)\s*:") + props = {} + order = [] + + i = 0 + n = len(body_until_footer) + while i < n: + line = body_until_footer[i] + m = prop_re.match(line) + if not m: + i += 1 + continue + key = m.group(1) + start = i + brace_count = line.count("{") - line.count("}") + j = i + 1 + while j < n and brace_count > 0: + brace_count += body_until_footer[j].count("{") - body_until_footer[j].count("}") + j += 1 + block = body_until_footer[start:j] + props[key] = block + order.append(key) + i = j + + return header, footer, props, order + + +def build_links_block(keys): + """Generate *_link blocks for given course keys (Math* or CSE*).""" + out = [] + for k in keys: + out.append(f" {k}_link: {{\n") + out.append(f" title: '{k}',\n") + out.append(" type: 'page',\n") + out.append(f" href: '/{k}'\n") + out.append(" },\n") + return out + + +def generate_new_meta(lines): + header, footer, props, order = parse_properties(lines) + + math_keys = [k for k in order if k.startswith("Math")] + cse_keys = [k for k in order if k.startswith("CSE")] + other_keys = [k for k in order if k not in math_keys + cse_keys + ["menu"]] + + if "menu" not in props: + raise ValueError("Expected a top-level 'menu' property.") + + out = [] + + # header (includes "export default {") + out.extend(header) + # comment block + out.extend(COMMENT_BLOCK) + # menu + out.extend(props["menu"]) + + # Math links + out.extend(build_links_block(math_keys)) + + # Math Courses section + out.append(" /* Math Courses Start */\n") + for k in math_keys: + out.extend(props[k]) + out.append(" /* Math Courses End */\n") + + # CSE links + out.extend(build_links_block(cse_keys)) + + # CSE Courses section + out.append(" /* CSE Courses Start */\n") + for k in cse_keys: + out.extend(props[k]) + out.append(" /* CSE Courses End */\n") + + # other properties (Swap, index, about, contact, etc.) in original order + for k in other_keys: + out.extend(props[k]) + + # footer (closing brace, etc.) + out.extend(footer) + + return out + + +def main(): + if len(sys.argv) > 1: + meta_path = Path(sys.argv[1]).resolve() + else: + meta_path = Path(__file__).with_name("_meta.js") + + if not meta_path.exists(): + raise SystemExit(f"Meta file not found: {meta_path}") + + lines = meta_path.read_text(encoding="utf-8").splitlines(keepends=True) + new_lines = generate_new_meta(lines) + meta_path.write_text("".join(new_lines), encoding="utf-8") + print(f"Rewrote meta file at {meta_path}") + + +if __name__ == "__main__": + main()