@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.
- package/bin/index.js +3 -0
- package/docs/GUIDE.md +333 -0
- package/docs/README.md +140 -0
- package/docs/SYNTAXES.md +335 -0
- package/lib/cli.js +90 -0
- package/lib/scaffold.js +102 -0
- package/lib/templates.js +1400 -0
- package/package.json +25 -0
package/docs/SYNTAXES.md
ADDED
|
@@ -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
|
+
}
|
package/lib/scaffold.js
ADDED
|
@@ -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
|
+
}
|