clewy-lang 1.0.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/README.md ADDED
@@ -0,0 +1,245 @@
1
+ # Clewy ✨
2
+
3
+ > The magic web-building language — `.cly` files become full websites.
4
+
5
+ ```
6
+ page "My App"
7
+ title "Hello World"
8
+ button "Click me" => show "Hello! 👋"
9
+ loop 3 => text "Simple is powerful"
10
+ ```
11
+
12
+ That's it. That compiles to a complete, styled, interactive website.
13
+
14
+ ---
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install -g clewy
20
+ # or use without installing:
21
+ npx clewy init my-app
22
+ ```
23
+
24
+ **Requirements:** Node.js 14+
25
+
26
+ ---
27
+
28
+ ## Quick Start
29
+
30
+ ```bash
31
+ npx clewy init my-app # Create a new project
32
+ cd my-app
33
+ npx clewy run # Start dev server with live reload
34
+ ```
35
+
36
+ Your browser opens automatically at `http://localhost:3000`.
37
+ Edit `main.cly` — the page updates instantly.
38
+
39
+ ---
40
+
41
+ ## Commands
42
+
43
+ | Command | What it does |
44
+ |---------|--------------|
45
+ | `npx clewy init <name>` | Create a new project |
46
+ | `npx clewy init <name> landing` | Create with a landing page template |
47
+ | `npx clewy init <name> todo` | Create with a todo app template |
48
+ | `npx clewy run` | Start dev server with live reload |
49
+ | `npx clewy run --port 8080` | Run on a custom port |
50
+ | `npx clewy build` | Build `index.html`, `style.css`, `script.js` |
51
+ | `npx clewy check` | Check `.cly` syntax without building |
52
+ | `npx clewy --help` | Show all commands |
53
+
54
+ ---
55
+
56
+ ## Clewy Language Reference
57
+
58
+ ### Page title
59
+ ```
60
+ page "My Awesome App"
61
+ ```
62
+
63
+ ### Headings
64
+ ```
65
+ title "Big Heading"
66
+ subtitle "Smaller heading"
67
+ ```
68
+
69
+ ### Text & links
70
+ ```
71
+ text "Any paragraph of text here"
72
+ link "Click here" "https://example.com"
73
+ ```
74
+
75
+ ### Buttons
76
+ ```
77
+ button "Click me" => show "Hello!" # Toggle a message
78
+ button "Pop" => alert "A browser popup" # Browser alert
79
+ ```
80
+
81
+ ### Input
82
+ ```
83
+ input "Enter your name..."
84
+ input "Search..." searchQuery # Named input (accessible in JS)
85
+ ```
86
+
87
+ ### Show a message
88
+ ```
89
+ show "This appears immediately on the page"
90
+ ```
91
+
92
+ ### Images
93
+ ```
94
+ image "https://example.com/photo.jpg" "Alt text"
95
+ image "local-photo.jpg"
96
+ ```
97
+
98
+ ### Navigation bar
99
+ ```
100
+ nav "Home" "About" "Contact" "Sign Up"
101
+ ```
102
+
103
+ ### Footer
104
+ ```
105
+ footer "© 2025 My App"
106
+ ```
107
+
108
+ ### Loops
109
+ ```
110
+ loop 5 => text "Repeated!" # Inline loop
111
+ loop 3 # Block loop
112
+ text "Multiple"
113
+ text "lines inside"
114
+ end
115
+ ```
116
+
117
+ ### Sections (grouped card)
118
+ ```
119
+ section "Features"
120
+ text "✓ Feature one"
121
+ text "✓ Feature two"
122
+ button "Learn more" => show "Details"
123
+ end
124
+ ```
125
+
126
+ ### Reusable components
127
+ ```
128
+ component PricingCard
129
+ title "Pro Plan"
130
+ text "$29/month"
131
+ button "Subscribe" => show "Let's go!"
132
+ end
133
+
134
+ use PricingCard
135
+ use PricingCard # Use it multiple times
136
+ ```
137
+
138
+ ### Variables
139
+ ```
140
+ var username "Alice"
141
+ var version "1.0"
142
+ ```
143
+
144
+ ### Comments
145
+ ```
146
+ # This is a comment — ignored by the compiler
147
+ ```
148
+
149
+ ---
150
+
151
+ ## Generated Output
152
+
153
+ Every `.cly` file compiles to three files:
154
+
155
+ | File | Contents |
156
+ |------|----------|
157
+ | `index.html` | Full HTML5 document |
158
+ | `style.css` | Complete design system (CSS variables, responsive) |
159
+ | `script.js` | All interactivity (button actions, inputs, toggles) |
160
+
161
+ The output is **zero-dependency HTML** — just open `index.html` in any browser.
162
+
163
+ ---
164
+
165
+ ## Project Structure
166
+
167
+ ```
168
+ clewy/ ← Clewy language engine
169
+ src/
170
+ parser.js ← Tokenizer + AST parser
171
+ compiler.js ← AST → HTML/CSS/JS
172
+ runtime.js ← Dev server + file watcher
173
+ cli.js ← Command-line interface
174
+ examples/
175
+ kitchen-sink.cly ← All features demonstrated
176
+ landing.cly ← Landing page example
177
+ tests/
178
+ test.js ← 40-test suite (parser + compiler)
179
+ package.json
180
+
181
+ my-app/ ← Your generated project
182
+ main.cly ← ← YOU EDIT THIS
183
+ index.html ← Generated
184
+ style.css ← Generated
185
+ script.js ← Generated
186
+ ```
187
+
188
+ ---
189
+
190
+ ## Design Principles
191
+
192
+ 1. **One command = one action** — no hidden complexity
193
+ 2. **Beginner first** — if you can describe it, you can build it
194
+ 3. **Scratch-inspired** — visual blocks become text commands
195
+ 4. **Zero config** — works instantly, no setup required
196
+ 5. **Readable output** — generated HTML/CSS/JS is clean and readable
197
+ 6. **Magic, not magic** — simple syntax, real web output
198
+
199
+ ---
200
+
201
+ ## Examples
202
+
203
+ ### Hello World
204
+ ```
205
+ page "Hello"
206
+ title "Hello, World! 🌍"
207
+ text "My first Clewy page"
208
+ button "Greet" => show "Hello from Clewy!"
209
+ ```
210
+
211
+ ### Simple Portfolio
212
+ ```
213
+ page "Jane Doe — Portfolio"
214
+ nav "Work" "About" "Contact"
215
+ title "Jane Doe"
216
+ subtitle "Designer & Developer"
217
+ text "I make beautiful things for the web."
218
+ section "Projects"
219
+ text "✦ Project Alpha"
220
+ text "✦ Project Beta"
221
+ text "✦ Project Gamma"
222
+ end
223
+ footer "© 2025 Jane Doe"
224
+ ```
225
+
226
+ ### Component-based layout
227
+ ```
228
+ component TeamMember
229
+ title "Team Member"
230
+ text "Role at Company"
231
+ link "LinkedIn" "https://linkedin.com"
232
+ end
233
+
234
+ section "Our Team"
235
+ use TeamMember
236
+ use TeamMember
237
+ use TeamMember
238
+ end
239
+ ```
240
+
241
+ ---
242
+
243
+ ## License
244
+
245
+ MIT — build anything, ship everything.
package/package.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "clewy-lang",
3
+ "version": "1.0.0",
4
+ "description": "The magic web-building language — write .cly files, get full websites",
5
+ "main": "src/compiler.js",
6
+ "bin": {
7
+ "clewy": "./src/cli.js"
8
+ },
9
+ "scripts": {
10
+ "test": "node tests/test.js"
11
+ },
12
+ "keywords": ["clewy", "web", "language", "transpiler", "beginner", "no-code", "static-site"],
13
+ "author": "Clewy",
14
+ "license": "MIT",
15
+ "engines": { "node": ">=14.0.0" },
16
+ "files": ["src/", "README.md"]
17
+ }
package/src/cli.js ADDED
@@ -0,0 +1,411 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Clewy CLI — clewy init / run / build / check / new
4
+ *
5
+ * Install globally: npm install -g clewy
6
+ * Or without install: npx clewy init my-app
7
+ */
8
+
9
+ 'use strict';
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const { execSync, exec } = require('child_process');
13
+
14
+ // ── colours ──────────────────────────────────────────────────────────────────
15
+ const C = {
16
+ reset:'\x1b[0m', bold:'\x1b[1m', dim:'\x1b[2m',
17
+ green:'\x1b[32m', yellow:'\x1b[33m', blue:'\x1b[34m',
18
+ cyan:'\x1b[36m', red:'\x1b[31m', magenta:'\x1b[35m', white:'\x1b[97m',
19
+ };
20
+ const c = (col, s) => `${C[col]}${s}${C.reset}`;
21
+ const ok = s => console.log(` ${c('green','✓')} ${s}`);
22
+ const err = s => console.log(` ${c('red','✗')} ${s}`);
23
+ const tip = s => console.log(` ${c('dim', s)}`);
24
+ const log = s => console.log(` ${s}`);
25
+
26
+ // ── banner ────────────────────────────────────────────────────────────────────
27
+ function banner() {
28
+ const v = require('../package.json').version;
29
+ console.log('');
30
+ console.log(c('cyan', ' ██████╗██╗ ███████╗██╗ ██╗██╗ ██╗'));
31
+ console.log(c('cyan', ' ██╔════╝██║ ██╔════╝██║ ██║╚██╗ ██╔╝'));
32
+ console.log(c('cyan', ' ██║ ██║ █████╗ ██║ █╗ ██║ ╚████╔╝ '));
33
+ console.log(c('cyan', ' ██║ ██║ ██╔══╝ ██║███╗██║ ╚██╔╝ '));
34
+ console.log(c('cyan', ' ╚██████╗███████╗███████╗╚███╔███╔╝ ██║ '));
35
+ console.log(c('cyan', ' ╚═════╝╚══════╝╚══════╝ ╚══╝╚══╝ ╚═╝ '));
36
+ console.log('');
37
+ console.log(` ${c('white','The magic web-building language')} ${c('dim','v'+v)}`);
38
+ console.log('');
39
+ }
40
+
41
+ // ── templates ─────────────────────────────────────────────────────────────────
42
+ const TEMPLATES = {
43
+
44
+ default: `# Welcome to Clewy! ✨
45
+ # Edit this file — your site updates live in the browser.
46
+
47
+ page "My App"
48
+
49
+ nav "Home" "About" "Contact"
50
+
51
+ title "Hello, World! 👋"
52
+ subtitle "You just wrote your first Clewy page"
53
+
54
+ text "Clewy turns simple commands into beautiful websites."
55
+ text "Edit this file and run clewy run to see your changes."
56
+
57
+ section "Try the buttons"
58
+ button "Say hello" => show "Hello from Clewy! 🎉"
59
+ button "Pop an alert" => alert "Clewy is working!"
60
+ end
61
+
62
+ section "Type something"
63
+ input "What is your name?" userName
64
+ button "Greet me" => show "Hey there, friend! 👋"
65
+ end
66
+
67
+ component Card
68
+ title "Reusable Card"
69
+ text "Define once — use anywhere."
70
+ button "Card action" => show "Component clicked ✓"
71
+ end
72
+
73
+ section "Components"
74
+ use Card
75
+ use Card
76
+ end
77
+
78
+ loop 3 => text "⭐ Clewy is minimal, instant, and fun"
79
+
80
+ footer "Built with Clewy — the magic web language ✨"
81
+ `,
82
+
83
+ landing: `page "My SaaS"
84
+
85
+ nav "Home" "Features" "Pricing" "Login"
86
+
87
+ title "Ship in minutes, not months 🚀"
88
+ subtitle "The fastest way to launch your idea"
89
+
90
+ text "Stop wrestling with HTML. Write what you mean — Clewy does the rest."
91
+
92
+ button "Start for free →" => show "Welcome! Check your inbox 📬"
93
+ button "See a demo" => alert "Live demo coming soon!"
94
+
95
+ section "Why Clewy?"
96
+ text "✦ No HTML, CSS or JavaScript to learn"
97
+ text "✦ Live preview as you type"
98
+ text "✦ Production-ready output"
99
+ text "✦ Works on every device"
100
+ end
101
+
102
+ component Feature
103
+ title "Magic Commands"
104
+ text "One line of Clewy = a full interactive element."
105
+ end
106
+
107
+ section "Features"
108
+ use Feature
109
+ end
110
+
111
+ loop 4 => text "★ Trusted by developers worldwide"
112
+
113
+ footer "© 2025 My SaaS — Made with Clewy"
114
+ `,
115
+
116
+ todo: `page "Todo App"
117
+
118
+ title "📝 My Todos"
119
+ subtitle "Stay on top of everything"
120
+
121
+ section "Add a task"
122
+ input "What needs doing?" newTask
123
+ button "Add ✓" => show "Task added!"
124
+ end
125
+
126
+ section "Tasks"
127
+ text "☐ Learn Clewy"
128
+ text "☐ Build something cool"
129
+ text "☐ Share it with friends"
130
+ text "☑ Install Clewy ← done!"
131
+ end
132
+
133
+ button "Clear all" => alert "Clear all tasks? (not wired up yet)"
134
+
135
+ footer "Keep going ⚡"
136
+ `,
137
+
138
+ portfolio: `page "My Portfolio"
139
+
140
+ nav "Work" "About" "Contact"
141
+
142
+ title "Hi, I'm Alex 👋"
143
+ subtitle "Designer & Developer"
144
+
145
+ text "I build fast, beautiful things for the web."
146
+ text "Currently open to new projects."
147
+
148
+ section "Selected Work"
149
+ text "✦ E-commerce redesign — 2× conversion rate"
150
+ text "✦ Mobile app — 50k downloads in 3 months"
151
+ text "✦ Brand identity — for a Y Combinator startup"
152
+ end
153
+
154
+ section "Skills"
155
+ loop 3 => text "React · Node.js · Figma · Clewy"
156
+ end
157
+
158
+ button "See my work" => show "Portfolio page coming soon! 👀"
159
+ button "Hire me" => show "Let's talk → alex@example.com 📬"
160
+
161
+ link "GitHub" "https://github.com"
162
+ link "LinkedIn" "https://linkedin.com"
163
+
164
+ footer "© 2025 Alex — Built with Clewy"
165
+ `,
166
+ };
167
+
168
+ // ── .gitignore content ────────────────────────────────────────────────────────
169
+ const GITIGNORE = `# Clewy — generated files (do NOT edit these manually)
170
+ index.html
171
+ style.css
172
+ script.js
173
+ .DS_Store
174
+ `;
175
+
176
+ // ── commands ──────────────────────────────────────────────────────────────────
177
+
178
+ function cmdInit(args) {
179
+ const appName = args[0];
180
+ const tmplName = args[1] || 'default';
181
+
182
+ if (!appName) {
183
+ err('Please provide a project name.');
184
+ log('');
185
+ log(` Example: ${c('cyan','clewy init my-app')}`);
186
+ log(` Example: ${c('cyan','clewy init my-app landing')}`);
187
+ log('');
188
+ process.exit(1);
189
+ }
190
+
191
+ const targetDir = path.resolve(process.cwd(), appName);
192
+
193
+ if (fs.existsSync(targetDir)) {
194
+ err(`Folder "${appName}" already exists.`);
195
+ process.exit(1);
196
+ }
197
+
198
+ if (!TEMPLATES[tmplName]) {
199
+ err(`Unknown template "${tmplName}". Available: ${Object.keys(TEMPLATES).join(', ')}`);
200
+ process.exit(1);
201
+ }
202
+
203
+ console.log('');
204
+ log(`${c('bold','Creating')} ${c('cyan', appName)} …`);
205
+ console.log('');
206
+
207
+ // Create folder + files
208
+ fs.mkdirSync(targetDir, { recursive: true });
209
+ fs.writeFileSync(path.join(targetDir, 'main.cly'), TEMPLATES[tmplName]);
210
+ fs.writeFileSync(path.join(targetDir, '.gitignore'), GITIGNORE);
211
+ fs.writeFileSync(path.join(targetDir, '.clewyrc'), JSON.stringify({ name: appName, version: '0.1.0', template: tmplName }, null, 2));
212
+
213
+ ok(`Created ${c('cyan', appName + '/main.cly')}`);
214
+ ok(`Created ${c('dim', appName + '/.gitignore')}`);
215
+ ok(`Created ${c('dim', appName + '/.clewyrc')}`);
216
+
217
+ console.log('');
218
+ log(c('bold', 'Next steps:'));
219
+ console.log('');
220
+ log(` ${c('cyan', `cd ${appName}`)}`);
221
+ log(` ${c('cyan', 'clewy run')}`);
222
+ console.log('');
223
+ tip(`Templates: default · landing · todo · portfolio`);
224
+ tip(`Example: clewy init my-site landing`);
225
+ console.log('');
226
+ }
227
+
228
+ function cmdBuild(args) {
229
+ const projectDir = process.cwd();
230
+ const { buildProject } = require('./runtime');
231
+
232
+ const clyFile = path.join(projectDir, 'main.cly');
233
+ if (!fs.existsSync(clyFile)) {
234
+ err('No main.cly found. Are you inside a Clewy project?');
235
+ tip('Run: clewy init my-app');
236
+ console.log('');
237
+ process.exit(1);
238
+ }
239
+
240
+ log('');
241
+ log(`${c('blue','⚙')} Building…`);
242
+
243
+ const ok2 = buildProject(projectDir);
244
+ if (!ok2) process.exit(1);
245
+
246
+ const sz = f => (fs.statSync(path.join(projectDir, f)).size / 1024).toFixed(1);
247
+
248
+ console.log('');
249
+ ok('Build complete!\n');
250
+ log(` ${c('cyan','index.html')} ${sz('index.html')} kB`);
251
+ log(` ${c('cyan','style.css')} ${sz('style.css')} kB`);
252
+ log(` ${c('cyan','script.js')} ${sz('script.js')} kB`);
253
+ console.log('');
254
+ tip('Open index.html in your browser, or run: clewy run');
255
+ console.log('');
256
+ }
257
+
258
+ function cmdRun(args) {
259
+ const projectDir = process.cwd();
260
+ const clyFile = path.join(projectDir, 'main.cly');
261
+
262
+ if (!fs.existsSync(clyFile)) {
263
+ err('No main.cly found. Are you inside a Clewy project?');
264
+ tip('Run: clewy init my-app');
265
+ console.log('');
266
+ process.exit(1);
267
+ }
268
+
269
+ let port = 3000;
270
+ const pi = args.indexOf('--port');
271
+ if (pi !== -1 && args[pi + 1]) port = parseInt(args[pi + 1], 10);
272
+
273
+ const { startServer } = require('./runtime');
274
+ startServer(projectDir, port);
275
+ }
276
+
277
+ function cmdNew(args) {
278
+ // clewy new button / clewy new page — interactive snippet helper
279
+ const what = args[0];
280
+ const snippets = {
281
+ button: `button "Label" => show "Message"`,
282
+ input: `input "Placeholder" varName`,
283
+ section: `section "Title"\n text "Content here"\nend`,
284
+ component: `component MyCard\n title "Card Title"\n text "Card content"\nend\n\nuse MyCard`,
285
+ loop: `loop 4 => text "Repeated text"`,
286
+ nav: `nav "Home" "About" "Contact"`,
287
+ };
288
+ if (!what || !snippets[what]) {
289
+ log('');
290
+ log(c('bold', ' Snippets — copy into your main.cly:'));
291
+ console.log('');
292
+ for (const [k, v] of Object.entries(snippets)) {
293
+ log(` ${c('yellow', k.padEnd(12))} ${c('dim', v.split('\n')[0])}`);
294
+ }
295
+ console.log('');
296
+ return;
297
+ }
298
+ console.log('');
299
+ log(c('bold', `Snippet: ${what}`));
300
+ console.log('');
301
+ snippets[what].split('\n').forEach(l => log(` ${c('cyan', l)}`));
302
+ console.log('');
303
+ }
304
+
305
+ function cmdCheck(args) {
306
+ const projectDir = process.cwd();
307
+ const clyPath = path.join(projectDir, 'main.cly');
308
+
309
+ if (!fs.existsSync(clyPath)) {
310
+ err('No main.cly found.');
311
+ process.exit(1);
312
+ }
313
+
314
+ const { parse } = require('./parser');
315
+ const source = fs.readFileSync(clyPath, 'utf8');
316
+
317
+ try {
318
+ const ast = parse(source);
319
+ const counts = summarize(ast.body);
320
+ const total = Object.values(counts).reduce((a,b)=>a+b,0);
321
+ console.log('');
322
+ ok(`Syntax OK — ${c('bold', total + ' nodes')} parsed`);
323
+ console.log('');
324
+ for (const [t, n] of Object.entries(counts)) {
325
+ log(` ${c('cyan', t.padEnd(14))} ${c('dim','×')} ${n}`);
326
+ }
327
+ console.log('');
328
+ } catch (e) {
329
+ console.log('');
330
+ err(`Syntax error: ${e.message}`);
331
+ console.log('');
332
+ process.exit(1);
333
+ }
334
+ }
335
+
336
+ function summarize(body) {
337
+ const m = {};
338
+ for (const n of body) {
339
+ m[n.type] = (m[n.type]||0)+1;
340
+ if (n.body) { const sub=summarize(n.body); for (const [k,v] of Object.entries(sub)) m[k]=(m[k]||0)+v; }
341
+ }
342
+ return m;
343
+ }
344
+
345
+ function cmdHelp() {
346
+ banner();
347
+ log(c('bold','Commands:'));
348
+ console.log('');
349
+ const cmds = [
350
+ ['init <name> [template]', 'Create a new Clewy project'],
351
+ ['run [--port N]', 'Start dev server with live reload'],
352
+ ['build', 'Compile main.cly → HTML/CSS/JS'],
353
+ ['check', 'Validate .cly syntax'],
354
+ ['new [element]', 'Show code snippets'],
355
+ ];
356
+ for (const [cmd, desc] of cmds) {
357
+ log(` ${c('cyan', ('clewy '+cmd).padEnd(32))} ${c('dim',desc)}`);
358
+ }
359
+ console.log('');
360
+ log(c('bold','Templates:'));
361
+ console.log('');
362
+ for (const t of Object.keys(TEMPLATES)) {
363
+ log(` ${c('yellow', t)}`);
364
+ }
365
+ console.log('');
366
+ log(c('bold','Clewy language:'));
367
+ console.log('');
368
+ const syntax = [
369
+ ['page "Title"', 'Browser tab title'],
370
+ ['title "Big heading"', 'h1 heading'],
371
+ ['subtitle "Smaller"', 'h2 heading'],
372
+ ['text "Paragraph"', 'Text block'],
373
+ ['button "X" => show "Y"', 'Button that shows a message'],
374
+ ['button "X" => alert "Y"', 'Button with popup'],
375
+ ['input "Hint" varName', 'Text input field'],
376
+ ['show "Message"', 'Always-visible message'],
377
+ ['loop N => text "..."', 'Repeat N times'],
378
+ ['component Name … end', 'Define a component'],
379
+ ['use Name', 'Render a component'],
380
+ ['section "Label" … end', 'Grouped card section'],
381
+ ['nav "A" "B" "C"', 'Navigation bar'],
382
+ ['link "Text" "url"', 'Hyperlink'],
383
+ ['image "url" "alt"', 'Image'],
384
+ ['footer "Text"', 'Page footer'],
385
+ ['# comment', 'Ignored line'],
386
+ ];
387
+ for (const [s,d] of syntax) {
388
+ log(` ${c('magenta', s.padEnd(36))} ${c('dim',d)}`);
389
+ }
390
+ console.log('');
391
+ log(` Docs & source: ${c('cyan','https://github.com/clewy-lang/clewy')}`);
392
+ console.log('');
393
+ }
394
+
395
+ // ── entry point ───────────────────────────────────────────────────────────────
396
+ const [,, cmd, ...rest] = process.argv;
397
+ switch (cmd) {
398
+ case 'init': cmdInit(rest); break;
399
+ case 'run': cmdRun(rest); break;
400
+ case 'build': cmdBuild(rest); break;
401
+ case 'check': cmdCheck(rest); break;
402
+ case 'new': cmdNew(rest); break;
403
+ case 'help': case '--help': case '-h': case undefined:
404
+ cmdHelp(); break;
405
+ default:
406
+ console.log('');
407
+ err(`Unknown command: "${cmd}"`);
408
+ tip('Run: clewy --help');
409
+ console.log('');
410
+ process.exit(1);
411
+ }