| 1136 | ignore_patterns = _load_graphifyignore(watch_root_for_ignore) |
| 1137 | |
| 1138 | class Handler(FileSystemEventHandler): |
| 1139 | def on_any_event(self, event): |
| 1140 | nonlocal last_trigger, pending |
| 1141 | if event.is_directory: |
| 1142 | return |
| 1143 | path = Path(os.fsdecode(event.src_path)) |
| 1144 | # Check .graphifyignore BEFORE the extension/dotfile/out filters so |
| 1145 | # the cheapest short-circuit for users with broad ignore patterns |
| 1146 | # (node_modules/, .venv/, build/, …) fires first. _is_ignored |
| 1147 | # tolerates absolute paths outside watch_root via its internal |
| 1148 | # relative_to guard, so a stray symlinked event won't raise. |
| 1149 | if ignore_patterns and _is_ignored(path, watch_root_for_ignore, ignore_patterns): |
| 1150 | return |
| 1151 | if path.suffix.lower() not in _WATCHED_EXTENSIONS: |
| 1152 | return |
| 1153 | try: |
| 1154 | filter_parts = path.relative_to(watch_root_for_ignore).parts |
| 1155 | except ValueError: |
| 1156 | filter_parts = path.parts |
| 1157 | if any(part.startswith(".") for part in filter_parts): |
| 1158 | return |
| 1159 | if _GRAPHIFY_OUT in filter_parts: |
| 1160 | return |
| 1161 | last_trigger = time.monotonic() |
| 1162 | pending = True |
| 1163 | changed.add(path) |
| 1164 | |
| 1165 | handler = Handler() |
| 1166 | # Use polling observer on macOS — FSEvents can miss rapid saves in some editors |