pulse-js-framework 1.7.4 → 1.7.6

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/README.md CHANGED
@@ -13,9 +13,12 @@ A declarative DOM framework with CSS selector-based structure and reactive pulsa
13
13
  - **No Build Required** - Works directly in the browser
14
14
  - **Lightweight** - Minimal footprint, maximum performance
15
15
  - **Router & Store** - Built-in SPA routing and state management
16
+ - **Form Handling** - Validation, async validators, field arrays
17
+ - **Async Primitives** - useAsync, useResource, usePolling with SWR caching
16
18
  - **Hot Module Replacement** - Full HMR with state preservation
17
19
  - **Mobile Apps** - Build native Android & iOS apps (zero dependencies)
18
20
  - **TypeScript Support** - Full type definitions for IDE autocomplete
21
+ - **DevTools** - Time-travel debugging, dependency graph visualization
19
22
 
20
23
  ## Installation
21
24
 
@@ -54,10 +57,7 @@ function Counter() {
54
57
  const increment = el('button.btn', '+');
55
58
  increment.onclick = () => count.update(n => n + 1);
56
59
 
57
- const decrement = el('button.btn', '-');
58
- decrement.onclick = () => count.update(n => n - 1);
59
-
60
- div.append(display, increment, decrement);
60
+ div.append(display, increment);
61
61
  return div;
62
62
  }
63
63
 
@@ -66,8 +66,6 @@ mount('#app', Counter());
66
66
 
67
67
  ## CSS Selector Syntax
68
68
 
69
- Create DOM elements using familiar CSS syntax:
70
-
71
69
  ```javascript
72
70
  el('div') // <div></div>
73
71
  el('.container') // <div class="container"></div>
@@ -80,23 +78,24 @@ el('h1', 'Hello World') // <h1>Hello World</h1>
80
78
  ## Reactivity
81
79
 
82
80
  ```javascript
83
- import { pulse, effect, computed } from 'pulse-js-framework';
81
+ import { pulse, effect, computed, batch } from 'pulse-js-framework';
84
82
 
85
- // Create reactive values
86
83
  const firstName = pulse('John');
87
84
  const lastName = pulse('Doe');
88
85
 
89
86
  // Computed values
90
- const fullName = computed(() =>
91
- `${firstName.get()} ${lastName.get()}`
92
- );
87
+ const fullName = computed(() => `${firstName.get()} ${lastName.get()}`);
93
88
 
94
89
  // Effects auto-run when dependencies change
95
- effect(() => {
96
- console.log(`Hello, ${fullName.get()}!`);
97
- });
90
+ effect(() => console.log(`Hello, ${fullName.get()}!`));
98
91
 
99
92
  firstName.set('Jane'); // Logs: "Hello, Jane Doe!"
93
+
94
+ // Batch updates (effects run once)
95
+ batch(() => {
96
+ firstName.set('John');
97
+ lastName.set('Smith');
98
+ });
100
99
  ```
101
100
 
102
101
  ## .pulse File Format
@@ -104,472 +103,159 @@ firstName.set('Jane'); // Logs: "Hello, Jane Doe!"
104
103
  ```pulse
105
104
  @page Counter
106
105
 
107
- // Import other components
108
- import Button from './Button.pulse'
109
- import { Header, Footer } from './components.pulse'
110
-
111
106
  state {
112
107
  count: 0
113
108
  }
114
109
 
115
110
  view {
116
111
  .counter {
117
- Header
118
112
  h1 "Count: {count}"
119
- Button @click(count++) "+"
120
- Button @click(count--) "-"
121
- Footer
113
+ button @click(count++) "+"
114
+ button @click(count--) "-"
122
115
  }
123
116
  }
124
117
 
125
118
  style {
126
- .counter {
127
- text-align: center
128
- padding: 20px
129
- }
119
+ .counter { text-align: center; padding: 20px }
130
120
  }
