@webjskit/cli 0.3.1 → 0.4.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/webjs.js CHANGED
@@ -6,6 +6,11 @@ import { fileURLToPath } from 'node:url';
6
6
  const __dirname = dirname(fileURLToPath(import.meta.url));
7
7
  const [cmd, ...rest] = process.argv.slice(2);
8
8
 
9
+ // Exactly three scaffolds exist — keep this list as the single source of
10
+ // truth. AI-agent docs in README.md / AGENTS.md / .cursorrules /
11
+ // .windsurfrules / .github/copilot-instructions.md mirror it.
12
+ const TEMPLATES = ['full-stack', 'api', 'saas'];
13
+
9
14
  const USAGE = `webjs — commands:
10
15
  webjs dev [--port 3000] Start dev server with live reload
11
16
  webjs start [--port 3000] Start production server (serves source directly; no build required)
@@ -14,6 +19,7 @@ const USAGE = `webjs — commands:
14
19
  webjs test [--server|--browser] Run server + browser tests
15
20
  webjs check Validate app against conventions
16
21
  webjs create <name> [--template full-stack|api|saas] Scaffold a new webjs app
22
+ (only 3 templates exist; default: full-stack with Prisma+SQLite)
17
23
  webjs db generate Run \`prisma generate\`
18
24
  webjs db migrate [name] Run \`prisma migrate dev\`
19
25
  webjs db studio Run \`prisma studio\`
@@ -201,11 +207,36 @@ async function main() {
201
207
  }
202
208
  case 'create': {
203
209
  const name = rest[0];
204
- if (!name) {
205
- console.error('Usage: webjs create <app-name> [--template full-stack|api]');
210
+ if (!name || name.startsWith('-')) {
211
+ console.error('Usage: webjs create <app-name> [--template full-stack|api|saas]');
206
212
  process.exit(1);
207
213
  }
208
214
  const template = flag(rest, '--template', 'full-stack');
215
+ if (!TEMPLATES.includes(template)) {
216
+ // AI agents sometimes hallucinate template names ("blog", "todo",
217
+ // "ecommerce"). Reject early with the canonical list + guidance
218
+ // on which scaffold to pick for which kind of app.
219
+ console.error(`Error: unknown template '${template}'.
220
+
221
+ Only three scaffolds exist:
222
+ full-stack (default) — pages + components + API + Prisma/SQLite.
223
+ Pick this for any app the user describes in product terms
224
+ (todo app, blog, dashboard, marketplace, social feed, …).
225
+ api — backend-only: route handlers + modules, no pages/SSR.
226
+ Pick this only if the user explicitly asks for an HTTP/JSON
227
+ API with no UI.
228
+ saas — auth + login/signup + protected dashboard + Prisma User
229
+ model. Pick this only if the user explicitly asks for auth
230
+ or a SaaS-shaped product.
231
+
232
+ The scaffold is a starting point — replace the example layout/page/
233
+ components/schema with the actual app the user requested. Use Prisma +
234
+ SQLite for persistence (already wired up); never store app data in JSON
235
+ files.
236
+
237
+ Full docs: https://docs.webjs.com`);
238
+ process.exit(1);
239
+ }
209
240
  const { scaffoldApp } = await import('../lib/create.js');
210
241
  await scaffoldApp(name, process.cwd(), { template });
211
242
  break;
package/lib/create.js CHANGED
@@ -25,6 +25,14 @@ const TEMPLATES = resolve(__dirname, '..', 'templates');
25
25
  */
26
26
  export async function scaffoldApp(name, cwd, opts = {}) {
27
27
  const template = opts.template || 'full-stack';
28
+ // Defence in depth — the CLI already validates this, but library
29
+ // callers (tests, programmatic use) might pass anything.
30
+ const VALID_TEMPLATES = ['full-stack', 'api', 'saas'];
31
+ if (!VALID_TEMPLATES.includes(template)) {
32
+ throw new Error(
33
+ `Unknown template '${template}'. Only ${VALID_TEMPLATES.join(' / ')} exist.`,
34
+ );
35
+ }
28
36
  const isApi = template === 'api';
29
37
  const isSaas = template === 'saas';
30
38
  const appDir = join(cwd, name);
@@ -79,6 +87,10 @@ export async function scaffoldApp(name, cwd, opts = {}) {
79
87
  '@web/test-runner': '^0.20.0',
80
88
  '@web/test-runner-playwright': '^0.11.0',
81
89
  'playwright': '^1.59.0',
90
+ // tsserver plugins for editor intelligence inside html`` templates.
91
+ // Order in tsconfig matters — see below.
92
+ 'ts-lit-plugin': '^2.0.0',
93
+ '@webjskit/ts-plugin': 'latest',
82
94
  },
83
95
  }, null, 2) + '\n');
