| 71 | |
| 72 | |
| 73 | def parse_course(body: str, treat_h2_as_lessons: bool) -> Tuple[List[str], List[Module], Optional[str]]: |
| 74 | lines = body.splitlines() |
| 75 | intro_lines: List[str] = [] |
| 76 | modules: List[Module] = [] |
| 77 | hero_line: Optional[str] = None |
| 78 | |
| 79 | current_module: Optional[Module] = None |
| 80 | current_lesson: Optional[Lesson] = None |
| 81 | |
| 82 | h2_re = re.compile(r"^##\s+(.+?)\s*$") |
| 83 | h3_re = re.compile(r"^###\s+(.+?)\s*$") |
| 84 | |
| 85 | def flush_lesson(): |
| 86 | nonlocal current_lesson |
| 87 | if current_lesson and current_module: |
| 88 | while current_lesson.body_lines and not current_lesson.body_lines[-1].strip(): |
| 89 | current_lesson.body_lines.pop() |
| 90 | current_module.lessons.append(current_lesson) |
| 91 | current_lesson = None |
| 92 | |
| 93 | for raw in lines: |
| 94 | line = raw.rstrip("\n") |
| 95 | if hero_line is None and line.strip().startswith("![Hero image]"): |
| 96 | hero_line = line.strip() |
| 97 | continue |
| 98 | |
| 99 | m2 = h2_re.match(line) |
| 100 | m3 = h3_re.match(line) |
| 101 | |
| 102 | if m2: |
| 103 | flush_lesson() |
| 104 | title = m2.group(1).strip() |
| 105 | if treat_h2_as_lessons: |
| 106 | if current_module is None: |
| 107 | current_module = Module(title="Course Lessons", order=1) |
| 108 | modules.append(current_module) |
| 109 | current_lesson = Lesson( |
| 110 | module_title=current_module.title, |
| 111 | module_order=current_module.order, |
| 112 | title=title, |
| 113 | ) |
| 114 | else: |
| 115 | current_module = Module(title=title, order=len(modules) + 1) |
| 116 | modules.append(current_module) |
| 117 | continue |
| 118 | |
| 119 | if m3 and not treat_h2_as_lessons: |
| 120 | flush_lesson() |
| 121 | if current_module is None: |
| 122 | current_module = Module(title="Course Lessons", order=len(modules) + 1) |
| 123 | modules.append(current_module) |
| 124 | current_lesson = Lesson( |
| 125 | module_title=current_module.title, |
| 126 | module_order=current_module.order, |
| 127 | title=m3.group(1).strip(), |
| 128 | ) |
| 129 | continue |
| 130 | |