131
121
  ```
132
122
 
133
- **Compiler Features:**
134
- - Import statements for component composition
135
- - Slots for content projection (`slot`, `slot "name"`)
136
- - CSS scoping (styles are automatically scoped to component)
137
- - Native `router {}` and `store {}` blocks
138
- - Detailed error messages with line/column info
139
- - Source map generation (v1.4.9) for debugging original `.pulse` code
140
-
141
- ### Router & Store DSL (v1.4.0)
123
+ See [Pulse DSL documentation](docs/pulse-dsl.md) for full syntax reference.
142
124
 
143
- Define routing and state management directly in your `.pulse` files:
144
-
145
- ```pulse
146
- @page App
147
-
148
- router {
149
- mode: "hash"
150
- base: "/app"
151
- routes {
152
- "/": HomePage
153
- "/users": UsersPage
154
- "/users/:id": UserDetailPage
155
- }
156
- beforeEach(to, from) {
157
- if (!store.isAuthenticated) return "/login"
158
- }
159
- }
160
-
161
- store {
162
- state {
163
- user: null
164
- theme: "dark"
165
- }
166
- getters {
167
- isAuthenticated() { return this.user !== null }
168
- }
169
- actions {
170
- login(userData) { this.user = userData }
171
- logout() { this.user = null }
172
- toggleTheme() { this.theme = this.theme === "dark" ? "light" : "dark" }
173
- }
174
- persist: true
175
- storageKey: "my-app"
176
- }
125
+ ## CLI Commands
177
126
 
178
- view {
179
- .app {
180
- nav {
181
- @link("/") "Home"
182
- @link("/users") "Users"
183
- }
184
- main {
185
- @outlet
186
- }
187
- }
188
- }
127
+ ```bash
128
+ pulse create <name> # Create new project
129
+ pulse dev [port] # Start dev server (default: 3000)
130
+ pulse build # Build for production
131
+ pulse compile <file> # Compile .pulse file
132
+ pulse lint [files] # Validate .pulse files
133
+ pulse format [files] # Format .pulse files
134
+ pulse analyze # Analyze bundle
189
135
  ```
190
136
 
191
- **Router DSL Features:**
192
- - Route definitions with path parameters (`:id`) and wildcards (`*path`)
193
- - Navigation guards (`beforeEach`, `afterEach`)
194
- - `@link("/path")` directive for navigation links
195
- - `@outlet` directive for route content
196
- - `@navigate`, `@back`, `@forward` directives
197
-
198
- **Store DSL Features:**
199
- - Reactive state with automatic signal creation
200
- - Getters with `this.x` → `store.x.get()` transformation
201
- - Actions with `this.x = y` → `store.x.set(y)` transformation
202
- - Built-in persistence via `persist: true`
203
- - Custom storage key
204
-
205
- ## API Reference
206
-
207
- ### Reactivity
208
-
209
- - `pulse(value)` - Create a reactive value
210
- - `pulse.get()` - Read value (tracks dependency)
211
- - `pulse.set(value)` - Set new value
212
- - `pulse.update(fn)` - Update with function
213
- - `pulse.peek()` - Read without tracking
214
- - `effect(fn)` - Create reactive side effect
215
- - `computed(fn)` - Create derived value
216
- - `batch(fn)` - Batch multiple updates
217
-
218
- ### DOM
219
-
220
- - `el(selector, ...children)` - Create element
221
- - `mount(target, element)` - Mount to DOM
222
- - `text(fn)` - Reactive text node
223
- - `list(items, template)` - Reactive list
224
- - `when(condition, then, else)` - Conditional render
137
+ See [CLI documentation](docs/cli.md) for full command reference.
138
+
139
+ ## Core Modules
225
140
 
226
141
  ### Router
227
142
 