84
96
 
@@ -92,10 +104,16 @@ export async function scaffoldApp(name, cwd, opts = {}) {
92
104
  noEmit: true,
93
105
  allowImportingTsExtensions: true,
94
106
  skipLibCheck: true,
95
- // ts-lit-plugin gives tag/attribute intelligence inside html`` templates
96
- // (autocomplete, type-check, go-to-definition for <my-element>).
97
- // Install: `npm i -D ts-lit-plugin`. Remove this plugin entry if you don't want it.
98
- plugins: [{ name: 'ts-lit-plugin', strict: true }],
107
+ // ts-lit-plugin: type-check + diagnostics inside html`` templates.
108
+ // @webjskit/ts-plugin: webjs-aware go-to-definition, "Unknown tag/attr"
109
+ // suppression for elements registered via Class.register('tag'), and
110
+ // attribute auto-complete sourced from `static properties`.
111
+ // Order matters — list ts-lit-plugin first; @webjskit/ts-plugin wraps
112
+ // it. Remove either entry if you don't want that capability.
113
+ plugins: [
114
+ { name: 'ts-lit-plugin', strict: true },
115
+ { name: '@webjskit/ts-plugin' },
116
+ ],
99
117
  },
100
118
  }, null, 2) + '\n');
101
119
 
@@ -579,5 +597,22 @@ AI-driven development (enforced for all AI agents):
579
597
  ✓ Commits are automatic, small, and meaningful
580
598
  ✓ No AI attribution in commit messages
581
599
  ✓ Convention validation via \`webjs check\`
600
+
601
+ For AI agents — read this before editing scaffolded files:
602
+ • The example layout / page / components / schema are REFERENCE ONLY.
603
+ Replace them with the app the user actually asked for. Don't ship
604
+ the scaffold's example User model or "Hello from …" page as the
605
+ final product.
606
+ • Use Prisma + SQLite for app data — it's already wired up. Define
607
+ real models in prisma/schema.prisma and run \`webjs db migrate\`.
608
+ NEVER store app data in JSON files, in-memory arrays, or
609
+ localStorage as a substitute for the database.
610
+ • Only three scaffolds exist: full-stack (default), api, saas. Don't
611
+ invent template names. If you need a different kind of app, pick
612
+ the closest scaffold and adapt it.
613
+ • Read AGENTS.md + CONVENTIONS.md in the new project before writing
614
+ any code. They are the contract.
615
+ • Need more detail? Full hosted docs are at https://docs.webjs.com
616
+ (every API, directive, recipe, and deployment guide).
582
617
  `);
583
618
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webjskit/cli",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "description": "webjs CLI — dev, start, create, db",
6
6
  "bin": {
@@ -13,7 +13,7 @@
13
13
  "README.md"
14
14
  ],
15
15
  "dependencies": {
16
- "@webjskit/server": "0.3.1"
16
+ "@webjskit/server": "0.4.0"
17
17
  },
