|
13 | 13 | import os |
14 | 14 | import re |
15 | 15 | import sys |
| 16 | +import subprocess |
16 | 17 | from pathlib import Path |
17 | 18 |
|
18 | 19 |
|
19 | 20 | def minify_cpp(code): |
20 | | - """Minify C++ code while preserving header guards and removing unnecessary whitespace.""" |
21 | | - lines = code.split('\n') |
22 | | - result = [] |
23 | | - in_multiline_comment = False |
24 | | - header_guard = None |
25 | | - endif_lines = [] |
26 | | - |
27 | | - for i, line in enumerate(lines): |
28 | | - stripped = line.strip() |
29 | | - |
30 | | - # Handle multiline comments |
31 | | - if '/*' in stripped: |
32 | | - in_multiline_comment = True |
33 | | - if '*/' in stripped: |
34 | | - in_multiline_comment = False |
35 | | - continue |
36 | | - if in_multiline_comment: |
37 | | - continue |
38 | | - |
39 | | - # Remove single-line comments |
40 | | - if '//' in stripped: |
41 | | - stripped = stripped.split('//')[0].strip() |
42 | | - |
43 | | - # Skip empty lines |
44 | | - if not stripped: |
45 | | - continue |
46 | | - |
47 | | - # Detect and preserve header guards |
48 | | - if stripped.startswith('#ifndef '): |
49 | | - header_guard = stripped |
50 | | - result.append(stripped) |
51 | | - continue |
52 | | - elif stripped.startswith('#define ') and header_guard and len(result) == 1: |
53 | | - result.append(stripped) |
54 | | - continue |
55 | | - elif stripped == '#endif' and header_guard: |
56 | | - endif_lines.append(stripped) |
57 | | - continue |
58 | | - |
59 | | - # Keep preprocessor directives as-is (they need to be on own lines) |
60 | | - if stripped.startswith('#'): |
61 | | - result.append(stripped) |
62 | | - continue |
63 | | - |
64 | | - # Compress spaces in code lines (but preserve strings) |
65 | | - def compress_line(line): |
66 | | - # Split by strings to preserve their content |
67 | | - parts = re.split(r'("(?:[^"\\]|\\.)*")', line) |
68 | | - for i in range(0, len(parts), 2): |
69 | | - # Compress multiple spaces to one |
70 | | - parts[i] = re.sub(r'\s+', ' ', parts[i]) |
71 | | - # Remove spaces around operators (but keep space for clarity in some cases) |
72 | | - parts[i] = re.sub(r'\s*([+\-*/%=<>!&|^~,;:?(){}[\]])\s*', r'\1', parts[i]) |
73 | | - # Remove leading/trailing spaces |
74 | | - parts[i] = parts[i].strip() |
75 | | - return ''.join(parts) |
76 | | - |
77 | | - compressed = compress_line(stripped) |
78 | | - if compressed: |
79 | | - result.append(compressed) |
80 | | - |
81 | | - # Join lines - try to put on same line when possible |
82 | | - code = '\n'.join(result) |
83 | | - |
84 | | - # Remove newlines after opening braces and before closing braces |
85 | | - code = re.sub(r'\{\n', '{', code) |
86 | | - code = re.sub(r'\n\}', '}', code) |
87 | | - |
88 | | - # Remove newlines around colons in class/struct definitions |
89 | | - code = re.sub(r'\n:', ':', code) |
90 | | - code = re.sub(r':\n', ':', code) |
91 | | - |
92 | | - # Remove multiple consecutive newlines (keep max 1) |
93 | | - code = re.sub(r'\n\n+', '\n', code) |
94 | | - |
95 | | - # Add back endif if we had header guards |
96 | | - if endif_lines: |
97 | | - code = code + '\n' + '\n'.join(endif_lines) |
98 | | - |
99 | | - return code |
| 21 | + """Delegate to the shared minifier so CI and local minified files match.""" |
| 22 | + minifier = Path(__file__).resolve().parents[2] / 'cp-algo/minify.py' |
| 23 | + try: |
| 24 | + result = subprocess.run( |
| 25 | + ['python3', str(minifier)], |
| 26 | + input=code, |
| 27 | + capture_output=True, |
| 28 | + text=True, |
| 29 | + check=True, |
| 30 | + ) |
| 31 | + return result.stdout |
| 32 | + except FileNotFoundError: |
| 33 | + print(f"Warning: minifier not found at {minifier}, skipping minification", file=sys.stderr) |
| 34 | + return code |
| 35 | + except subprocess.CalledProcessError as e: |
| 36 | + print(f"Warning: minifier failed ({e}); skipping minification", file=sys.stderr) |
| 37 | + if e.stdout: |
| 38 | + return e.stdout |
| 39 | + return code |
100 | 40 |
|
101 | 41 |
|
102 | 42 | def process_file(bundled_path, minified_path, committed_path=None): |
|
0 commit comments