228
143
  ```javascript
229
- import { createRouter } from 'pulse-js-framework/runtime/router.js';
144
+ import { createRouter, lazy } from 'pulse-js-framework/runtime/router';
230
145
 
231
146
  const router = createRouter({
232
147
  routes: {
233
148
  '/': HomePage,
234
- '/about': AboutPage,
235
149
  '/users/:id': UserPage,
236
- '/admin': {
237
- handler: AdminPage,
238
- meta: { requiresAuth: true },
239
- beforeEnter: (to, from) => {
240
- if (!isAuthenticated()) return '/login';
241
- },
242
- children: {
243
- '/users': AdminUsersPage,
244
- '/settings': AdminSettingsPage
245
- }
246
- }
247
- },
248
- scrollBehavior: (to, from, savedPosition) => {
249
- return savedPosition || { x: 0, y: 0 };
250
- }
251
- });
252
-
253
- // Navigation guards
254
- router.beforeEach((to, from) => {
255
- if (to.meta.requiresAuth && !isAuthenticated()) {
256
- return '/login';
150
+ '/dashboard': lazy(() => import('./Dashboard.js'))
257
151
  }
258
152
  });
259
-
260
- router.start();
261
- ```
262
-
263
- **Router Features:**
264
- - Route params (`:id`) and wildcards (`*path`)
265
- - Nested routes with `children`
266
- - Route meta fields
267
- - Per-route guards (`beforeEnter`)
268
- - Global guards (`beforeEach`, `beforeResolve`, `afterEach`)
269
- - Scroll restoration
270
- - Lazy-loaded routes with `lazy()` and `preload()`
271
- - Middleware pipeline (Koa-style)
272
-
273
- #### Lazy Loading & Middleware (v1.4.9)
274
-
275
- ```javascript
276
- import { createRouter, lazy, preload } from 'pulse-js-framework/runtime/router';
277
-
278
- // Lazy load components
279
- const routes = {
280
- '/': HomePage,
281
- '/dashboard': lazy(() => import('./Dashboard.js')),
282
- '/settings': lazy(() => import('./Settings.js'), {
283
- loading: () => el('div.spinner', 'Loading...'),
284
- error: (err) => el('div.error', `Failed: ${err.message}`),
285
- timeout: 5000
286
- })
287
- };
288
-
289
- // Preload on hover
290
- link.addEventListener('mouseenter', () => preload(routes['/dashboard']));
291
-
292
- // Middleware
293
- const router = createRouter({
294
- routes,
295
- middleware: [
296
- // Logger middleware
297
- async (ctx, next) => {
298
- console.log('Navigating to:', ctx.to.path);
299
- await next();
300
- },
301
- // Auth middleware
302
- async (ctx, next) => {
303
- if (ctx.to.meta.requiresAuth && !isLoggedIn()) {
304
- return ctx.redirect('/login');
305
- }
306
- await next();
307
- }
308
- ]
309
- });
310
-
311
- // Add middleware dynamically
312
- const unsubscribe = router.use(async (ctx, next) => {
313
- ctx.meta.startTime = Date.now();
314
- await next();
315
- });
316
153
  ```
317
154
 
318
155
  ### Store
319
156
 
320
157
  ```javascript
321
- import { createStore } from 'pulse-js-framework/runtime/store.js';
322
-
323
- const store = createStore({
324
- user: null,
325
- theme: 'light'
326
- }, { persist: true });
327
-
328
- store.user.set({ name: 'John' });
329
- ```
330
-
331
- ### HMR (Hot Module Replacement)
332
-
333
- Pulse supports full HMR with state preservation during development:
334
-
335
- ```javascript
336
- import { createHMRContext } from 'pulse-js-framework/runtime/hmr';
158
+ import { createStore, createActions } from 'pulse-js-framework/runtime/store';
337
159
 
338
- const hmr = createHMRContext(import.meta.url);
339
-
340
- // State preserved across HMR updates
341
- const count = hmr.preservePulse('count', 0);
342
- const items = hmr.preservePulse('items', []);
343
-
344
- // Effects tracked for automatic cleanup
345
- hmr.setup(() => {
346
- effect(() => {
347
- document.title = `Count: ${count.get()}`;
348
- });
160
+ const store = createStore({ user: null, theme: 'light' }, { persist: true });
161
+ const actions = createActions(store, {
162
+ login: (store, user) => store.user.set(user)
349
163
  });
350
-
351
- // Accept HMR updates
352
- hmr.accept();
353
164
  ```
354
165
 
355
- **HMR Features:**
356
- - `preservePulse(key, value)` - Create pulses that survive module replacement
357
- - `setup(callback)` - Execute with effect tracking for cleanup
358
- - Automatic event listener cleanup (no accumulation)
359
- - Works with Vite dev server
360
-
361
- ### Logger
166
+ ### Form
362
167
 
363
168
  ```javascript
364
- import { createLogger, setLogLevel, LogLevel } from 'pulse-js-framework/runtime/logger';
365
-
366
- // Create a namespaced logger
367
- const log = createLogger('MyComponent');
368
-
369
- log.info('Component initialized'); // [MyComponent] Component initialized
370
- log.warn('Deprecated method used');
371
- log.error('Failed to load', error);
372
- log.debug('Detailed info'); // Only shown at DEBUG level
373
-
374
- // Set global log level
375
- setLogLevel(LogLevel.DEBUG); // SILENT, ERROR, WARN, INFO, DEBUG
376
-
377
- // Child loggers for sub-namespaces
378
- const childLog = log.child('Validation');
379
- childLog.info('Validating'); // [MyComponent:Validation] Validating
380
- ```
381
-
382
- ## CLI Commands
383
-
384
- ```bash
385
- # Project Commands
386
- pulse create <name> # Create new project
387
- pulse dev [port] # Start dev server (default: 3000)
388
- pulse build # Build for production
389
- pulse preview [port] # Preview production build (default: 4173)
390
- pulse compile <file> # Compile .pulse file to JavaScript
391
-
392
- # Code Quality
393
- pulse lint [files] # Validate .pulse files for errors and style
394
- pulse lint --fix # Auto-fix fixable issues
395
- pulse format [files] # Format .pulse files consistently
396
- pulse format --check # Check formatting without writing
397
- pulse analyze # Analyze bundle size and dependencies
398
- pulse analyze --json # Output analysis as JSON
399
-
400
- # Mobile
401
- pulse mobile init # Initialize mobile platforms
402
- pulse mobile build android|ios # Build native app
403
- pulse mobile run android|ios # Run on device/emulator
404
- ```
405
-
406
- ### Lint Command
407
-
408
- Validates `.pulse` files for errors and style issues:
409
-
410
- ```bash
411
- pulse lint src/ # Lint all files in src/
412
- pulse lint "**/*.pulse" # Lint all .pulse files
413
- pulse lint --fix # Auto-fix fixable issues
414
- ```
415
-
416
- **Checks performed:**
417
- - Undefined references (state variables, components)
418
- - Unused imports and state variables
419
- - Naming conventions (PascalCase for pages, camelCase for state)
420
- - Empty blocks
421
- - Import order
169
+ import { useForm, validators } from 'pulse-js-framework/runtime/form';
422
170
 