18
18
  "publishConfig": {
19
19
  "access": "public"
@@ -2,7 +2,28 @@
2
2
 
3
3
  You are working on a webjs app — an AI-first, no-build, web-components-first
4
4
  framework. Read AGENTS.md for the full API reference and CONVENTIONS.md for
5
- project-specific conventions before writing any code.
5
+ project-specific conventions before writing any code. When AGENTS.md doesn't
6
+ cover what you need, the full hosted docs are at **https://docs.webjs.com**.
7
+
8
+ ## Persistence + scaffold rules (non-negotiable)
9
+
10
+ - **Use Prisma + SQLite for data, never JSON files.** It's already wired up
11
+ (`prisma/schema.prisma`, `lib/prisma.ts`, `npm run db:migrate`). For ANY
12
+ data the app stores (todos, posts, messages, products, comments…),
13
+ define a Prisma model. NEVER create `data/*.json`, `db.json`, or any
14
+ JSON file as a fake database. NEVER use module-scope arrays / Maps as
15
+ a substitute. NEVER use localStorage for app data. `webjs check`'s
16
+ `no-json-data-files` rule will fail the build if you do.
17
+ - **The scaffold is reference, not the final product.** Replace
18
+ `app/page.ts`, the example `User` model, the example users module, etc.
19
+ with the app the user actually asked for. Don't ship "Hello from
20
+ <app-name>" as the deliverable.
21
+ - **Only three templates exist:** `webjs create <name>` (default
22
+ full-stack), `--template api`, `--template saas`. The CLI rejects any
23
+ other `--template` value. Pick:
24
+ - Any product UI (todo, blog, dashboard, marketplace, social…) → default
25
+ - HTTP/JSON API only, no UI → `--template api`
26
+ - Auth / login / signup / SaaS → `--template saas`
6
27
 
7
28
  ## Before starting ANY work
8
29
 
@@ -2,7 +2,28 @@
2
2
 
3
3
  You are working on a webjs app — an AI-first, no-build, web-components-first
4
4
  framework. Read AGENTS.md for the full API reference and CONVENTIONS.md for
5
- project-specific conventions.
5
+ project-specific conventions. When AGENTS.md doesn't cover what you need,
6
+ the full hosted docs are at **https://docs.webjs.com**.
7
+
8
+ ## Persistence + scaffold rules (non-negotiable)
9
+
10
+ - **Use Prisma + SQLite for data, never JSON files.** It's already wired up
11
+ (`prisma/schema.prisma`, `lib/prisma.ts`, `npm run db:migrate`). For ANY
12
+ data the app stores (todos, posts, messages, products, comments…),
13
+ define a Prisma model. NEVER create `data/*.json`, `db.json`, or any
14
+ JSON file as a fake database. NEVER use module-scope arrays / Maps as
15
+ a substitute. NEVER use localStorage for app data. `webjs check`'s
16
+ `no-json-data-files` rule will fail the build if you do.
17
+ - **The scaffold is reference, not the final product.** Replace
18
+ `app/page.ts`, the example `User` model, the example users module, etc.
19
+ with the app the user actually asked for. Don't ship "Hello from
20
+ <app-name>" as the deliverable.
21
+ - **Only three templates exist:** `webjs create <name>` (default
22
+ full-stack), `--template api`, `--template saas`. The CLI rejects any
23
+ other `--template` value. Pick:
24
+ - Any product UI (todo, blog, dashboard, marketplace, social…) → default
25
+ - HTTP/JSON API only, no UI → `--template api`
26
+ - Auth / login / signup / SaaS → `--template saas`
6
27
 
7
28
  ## Before starting ANY work
8
29
 
@@ -2,7 +2,28 @@
2
2
 
3
3
  You are working on a webjs app — an AI-first, no-build, web-components-first
4
4
  framework. Read AGENTS.md for the full API reference and CONVENTIONS.md for
5
- project-specific conventions before writing any code.
5
+ project-specific conventions before writing any code. When AGENTS.md doesn't
6
+ cover what you need, the full hosted docs are at **https://docs.webjs.com**.
7
+
8
+ ## Persistence + scaffold rules (non-negotiable)
9
+
10
+ - **Use Prisma + SQLite for data, never JSON files.** It's already wired up
11
+ (`prisma/schema.prisma`, `lib/prisma.ts`, `npm run db:migrate`). For ANY
12
+ data the app stores (todos, posts, messages, products, comments…),
13
+ define a Prisma model. NEVER create `data/*.json`, `db.json`, or any
14
+ JSON file as a fake database. NEVER use module-scope arrays / Maps as
15
+ a substitute. NEVER use localStorage for app data. `webjs check`'s
16
+ `no-json-data-files` rule will fail the build if you do.
17
+ - **The scaffold is reference, not the final product.** Replace
18
+ `app/page.ts`, the example `User` model, the example users module, etc.
19
+ with the app the user actually asked for. Don't ship "Hello from
20
+ <app-name>" as the deliverable.
21
+ - **Only three templates exist:** `webjs create <name>` (default
22
+ full-stack), `--template api`, `--template saas`. The CLI rejects any
23
+ other `--template` value. Pick:
24
+ - Any product UI (todo, blog, dashboard, marketplace, social…) → default
25
+ - HTTP/JSON API only, no UI → `--template api`
26
+ - Auth / login / signup / SaaS → `--template saas`
6
27
 
7
28
  ## Before starting ANY work
8
29
 
@@ -2,8 +2,57 @@
2
2
 
3
3
  Read this before editing any file. This is a webjs app: AI-first, web-
4
4
  components-first, no build step. The framework's own full API reference
5
- lives at https://github.com/vivek7405/webjs/blob/main/AGENTS.md treat
6
- this file as the app-scoped companion.
5
+ lives at https://github.com/vivek7405/webjs/blob/main/AGENTS.md and the
6
+ full hosted documentation (every API, recipe, and example) lives at
7
+ **https://docs.webjs.com** — treat this file as the app-scoped
8
+ companion and reach for docs.webjs.com whenever you need more detail.
9
+
10
+ ## If you just scaffolded this app (AI agents — read first)
11
+
12
+ This project was created with `webjs create`. The files you see right
13
+ now — `app/page.ts` ("Hello from {{APP_NAME}}"), the example `User`
14
+ model in `prisma/schema.prisma`, the `theme-toggle` component, the
15
+ example users module (api/saas templates) — are **starting-point
16
+ references, not the final product**. Your job is to replace them with
17
+ the app the user actually asked for.
18
+
19
+ **Non-negotiables for every webjs app:**
20
+
21
+ 1. **Use Prisma + SQLite for persistence.** It's already wired up
22
+ (`prisma/schema.prisma`, `lib/prisma.ts`, `npm run db:migrate`,
23
+ `predev` hook running `prisma generate`). For any data the app
24
+ stores — todos, posts, messages, products, comments, anything —
25
+ define a Prisma model and persist there.
26
+ - **NEVER** store app data in JSON files (`data/todos.json`,
27
+ `db.json`, …). The convention check `no-json-data-files` flags
28
+ this and the user's prompt explicitly forbids it.
29
+ - **NEVER** use in-memory arrays or `Map`s as a substitute for the
30
+ database — they vanish on every dev-server reload and aren't
31
+ shared across processes.
32
+ - **NEVER** use `localStorage` to persist app data — it's per-browser
33
+ and doesn't reach the server.
34
+ 2. **One of three scaffolds only.** The CLI exposes exactly three:
35
+ `full-stack` (default), `--template api`, `--template saas`. Don't
36
+ reach for a `--template blog` / `--template todo` / `--template
37
+ ecommerce` — they don't exist and the CLI will reject them.
38
+ 3. **First step after scaffolding:** edit `prisma/schema.prisma` to the
39
+ app's real domain models (delete the example `User` model unless the
40
+ app actually needs users), run `webjs db migrate <name>`, then build
41
+ pages / actions / queries against those models.
42
+
43
+ **Picking the right scaffold from the user's prompt** (you do this BEFORE
44
+ running `webjs create`; if you're reading this you've already scaffolded —
45
+ verify the choice was correct, otherwise re-scaffold in a fresh dir):
46
+
47
+ | User asks for… | Scaffold |
48
+ |---|---|
49
+ | Todo app, blog, notes, dashboard, marketplace, social feed, e-commerce, any product with a UI | `webjs create <name>` (default full-stack) |
50
+ | HTTP/JSON API only, no UI | `webjs create <name> --template api` |
51
+ | Anything with login / signup / accounts / protected pages / SaaS | `webjs create <name> --template saas` |
52
+
53
+ When in doubt, **full-stack is the default**. Pick `api` only if the user
54
+ is explicit about wanting a backend-only API. Pick `saas` only if the user
55
+ is explicit about auth / accounts / SaaS.
7
56
 
