Skip to content

Commit 5426b54

Browse files
committed
1 parent 2dbdc12 commit 5426b54

File tree

2 files changed

+198
-0
lines changed

2 files changed

+198
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Prompts used are linked to from [the commit messages](https://github.com/simonw/
2525
- [Social media cropper](https://tools.simonwillison.net/social-media-cropper) - open or paste in an image, crop it to 2x1 and download a compressed JPEG for use as a social media card
2626
- [Writing Style Analyzer](https://tools.simonwillison.net/writing-style) - identify weasel words, passive voice, duplicate words - adapted from [these shell scripts](https://matt.might.net/articles/shell-scripts-for-passive-voice-weasel-words-duplicates/) published by Matt Might
2727
- [Navigation for headings](https://tools.simonwillison.net/nav-for-headings) - paste in an HTML document with headings, each heading is assigned a unique ID and the tool then generates a navigation `<ul>`
28+
- [JSON to YAML](https://tools.simonwillison.net/json-to-yaml) - convert JSON to YAML, showing different styles of YAML output
2829

2930
## LLM playgrounds and debuggers
3031

json-to-yaml.html

+197
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>JSON to YAML Converter</title>
7+
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-yaml/4.1.0/js-yaml.min.js"></script>
8+
<style>
9+
* {
10+
box-sizing: border-box;
11+
}
12+
13+
body {
14+
font-family: Helvetica, Arial, sans-serif;
15+
margin: 0;
16+
padding: 20px;
17+
background: #f5f5f5;
18+
max-width: 800px;
19+
margin: 0 auto;
20+
}
21+
22+
.panel {
23+
background: white;
24+
padding: 20px;
25+
border-radius: 8px;
26+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
27+
margin-bottom: 20px;
28+
}
29+
30+
textarea {
31+
width: 100%;
32+
height: 200px;
33+
padding: 12px;
34+
border: 1px solid #ddd;
35+
border-radius: 4px;
36+
font-family: monospace;
37+
font-size: 16px;
38+
resize: vertical;
39+
line-height: 1.4;
40+
}
41+
42+
.output-section {
43+
margin-top: 16px;
44+
}
45+
46+
.output-header {
47+
display: flex;
48+
justify-content: space-between;
49+
align-items: center;
50+
margin-bottom: 8px;
51+
}
52+
53+
label {
54+
display: block;
55+
margin-bottom: 8px;
56+
font-weight: bold;
57+
}
58+
59+
button {
60+
background: #2563eb;
61+
color: white;
62+
border: none;
63+
padding: 8px 16px;
64+
border-radius: 4px;
65+
cursor: pointer;
66+
font-size: 16px;
67+
}
68+
69+
button:hover {
70+
background: #1d4ed8;
71+
}
72+
73+
.error {
74+
color: #dc2626;
75+
margin-top: 8px;
76+
font-size: 14px;
77+
}
78+
</style>
79+
</head>
80+
<body>
81+
<div class="panel">
82+
<label for="jsonInput">JSON Input</label>
83+
<textarea id="jsonInput" placeholder="Paste your JSON here..."></textarea>
84+
<div id="error" class="error"></div>
85+
</div>
86+
87+
<div class="panel">
88+
<div class="output-section">
89+
<div class="output-header">
90+
<label>Block Style YAML</label>
91+
<button data-copy="block">Copy</button>
92+
</div>
93+
<textarea id="blockOutput" readonly></textarea>
94+
</div>
95+
96+
<div class="output-section">
97+
<div class="output-header">
98+
<label>Flow Style YAML (Compact)</label>
99+
<button data-copy="flow">Copy</button>
100+
</div>
101+
<textarea id="flowOutput" readonly></textarea>
102+
</div>
103+
104+
<div class="output-section">
105+
<div class="output-header">
106+
<label>Quoted Strings YAML</label>
107+
<button data-copy="quote">Copy</button>
108+
</div>
109+
<textarea id="quoteOutput" readonly></textarea>
110+
</div>
111+
</div>
112+
113+
<script type="module">
114+
const jsonInput = document.getElementById('jsonInput')
115+
const blockOutput = document.getElementById('blockOutput')
116+
const flowOutput = document.getElementById('flowOutput')
117+
const quoteOutput = document.getElementById('quoteOutput')
118+
const errorDiv = document.getElementById('error')
119+
120+
function convertToYaml() {
121+
const jsonStr = jsonInput.value
122+
errorDiv.textContent = ''
123+
124+
if (!jsonStr.trim()) {
125+
blockOutput.value = ''
126+
flowOutput.value = ''
127+
quoteOutput.value = ''
128+
return
129+
}
130+
131+
try {
132+
const jsonObj = JSON.parse(jsonStr)
133+
134+
// Block style
135+
blockOutput.value = jsyaml.dump(jsonObj, {
136+
indent: 2,
137+
noArrayIndent: true
138+
})
139+
140+
// Flow style (compact)
141+
flowOutput.value = jsyaml.dump(jsonObj, {
142+
flowLevel: 1,
143+
noArrayIndent: true
144+
})
145+
146+
// Quoted strings
147+
quoteOutput.value = jsyaml.dump(jsonObj, {
148+
styles: {
149+
'!!str': 'double'
150+
},
151+
noArrayIndent: true
152+
})
153+
} catch (err) {
154+
errorDiv.textContent = 'Invalid JSON: ' + err.message
155+
}
156+
}
157+
158+
jsonInput.addEventListener('input', convertToYaml)
159+
160+
document.querySelectorAll('button[data-copy]').forEach(button => {
161+
button.addEventListener('click', async () => {
162+
const style = button.dataset.copy
163+
const output = document.getElementById(style + 'Output')
164+
165+
try {
166+
await navigator.clipboard.writeText(output.value)
167+
const originalText = button.textContent
168+
button.textContent = 'Copied!'
169+
setTimeout(() => {
170+
button.textContent = originalText
171+
}, 2000)
172+
} catch (err) {
173+
errorDiv.textContent = 'Failed to copy: ' + err.message
174+
}
175+
})
176+
})
177+
178+
// Add some example JSON on load
179+
jsonInput.value = `{
180+
"models": [
181+
{
182+
"provider": "gemini",
183+
"model_id": "gemini-1.5-flash",
184+
"tiers": [
185+
{
186+
"max_tokens": 128000,
187+
"input_cost": 7,
188+
"output_cost": 30
189+
}
190+
]
191+
}
192+
]
193+
}`
194+
convertToYaml()
195+
</script>
196+
</body>
197+
</html>

0 commit comments

Comments
 (0)