423
- ### Format Command
424
-
425
- Formats `.pulse` files with consistent style:
426
-
427
- ```bash
428
- pulse format # Format all .pulse files
429
- pulse format src/App.pulse # Format specific file
430
- pulse format --check # Check without writing (CI mode)
171
+ const { fields, handleSubmit, isValid } = useForm(
172
+ { email: '', password: '' },
173
+ {
174
+ email: [validators.required(), validators.email()],
175
+ password: [validators.required(), validators.minLength(8)]
176
+ }
177
+ );
431
178
  ```
432
179
 
433
- **Formatting rules:**
434
- - 2-space indentation
435
- - Sorted imports (alphabetically)
436
- - Consistent brace placement
437
- - Proper spacing around operators
180
+ ### Async
438
181
 
439
- ### Analyze Command
182
+ ```javascript
183
+ import { useAsync, useResource } from 'pulse-js-framework/runtime/async';
440
184
 
441
- Analyzes your Pulse project for bundle insights:
185
+ const { data, loading } = useAsync(() => fetch('/api/users').then(r => r.json()));
442
186
 
443
- ```bash
444
- pulse analyze # Console report
445
- pulse analyze --json # JSON output
446
- pulse analyze --verbose # Detailed metrics
187
+ const users = useResource('users', fetchUsers, { refreshInterval: 30000 });
447
188
  ```
448
189
 
449
- **Analysis includes:**
450
- - File count and total size
451
- - Component complexity scores
452
- - Import dependency graph
453
- - Dead code detection (unreachable files)
190
+ See [API documentation](docs/api.md) for full reference.
454
191
 
455
192
  ## Mobile Apps
456
193
 
457
- Build native Android and iOS apps from your Pulse project with zero external dependencies:
194
+ Build native Android and iOS apps:
458
195
 
459
196
  ```bash
460
- # Initialize mobile platforms
461
197
  pulse mobile init
462
-
463
- # Build your web app first
464
198
  pulse build
465
-
466
- # Build for Android (requires Android SDK)
467
199
  pulse mobile build android
468
-
469
- # Build for iOS (requires macOS + Xcode)
470
- pulse mobile build ios
471
-
472
- # Run on device/emulator
473
200
  pulse mobile run android
474
201
  ```
475
202
 
476
- ### Native APIs
477
-
478
- Access native features in your Pulse app:
479
-
480
203
  ```javascript
481
- import { createNativeStorage, NativeUI, onNativeReady } from 'pulse-js-framework/runtime/native';
482
-
483
- onNativeReady(({ platform }) => {
484
- console.log(`Running on ${platform}`); // 'android', 'ios', or 'web'
485
-
486
- // Persistent native storage with Pulse reactivity
487
- const storage = createNativeStorage();
488
- const count = storage.get('count', 0);
489
- count.set(42); // Auto-persisted to native storage
204
+ import { createNativeStorage, NativeUI } from 'pulse-js-framework/runtime/native';
490
205
 
491
- // Native toast notification
492
- NativeUI.toast('Hello from Pulse!');
493
-
494
- // Haptic feedback
495
- NativeUI.vibrate(100);
496
- });
206
+ const storage = createNativeStorage();
207
+ const theme = storage.get('theme', 'light');
208
+ NativeUI.toast('Hello from native!');
497
209
  ```
498
210
 
499
- **Available APIs:** Storage, Device Info, Network Status, Toast, Vibration, Clipboard, App Lifecycle
211
+ See [Mobile documentation](docs/mobile.md) for full guide.
500
212
 
501
213
  ## IDE Extensions
502
214
 
503
- Pulse provides extensions for popular IDEs with syntax highlighting and snippets.
504
-
505
215
  ### VS Code
506
216
 
507
217
  ```bash