8
57
  ## Framework source is in `node_modules/`
9
58
 
@@ -28,7 +77,8 @@ node_modules/@webjskit/
28
77
  src/actions.js ← .server.ts scanner, RPC, expose()
29
78
  src/auth.js, session.js, cache.js, rate-limit.js, csrf.js
30
79
  cli/ webjs CLI (dev / start / build / test / check / create / db)
31
- ts-plugin/ tsserver go-to-definition for custom-element tag names
80
+ ts-plugin/ tsserver plugin: go-to-definition + diagnostic suppression
81
+ + attribute auto-complete for Class.register('tag') elements
32
82
  ```
33
83
 
34
84
  Reaching straight for the source is the fastest way to resolve "why
@@ -1,70 +1,2 @@
1
- # CLAUDE.md — {{APP_NAME}}
2
-
3
- This file instructs AI coding agents on how to work in this project.
4
- **Do not duplicate content here** — reference the authoritative sources below.
5
-
6
- ## Required reading (in this order)
7
-
8
- 1. **[AGENTS.md](./AGENTS.md)** — Full webjs API reference, file conventions,
9
- invariants, recipes, directives, lifecycle, controllers, context, task.
10
- 2. **[CONVENTIONS.md](./CONVENTIONS.md)** — Project-specific conventions for
11
- module architecture, testing rules, component patterns, code style.
12
- Users may override sections.
13
-
14
- ## AI-driven development workflow
15
-
16
- **CRITICAL: Every code change MUST include the following — automatically,
17
- without the user having to ask:**
18
-
19
- ### 1. Commit and push often (mandatory, never skip)
20
-
21
- **Commit AND push after each logical unit of work** — a completed
22
- feature, a passing test, a doc update. Don't accumulate uncommitted
23
- or unpushed changes. Small focused commits with meaningful messages.
24
- No AI attribution trailers. Always `git push` after committing.
25
- This is automatic — the user should never have to ask.
26
-
27
- ### 2. Tests (mandatory, never skip)
28
-
29
- - **New server action or query** → add unit test in `test/unit/<module>.test.ts`
30
- - **New or modified component** → add unit test (SSR rendering via `renderToString`)
31
- - **New or modified page/route** → add E2E test in `test/browser/<feature>.test.ts`
32
- - **Bug fix** → add regression test proving the fix
33
- - **Refactor** → run existing tests, ensure they pass
34
-
35
- After writing code, ALWAYS run `webjs test`. If E2E-relevant,
36
- also run `webjs test --browser`. Never report a task as done with
37
- failing tests.
38
-
39
- ### 3. Documentation (mandatory, never skip)
40
-
41
- When adding or modifying features, update:
42
-
43
- - **AGENTS.md** — API surface table, directive reference, recipes, or
44
- relevant sections. This is the source of truth for the framework.
45
- - **CONVENTIONS.md** — Only if the change introduces or modifies a convention.
46
-
47
- If this project has a **docs/** directory, also:
48
- - Add or update the relevant documentation page under `docs/`.
49
-
50
- If this project has a **website/** directory, also:
51
- - Update the website landing page if the feature is user-facing/marketable.
52
-
53
- ### 4. Convention validation
54
-
55
- After making changes, run `webjs check` and fix any violations before
56
- reporting the task as done.
57
-
58
- ## Quick reference
59
-
60
- ```sh
61
- webjs dev # dev server with live reload
62
- webjs test # run unit tests
63
- webjs test --browser # run unit + E2E tests
64
- webjs check # validate conventions
65
- webjs build # (optional) production bundle
66
- webjs start # production server
67
- ```
68
-
69
- All API details, recipes, and feature documentation → see **[AGENTS.md](./AGENTS.md)**.
70
- All project conventions and overrides → see **[CONVENTIONS.md](./CONVENTIONS.md)**.
1
+ @AGENTS.md
2
+ @CONVENTIONS.md
@@ -74,6 +74,70 @@ docs" — that is the agent's default behavior in a webjs project.
74
74
 
75
75
  ---
76
76
 
77
+ ## Data persistence — Prisma + SQLite, never JSON files
78
+
79
+ <!-- OVERRIDE -->
80
+
81
+ Every webjs app uses **Prisma + SQLite** for persistence by default. The
82
+ scaffold ships `prisma/schema.prisma`, `lib/prisma.ts` (singleton), the
83
+ `predev` / `prestart` hooks that run `prisma generate` / `prisma migrate
84
+ deploy`, and `npm run db:migrate` / `db:generate` / `db:studio` scripts.
85
+
86
+ **AI agents — these rules are absolute:**
87
+
88
+ 1. For ANY data the app stores (todos, posts, messages, products,
89
+ comments, users…), define a Prisma model in `prisma/schema.prisma`
90
+ and persist there.
91
+ 2. **NEVER** create JSON files under `data/`, `db.json`, `posts.json`,
92
+ `todos.json`, etc. as a fake database. The `no-json-data-files`
93
+ convention check flags this and `webjs check` will fail.
94
+ 3. **NEVER** use module-scope arrays or `Map`s as a "store" — they
95
+ reset on every dev-server reload and can't scale beyond one process.
96
+ 4. **NEVER** use `localStorage` / `sessionStorage` to persist app data —
97
+ it's per-browser and never reaches the server. Use it only for UI
98
+ preferences (theme, sidebar collapsed, etc.).
99
+ 5. To add a model: edit `prisma/schema.prisma`, then `npm run db:migrate
100
+ -- --name <description>`. Access via `import { prisma } from
101
+ '../../../lib/prisma.ts'` — never `new PrismaClient()`.
102
+
103
+ To switch to Postgres or MySQL: change `provider` in
104
+ `prisma/schema.prisma` and the `DATABASE_URL` in `.env`. Do this only
105
+ if the user explicitly asks for it — SQLite is the right default for
106
+ dev and small production workloads.
107
+
108
+ ---
109
+
110
+ ## The scaffold is reference, not the final product
111
+
112
+ <!-- OVERRIDE -->
113
+
114
+ This project was created with `webjs create`. Every file you see right
115
+ now — `app/page.ts` ("Hello from …"), the example `User` model, the
116
+ `theme-toggle` component, the example users module (api / saas
117
+ templates) — is a **starting point**.
118
+
119
+ When the user asks the agent to build their actual app:
120
+
121
+ 1. **Replace the example `User` model** in `prisma/schema.prisma` with
122
+ the real domain models the app needs (e.g. `Todo`, `Post`, `Message`)
123
+ — unless the app actually has users.
124
+ 2. **Replace `app/page.ts`** with the app's real homepage. Don't ship
125
+ "Hello from …" as the deliverable.
126
+ 3. **Delete or replace `components/theme-toggle.ts`** if the app doesn't
127
+ need a theme picker.
128
+ 4. **Delete the example users module** (api/saas templates) if the app
129
+ doesn't use it.
130
+ 5. **Keep:** the Prisma setup, the test config, the agent config files
131
+ (`AGENTS.md`, `CONVENTIONS.md`, `CLAUDE.md`, `.cursorrules`, etc.),
132
+ `lib/prisma.ts`, the directory conventions, the design tokens in
133
+ `app/layout.ts`. These are the infrastructure, not the example app.
134
+
135
+ The scaffold exists so the agent doesn't reinvent the directory layout,
136
+ the Prisma wiring, the test runner config, or the convention files. It
137
+ does NOT exist so the agent ships the example homepage.
138
+
139
+ ---
140
+
77
141
  ## Sensible defaults
78
142
 
79
143
  <!-- OVERRIDE -->
@@ -225,6 +289,14 @@ export class MyWidget extends WebComponent {
225
289
  declare count: number;
226
290
  // Light DOM is the default; Tailwind utility classes apply directly.
227
291
 
292
+ constructor() {
293
+ super();
294
+ // Defaults go here — never as class-field initializers
295
+ // (`label = ''` would clobber the framework's reactive accessor).
296
+ this.label = '';
297
+ this.count = 0;
298
+ }
299
+
228
300
  render() {
229
301
  return html`
