create-stator 1.0.0 → 1.1.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/index.js +71 -18
- package/package.json +5 -2
- package/templates/minimal/README.md +31 -0
- package/{template → templates/minimal}/package.json +1 -1
- package/{template → templates/minimal}/tsconfig.json +19 -4
- /package/{template → templates/minimal}/_gitignore +0 -0
- /package/{template → templates/minimal}/build.ts +0 -0
- /package/{template → templates/minimal}/machines/counter.ts +0 -0
- /package/{template → templates/minimal}/routes/index.stator +0 -0
- /package/{template → templates/minimal}/server.ts +0 -0
- /package/{template → templates/minimal}/start.ts +0 -0
- /package/{template → templates/minimal}/static/app.css +0 -0
- /package/{template → templates/minimal}/stator-env.d.ts +0 -0
- /package/{template → templates/minimal}/sync.ts +0 -0
- /package/{template → templates/minimal}/templates/layout.stator +0 -0
package/index.js
CHANGED
|
@@ -1,29 +1,82 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
3
|
-
//
|
|
2
|
+
// Stator scaffolder. Interactive (clack) when run bare; every prompt has a
|
|
3
|
+
// flag so CI and scripts stay prompt-free:
|
|
4
|
+
// pnpm create stator → prompts for directory + template
|
|
5
|
+
// pnpm create stator my-app --template minimal → no prompts
|
|
4
6
|
import { cp, readdir, readFile, rename, stat, writeFile } from 'node:fs/promises'
|
|
5
7
|
import { basename, join, resolve } from 'node:path'
|
|
6
8
|
import { fileURLToPath } from 'node:url'
|
|
9
|
+
import { parseArgs } from 'node:util'
|
|
10
|
+
import * as p from '@clack/prompts'
|
|
7
11
|
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
const TEMPLATES = [
|
|
13
|
+
{
|
|
14
|
+
value: 'minimal',
|
|
15
|
+
label: 'Minimal',
|
|
16
|
+
hint: 'one machine, one page — the smallest real app',
|
|
17
|
+
},
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
const { values: flags, positionals } = parseArgs({
|
|
21
|
+
allowPositionals: true,
|
|
22
|
+
options: {
|
|
23
|
+
template: { type: 'string', short: 't' },
|
|
24
|
+
help: { type: 'boolean', short: 'h' },
|
|
25
|
+
},
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
if (flags.help) {
|
|
29
|
+
console.log(
|
|
30
|
+
`Usage: pnpm create stator [directory] [--template ${TEMPLATES.map((t) => t.value).join('|')}]`,
|
|
31
|
+
)
|
|
32
|
+
process.exit(0)
|
|
13
33
|
}
|
|
14
34
|
|
|
35
|
+
p.intro('create-stator')
|
|
36
|
+
|
|
37
|
+
// --- target directory ---
|
|
38
|
+
let target = positionals[0]
|
|
39
|
+
if (!target) {
|
|
40
|
+
const answer = await p.text({
|
|
41
|
+
message: 'Where should the project live?',
|
|
42
|
+
placeholder: './my-stator-app',
|
|
43
|
+
validate: (v) => (v.trim() === '' ? 'A directory is required.' : undefined),
|
|
44
|
+
})
|
|
45
|
+
bailIfCancelled(answer)
|
|
46
|
+
target = answer
|
|
47
|
+
}
|
|
15
48
|
const dest = resolve(process.cwd(), target)
|
|
49
|
+
|
|
16
50
|
try {
|
|
17
51
|
const existing = await readdir(dest)
|
|
18
52
|
if (existing.length > 0) {
|
|
19
|
-
|
|
53
|
+
p.cancel(`${target} exists and is not empty — refusing to overwrite.`)
|
|
20
54
|
process.exit(1)
|
|
21
55
|
}
|
|
22
56
|
} catch {
|
|
23
57
|
// does not exist — fine
|
|
24
58
|
}
|
|
25
59
|
|
|
26
|
-
|
|
60
|
+
// --- template ---
|
|
61
|
+
let template = flags.template
|
|
62
|
+
if (template && !TEMPLATES.some((t) => t.value === template)) {
|
|
63
|
+
p.cancel(`Unknown template "${template}". Available: ${TEMPLATES.map((t) => t.value).join(', ')}`)
|
|
64
|
+
process.exit(1)
|
|
65
|
+
}
|
|
66
|
+
if (!template) {
|
|
67
|
+
if (TEMPLATES.length === 1) {
|
|
68
|
+
template = TEMPLATES[0].value
|
|
69
|
+
} else {
|
|
70
|
+
const answer = await p.select({ message: 'Which template?', options: TEMPLATES })
|
|
71
|
+
bailIfCancelled(answer)
|
|
72
|
+
template = answer
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// --- scaffold ---
|
|
77
|
+
const s = p.spinner()
|
|
78
|
+
s.start('Copying template')
|
|
79
|
+
const templateDir = fileURLToPath(new URL(`./templates/${template}`, import.meta.url))
|
|
27
80
|
await cp(templateDir, dest, { recursive: true })
|
|
28
81
|
|
|
29
82
|
// npm strips dotfiles from published packages; ship as _gitignore and rename.
|
|
@@ -41,14 +94,14 @@ const pkgPath = join(dest, 'package.json')
|
|
|
41
94
|
const pkg = JSON.parse(await readFile(pkgPath, 'utf8'))
|
|
42
95
|
pkg.name = name
|
|
43
96
|
await writeFile(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`)
|
|
97
|
+
s.stop(`Scaffolded ${name} (${template})`)
|
|
44
98
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
Next steps:
|
|
49
|
-
cd ${target}
|
|
50
|
-
pnpm install
|
|
51
|
-
pnpm dev # http://localhost:3000
|
|
99
|
+
p.note([`cd ${target}`, 'pnpm install', 'pnpm dev'].join('\n'), 'Next steps')
|
|
100
|
+
p.outro('Docs: https://docs.statorjs.dev · Demo: https://demo.statorjs.dev')
|
|
52
101
|
|
|
53
|
-
|
|
54
|
-
|
|
102
|
+
function bailIfCancelled(v) {
|
|
103
|
+
if (p.isCancel(v)) {
|
|
104
|
+
p.cancel('Cancelled.')
|
|
105
|
+
process.exit(0)
|
|
106
|
+
}
|
|
107
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-stator",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Scaffold a new Stator app: pnpm create stator my-app",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"index.js",
|
|
12
|
-
"
|
|
12
|
+
"templates"
|
|
13
13
|
],
|
|
14
14
|
"repository": {
|
|
15
15
|
"type": "git",
|
|
@@ -19,5 +19,8 @@
|
|
|
19
19
|
"homepage": "https://github.com/statorjs/stator#readme",
|
|
20
20
|
"engines": {
|
|
21
21
|
"node": ">=20"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@clack/prompts": "^1.7.0"
|
|
22
25
|
}
|
|
23
26
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# A Stator app
|
|
2
|
+
|
|
3
|
+
```sh
|
|
4
|
+
pnpm install
|
|
5
|
+
pnpm dev # dev server with live reload + the wire inspector
|
|
6
|
+
pnpm typecheck # sync generated component types, then tsc
|
|
7
|
+
pnpm build # production build into dist/
|
|
8
|
+
pnpm start # serve the production build
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## The mental model
|
|
12
|
+
|
|
13
|
+
State lives **on the server**, in machines. Pages declare what they read;
|
|
14
|
+
when an event changes a machine, the server diffs and sends small JSON
|
|
15
|
+
patches to the browser. There is no client renderer and no API layer.
|
|
16
|
+
|
|
17
|
+
- `machines/counter.ts` — a session-scoped machine: typed events, guarded
|
|
18
|
+
transitions, selectors. Session state survives a page reload because the
|
|
19
|
+
server owns it.
|
|
20
|
+
- `routes/index.stator` — a page: frontmatter declares `Stator.reads`, the
|
|
21
|
+
template calls `read(machine, selector)` wherever live values render.
|
|
22
|
+
- `templates/layout.stator` — a component with a `<children />` slot.
|
|
23
|
+
|
|
24
|
+
Try it: run `pnpm dev`, click **+1**, then reload the page — the count
|
|
25
|
+
persists. Open the inspector (bottom of the page) and click again to watch
|
|
26
|
+
the patch arrive on the wire.
|
|
27
|
+
|
|
28
|
+
## Learn more
|
|
29
|
+
|
|
30
|
+
- Docs: https://docs.statorjs.dev — start with the tutorial
|
|
31
|
+
- Reference app: https://demo.statorjs.dev ([source](https://github.com/statorjs/stator/tree/main/apps/store))
|
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
"target": "ES2022",
|
|
4
4
|
"module": "ESNext",
|
|
5
5
|
"moduleResolution": "Bundler",
|
|
6
|
-
"lib": [
|
|
6
|
+
"lib": [
|
|
7
|
+
"ES2022",
|
|
8
|
+
"DOM",
|
|
9
|
+
"DOM.Iterable"
|
|
10
|
+
],
|
|
7
11
|
"strict": true,
|
|
8
12
|
"noUncheckedIndexedAccess": true,
|
|
9
13
|
"esModuleInterop": true,
|
|
@@ -11,8 +15,19 @@
|
|
|
11
15
|
"isolatedModules": true,
|
|
12
16
|
"allowImportingTsExtensions": true,
|
|
13
17
|
"noEmit": true,
|
|
14
|
-
"rootDirs": [
|
|
18
|
+
"rootDirs": [
|
|
19
|
+
".",
|
|
20
|
+
".stator/types"
|
|
21
|
+
],
|
|
22
|
+
"jsx": "preserve"
|
|
15
23
|
},
|
|
16
|
-
"include": [
|
|
17
|
-
|
|
24
|
+
"include": [
|
|
25
|
+
"**/*.ts",
|
|
26
|
+
"**/*.stator"
|
|
27
|
+
],
|
|
28
|
+
"exclude": [
|
|
29
|
+
"node_modules",
|
|
30
|
+
"static",
|
|
31
|
+
"dist"
|
|
32
|
+
]
|
|
18
33
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|