508
- # Windows (PowerShell)
509
- cd vscode-extension
510
- powershell -ExecutionPolicy Bypass -File install.ps1
511
-
512
- # macOS/Linux
513
- cd vscode-extension
514
- bash install.sh
218
+ cd vscode-extension && bash install.sh
515
219
  ```
516
220
 
517
- Then restart VS Code. You'll get:
518
- - Syntax highlighting for `.pulse` files
519
- - Code snippets (`page`, `state`, `view`, `@click`, etc.)
520
- - Bracket matching and auto-closing
521
- - Comment toggling (Ctrl+/)
522
-
523
221
  ### IntelliJ IDEA / WebStorm
524
222
 
525
223
  ```bash
526
- cd intellij-plugin
527
- ./gradlew buildPlugin
224
+ cd intellij-plugin && ./gradlew buildPlugin
528
225
  ```
529
226
 
530
- Then install the plugin from `build/distributions/pulse-language-1.0.0.zip`:
531
- 1. Open **Settings** > **Plugins**
532
- 2. Click gear icon > **Install Plugin from Disk...**
533
- 3. Select the `.zip` file and restart
534
-
535
- Features:
536
- - Syntax highlighting for `.pulse` files
537
- - 17 Live Templates (snippets)
538
- - Code folding for blocks
539
- - Customizable color scheme
227
+ Features: Syntax highlighting, code snippets, bracket matching.
540
228
 
541
229
  ## TypeScript Support
542
230
 
543
- Pulse includes full TypeScript definitions for IDE autocomplete and type checking:
231
+ Full type definitions included:
544
232
 
545
233
  ```typescript
546
- import { pulse, effect, computed, Pulse } from 'pulse-js-framework/runtime';
547
- import { el, list, when } from 'pulse-js-framework/runtime';
234
+ import { pulse, Pulse } from 'pulse-js-framework/runtime';
548
235
  import { createRouter, Router } from 'pulse-js-framework/runtime/router';
549
- import { createStore, Store } from 'pulse-js-framework/runtime/store';
550
236
 
551
- // Full autocomplete for all APIs
552
237
  const count: Pulse<number> = pulse(0);
553
- const doubled = computed(() => count.get() * 2);
554
-
555
- effect(() => {
556
- console.log(count.get()); // Type-safe access
557
- });
558
238
  ```
559
239
 
560
- Types are automatically detected by IDEs (VS Code, WebStorm) without additional configuration.
561
-
562
240
  ## Examples
563
241
 
564
- - [HMR Demo](examples/hmr) - Hot Module Replacement with `.pulse` components and state preservation
565
- - [Blog](examples/blog) - Full blog app with CRUD, categories, search, dark mode
566
- - [Todo App](examples/todo) - Task management with filters and persistence
567
- - [Chat App](examples/chat) - Real-time messaging interface
568
- - [E-commerce](examples/ecommerce) - Shopping cart with product catalog
569
- - [Weather App](examples/meteo) - Weather dashboard with forecasts
570
- - [Router Demo](examples/router) - SPA routing with guards
571
- - [Store Demo](examples/store) - State management with undo/redo
572
- - [Admin Dashboard](examples/dashboard) - Complete admin UI with all features
242
+ | Example | Description |
243
+ |---------|-------------|
244
+ | [Todo App](examples/todo) | Task management with filters |
245
+ | [Blog](examples/blog) | CRUD, categories, search |
246
+ | [Chat App](examples/chat) | Real-time messaging |
247
+ | [E-commerce](examples/ecommerce) | Shopping cart |
248
+ | [Dashboard](examples/dashboard) | Admin UI |
249
+ | [HMR Demo](examples/hmr) | Hot module replacement |
250
+ | [Router Demo](examples/router) | SPA routing |
251
+ | [Store Demo](examples/store) | State with undo/redo |
252
+
253
+ ## Documentation
254
+
255
+ - [API Reference](docs/api.md) - Complete API documentation
256
+ - [CLI Commands](docs/cli.md) - Command line interface
257
+ - [Pulse DSL](docs/pulse-dsl.md) - .pulse file syntax
258
+ - [Mobile Apps](docs/mobile.md) - Native Android & iOS
573
259
 
574
260
  ## License
575
261