themebooth 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +57 -0
- package/README.md +1 -0
- package/dist/bin/themebooth.js +27 -0
- package/dist/bin/themebooth.js.map +1 -1
- package/dist/cli/validate.d.ts +7 -0
- package/dist/cli/validate.d.ts.map +1 -0
- package/dist/cli/validate.js +689 -0
- package/dist/cli/validate.js.map +1 -0
- package/dist/core/colors.d.ts +11 -0
- package/dist/core/colors.d.ts.map +1 -0
- package/dist/core/colors.js +214 -0
- package/dist/core/colors.js.map +1 -0
- package/dist/core/schemas.d.ts.map +1 -1
- package/dist/core/schemas.js +3 -3
- package/dist/core/schemas.js.map +1 -1
- package/dist/preview/renderer.d.ts.map +1 -1
- package/dist/preview/renderer.js +578 -117
- package/dist/preview/renderer.js.map +1 -1
- package/package.json +1 -1
package/dist/preview/renderer.js
CHANGED
|
@@ -7,47 +7,45 @@ function generateColorPalette(manifest, resolved) {
|
|
|
7
7
|
for (const [name, color] of Object.entries(manifest.variables || {})) {
|
|
8
8
|
const resolvedColor = resolved[name] || color;
|
|
9
9
|
html += `
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
<div class="color-box">
|
|
11
|
+
<div class="swatch" style="background-color: ${resolvedColor};"></div>
|
|
12
|
+
<div class="name">${name}</div>
|
|
13
|
+
<div class="value">${resolvedColor}</div>
|
|
14
|
+
</div>`;
|
|
15
15
|
}
|
|
16
16
|
return html;
|
|
17
17
|
}
|
|
18
18
|
function generateCSSFromTheme(manifest) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
css +=
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
css += "}\n";
|
|
32
|
-
css +=
|
|
33
|
-
css +=
|
|
34
|
-
|
|
35
|
-
css += "font-style: italic; ";
|
|
36
|
-
css += "}\n";
|
|
37
|
-
css += `.number { color: ${manifest.tokens?.number?.foreground || "#b5cea8"}; }\n`;
|
|
38
|
-
css += `.builtin { color: ${manifest.tokens?.["constant.builtin"]?.foreground || "#4ec9b0"}; }\n`;
|
|
19
|
+
const keywordColor = manifest.tokens?.keyword?.foreground || "#569cd6";
|
|
20
|
+
const stringColor = manifest.tokens?.string?.foreground || "#ce9178";
|
|
21
|
+
const commentColor = manifest.tokens?.comment?.foreground || "#6a9955";
|
|
22
|
+
const numberColor = manifest.tokens?.number?.foreground || "#b5cea8";
|
|
23
|
+
const builtinColor = manifest.tokens?.["constant.builtin"]?.foreground || "#4ec9b0";
|
|
24
|
+
const typeColor = manifest.tokens?.["entity.name.type"]?.foreground || "#4ec9b0";
|
|
25
|
+
const methodColor = manifest.tokens?.["entity.name.function"]?.foreground || "#dcdcaa";
|
|
26
|
+
const operatorColor = manifest.tokens?.operator?.foreground || "#d4d4d4";
|
|
27
|
+
let css = ".keyword { color: " + keywordColor + "; font-weight: bold; }\n";
|
|
28
|
+
css += ".string { color: " + stringColor + "; }\n";
|
|
29
|
+
css += ".comment { color: " + commentColor + "; font-style: italic; }\n";
|
|
30
|
+
css += ".number { color: " + numberColor + "; }\n";
|
|
31
|
+
css += ".builtin { color: " + builtinColor + "; }\n";
|
|
32
|
+
css += ".type { color: " + typeColor + "; }\n";
|
|
33
|
+
css += ".method { color: " + methodColor + "; }\n";
|
|
34
|
+
css += ".operator { color: " + operatorColor + "; }\n";
|
|
39
35
|
return css;
|
|
40
36
|
}
|
|
41
37
|
function renderPreview(manifest, themeName) {
|
|
42
|
-
// Resolve variables for color display
|
|
43
38
|
const variableResolution = (0, variables_1.resolveVariables)(manifest);
|
|
44
39
|
const resolved = variableResolution.success ? variableResolution.variables : {};
|
|
45
|
-
// Get interpolated manifest for rendering
|
|
46
40
|
const interpolated = variableResolution.success ?
|
|
47
41
|
(0, variables_1.interpolateManifest)(manifest, resolved)
|
|
48
42
|
: manifest;
|
|
49
43
|
const colorPalette = generateColorPalette(manifest, resolved);
|
|
50
44
|
const themeCSS = generateCSSFromTheme(interpolated);
|
|
45
|
+
const bgColor = interpolated.colors?.["editor.background"] || "#1e1e1e";
|
|
46
|
+
const fgColor = interpolated.colors?.["editor.foreground"] || "#d4d4d4";
|
|
47
|
+
const accentColor = interpolated.colors?.["editor.lineNumberActiveForeground"] || "#61dafb";
|
|
48
|
+
const dimColor = interpolated.colors?.["editorWhitespace.foreground"] || "#888";
|
|
51
49
|
return `<!DOCTYPE html>
|
|
52
50
|
<html lang="en">
|
|
53
51
|
<head>
|
|
@@ -63,93 +61,155 @@ function renderPreview(manifest, themeName) {
|
|
|
63
61
|
|
|
64
62
|
body {
|
|
65
63
|
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
66
|
-
background-color: ${
|
|
67
|
-
color: ${
|
|
64
|
+
background-color: ${bgColor};
|
|
65
|
+
color: ${fgColor};
|
|
68
66
|
padding: 20px;
|
|
69
67
|
line-height: 1.6;
|
|
70
68
|
}
|
|
71
69
|
|
|
72
|
-
.
|
|
73
|
-
|
|
70
|
+
.wrapper {
|
|
71
|
+
display: flex;
|
|
72
|
+
gap: 20px;
|
|
73
|
+
max-width: 1600px;
|
|
74
74
|
margin: 0 auto;
|
|
75
|
+
min-height: 100vh;
|
|
75
76
|
}
|
|
76
77
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
.palette-panel {
|
|
79
|
+
width: 180px;
|
|
80
|
+
flex-shrink: 0;
|
|
81
|
+
display: flex;
|
|
82
|
+
flex-direction: column;
|
|
83
|
+
gap: 10px;
|
|
80
84
|
}
|
|
81
85
|
|
|
82
|
-
.
|
|
83
|
-
|
|
84
|
-
|
|
86
|
+
.palette-panel h2 {
|
|
87
|
+
font-size: 14px;
|
|
88
|
+
color: ${accentColor};
|
|
89
|
+
margin-bottom: 15px;
|
|
90
|
+
padding-bottom: 8px;
|
|
91
|
+
border-bottom: 1px solid #444;
|
|
85
92
|
}
|
|
86
93
|
|
|
87
|
-
.
|
|
88
|
-
|
|
94
|
+
.palette {
|
|
95
|
+
display: flex;
|
|
96
|
+
flex-wrap: wrap;
|
|
97
|
+
gap: 8px;
|
|
98
|
+
padding-right: 5px;
|
|
89
99
|
}
|
|
90
100
|
|
|
91
|
-
.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
101
|
+
.color-box {
|
|
102
|
+
display: flex;
|
|
103
|
+
flex-direction: column;
|
|
104
|
+
align-items: center;
|
|
105
|
+
gap: 4px;
|
|
106
|
+
flex: 0 1 calc(50% - 4px);
|
|
107
|
+
min-width: 70px;
|
|
97
108
|
}
|
|
98
109
|
|
|
99
|
-
.
|
|
100
|
-
|
|
110
|
+
.color-box .swatch {
|
|
111
|
+
width: 48px;
|
|
112
|
+
height: 48px;
|
|
113
|
+
border-radius: 3px;
|
|
101
114
|
border: 1px solid #3e3e42;
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
overflow-x: auto;
|
|
105
|
-
margin-bottom: 15px;
|
|
115
|
+
cursor: pointer;
|
|
116
|
+
transition: all 0.2s ease;
|
|
106
117
|
}
|
|
107
118
|
|
|
108
|
-
.
|
|
119
|
+
.color-box .swatch:hover {
|
|
120
|
+
border-color: ${accentColor};
|
|
121
|
+
box-shadow: 0 0 8px rgba(97, 218, 251, 0.3);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.color-box .name {
|
|
125
|
+
font-size: 9px;
|
|
126
|
+
color: #888;
|
|
127
|
+
text-align: center;
|
|
128
|
+
word-break: break-word;
|
|
129
|
+
max-width: 50px;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.color-box .value {
|
|
133
|
+
font-size: 8px;
|
|
134
|
+
color: ${accentColor};
|
|
135
|
+
font-family: monospace;
|
|
136
|
+
display: none;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.color-box:hover .value {
|
|
109
140
|
display: block;
|
|
110
141
|
}
|
|
111
142
|
|
|
112
|
-
|
|
143
|
+
.main-content {
|
|
144
|
+
flex: 1;
|
|
145
|
+
}
|
|
113
146
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
147
|
+
h1 {
|
|
148
|
+
margin-bottom: 10px;
|
|
149
|
+
color: ${accentColor};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.subtitle {
|
|
153
|
+
color: ${dimColor};
|
|
118
154
|
margin-bottom: 20px;
|
|
119
155
|
}
|
|
120
156
|
|
|
121
|
-
.
|
|
157
|
+
.controls {
|
|
158
|
+
margin-bottom: 20px;
|
|
122
159
|
display: flex;
|
|
123
|
-
|
|
160
|
+
gap: 10px;
|
|
124
161
|
align-items: center;
|
|
125
|
-
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.controls label {
|
|
165
|
+
color: ${dimColor};
|
|
166
|
+
font-size: 14px;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.controls select {
|
|
170
|
+
background-color: #252526;
|
|
126
171
|
border: 1px solid #3e3e42;
|
|
127
172
|
border-radius: 4px;
|
|
128
|
-
|
|
173
|
+
color: ${fgColor};
|
|
174
|
+
padding: 8px 12px;
|
|
175
|
+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
176
|
+
font-size: 13px;
|
|
177
|
+
cursor: pointer;
|
|
129
178
|
}
|
|
130
179
|
|
|
131
|
-
.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
180
|
+
.controls select:hover {
|
|
181
|
+
border-color: ${accentColor};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.code-sample {
|
|
185
|
+
background-color: #252526;
|
|
136
186
|
border: 1px solid #3e3e42;
|
|
187
|
+
border-radius: 4px;
|
|
188
|
+
padding: 15px;
|
|
189
|
+
overflow-x: auto;
|
|
190
|
+
display: none;
|
|
191
|
+
max-height: 600px;
|
|
137
192
|
}
|
|
138
193
|
|
|
139
|
-
.
|
|
194
|
+
.code-sample.active {
|
|
195
|
+
display: block;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.code-sample pre {
|
|
199
|
+
margin: 0;
|
|
200
|
+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
140
201
|
font-size: 12px;
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
202
|
+
line-height: 1.5;
|
|
203
|
+
white-space: pre;
|
|
204
|
+
overflow-x: auto;
|
|
144
205
|
}
|
|
145
206
|
|
|
146
|
-
.
|
|
147
|
-
font-size:
|
|
148
|
-
color: ${interpolated.colors?.["editor.lineNumberActiveForeground"] || "#61dafb"};
|
|
149
|
-
font-family: monospace;
|
|
150
|
-
margin-top: 5px;
|
|
207
|
+
.code-sample code {
|
|
208
|
+
font-size: 12px;
|
|
151
209
|
}
|
|
152
210
|
|
|
211
|
+
${themeCSS}
|
|
212
|
+
|
|
153
213
|
.status {
|
|
154
214
|
padding: 10px 15px;
|
|
155
215
|
border-radius: 4px;
|
|
@@ -177,62 +237,453 @@ function renderPreview(manifest, themeName) {
|
|
|
177
237
|
font-size: 12px;
|
|
178
238
|
color: #888;
|
|
179
239
|
}
|
|
240
|
+
|
|
241
|
+
::-webkit-scrollbar {
|
|
242
|
+
width: 8px;
|
|
243
|
+
height: 8px;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
::-webkit-scrollbar-track {
|
|
247
|
+
background: ${bgColor};
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
::-webkit-scrollbar-thumb {
|
|
251
|
+
background: #404040;
|
|
252
|
+
border-radius: 4px;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
::-webkit-scrollbar-thumb:hover {
|
|
256
|
+
background: #505050;
|
|
257
|
+
}
|
|
180
258
|
</style>
|
|
181
259
|
</head>
|
|
182
260
|
<body>
|
|
183
|
-
<div class="
|
|
184
|
-
<
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
<div id="status" class="status success" style="display:none;"></div>
|
|
188
|
-
|
|
189
|
-
<div class="section">
|
|
190
|
-
<h2>Color Palette</h2>
|
|
261
|
+
<div class="wrapper">
|
|
262
|
+
<div class="palette-panel">
|
|
263
|
+
<h2>Palette</h2>
|
|
191
264
|
<div class="palette" id="palette">${colorPalette}</div>
|
|
192
265
|
</div>
|
|
193
266
|
|
|
194
|
-
<div class="
|
|
195
|
-
<
|
|
196
|
-
<
|
|
197
|
-
|
|
198
|
-
<
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
267
|
+
<div class="main-content">
|
|
268
|
+
<h1>${themeName}</h1>
|
|
269
|
+
<p class="subtitle">Live Preview • Edit manifest.json to see changes</p>
|
|
270
|
+
|
|
271
|
+
<div id="status" class="status success" style="display:none;"></div>
|
|
272
|
+
|
|
273
|
+
<div class="controls">
|
|
274
|
+
<label for="language-select">Language:</label>
|
|
275
|
+
<select id="language-select" onchange="switchLanguage(this.value)">
|
|
276
|
+
<option value="javascript">JavaScript</option>
|
|
277
|
+
<option value="python">Python</option>
|
|
278
|
+
<option value="java">Java</option>
|
|
279
|
+
<option value="php">PHP</option>
|
|
280
|
+
<option value="json">JSON</option>
|
|
281
|
+
</select>
|
|
282
|
+
</div>
|
|
283
|
+
|
|
284
|
+
<div class="code-sample active" id="javascript">
|
|
285
|
+
<pre><code>
|
|
286
|
+
<span class="comment">// Advanced JavaScript with multiple language primitives</span>
|
|
287
|
+
<span class="comment">// Demonstrates classes, interfaces, functions, async/await, destructuring, etc.</span>
|
|
288
|
+
|
|
289
|
+
<span class="keyword">interface</span> User {
|
|
290
|
+
id: <span class="type">number</span>;
|
|
291
|
+
name: <span class="type">string</span>;
|
|
292
|
+
email: <span class="type">string</span>;
|
|
293
|
+
role: <span class="type">'admin'</span> | <span class="type">'user'</span>;
|
|
203
294
|
}
|
|
204
|
-
|
|
295
|
+
|
|
296
|
+
<span class="keyword">class</span> <span class="type">UserManager</span> {
|
|
297
|
+
<span class="keyword">private</span> users: User[] = [];
|
|
298
|
+
<span class="keyword">private</span> <span class="keyword">readonly</span> maxUsers = <span class="number">100</span>;
|
|
299
|
+
|
|
300
|
+
<span class="keyword">constructor</span>(<span class="keyword">private</span> apiUrl: <span class="type">string</span>) {}
|
|
301
|
+
|
|
302
|
+
<span class="keyword">async</span> <span class="method">fetchUsers</span>(): <span class="type">Promise</span><User[]> {
|
|
303
|
+
<span class="keyword">try</span> {
|
|
304
|
+
<span class="keyword">const</span> response = <span class="keyword">await</span> fetch(this.apiUrl);
|
|
305
|
+
<span class="keyword">const</span> data = <span class="keyword">await</span> response.json();
|
|
306
|
+
<span class="keyword">this</span>.users = data;
|
|
307
|
+
<span class="keyword">return</span> this.users;
|
|
308
|
+
} <span class="keyword">catch</span> (error) {
|
|
309
|
+
console.error(<span class="string">'Failed to fetch users:'</span>, error);
|
|
310
|
+
<span class="keyword">return</span> [];
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
<span class="method">addUser</span>(user: User): <span class="type">boolean</span> {
|
|
315
|
+
<span class="keyword">if</span> (<span class="keyword">this</span>.users.length >= <span class="keyword">this</span>.maxUsers) {
|
|
316
|
+
<span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">'User limit exceeded'</span>);
|
|
317
|
+
}
|
|
318
|
+
<span class="keyword">this</span>.users.push(user);
|
|
319
|
+
<span class="keyword">return</span> <span class="keyword">true</span>;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
<span class="method">removeUser</span>(id: <span class="type">number</span>): <span class="type">boolean</span> {
|
|
323
|
+
<span class="keyword">const</span> index = <span class="keyword">this</span>.users.findIndex(u => u.id === id);
|
|
324
|
+
<span class="keyword">if</span> (index > <span class="operator">-</span><span class="number">1</span>) {
|
|
325
|
+
<span class="keyword">this</span>.users.splice(index, <span class="number">1</span>);
|
|
326
|
+
<span class="keyword">return</span> <span class="keyword">true</span>;
|
|
327
|
+
}
|
|
328
|
+
<span class="keyword">return</span> <span class="keyword">false</span>;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
<span class="method">filterByRole</span>(role: <span class="type">string</span>): User[] {
|
|
332
|
+
<span class="keyword">return</span> <span class="keyword">this</span>.users.filter(user => user.role === role);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
<span class="method">mapToEmails</span>(): <span class="type">string</span>[] {
|
|
336
|
+
<span class="keyword">return</span> <span class="keyword">this</span>.users.map(({ email }) => email);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
<span class="method">getAdmins</span>(): User[] {
|
|
340
|
+
<span class="keyword">const</span> { users } = <span class="keyword">this</span>;
|
|
341
|
+
<span class="keyword">return</span> users.filter(u => u.role === <span class="string">'admin'</span>);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
<span class="comment">// Anonymous function with arrow syntax</span>
|
|
346
|
+
<span class="keyword">const</span> calculateSum = (arr: <span class="type">number</span>[]): <span class="type">number</span> => {
|
|
347
|
+
<span class="keyword">return</span> arr.reduce((sum, val) => sum + val, <span class="number">0</span>);
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
<span class="comment">// Higher-order function</span>
|
|
351
|
+
<span class="keyword">const</span> memoize = <T, U>(fn: (arg: T) => U) => {
|
|
352
|
+
<span class="keyword">const</span> cache = <span class="keyword">new</span> Map<T, U>();
|
|
353
|
+
<span class="keyword">return</span> (arg: T): U => {
|
|
354
|
+
<span class="keyword">if</span> (cache.has(arg)) {
|
|
355
|
+
<span class="keyword">return</span> cache.get(arg)!;
|
|
356
|
+
}
|
|
357
|
+
<span class="keyword">const</span> result = fn(arg);
|
|
358
|
+
cache.set(arg, result);
|
|
359
|
+
<span class="keyword">return</span> result;
|
|
360
|
+
};
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
<span class="comment">// Object destructuring with rest operator</span>
|
|
364
|
+
<span class="keyword">const</span> { name, email, ...rest } = <span class="keyword">this</span>.users[<span class="number">0</span>];
|
|
365
|
+
|
|
366
|
+
<span class="comment">// Array destructuring</span>
|
|
367
|
+
<span class="keyword">const</span> [first, second, ...others] = <span class="keyword">this</span>.users;
|
|
368
|
+
|
|
369
|
+
<span class="comment">// Async iterator pattern</span>
|
|
370
|
+
<span class="keyword">async</span> <span class="keyword">function</span>* <span class="method">asyncGenerator</span>() {
|
|
371
|
+
<span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i < <span class="number">5</span>; i++) {
|
|
372
|
+
<span class="keyword">await</span> <span class="keyword">new</span> Promise(r => setTimeout(r, <span class="number">1000</span>));
|
|
373
|
+
<span class="keyword">yield</span> i;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
<span class="comment">// Usage example</span>
|
|
378
|
+
<span class="keyword">const</span> manager = <span class="keyword">new</span> UserManager(<span class="string">'https://api.example.com/users'</span>);
|
|
379
|
+
manager.fetchUsers();
|
|
380
|
+
<span class="keyword">const</span> admins = manager.getAdmins();
|
|
381
|
+
<span class="keyword">const</span> emails = manager.mapToEmails();
|
|
382
|
+
</code></pre>
|
|
205
383
|
</div>
|
|
206
|
-
</div>
|
|
207
384
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
385
|
+
<div class="code-sample" id="python">
|
|
386
|
+
<pre><code>
|
|
387
|
+
<span class="comment"># Advanced Python with classes, decorators, async, comprehensions</span>
|
|
388
|
+
<span class="comment"># Demonstrates various Python language features and patterns</span>
|
|
389
|
+
|
|
390
|
+
<span class="keyword">from</span> typing <span class="keyword">import</span> List, Dict, Optional, TypeVar, Generic
|
|
391
|
+
<span class="keyword">from</span> abc <span class="keyword">import</span> ABC, abstractmethod
|
|
392
|
+
<span class="keyword">import</span> asyncio
|
|
393
|
+
<span class="keyword">from</span> functools <span class="keyword">import</span> wraps
|
|
394
|
+
|
|
395
|
+
T = TypeVar(<span class="string">'T'</span>)
|
|
396
|
+
|
|
397
|
+
<span class="comment"># Abstract base class</span>
|
|
398
|
+
<span class="keyword">class</span> <span class="type">Repository</span>(ABC):
|
|
399
|
+
<span class="keyword">@abstractmethod</span>
|
|
400
|
+
<span class="keyword">async</span> <span class="keyword">def</span> <span class="method">fetch</span>(self):
|
|
401
|
+
<span class="keyword">pass</span>
|
|
402
|
+
|
|
403
|
+
<span class="keyword">class</span> <span class="type">User</span>:
|
|
404
|
+
<span class="keyword">def</span> <span class="method">__init__</span>(self, id: int, name: str, email: str):
|
|
405
|
+
self.id = id
|
|
406
|
+
self.name = name
|
|
407
|
+
self.email = email
|
|
408
|
+
|
|
409
|
+
<span class="keyword">def</span> <span class="method">__repr__</span>(self):
|
|
410
|
+
<span class="keyword">return</span> <span class="string">f"User(id={self.id}, name={self.name})"</span>
|
|
411
|
+
|
|
412
|
+
<span class="keyword">class</span> <span class="type">UserManager</span>(Repository):
|
|
413
|
+
<span class="keyword">def</span> <span class="method">__init__</span>(self, api_url: str):
|
|
414
|
+
self.api_url = api_url
|
|
415
|
+
self.users: List[User] = []
|
|
416
|
+
|
|
417
|
+
<span class="keyword">async</span> <span class="keyword">def</span> <span class="method">fetch</span>(self) -> List[User]:
|
|
418
|
+
<span class="keyword">try</span>:
|
|
419
|
+
<span class="comment"># Simulated async API call</span>
|
|
420
|
+
<span class="keyword">await</span> asyncio.sleep(<span class="number">1</span>)
|
|
421
|
+
<span class="keyword">return</span> self.users
|
|
422
|
+
<span class="keyword">except</span> Exception <span class="keyword">as</span> e:
|
|
423
|
+
print(<span class="string">f"Error fetching users: {e}"</span>)
|
|
424
|
+
<span class="keyword">return</span> []
|
|
425
|
+
|
|
426
|
+
<span class="keyword">def</span> <span class="method">add_user</span>(self, user: User) -> bool:
|
|
427
|
+
self.users.append(user)
|
|
428
|
+
<span class="keyword">return</span> <span class="keyword">True</span>
|
|
429
|
+
|
|
430
|
+
<span class="keyword">def</span> <span class="method">get_by_role</span>(self, role: str) -> List[User]:
|
|
431
|
+
<span class="keyword">return</span> [u <span class="keyword">for</span> u <span class="keyword">in</span> self.users <span class="keyword">if</span> hasattr(u, <span class="string">'role'</span>) <span class="keyword">and</span> u.role == role]
|
|
432
|
+
|
|
433
|
+
<span class="keyword">def</span> <span class="method">get_emails</span>(self) -> List[str]:
|
|
434
|
+
<span class="keyword">return</span> [u.email <span class="keyword">for</span> u <span class="keyword">in</span> self.users]
|
|
435
|
+
|
|
436
|
+
<span class="keyword">def</span> <span class="method">filter_by_name</span>(self, pattern: str) -> List[User]:
|
|
437
|
+
<span class="keyword">return</span> [u <span class="keyword">for</span> u <span class="keyword">in</span> self.users <span class="keyword">if</span> pattern <span class="keyword">in</span> u.name]
|
|
438
|
+
|
|
439
|
+
<span class="comment"># Decorator function</span>
|
|
440
|
+
<span class="keyword">def</span> <span class="method">timer</span>(func):
|
|
441
|
+
<span class="keyword">@wraps</span>(func)
|
|
442
|
+
<span class="keyword">def</span> <span class="method">wrapper</span>(*args, **kwargs):
|
|
443
|
+
import time
|
|
444
|
+
start = time.time()
|
|
445
|
+
result = func(*args, **kwargs)
|
|
446
|
+
elapsed = time.time() - start
|
|
447
|
+
print(<span class="string">f"{func.__name__} took {elapsed:.2f}s"</span>)
|
|
448
|
+
<span class="keyword">return</span> result
|
|
449
|
+
<span class="keyword">return</span> wrapper
|
|
450
|
+
|
|
451
|
+
<span class="comment"># Generator function</span>
|
|
452
|
+
<span class="keyword">def</span> <span class="method">count_up_to</span>(n: int):
|
|
453
|
+
i = <span class="number">0</span>
|
|
454
|
+
<span class="keyword">while</span> i < n:
|
|
455
|
+
<span class="keyword">yield</span> i
|
|
456
|
+
i += <span class="number">1</span>
|
|
457
|
+
|
|
458
|
+
<span class="keyword">async</span> <span class="keyword">def</span> <span class="method">main</span>():
|
|
459
|
+
manager = <span class="type">UserManager</span>(<span class="string">'https://api.example.com'</span>)
|
|
460
|
+
users = <span class="keyword">await</span> manager.fetch()
|
|
461
|
+
<span class="keyword">return</span> users
|
|
462
|
+
|
|
463
|
+
<span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:
|
|
464
|
+
asyncio.run(main())
|
|
465
|
+
</code></pre>
|
|
220
466
|
</div>
|
|
221
|
-
</div>
|
|
222
467
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
468
|
+
<div class="code-sample" id="java">
|
|
469
|
+
<pre><code>
|
|
470
|
+
<span class="comment">// Advanced Java with interfaces, generics, lambdas, annotations</span>
|
|
471
|
+
<span class="comment">// Demonstrates comprehensive language features and patterns</span>
|
|
472
|
+
|
|
473
|
+
<span class="keyword">package</span> com.example.user;
|
|
474
|
+
|
|
475
|
+
<span class="keyword">import</span> java.util.*;
|
|
476
|
+
<span class="keyword">import</span> java.util.stream.*;
|
|
477
|
+
<span class="keyword">import</span> java.util.concurrent.*;
|
|
478
|
+
|
|
479
|
+
<span class="keyword">public</span> <span class="keyword">interface</span> <span class="type">Repository</span><T> {
|
|
480
|
+
Optional<T> findById(<span class="type">int</span> id);
|
|
481
|
+
List<T> findAll();
|
|
482
|
+
<span class="keyword">void</span> save(T entity);
|
|
483
|
+
<span class="keyword">void</span> delete(T entity);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
<span class="keyword">public</span> <span class="keyword">class</span> <span class="type">User</span> {
|
|
487
|
+
<span class="keyword">private</span> <span class="keyword">final</span> <span class="type">int</span> id;
|
|
488
|
+
<span class="keyword">private</span> <span class="keyword">final</span> <span class="type">String</span> name;
|
|
489
|
+
<span class="keyword">private</span> <span class="keyword">final</span> <span class="type">String</span> email;
|
|
490
|
+
<span class="keyword">private</span> <span class="type">UserRole</span> role;
|
|
491
|
+
|
|
492
|
+
<span class="keyword">public</span> <span class="type">User</span>(<span class="type">int</span> id, <span class="type">String</span> name, <span class="type">String</span> email) {
|
|
493
|
+
<span class="keyword">this</span>.id = id;
|
|
494
|
+
<span class="keyword">this</span>.name = name;
|
|
495
|
+
<span class="keyword">this</span>.email = email;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
<span class="keyword">public</span> <span class="type">int</span> <span class="method">getId</span>() { <span class="keyword">return</span> id; }
|
|
499
|
+
<span class="keyword">public</span> <span class="type">String</span> <span class="method">getName</span>() { <span class="keyword">return</span> name; }
|
|
500
|
+
<span class="keyword">public</span> <span class="type">String</span> <span class="method">getEmail</span>() { <span class="keyword">return</span> email; }
|
|
501
|
+
|
|
502
|
+
@Override
|
|
503
|
+
<span class="keyword">public</span> <span class="type">String</span> <span class="method">toString</span>() {
|
|
504
|
+
<span class="keyword">return</span> <span class="string">String.format("User(id=%d, name=%s)"</span>, id, name);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
<span class="keyword">public</span> <span class="keyword">enum</span> <span class="type">UserRole</span> {
|
|
509
|
+
ADMIN, USER, GUEST
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
<span class="keyword">public</span> <span class="keyword">class</span> <span class="type">UserManager</span> <span class="keyword">implements</span> <span class="type">Repository</span><<span class="type">User</span>> {
|
|
513
|
+
<span class="keyword">private</span> <span class="keyword">final</span> List<<span class="type">User</span>> users;
|
|
514
|
+
<span class="keyword">private</span> <span class="keyword">final</span> <span class="type">String</span> apiUrl;
|
|
515
|
+
<span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> MAX_USERS = <span class="number">100</span>;
|
|
516
|
+
|
|
517
|
+
<span class="keyword">public</span> <span class="type">UserManager</span>(<span class="type">String</span> apiUrl) {
|
|
518
|
+
<span class="keyword">this</span>.apiUrl = apiUrl;
|
|
519
|
+
<span class="keyword">this</span>.users = <span class="keyword">new</span> CopyOnWriteArrayList<>();
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
@Override
|
|
523
|
+
<span class="keyword">public</span> Optional<<span class="type">User</span>> <span class="method">findById</span>(<span class="type">int</span> id) {
|
|
524
|
+
<span class="keyword">return</span> users.stream()
|
|
525
|
+
.filter(u -> u.getId() == id)
|
|
526
|
+
.findFirst();
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
@Override
|
|
530
|
+
<span class="keyword">public</span> List<<span class="type">User</span>> <span class="method">findAll</span>() {
|
|
531
|
+
<span class="keyword">return</span> <span class="keyword">new</span> ArrayList<>(users);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
@Override
|
|
535
|
+
<span class="keyword">public</span> <span class="keyword">void</span> <span class="method">save</span>(<span class="type">User</span> user) {
|
|
536
|
+
<span class="keyword">if</span> (users.size() >= MAX_USERS) {
|
|
537
|
+
<span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException(<span class="string">"User limit exceeded"</span>);
|
|
538
|
+
}
|
|
539
|
+
users.add(user);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
@Override
|
|
543
|
+
<span class="keyword">public</span> <span class="keyword">void</span> <span class="method">delete</span>(<span class="type">User</span> user) {
|
|
544
|
+
users.remove(user);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
<span class="keyword">public</span> List<<span class="type">String</span>> <span class="method">getEmails</span>() {
|
|
548
|
+
<span class="keyword">return</span> users.stream()
|
|
549
|
+
.map(<span class="type">User</span>::getEmail)
|
|
550
|
+
.collect(Collectors.toList());
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
<span class="keyword">public</span> <span class="type">Map</span><<span class="type">Integer</span>, <span class="type">User</span>> <span class="method">toMap</span>() {
|
|
554
|
+
<span class="keyword">return</span> users.stream()
|
|
555
|
+
.collect(Collectors.toMap(<span class="type">User</span>::getId, u -> u));
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
<span class="keyword">public</span> <T> List<T> <span class="method">map</span>(<span class="type">Function</span><<span class="type">User</span>, T> mapper) {
|
|
559
|
+
<span class="keyword">return</span> users.stream()
|
|
560
|
+
.map(mapper)
|
|
561
|
+
.collect(Collectors.toList());
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
<span class="keyword">public</span> <span class="type">CompletableFuture</span><List<<span class="type">User</span>>> <span class="method">fetchUsersAsync</span>() {
|
|
565
|
+
<span class="keyword">return</span> <span class="type">CompletableFuture</span>.supplyAsync(() -> {
|
|
566
|
+
<span class="keyword">try</span> {
|
|
567
|
+
<span class="type">Thread</span>.sleep(<span class="number">1000</span>);
|
|
568
|
+
<span class="keyword">return</span> users;
|
|
569
|
+
} <span class="keyword">catch</span> (<span class="type">InterruptedException</span> e) {
|
|
570
|
+
<span class="type">Thread</span>.currentThread().interrupt();
|
|
571
|
+
<span class="keyword">return</span> <span class="keyword">new</span> ArrayList<>();
|
|
572
|
+
}
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
</code></pre>
|
|
577
|
+
</div>
|
|
578
|
+
|
|
579
|
+
<div class="code-sample" id="php">
|
|
580
|
+
<pre><code>
|
|
581
|
+
<span class="keyword"><?php</span>
|
|
582
|
+
|
|
583
|
+
<span class="keyword">namespace</span> App\\User;
|
|
584
|
+
|
|
585
|
+
<span class="keyword">use</span> Exception;
|
|
586
|
+
|
|
587
|
+
<span class="comment">// Interface definition</span>
|
|
588
|
+
<span class="keyword">interface</span> <span class="type">RepositoryInterface</span> {
|
|
589
|
+
<span class="keyword">public</span> <span class="keyword">function</span> findById(<span class="type">int</span> \$id);
|
|
590
|
+
<span class="keyword">public</span> <span class="keyword">function</span> findAll(): <span class="type">array</span>;
|
|
591
|
+
<span class="keyword">public</span> <span class="keyword">function</span> save(\$entity): <span class="type">bool</span>;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
<span class="keyword">class</span> <span class="type">User</span> {
|
|
595
|
+
<span class="keyword">private</span> <span class="type">int</span> \$id;
|
|
596
|
+
<span class="keyword">private</span> <span class="type">string</span> \$name;
|
|
597
|
+
<span class="keyword">private</span> <span class="type">string</span> \$email;
|
|
598
|
+
|
|
599
|
+
<span class="keyword">public</span> <span class="keyword">function</span> <span class="method">__construct</span>(<span class="type">int</span> \$id, <span class="type">string</span> \$name, <span class="type">string</span> \$email) {
|
|
600
|
+
\$this->id = \$id;
|
|
601
|
+
\$this->name = \$name;
|
|
602
|
+
\$this->email = \$email;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
<span class="keyword">public</span> <span class="keyword">function</span> <span class="method">getId</span>(): <span class="type">int</span> {
|
|
606
|
+
<span class="keyword">return</span> \$this->id;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
<span class="keyword">public</span> <span class="keyword">function</span> <span class="method">getName</span>(): <span class="type">string</span> {
|
|
610
|
+
<span class="keyword">return</span> \$this->name;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
<span class="keyword">public</span> <span class="keyword">function</span> <span class="method">getEmail</span>(): <span class="type">string</span> {
|
|
614
|
+
<span class="keyword">return</span> \$this->email;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
<span class="keyword">public</span> <span class="keyword">function</span> <span class="method">__toString</span>(): <span class="type">string</span> {
|
|
618
|
+
<span class="keyword">return</span> <span class="string">"User(id={\$this->id}, name={\$this->name})"</span>;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
<span class="keyword">class</span> <span class="type">UserManager</span> <span class="keyword">implements</span> <span class="type">RepositoryInterface</span> {
|
|
623
|
+
<span class="keyword">private</span> <span class="type">array</span> \$users = [];
|
|
624
|
+
<span class="keyword">private</span> <span class="type">string</span> \$apiUrl;
|
|
625
|
+
<span class="keyword">private</span> <span class="keyword">const</span> MAX_USERS = <span class="number">100</span>;
|
|
626
|
+
|
|
627
|
+
<span class="keyword">public</span> <span class="keyword">function</span> <span class="method">__construct</span>(<span class="type">string</span> \$apiUrl) {
|
|
628
|
+
\$this->apiUrl = \$apiUrl;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
<span class="keyword">public</span> <span class="keyword">function</span> <span class="method">findById</span>(<span class="type">int</span> \$id) {
|
|
632
|
+
<span class="keyword">foreach</span> (\$this->users <span class="keyword">as</span> \$user) {
|
|
633
|
+
<span class="keyword">if</span> (\$user->getId() === \$id) {
|
|
634
|
+
<span class="keyword">return</span> \$user;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
<span class="keyword">return</span> <span class="keyword">null</span>;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
<span class="keyword">public</span> <span class="keyword">function</span> <span class="method">findAll</span>(): <span class="type">array</span> {
|
|
641
|
+
<span class="keyword">return</span> \$this->users;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
<span class="keyword">public</span> <span class="keyword">function</span> <span class="method">save</span>(\$user): <span class="type">bool</span> {
|
|
645
|
+
<span class="keyword">if</span> (<span class="builtin">count</span>(\$this->users) >= <span class="keyword">self</span>::MAX_USERS) {
|
|
646
|
+
<span class="keyword">throw</span> <span class="keyword">new</span> Exception(<span class="string">'User limit exceeded'</span>);
|
|
647
|
+
}
|
|
648
|
+
\$this->users[] = \$user;
|
|
649
|
+
<span class="keyword">return</span> <span class="keyword">true</span>;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
<span class="keyword">public</span> <span class="keyword">function</span> <span class="method">getEmails</span>(): <span class="type">array</span> {
|
|
653
|
+
<span class="keyword">return</span> <span class="builtin">array_map</span>(<span class="keyword">fn</span>(\$u) => \$u->getEmail(), \$this->users);
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
<span class="keyword">public</span> <span class="keyword">function</span> <span class="method">filter</span>(<span class="type">callable</span> \$predicate): <span class="type">array</span> {
|
|
657
|
+
<span class="keyword">return</span> <span class="builtin">array_filter</span>(\$this->users, \$predicate);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
<span class="keyword">public</span> <span class="keyword">function</span> <span class="method">map</span>(<span class="type">callable</span> \$fn): <span class="type">array</span> {
|
|
661
|
+
<span class="keyword">return</span> <span class="builtin">array_map</span>(\$fn, \$this->users);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
<span class="keyword">?></span>
|
|
666
|
+
</code></pre>
|
|
667
|
+
</div>
|
|
668
|
+
|
|
669
|
+
<div class="code-sample" id="json">
|
|
670
|
+
<pre><code>
|
|
227
671
|
{
|
|
228
|
-
<span class="string">"
|
|
229
|
-
|
|
672
|
+
<span class="string">"theme"</span>: {
|
|
673
|
+
<span class="string">"name"</span>: <span class="string">"${themeName}"</span>,
|
|
674
|
+
<span class="string">"version"</span>: <span class="string">"2.0.0"</span>,
|
|
675
|
+
<span class="string">"description"</span>: <span class="string">"Color theme"</span>,
|
|
676
|
+
<span class="string">"author"</span>: <span class="string">"Theme Creator"</span>
|
|
677
|
+
},
|
|
230
678
|
<span class="string">"colors"</span>: {
|
|
231
|
-
<span class="string">"
|
|
232
|
-
|
|
679
|
+
<span class="string">"primary"</span>: {
|
|
680
|
+
<span class="string">"background"</span>: <span class="string">"${interpolated.colors?.["editor.background"] || "#1e1e1e"}"</span>,
|
|
681
|
+
<span class="string">"foreground"</span>: <span class="string">"${interpolated.colors?.["editor.foreground"] || "#d4d4d4"}"</span>,
|
|
682
|
+
<span class="string">"accent"</span>: <span class="string">"${accentColor}"</span>
|
|
683
|
+
}
|
|
233
684
|
}
|
|
234
685
|
}
|
|
235
|
-
</code>
|
|
686
|
+
</code></pre>
|
|
236
687
|
</div>
|
|
237
688
|
</div>
|
|
238
689
|
</div>
|
|
@@ -240,7 +691,17 @@ greet(<span class="string">"Python"</span>)
|
|
|
240
691
|
<div class="reload-hint">🔄 Watching for changes...</div>
|
|
241
692
|
|
|
242
693
|
<script>
|
|
243
|
-
|
|
694
|
+
function switchLanguage(language) {
|
|
695
|
+
document.querySelectorAll('.code-sample').forEach(sample => {
|
|
696
|
+
sample.classList.remove('active');
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
const selected = document.getElementById(language);
|
|
700
|
+
if (selected) {
|
|
701
|
+
selected.classList.add('active');
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
244
705
|
const ws = new WebSocket(\`ws://\${window.location.host}/ws\`);
|
|
245
706
|
ws.addEventListener('message', (event) => {
|
|
246
707
|
if (event.data === 'reload') {
|