@emberkit/cli 0.6.1-alpha.8 → 0.6.1

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,10 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ /** `packages/cli/package.json` version (works when running compiled output in `dist/`). */
5
+ export function getCliPackageVersion() {
6
+ const here = dirname(fileURLToPath(import.meta.url));
7
+ const pkgPath = join(here, "../package.json");
8
+ const raw = readFileSync(pkgPath, "utf8");
9
+ return JSON.parse(raw).version;
10
+ }
package/dist/cli.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import inquirer from "inquirer";
2
+ import { getCliPackageVersion } from "./cli-package-version.js";
2
3
  import { dev } from "./commands/dev.js";
3
4
  import { build } from "./commands/build.js";
4
5
  import { preview } from "./commands/preview.js";
@@ -29,7 +30,7 @@ export async function runCLI(args) {
29
30
  break;
30
31
  case "--version":
31
32
  case "-v":
32
- console.log("EmberKit CLI v0.6.0");
33
+ console.log(`EmberKit CLI v${getCliPackageVersion()}`);
33
34
  break;
34
35
  case "--help":
35
36
  case "-h":
@@ -43,7 +44,7 @@ export async function runCLI(args) {
43
44
  }
44
45
  function showHelp() {
45
46
  console.log(`
46
- 🔥 EmberKit CLI v0.6.0
47
+ 🔥 EmberKit CLI v${getCliPackageVersion()}
47
48
 
48
49
  Usage: emberkit <command> [options]
49
50
 
@@ -0,0 +1,10 @@
1
+ // Semver ranges for @emberkit/* packages written into generated projects.
2
+ // When releasing libraries, bump these to match packages/*/package.json "version".
3
+ export const EMBERKIT_PACKAGE_VERSIONS = {
4
+ core: "^0.2.6",
5
+ ui: "^0.3.0",
6
+ icons: "^0.2.3",
7
+ cli: "^0.6.1",
8
+ edge: "^0.2.3",
9
+ tsconfig: "^0.2.1",
10
+ };
@@ -2,13 +2,16 @@
2
2
  * Shared builders for project template boilerplate.
3
3
  * Each template composes from these instead of duplicating identical config files.
4
4
  */
5
+ import { EMBERKIT_PACKAGE_VERSIONS as V } from "../../../emberkit-package-versions.js";
5
6
  export function buildPackageJson(options = {}) {
6
7
  const { hasTailwind = false, hasUI = false } = options;
7
- const deps = { "@emberkit/core": "^0.2.4" };
8
- if (hasUI)
9
- deps["@emberkit/ui"] = "^0.2.3";
8
+ const deps = { "@emberkit/core": V.core };
9
+ if (hasUI) {
10
+ deps["@emberkit/ui"] = V.ui;
11
+ deps["@emberkit/icons"] = V.icons;
12
+ }
10
13
  const devDeps = {
11
- "@emberkit/cli": "^0.2.4",
14
+ "@emberkit/cli": V.cli,
12
15
  typescript: "^5.7.0",
13
16
  vite: "^6.0.0",
14
17
  };
@@ -137,7 +137,7 @@ const HomePage: RouteComponent = () => {
137
137
  <div className="space-y-10">
138
138
  {posts.map((post) => (
139
139
  <article key={post.slug} className="group">
140
- <a href={\`/posts/\${post.slug}\`} className="block">
140
+ <a href={post.slug} className="block">
141
141
  <h2 className="text-xl font-semibold font-serif mb-2 group-hover:text-blue-600 transition-colors">
142
142
  {post.title}
143
143
  </h2>
@@ -156,7 +156,7 @@ const HomePage: RouteComponent = () => {
156
156
  };
157
157
 
158
158
  export default HomePage;`,
159
- "src/routes/[slug].tsx": `import type { RouteComponent, RouteParams } from '@emberkit/core';
159
+ "src/routes/[slug].tsx": `import type { RouteParams } from '@emberkit/core';
160
160
  import { Head } from '@emberkit/core';
161
161
 
162
162
  interface PostData {
@@ -190,11 +190,11 @@ const posts: Record<string, PostData> = {
190
190
  content: \`
191
191
  <p>Signals are the reactive primitive at the core of EmberKit.</p>
192
192
  <h2>Creating Signals</h2>
193
- <pre><code>const count = signal(0);</code></pre>
193
+ <pre><code>const [count, setCount] = createSignal(0);</code></pre>
194
194
  <h2>Computed Values</h2>
195
- <pre><code>const doubled = computed(() => count.value * 2);</code></pre>
195
+ <pre><code>const doubled = createMemo(() => count() * 2);</code></pre>
196
196
  <h2>Side Effects</h2>
197
- <pre><code>effect(() => console.log(count.value));</code></pre>
197
+ <pre><code>createEffect(() => console.log(count()));</code></pre>
198
198
  \`,
199
199
  },
200
200
  'file-based-routing': {
@@ -212,11 +212,7 @@ const posts: Record<string, PostData> = {
212
212
  },
213
213
  };
214
214
 
215
- interface Params {
216
- slug: string;
217
- }
218
-
219
- const PostPage: RouteComponent<Params> = ({ params }: RouteParams<Params>) => {
215
+ export default function PostPage({ params }: RouteParams<{ slug: string }>) {
220
216
  const post = posts[params.slug];
221
217
 
222
218
  if (!post) {
@@ -250,9 +246,7 @@ const PostPage: RouteComponent<Params> = ({ params }: RouteParams<Params>) => {
250
246
  </article>
251
247
  </>
252
248
  );
253
- };
254
-
255
- export default PostPage;`,
249
+ }`,
256
250
  "src/routes/about.tsx": `import type { RouteComponent } from '@emberkit/core';
257
251
  import { Head } from '@emberkit/core';
258
252
 
@@ -28,11 +28,11 @@ body {
28
28
  @apply bg-gray-50 text-gray-900 font-sans;
29
29
  }`,
30
30
  "src/routes/_layout.tsx": `import type { RouteComponent } from '@emberkit/core';
31
- import { signal } from '@emberkit/core';
31
+ import { createSignal } from '@emberkit/core';
32
32
  import { Sidebar, Header } from '@emberkit/ui';
33
33
 
34
34
  const Layout: RouteComponent = ({ children }) => {
35
- const sidebarOpen = signal(true);
35
+ const [sidebarOpen, setSidebarOpen] = createSignal(true);
36
36
 
37
37
  const sidebarItems = [
38
38
  { label: 'Dashboard', href: '/dashboard', icon: 'grid' },
@@ -47,15 +47,15 @@ const Layout: RouteComponent = ({ children }) => {
47
47
  <Sidebar
48
48
  logo={<span className="font-bold text-lg">&#9889; {{name}}</span>}
49
49
  items={sidebarItems}
50
- collapsed={!sidebarOpen.value}
51
- onToggle={() => { sidebarOpen.value = !sidebarOpen.value; }}
50
+ collapsed={!sidebarOpen()}
51
+ onToggle={() => { setSidebarOpen(!sidebarOpen()); }}
52
52
  className="w-64"
53
53
  />
54
54
  <div className="flex-1 flex flex-col min-w-0">
55
55
  <Header
56
56
  title="Dashboard"
57
57
  user={{ name: 'User', avatar: '' }}
58
- onMenuClick={() => { sidebarOpen.value = !sidebarOpen.value; }}
58
+ onMenuClick={() => { setSidebarOpen(!sidebarOpen()); }}
59
59
  />
60
60
  <main className="flex-1 p-6 overflow-auto">
61
61
  {children}
@@ -162,7 +162,7 @@ const DashboardPage: RouteComponent = () => {
162
162
  export default DashboardPage;`,
163
163
  "src/routes/users.tsx": `import type { RouteComponent } from '@emberkit/core';
164
164
  import { Card, Badge, Button, Input } from '@emberkit/ui';
165
- import { signal } from '@emberkit/core';
165
+ import { createSignal } from '@emberkit/core';
166
166
 
167
167
  interface User {
168
168
  id: number;
@@ -182,12 +182,12 @@ const users: User[] = [
182
182
  ];
183
183
 
184
184
  const UsersPage: RouteComponent = () => {
185
- const search = signal('');
185
+ const [search, setSearch] = createSignal('');
186
186
 
187
187
  const filteredUsers = users.filter(
188
188
  (u) =>
189
- u.name.toLowerCase().includes(search.value.toLowerCase()) ||
190
- u.email.toLowerCase().includes(search.value.toLowerCase())
189
+ u.name.toLowerCase().includes(search().toLowerCase()) ||
190
+ u.email.toLowerCase().includes(search().toLowerCase())
191
191
  );
192
192
 
193
193
  const statusVariant = (status: User['status']) => {
@@ -212,8 +212,8 @@ const UsersPage: RouteComponent = () => {
212
212
  <div className="mb-4">
213
213
  <Input
214
214
  placeholder="Search users..."
215
- value={search.value}
216
- onInput={(e) => { search.value = e.currentTarget.value; }}
215
+ value={search()}
216
+ onInput={(e) => { setSearch(e.currentTarget.value); }}
217
217
  className="max-w-sm"
218
218
  />
219
219
  </div>
@@ -260,17 +260,17 @@ const UsersPage: RouteComponent = () => {
260
260
  export default UsersPage;`,
261
261
  "src/routes/settings.tsx": `import type { RouteComponent } from '@emberkit/core';
262
262
  import { Card, Input, Button, Alert } from '@emberkit/ui';
263
- import { signal } from '@emberkit/core';
263
+ import { createSignal } from '@emberkit/core';
264
264
 
265
265
  const SettingsPage: RouteComponent = () => {
266
- const name = signal('John Doe');
267
- const email = signal('john@example.com');
268
- const saved = signal(false);
266
+ const [name, setName] = createSignal('John Doe');
267
+ const [email, setEmail] = createSignal('john@example.com');
268
+ const [saved, setSaved] = createSignal(false);
269
269
 
270
270
  const handleSave = (e: Event) => {
271
271
  e.preventDefault();
272
- saved.value = true;
273
- setTimeout(() => { saved.value = false; }, 3000);
272
+ setSaved(true);
273
+ setTimeout(() => { setSaved(false); }, 3000);
274
274
  };
275
275
 
276
276
  return (
@@ -280,7 +280,7 @@ const SettingsPage: RouteComponent = () => {
280
280
  <p className="text-gray-600 mt-1">Manage your account preferences.</p>
281
281
  </div>
282
282
 
283
- {saved.value && (
283
+ {saved() && (
284
284
  <Alert variant="success">Settings saved successfully!</Alert>
285
285
  )}
286
286
 
@@ -289,14 +289,14 @@ const SettingsPage: RouteComponent = () => {
289
289
  <form onSubmit={handleSave} className="space-y-4">
290
290
  <Input
291
291
  label="Full Name"
292
- value={name.value}
293
- onInput={(e) => { name.value = e.currentTarget.value; }}
292
+ value={name()}
293
+ onInput={(e) => { setName(e.currentTarget.value); }}
294
294
  />
295
295
  <Input
296
296
  label="Email"
297
297
  type="email"
298
- value={email.value}
299
- onInput={(e) => { email.value = e.currentTarget.value; }}
298
+ value={email()}
299
+ onInput={(e) => { setEmail(e.currentTarget.value); }}
300
300
  />
301
301
  <div className="flex justify-end">
302
302
  <Button variant="primary" type="submit">Save Changes</Button>
@@ -103,11 +103,11 @@ const Layout: RouteComponent = ({ children }) => {
103
103
 
104
104
  export default Layout;`,
105
105
  "src/routes/index.tsx": `import type { RouteComponent } from '@emberkit/core';
106
- import { signal } from '@emberkit/core';
106
+ import { createSignal } from '@emberkit/core';
107
107
  import { Button, Card, Badge } from '@emberkit/ui';
108
108
 
109
109
  const HomePage: RouteComponent = () => {
110
- const annual = signal(false);
110
+ const [annual, setAnnual] = createSignal(false);
111
111
 
112
112
  const features = [
113
113
  { icon: '&#9889;', title: 'Lightning Fast', desc: 'Sub-10KB runtime with tree-shakeable architecture' },
@@ -121,8 +121,8 @@ const HomePage: RouteComponent = () => {
121
121
  const plans = [
122
122
  {
123
123
  name: 'Starter',
124
- price: annual.value ? '$0' : '$0',
125
- period: annual.value ? '/year' : '/month',
124
+ price: annual() ? '$0' : '$0',
125
+ period: annual() ? '/year' : '/month',
126
126
  desc: 'Perfect for side projects',
127
127
  features: ['1 user', '5 projects', '1GB storage', 'Community support'],
128
128
  cta: 'Get Started Free',
@@ -130,8 +130,8 @@ const HomePage: RouteComponent = () => {
130
130
  },
131
131
  {
132
132
  name: 'Pro',
133
- price: annual.value ? '$199' : '$19',
134
- period: annual.value ? '/year' : '/month',
133
+ price: annual() ? '$199' : '$19',
134
+ period: annual() ? '/year' : '/month',
135
135
  desc: 'For growing teams',
136
136
  features: ['10 users', 'Unlimited projects', '50GB storage', 'Priority support', 'Analytics', 'API access'],
137
137
  cta: 'Start Free Trial',
@@ -211,14 +211,14 @@ const HomePage: RouteComponent = () => {
211
211
  <p className="text-lg text-slate-600 mb-8">Choose the plan that works for your team</p>
212
212
  <div className="inline-flex items-center gap-3 p-1 bg-white rounded-lg border border-slate-200">
213
213
  <button
214
- className={\`px-4 py-2 text-sm font-medium rounded-md transition-colors \${!annual.value ? 'bg-brand-600 text-white' : 'text-slate-600'}\`}
215
- onClick={() => { annual.value = false; }}
214
+ className={\`px-4 py-2 text-sm font-medium rounded-md transition-colors \${!annual() ? 'bg-brand-600 text-white' : 'text-slate-600'}\`}
215
+ onClick={() => { setAnnual(false); }}
216
216
  >
217
217
  Monthly
218
218
  </button>
219
219
  <button
220
- className={\`px-4 py-2 text-sm font-medium rounded-md transition-colors \${annual.value ? 'bg-brand-600 text-white' : 'text-slate-600'}\`}
221
- onClick={() => { annual.value = true; }}
220
+ className={\`px-4 py-2 text-sm font-medium rounded-md transition-colors \${annual() ? 'bg-brand-600 text-white' : 'text-slate-600'}\`}
221
+ onClick={() => { setAnnual(true); }}
222
222
  >
223
223
  Annual <span className="text-brand-600 ml-1 font-semibold">-20%</span>
224
224
  </button>
@@ -280,19 +280,19 @@ export default HomePage;`,
280
280
  "src/routes/login.tsx": `import type { RouteComponent } from '@emberkit/core';
281
281
  import { Head } from '@emberkit/core';
282
282
  import { Button, Input, Card } from '@emberkit/ui';
283
- import { signal } from '@emberkit/core';
283
+ import { createSignal } from '@emberkit/core';
284
284
 
285
285
  const LoginPage: RouteComponent = () => {
286
- const email = signal('');
287
- const password = signal('');
288
- const error = signal<string | null>(null);
286
+ const [email, setEmail] = createSignal('');
287
+ const [password, setPassword] = createSignal('');
288
+ const [error, setError] = createSignal<string | null>(null);
289
289
 
290
290
  const handleSubmit = (e: Event) => {
291
291
  e.preventDefault();
292
- error.value = null;
292
+ setError(null);
293
293
 
294
- if (!email.value || !password.value) {
295
- error.value = 'Please fill in all fields';
294
+ if (!email() || !password()) {
295
+ setError('Please fill in all fields');
296
296
  return;
297
297
  }
298
298
 
@@ -315,18 +315,18 @@ const LoginPage: RouteComponent = () => {
315
315
  label="Email"
316
316
  type="email"
317
317
  placeholder="you@example.com"
318
- value={email.value}
319
- onInput={(e) => { email.value = e.currentTarget.value; }}
318
+ value={email()}
319
+ onInput={(e) => { setEmail(e.currentTarget.value); }}
320
320
  />
321
321
  <Input
322
322
  label="Password"
323
323
  type="password"
324
324
  placeholder="&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;"
325
- value={password.value}
326
- onInput={(e) => { password.value = e.currentTarget.value; }}
325
+ value={password()}
326
+ onInput={(e) => { setPassword(e.currentTarget.value); }}
327
327
  />
328
- {error.value && (
329
- <p className="text-red-500 text-sm">{error.value}</p>
328
+ {error() && (
329
+ <p className="text-red-500 text-sm">{error()}</p>
330
330
  )}
331
331
  <div className="flex items-center justify-between text-sm">
332
332
  <label className="flex items-center gap-2">
@@ -350,20 +350,20 @@ export default LoginPage;`,
350
350
  "src/routes/signup.tsx": `import type { RouteComponent } from '@emberkit/core';
351
351
  import { Head } from '@emberkit/core';
352
352
  import { Button, Input, Card } from '@emberkit/ui';
353
- import { signal } from '@emberkit/core';
353
+ import { createSignal } from '@emberkit/core';
354
354
 
355
355
  const SignupPage: RouteComponent = () => {
356
- const name = signal('');
357
- const email = signal('');
358
- const password = signal('');
359
- const error = signal<string | null>(null);
356
+ const [name, setName] = createSignal('');
357
+ const [email, setEmail] = createSignal('');
358
+ const [password, setPassword] = createSignal('');
359
+ const [error, setError] = createSignal<string | null>(null);
360
360
 
361
361
  const handleSubmit = (e: Event) => {
362
362
  e.preventDefault();
363
- error.value = null;
363
+ setError(null);
364
364
 
365
- if (!name.value || !email.value || !password.value) {
366
- error.value = 'Please fill in all fields';
365
+ if (!name() || !email() || !password()) {
366
+ setError('Please fill in all fields');
367
367
  return;
368
368
  }
369
369
 
@@ -385,25 +385,25 @@ const SignupPage: RouteComponent = () => {
385
385
  <Input
386
386
  label="Full Name"
387
387
  placeholder="John Doe"
388
- value={name.value}
389
- onInput={(e) => { name.value = e.currentTarget.value; }}
388
+ value={name()}
389
+ onInput={(e) => { setName(e.currentTarget.value); }}
390
390
  />
391
391
  <Input
392
392
  label="Email"
393
393
  type="email"
394
394
  placeholder="you@example.com"
395
- value={email.value}
396
- onInput={(e) => { email.value = e.currentTarget.value; }}
395
+ value={email()}
396
+ onInput={(e) => { setEmail(e.currentTarget.value); }}
397
397
  />
398
398
  <Input
399
399
  label="Password"
400
400
  type="password"
401
401
  placeholder="8+ characters"
402
- value={password.value}
403
- onInput={(e) => { password.value = e.currentTarget.value; }}
402
+ value={password()}
403
+ onInput={(e) => { setPassword(e.currentTarget.value); }}
404
404
  />
405
- {error.value && (
406
- <p className="text-red-500 text-sm">{error.value}</p>
405
+ {error() && (
406
+ <p className="text-red-500 text-sm">{error()}</p>
407
407
  )}
408
408
  <p className="text-xs text-slate-500">
409
409
  By signing up, you agree to our {' '}
@@ -103,7 +103,7 @@ const Layout: RouteComponent = ({ children }) => {
103
103
 
104
104
  export default Layout;`,
105
105
  "src/routes/index.tsx": `import type { RouteComponent } from '@emberkit/core';
106
- import { signal } from '@emberkit/core';
106
+ import { createSignal } from '@emberkit/core';
107
107
  import {
108
108
  Button,
109
109
  Card,
@@ -116,7 +116,7 @@ import {
116
116
  } from '@emberkit/ui';
117
117
 
118
118
  const HomePage: RouteComponent = () => {
119
- const activeTab = signal('features');
119
+ const [activeTab, setActiveTab] = createSignal('features');
120
120
 
121
121
  const features = [
122
122
  { icon: '⚡', title: 'Lightning Fast', desc: 'Sub-10KB runtime with tree-shakeable architecture' },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emberkit/cli",
3
- "version": "0.6.1-alpha.8",
3
+ "version": "0.6.1",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "description": "CLI tool for EmberKit projects",
@@ -40,7 +40,11 @@
40
40
  "inquirer": "^9.2.0"
41
41
  },
42
42
  "devDependencies": {
43
- "@types/inquirer": "^9.0.3"
43
+ "@eslint/js": "^10.0.1",
44
+ "@types/inquirer": "^9.0.3",
45
+ "eslint": "^10.0.0",
46
+ "eslint-plugin-perfectionist": "^5.9.0",
47
+ "typescript-eslint": "^8.59.3"
44
48
  },
45
49
  "scripts": {
46
50
  "build": "tsc",