-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcombine.py
More file actions
124 lines (99 loc) · 3.24 KB
/
Copy pathcombine.py
File metadata and controls
124 lines (99 loc) · 3.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#!/usr/bin/env python3
"""
Combines multiple source files into a single Markdown document.
Usage:
python combine.py path/to/file1.js path/to/file2.ts path/to/file3.prisma
python combine.py $(cat filelist.txt)
Output:
Creates 'combined_output.md' in the current directory.
"""
import sys
import os
# Map file extensions to markdown language identifiers
EXTENSION_MAP = {
'.js': 'js',
'.jsx': 'jsx',
'.ts': 'ts',
'.tsx': 'tsx',
'.py': 'python',
'.prisma': 'prisma',
'.json': 'json',
'.sql': 'sql',
'.html': 'html',
'.css': 'css',
'.yml': 'yaml',
'.yaml': 'yaml',
'.md': 'markdown',
'.env': 'env',
'.sh': 'bash',
'.bash': 'bash',
'.txt': 'text',
'.xml': 'xml',
'.toml': 'toml',
'.graphql': 'graphql',
'.dockerfile': 'dockerfile',
}
def get_language(filepath: str) -> str:
"""Determine the markdown code fence language from file extension."""
_, ext = os.path.splitext(filepath)
ext = ext.lower()
# Handle special filenames without typical extensions
basename = os.path.basename(filepath).lower()
if basename == 'dockerfile':
return 'dockerfile'
if basename == '.env' or basename.startswith('.env'):
return 'env'
return EXTENSION_MAP.get(ext, ext.lstrip('.') or 'text')
def combine_files(filepaths: list[str], output_path: str = 'combined_output.md'):
"""Read all files and write them into a single markdown document."""
found = []
missing = []
for fp in filepaths:
if os.path.isfile(fp):
found.append(fp)
else:
missing.append(fp)
if missing:
print(f"\n⚠️ {len(missing)} file(s) not found:")
for m in missing:
print(f" ✗ {m}")
if not found:
print("\n❌ No valid files to process. Exiting.")
sys.exit(1)
lines = []
for fp in found:
lang = get_language(fp)
# Normalize path separators for display
display_path = fp.replace('\\', '/')
try:
with open(fp, 'r', encoding='utf-8', errors='replace') as f:
content = f.read()
except Exception as e:
print(f" ⚠️ Could not read {fp}: {e}")
content = f"# ERROR: Could not read file — {e}"
lines.append(f"## `{display_path}`")
lines.append(f"```{lang}")
lines.append(content.rstrip())
lines.append("```")
lines.append("") # blank line between files
output = '\n'.join(lines)
with open(output_path, 'w', encoding='utf-8') as f:
f.write(output)
print(f"\n✅ Combined {len(found)} file(s) → {output_path}")
print(f" Size: {len(output):,} characters")
if missing:
print(f" ⚠️ Skipped {len(missing)} missing file(s)")
def main():
if len(sys.argv) < 2:
print("Usage: python combine.py <file1> <file2> <file3> ...")
print("")
print("Example:")
print(" python combine.py backend/prisma/schema.prisma backend/server.js")
print("")
print("Tip: You can also pipe a file list:")
print(" python combine.py $(cat files_to_send.txt)")
sys.exit(1)
filepaths = sys.argv[1:]
combine_files(filepaths)
if __name__ == '__main__':
main()