230
302
  <div class="p-4 border border-border rounded-lg">
@@ -241,9 +313,11 @@ attribute coercion, reflection). `declare` types the field for
241
313
  TypeScript without emitting a class-field initializer that would
242
314
  clobber the reactive accessor at construction time. The two
243
315
  declarations together give you full intelligence in any tsserver-backed
244
- editor — see the Editor Setup docs for `ts-lit-plugin` setup that
245
- extends this to tag / attribute intelligence inside `html\`…\``
246
- templates.
316
+ editor — see the Editor Setup docs for the `ts-lit-plugin` +
317
+ `@webjskit/ts-plugin` setup that extends this to tag / attribute
318
+ intelligence inside `html\`…\`` templates (go-to-definition, attribute
319
+ auto-complete from `static properties`, no "Unknown tag" red-squiggle on
320
+ registered webjs elements).
247
321
 
248
322
  **Rules:**
249
323
  - One component per file
@@ -254,6 +328,7 @@ templates.
254
328
  - `my-widget .body`, `my-widget .title` (descendant selector)
255
329
  - Tag name must contain a hyphen (HTML spec)
256
330
  - Always call `Class.register('tag')` — the standard DOM API
331
+ - **Reactive props use `declare propName: Type` (no value) plus a default in `constructor()` after `super()`.** Never write `propName = value` or `propName: Type = value` as a class-field initializer — it compiles to `Object.defineProperty(this, …)` after `super()` and clobbers the framework's reactive accessor, silently breaking re-renders. `webjs check` flags this via the `reactive-props-use-declare` rule.
257
332
  - Use `setState()` for state changes, never mutate `this.state` directly
258
333
  - Use lifecycle hooks (`firstUpdated`, `updated`) only when needed
259
334