@firesmasher/velox.js 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.
@@ -0,0 +1,335 @@
1
+ # Velox.js — Syntax Reference
2
+
3
+ ## Statements
4
+
5
+ Every Velox statement ends with `;`
6
+
7
+ ```
8
+ Command("argument") $modifiers;
9
+ ```
10
+
11
+ Arguments go inside `"double quotes"`. Statements without an argument still need `()`:
12
+
13
+ ```
14
+ Dom.hide();
15
+ Dom.setText("Hello");
16
+ ```
17
+
18
+ ---
19
+
20
+ ## Connecting .vlx to HTML
21
+
22
+ Velox scans all `<?velox ... >` tags at page load. There are three patterns:
23
+
24
+ **Pattern 1 — inline command, runs at page load:**
25
+ ```html
26
+ <?velox Dom.setText("Hello") $target="$id(output)" >
27
+ ```
28
+
29
+ **Pattern 2 — run a .vlx file at page load:**
30
+ ```html
31
+ <?velox Velox.run("assets/scripts/velox/myscript.vlx") $target="$id(output)" >
32
+ ```
33
+
34
+ **Pattern 3 — event listener (runs on user interaction):**
35
+ ```html
36
+ <?velox $on click "$id(myBtn)": Dom.setText("Clicked!") $target="$id(output)" >
37
+ <?velox $on click "$id(myBtn)": Velox.run("myscript.vlx") $target="$id(output)" >
38
+ ```
39
+
40
+ > `velox.js` must be loaded **before** the closing `</body>` tag.
41
+
42
+ ---
43
+
44
+ ## Target Selectors
45
+
46
+ Used in `$target="..."` and `$on` event selectors.
47
+
48
+ | Syntax | Resolves to |
49
+ |---|---|
50
+ | `$id(myId)` | `document.getElementById("myId")` |
51
+ | `$class(myClass)` | first element with that class |
52
+ | `$query(.card > p)` | `document.querySelector(...)` — any CSS selector |
53
+ | `$tag(div)` | first element of that tag |
54
+
55
+ ---
56
+
57
+ ## Modifiers
58
+
59
+ Modifiers go after the command call on the same statement.
60
+
61
+ ### `$target="selector"`
62
+ Set which element the command operates on.
63
+ ```
64
+ Dom.setText("Hello") $target="$id(output)";
65
+ ```
66
+
67
+ ### `$type="value"`
68
+ Changes the behaviour of certain commands.
69
+ ```
70
+ Url.fetch("file.zip") $type="download";
71
+ file.localFetch("data.json") $type="download";
72
+ ```
73
+
74
+ ### `$delay N`
75
+ Wait N milliseconds before running.
76
+ ```
77
+ Dom.show() $target="$id(box)" $delay 500;
78
+ ```
79
+
80
+ ### `$repeat N`
81
+ Run the command N times (combined with `$delay` for intervals).
82
+ ```
83
+ echo("tick") $repeat 5 $delay 1000;
84
+ ```
85
+
86
+ ---
87
+
88
+ ## Conditional Blocks
89
+
90
+ Conditionals go after the command and fire based on whether it succeeded.
91
+
92
+ ```
93
+ Command("arg")
94
+ $if .: echo("success")
95
+ $else: echo.err("failed");
96
+ ```
97
+
98
+ | Block | Fires when |
99
+ |---|---|
100
+ | `$if .` | command succeeded (result is true) |
101
+ | `$if 1` | always fires |
102
+ | `$if 0` | never fires |
103
+ | `$if else .` | previous `$if` did not fire, and result is true |
104
+ | `$else` | previous `$if` / `$if else` did not fire |
105
+
106
+ Callbacks inside `$if` / `$else` support: `echo()`, `echo.err()`, `echo.warn()`, `Dom.*`, `Anim.*`, `Page.redirect()`, `Page.reload()`, `Page.scrollTop()`, `Var.set()`.
107
+
108
+ ---
109
+
110
+ ## Event Listeners — `$on`
111
+
112
+ ```
113
+ $on <event> "<selector>": <command>;
114
+ ```
115
+
116
+ Only usable inside `<?velox ... >` tags or as top-level statements in a `.vlx` file.
117
+
118
+ ```
119
+ $on click "$id(btn)": Dom.setText("Clicked") $target="$id(out)";
120
+ $on hover "$id(card)": Anim.pulse() $target="$id(card)";
121
+ $on input "$id(search)": Dom.getValue() $target="$id(search)";
122
+ $on submit "$id(myForm)": Form.serialize("$id(myForm)") $target="$id(out)";
123
+ ```
124
+
125
+ | Event | DOM event |
126
+ |---|---|
127
+ | `click` | `click` |
128
+ | `hover` | `mouseenter` |
129
+ | `input` | `input` |
130
+ | `change` | `change` |
131
+ | `submit` | `submit` (also calls `preventDefault`) |
132
+ | `keydown` | `keydown` |
133
+ | `load` | `window load` |
134
+
135
+ ---
136
+
137
+ ## Value Rules
138
+
139
+ | Value | Meaning |
140
+ |---|---|
141
+ | `1` | true |
142
+ | `0` | false |
143
+ | `.` | pass / null / use result |
144
+ | `_` | same as `.` |
145
+
146
+ ---
147
+
148
+ ## Path Rules
149
+
150
+ | Path format | Resolves to |
151
+ |---|---|
152
+ | `https://example.com/x` | used as-is |
153
+ | `/assets/file.js` | absolute from server root |
154
+ | `../../assets/file.js` | converted to `/assets/file.js` |
155
+ | `@env:myKey` | looked up in `quickPaths.json` |
156
+
157
+ ---
158
+
159
+ ## .vlx File Format
160
+
161
+ ```vlx
162
+ // This is a comment
163
+
164
+ Dom.setText("Hello") $target="$id(output)";
165
+ Dom.addClass("active") $target="$id(output)";
166
+
167
+ Var.set("user:Alice");
168
+ Var.get("user") $target="$id(name)"
169
+ $if .: echo("Got it")
170
+ $else: echo.err("Missing");
171
+
172
+ echo("Script done");
173
+ ```
174
+
175
+ - One statement per line is recommended but not required
176
+ - Statements end with `;`
177
+ - Line comments use `//`
178
+ - No commas between statements
179
+ - Arguments always use `"double quotes"`
180
+
181
+ ---
182
+
183
+ ## Commands
184
+
185
+ ### DOM
186
+
187
+ ```
188
+ Dom.setText("text") — set textContent of target
189
+ Dom.setHtml("html") — set innerHTML of target
190
+ Dom.append("html") — append HTML inside target
191
+ Dom.prepend("html") — prepend HTML inside target
192
+ Dom.remove() — remove target from DOM
193
+ Dom.clear() — clear innerHTML of target
194
+ Dom.show() — remove display:none
195
+ Dom.hide() — set display:none
196
+ Dom.toggle() — toggle visibility
197
+ Dom.addClass("name") — add CSS class
198
+ Dom.removeClass("name") — remove CSS class
199
+ Dom.toggleClass("name") — toggle CSS class
200
+ Dom.setAttr("attr:value") — set HTML attribute
201
+ Dom.removeAttr("attr") — remove HTML attribute
202
+ Dom.setStyle("prop:value") — set inline CSS property
203
+ Dom.focus() — focus element
204
+ Dom.click() — trigger click on element
205
+ Dom.scrollTo() — scroll element into view
206
+ Dom.getValue() — log input value (console)
207
+ Dom.setValue("val") — set input value
208
+ ```
209
+
210
+ ### Animation
211
+
212
+ ```
213
+ Anim.fadeIn("300") — fade in over N ms
214
+ Anim.fadeOut("300") — fade out over N ms
215
+ Anim.slide("down:300") — slide open over N ms
216
+ Anim.slide("up:300") — slide close over N ms
217
+ Anim.shake() — shake element
218
+ Anim.pulse("600") — pulse element over N ms
219
+ ```
220
+
221
+ ### Events
222
+
223
+ ```
224
+ $on click "$id(btn)": Dom.show() $target="$id(box)";
225
+ $on hover "$id(btn)": Anim.pulse() $target="$id(btn)";
226
+ $on input "$id(inp)": Dom.getValue() $target="$id(inp)";
227
+ $on change "$id(sel)": echo("changed");
228
+ $on submit "$id(frm)": Form.serialize("$id(frm)");
229
+ $on keydown "$id(inp)": echo("key pressed");
230
+ ```
231
+
232
+ ### Form
233
+
234
+ ```
235
+ Form.getValue("$id(inp)") — log input value
236
+ Form.setValue("$id(inp):value") — set input value
237
+ Form.clear("$id(frm)") — clear all inputs in form
238
+ Form.serialize("$id(frm)") — log form as JSON, insert into target
239
+ ```
240
+
241
+ ### Local Storage
242
+
243
+ ```
244
+ Store.set("key:value") — set item
245
+ Store.get("key") — get item, insert into target
246
+ Store.remove("key") — remove item
247
+ Store.clear() — clear all
248
+ ```
249
+
250
+ ### Cookies
251
+
252
+ ```
253
+ Cookie.set("key:value") — set cookie (365 day expiry)
254
+ Cookie.get("key") — get cookie, insert into target
255
+ Cookie.remove("key") — expire cookie
256
+ ```
257
+
258
+ ### Variables (in-memory)
259
+
260
+ ```
261
+ Var.set("key:value") — store variable for this session
262
+ Var.get("key") — get variable, insert into target
263
+ Var.clear("key") — delete one variable
264
+ Var.clear("*") — delete all variables
265
+ ```
266
+
267
+ ### Network
268
+
269
+ ```
270
+ Url.get("https://...") — fetch text, insert into target
271
+ Url.getJson("https://...") — fetch JSON, insert pretty-printed into target
272
+ Url.post("https://...") — POST request
273
+ Url.postJson("https://...:body") — POST with JSON body
274
+ Url.fetch("https://...") — generic fetch
275
+ Url.fetch("https://...") $type="download" — download file
276
+ iframe.Url("https://...") — load URL in iframe inside target
277
+ ```
278
+
279
+ ### File
280
+
281
+ ```
282
+ file.localFetch("/path/to/file") — fetch local file
283
+ file.localFetch("/path/to/file") $type="download" — download local file
284
+ ```
285
+
286
+ ### Page
287
+
288
+ ```
289
+ Page.redirect("https://...") — navigate to URL
290
+ Page.reload() — reload page
291
+ Page.title("My Page") — set document.title
292
+ Page.meta("description:text") — set/update <meta name="...">
293
+ Page.scrollTop() — scroll window to top
294
+ ```
295
+
296
+ ### Router (SPA)
297
+
298
+ ```
299
+ Router.define("/:vlxPath") — register route → .vlx file
300
+ Router.go("/about") — navigate to route
301
+ Router.start() $target="$id(outlet)" — start hash router, render into target
302
+ ```
303
+
304
+ ### Template
305
+
306
+ Requires a `<template id="tplId">` tag in your HTML with `{{key}}` placeholders.
307
+
308
+ ```
309
+ Template.render("tplId:{\"name\":\"Alice\",\"role\":\"Admin\"}")
310
+ $target="$id(output)";
311
+ ```
312
+
313
+ ### Script / Style
314
+
315
+ ```
316
+ Script.load("/assets/scripts/javascript/lib.js");
317
+ Style.load("/assets/css/theme.css");
318
+ ```
319
+
320
+ ### Logging
321
+
322
+ ```
323
+ echo("message") — console.log
324
+ echo.warn("message") — console.warn
325
+ echo.err("message") — console.error
326
+ ```
327
+
328
+ ### Velox.run
329
+
330
+ Runs a `.vlx` file. Used inside `<?velox >` tags or `$on` event callbacks.
331
+
332
+ ```html
333
+ <?velox Velox.run("assets/scripts/velox/myscript.vlx") $target="$id(output)" >
334
+ <?velox $on click "$id(btn)": Velox.run("myscript.vlx") $target="$id(out)" >
335
+ ```
package/lib/cli.js ADDED
@@ -0,0 +1,90 @@
1
+ import prompts from "prompts";
2
+ import kleur from "kleur";
3
+ import fs from "fs";
4
+ import path from "path";
5
+ import { scaffold } from "./scaffold.js";
6
+
7
+ const BANNER = `
8
+ ${kleur.cyan().bold(" ██╗ ██╗███████╗██╗ ██████╗ ██╗ ██╗")}
9
+ ${kleur.cyan().bold(" ██║ ██║██╔════╝██║ ██╔═══██╗╚██╗██╔╝")}
10
+ ${kleur.cyan().bold(" ██║ ██║█████╗ ██║ ██║ ██║ ╚███╔╝ ")}
11
+ ${kleur.cyan().bold(" ╚██╗ ██╔╝██╔══╝ ██║ ██║ ██║ ██╔██╗ ")}
12
+ ${kleur.cyan().bold(" ╚████╔╝ ███████╗███████╗╚██████╔╝██╔╝ ██╗")}
13
+ ${kleur.cyan().bold(" ╚═══╝ ╚══════╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝")}
14
+ ${kleur.gray(" Velox.js — The Fast Frontend Framework")}
15
+ `;
16
+
17
+ export async function run() {
18
+ console.log(BANNER);
19
+
20
+ // Get project name from CLI arg or prompt
21
+ const argName = process.argv[2];
22
+
23
+ let projectName = argName && !argName.startsWith("-") ? argName : null;
24
+
25
+ const answers = await prompts(
26
+ [
27
+ {
28
+ type: projectName ? null : "text",
29
+ name: "projectName",
30
+ message: "Project name:",
31
+ initial: "my-velox-app",
32
+ validate: (v) =>
33
+ /^[a-z0-9\-_]+$/i.test(v) || "Use only letters, numbers, hyphens, or underscores",
34
+ },
35
+ {
36
+ type: "text",
37
+ name: "author",
38
+ message: "Author:",
39
+ initial: "",
40
+ },
41
+ {
42
+ type: "text",
43
+ name: "version",
44
+ message: "Version:",
45
+ initial: "1.0.0",
46
+ validate: (v) =>
47
+ /^\d+\.\d+\.\d+$/.test(v) || "Use semantic versioning (e.g. 1.0.0)",
48
+ },
49
+ {
50
+ type: "select",
51
+ name: "defaultPage",
52
+ message: "Include a starter index.html?",
53
+ choices: [
54
+ { title: "Yes", value: true },
55
+ { title: "No — empty project", value: false },
56
+ ],
57
+ },
58
+ ],
59
+ {
60
+ onCancel: () => {
61
+ console.log(kleur.red("\n✖ Cancelled."));
62
+ process.exit(1);
63
+ },
64
+ }
65
+ );
66
+
67
+ if (projectName) answers.projectName = projectName;
68
+
69
+ const targetDir = path.resolve(process.cwd(), answers.projectName);
70
+
71
+ if (fs.existsSync(targetDir)) {
72
+ console.log(
73
+ kleur.red(`\n✖ Directory "${answers.projectName}" already exists.`)
74
+ );
75
+ process.exit(1);
76
+ }
77
+
78
+ console.log(
79
+ `\n${kleur.cyan("◆")} Scaffolding ${kleur.bold(answers.projectName)}...\n`
80
+ );
81
+
82
+ await scaffold(targetDir, answers);
83
+
84
+ console.log(`${kleur.green("✔")} Done!\n`);
85
+ console.log(` ${kleur.gray("cd")} ${kleur.cyan(answers.projectName)}`);
86
+ console.log(` ${kleur.gray("Open")} ${kleur.cyan("public/index.html")} ${kleur.gray("to get started")}\n`);
87
+ console.log(
88
+ ` ${kleur.gray("Docs:")} ${kleur.underline("https://veloxjs.dev")}\n`
89
+ );
90
+ }
@@ -0,0 +1,102 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import kleur from "kleur";
4
+ import { templates } from "./templates.js";
5
+
6
+ const STRUCTURE = [
7
+ "docs",
8
+ "public",
9
+ "assets/css",
10
+ "assets/scripts/javascript",
11
+ "assets/scripts/velox",
12
+ "assets/icons/svg",
13
+ "assets/icons/png",
14
+ ".velox/conf",
15
+ "tags/savedFiles",
16
+ "tags/json",
17
+ "storage/variables",
18
+ "storage/env",
19
+ ];
20
+
21
+ const FILES = [
22
+ {
23
+ path: ".velox/conf/config.jsonc",
24
+ content: (a) => templates.config(a),
25
+ },
26
+ {
27
+ path: "storage/env/quickPaths.json",
28
+ content: () => templates.quickPaths(),
29
+ },
30
+ {
31
+ path: "storage/variables/normal.json",
32
+ content: () => `{}`,
33
+ },
34
+ {
35
+ path: "storage/variables/sha1.json",
36
+ content: () => `{}`,
37
+ },
38
+ {
39
+ path: "tags/json/UrlS.json",
40
+ content: () => templates.urlS(),
41
+ },
42
+ {
43
+ path: "assets/css/style.css",
44
+ content: (a) => templates.css(a),
45
+ },
46
+ {
47
+ path: "assets/scripts/velox/velox.js",
48
+ content: () => templates.veloxRuntime(),
49
+ },
50
+ {
51
+ path: "tags/savedFiles/.gitkeep",
52
+ content: () => "",
53
+ },
54
+ {
55
+ path: ".gitignore",
56
+ content: () => templates.gitignore(),
57
+ },
58
+ {
59
+ path: "velox.project.json",
60
+ content: (a) => templates.projectMeta(a),
61
+ },
62
+ {
63
+ path: "docs/README.md",
64
+ content: () => fs.readFileSync(new URL("../docs/README.md", import.meta.url), "utf8"),
65
+ },
66
+ {
67
+ path: "docs/SYNTAXES.md",
68
+ content: () => fs.readFileSync(new URL("../docs/SYNTAXES.md", import.meta.url), "utf8"),
69
+ },
70
+ {
71
+ path: "docs/GUIDE.md",
72
+ content: () => fs.readFileSync(new URL("../docs/GUIDE.md", import.meta.url), "utf8"),
73
+ },
74
+ ];
75
+
76
+ export async function scaffold(targetDir, answers) {
77
+ for (const dir of STRUCTURE) {
78
+ const full = path.join(targetDir, dir);
79
+ fs.mkdirSync(full, { recursive: true });
80
+ logCreated("dir", dir);
81
+ }
82
+
83
+ for (const file of FILES) {
84
+ const full = path.join(targetDir, file.path);
85
+ fs.writeFileSync(full, file.content(answers), "utf8");
86
+ logCreated("file", file.path);
87
+ }
88
+
89
+ if (answers.defaultPage) {
90
+ const indexPath = path.join(targetDir, "public/index.html");
91
+ fs.writeFileSync(indexPath, templates.indexHtml(answers), "utf8");
92
+ logCreated("file", "public/index.html");
93
+ } else {
94
+ fs.writeFileSync(path.join(targetDir, "public/.gitkeep"), "", "utf8");
95
+ logCreated("file", "public/.gitkeep");
96
+ }
97
+ }
98
+
99
+ function logCreated(type, filePath) {
100
+ const icon = type === "dir" ? kleur.blue(" ▸ dir ") : kleur.green(" ✔ file");
101
+ console.log(`${icon} ${kleur.gray(filePath)}`);
102
+ }