Skip to content

Instantly share code, notes, and snippets.

@skorotkiewicz
Created December 6, 2025 06:44
Show Gist options
  • Select an option

  • Save skorotkiewicz/359d3b48d71cd085886a494a2c81208b to your computer and use it in GitHub Desktop.

Select an option

Save skorotkiewicz/359d3b48d71cd085886a494a2c81208b to your computer and use it in GitHub Desktop.
The tool stores comments in a .jsonc file and maintains clean JSON in the original file.
#!/usr/bin/env python3
"""
JSON with Comments editor - Edit JSON files with comments
Usage:
./jsonc <file> - Edit JSON with comments in your editor
cat <file> - View clean JSON without comments
The tool stores comments in a .jsonc file and maintains clean JSON in the original file.
"""
import sys
import json
import os
import subprocess
import tempfile
import re
def strip_comments(text):
"""Remove // and /* */ style comments from JSON text"""
# Remove /* */ comments
text = re.sub(r'/\*.*?\*/', '', text, flags=re.DOTALL)
# Remove // comments
lines = []
for line in text.split('\n'):
in_string = False
escape = False
for i, char in enumerate(line):
if escape:
escape = False
continue
if char == '\\':
escape = True
continue
if char == '"':
in_string = not in_string
if char == '/' and i + 1 < len(line) and line[i + 1] == '/' and not in_string:
line = line[:i]
break
lines.append(line)
return '\n'.join(lines)
def edit_json(json_path):
"""Edit JSON with comments"""
base = os.path.splitext(json_path)[0]
jsonc_path = base + '.jsonc'
# Determine what content to edit
if os.path.exists(jsonc_path):
# Edit existing .jsonc file
with open(jsonc_path, 'r') as f:
content = f.read()
elif os.path.exists(json_path):
# Create .jsonc from existing .json
with open(json_path, 'r') as f:
content = f.read()
print(f"Creating {jsonc_path} from {json_path}")
else:
# Create new file with template
content = """{
// Add your configuration here
"example": "value"
}"""
print(f"Creating new files: {json_path} and {jsonc_path}")
# Open in editor
editor = os.environ.get('EDITOR', 'nano')
with tempfile.NamedTemporaryFile(mode='w', suffix='.jsonc', delete=False) as tf:
tf.write(content)
temp_path = tf.name
try:
subprocess.run([editor, temp_path], check=True)
# Read edited content
with open(temp_path, 'r') as f:
new_content = f.read()
# Validate JSON
try:
data = json.loads(strip_comments(new_content))
except json.JSONDecodeError as e:
print(f"Error: Invalid JSON: {e}", file=sys.stderr)
sys.exit(1)
# Save .jsonc with comments
with open(jsonc_path, 'w') as f:
f.write(new_content)
# Save .json without comments (pretty-printed)
with open(json_path, 'w') as f:
json.dump(data, f, indent=2)
print(f"Saved {json_path} (clean) and {jsonc_path} (with comments)")
finally:
os.unlink(temp_path)
def main():
if len(sys.argv) < 2:
print(__doc__)
sys.exit(1)
edit_json(sys.argv[1])
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment