pulse-js-framework 1.4.8 → 1.4.10
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 +48 -1
- package/cli/lint.js +117 -0
- package/compiler/index.js +33 -3
- package/compiler/sourcemap.js +360 -0
- package/compiler/transformer.js +108 -2
- package/package.json +5 -5
- package/runtime/router.js +374 -8
- package/types/hmr.d.ts +112 -0
- package/types/index.d.ts +25 -1
- package/types/router.d.ts +89 -0
- package/types/sourcemap.d.ts +126 -0
package/types/hmr.d.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pulse Framework - HMR (Hot Module Replacement) Type Definitions
|
|
3
|
+
* @module pulse-js-framework/runtime/hmr
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Pulse, PulseOptions } from './pulse';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* HMR Context interface for state preservation and effect cleanup
|
|
10
|
+
*/
|
|
11
|
+
export interface HMRContext {
|
|
12
|
+
/**
|
|
13
|
+
* Persistent data storage across HMR updates.
|
|
14
|
+
* Values stored here survive module reloads.
|
|
15
|
+
*/
|
|
16
|
+
data: Record<string, unknown>;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Create a pulse with state preservation across HMR updates.
|
|
20
|
+
* If a value exists from a previous module load, it's restored.
|
|
21
|
+
*
|
|
22
|
+
* @param key - Unique key for this pulse within the module
|
|
23
|
+
* @param initialValue - Initial value (used on first load only)
|
|
24
|
+
* @param options - Pulse options (equals function, etc.)
|
|
25
|
+
* @returns A pulse instance with preserved state
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* const count = hmr.preservePulse('count', 0);
|
|
29
|
+
* const todos = hmr.preservePulse('todos', [], { equals: deepEquals });
|
|
30
|
+
*/
|
|
31
|
+
preservePulse<T>(key: string, initialValue: T, options?: PulseOptions<T>): Pulse<T>;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Execute code with module tracking enabled.
|
|
35
|
+
* Effects created within this callback will be registered
|
|
36
|
+
* for automatic cleanup during HMR.
|
|
37
|
+
*
|
|
38
|
+
* @param callback - Code to execute with tracking
|
|
39
|
+
* @returns The return value of the callback
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* hmr.setup(() => {
|
|
43
|
+
* effect(() => {
|
|
44
|
+
* document.title = `Count: ${count.get()}`;
|
|
45
|
+
* });
|
|
46
|
+
* });
|
|
47
|
+
*/
|
|
48
|
+
setup<T>(callback: () => T): T;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Register a callback to run when the module accepts an HMR update.
|
|
52
|
+
* Call without arguments to auto-accept updates.
|
|
53
|
+
*
|
|
54
|
+
* @param callback - Optional callback for custom handling
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* hmr.accept(); // Auto-accept
|
|
58
|
+
* hmr.accept(() => console.log('Module updated!'));
|
|
59
|
+
*/
|
|
60
|
+
accept(callback?: () => void): void;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Register a callback to run before the module is replaced.
|
|
64
|
+
* Use this for custom cleanup logic.
|
|
65
|
+
*
|
|
66
|
+
* @param callback - Cleanup callback
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* hmr.dispose(() => {
|
|
70
|
+
* socket.close();
|
|
71
|
+
* clearInterval(timer);
|
|
72
|
+
* });
|
|
73
|
+
*/
|
|
74
|
+
dispose(callback: () => void): void;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Create an HMR context for a module.
|
|
79
|
+
* Provides utilities for state preservation and effect cleanup during HMR.
|
|
80
|
+
*
|
|
81
|
+
* In production or non-HMR environments, returns a no-op context
|
|
82
|
+
* that works normally but without HMR-specific behavior.
|
|
83
|
+
*
|
|
84
|
+
* @param moduleId - The module identifier (typically import.meta.url)
|
|
85
|
+
* @returns HMR context with preservation utilities
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* import { createHMRContext } from 'pulse-js-framework/runtime/hmr';
|
|
89
|
+
*
|
|
90
|
+
* const hmr = createHMRContext(import.meta.url);
|
|
91
|
+
*
|
|
92
|
+
* // Preserve state across HMR
|
|
93
|
+
* const todos = hmr.preservePulse('todos', []);
|
|
94
|
+
* const filter = hmr.preservePulse('filter', 'all');
|
|
95
|
+
*
|
|
96
|
+
* // Setup effects with automatic cleanup
|
|
97
|
+
* hmr.setup(() => {
|
|
98
|
+
* effect(() => {
|
|
99
|
+
* document.title = `${todos.get().length} todos`;
|
|
100
|
+
* });
|
|
101
|
+
* });
|
|
102
|
+
*
|
|
103
|
+
* // Accept HMR updates
|
|
104
|
+
* hmr.accept();
|
|
105
|
+
*/
|
|
106
|
+
export function createHMRContext(moduleId: string): HMRContext;
|
|
107
|
+
|
|
108
|
+
declare const hmr: {
|
|
109
|
+
createHMRContext: typeof createHMRContext;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export default hmr;
|
package/types/index.d.ts
CHANGED
|
@@ -90,8 +90,15 @@ export {
|
|
|
90
90
|
LinkOptions,
|
|
91
91
|
MatchedRoute,
|
|
92
92
|
Router,
|
|
93
|
+
MiddlewareContext,
|
|
94
|
+
MiddlewareFn,
|
|
95
|
+
LazyOptions,
|
|
96
|
+
LazyRouteHandler,
|
|
97
|
+
RouteContext,
|
|
93
98
|
createRouter,
|
|
94
|
-
simpleRouter
|
|
99
|
+
simpleRouter,
|
|
100
|
+
lazy,
|
|
101
|
+
preload
|
|
95
102
|
} from './router';
|
|
96
103
|
|
|
97
104
|
// Store
|
|
@@ -137,3 +144,20 @@ export {
|
|
|
137
144
|
logger,
|
|
138
145
|
loggers
|
|
139
146
|
} from './logger';
|
|
147
|
+
|
|
148
|
+
// HMR (Hot Module Replacement)
|
|
149
|
+
export {
|
|
150
|
+
HMRContext,
|
|
151
|
+
createHMRContext
|
|
152
|
+
} from './hmr';
|
|
153
|
+
|
|
154
|
+
// Source Maps (Compiler)
|
|
155
|
+
export {
|
|
156
|
+
Position,
|
|
157
|
+
Mapping,
|
|
158
|
+
SourceMapV3,
|
|
159
|
+
OriginalPosition,
|
|
160
|
+
SourceMapGenerator,
|
|
161
|
+
SourceMapConsumer,
|
|
162
|
+
encodeVLQ
|
|
163
|
+
} from './sourcemap';
|
package/types/router.d.ts
CHANGED
|
@@ -69,12 +69,57 @@ export interface Routes {
|
|
|
69
69
|
[path: string]: RouteHandler | RouteDefinition;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
// =============================================================================
|
|
73
|
+
// Middleware Types
|
|
74
|
+
// =============================================================================
|
|
75
|
+
|
|
76
|
+
/** Middleware context passed to each middleware function */
|
|
77
|
+
export interface MiddlewareContext {
|
|
78
|
+
/** Target route */
|
|
79
|
+
to: NavigationTarget;
|
|
80
|
+
/** Source route */
|
|
81
|
+
from: NavigationTarget;
|
|
82
|
+
/** Shared metadata between middlewares */
|
|
83
|
+
meta: Record<string, unknown>;
|
|
84
|
+
/** Redirect to another path */
|
|
85
|
+
redirect(path: string): void;
|
|
86
|
+
/** Abort navigation */
|
|
87
|
+
abort(): void;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Middleware function */
|
|
91
|
+
export type MiddlewareFn = (
|
|
92
|
+
ctx: MiddlewareContext,
|
|
93
|
+
next: () => Promise<void>
|
|
94
|
+
) => void | Promise<void>;
|
|
95
|
+
|
|
96
|
+
// =============================================================================
|
|
97
|
+
// Lazy Loading Types
|
|
98
|
+
// =============================================================================
|
|
99
|
+
|
|
100
|
+
/** Lazy loading options */
|
|
101
|
+
export interface LazyOptions {
|
|
102
|
+
/** Loading component shown while loading */
|
|
103
|
+
loading?: () => Node;
|
|
104
|
+
/** Error component shown on failure */
|
|
105
|
+
error?: (err: Error) => Node;
|
|
106
|
+
/** Timeout in milliseconds (default: 10000) */
|
|
107
|
+
timeout?: number;
|
|
108
|
+
/** Delay before showing loading component (default: 200) */
|
|
109
|
+
delay?: number;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Lazy route handler */
|
|
113
|
+
export type LazyRouteHandler = (ctx: RouteContext) => Node;
|
|
114
|
+
|
|
72
115
|
/** Router options */
|
|
73
116
|
export interface RouterOptions {
|
|
74
117
|
routes?: Routes;
|
|
75
118
|
mode?: 'history' | 'hash';
|
|
76
119
|
base?: string;
|
|
77
120
|
scrollBehavior?: ScrollBehaviorFn;
|
|
121
|
+
/** Middleware functions */
|
|
122
|
+
middleware?: MiddlewareFn[];
|
|
78
123
|
}
|
|
79
124
|
|
|
80
125
|
/** Navigation options */
|
|
@@ -84,6 +129,15 @@ export interface NavigateOptions {
|
|
|
84
129
|
state?: unknown;
|
|
85
130
|
}
|
|
86
131
|
|
|
132
|
+
/** Route context passed to route handlers */
|
|
133
|
+
export interface RouteContext {
|
|
134
|
+
params: RouteParams;
|
|
135
|
+
query: QueryParams;
|
|
136
|
+
path: string;
|
|
137
|
+
navigate: Router['navigate'];
|
|
138
|
+
router: Router;
|
|
139
|
+
}
|
|
140
|
+
|
|
87
141
|
/** Link options */
|
|
88
142
|
export interface LinkOptions {
|
|
89
143
|
exact?: boolean;
|
|
@@ -141,6 +195,12 @@ export interface Router {
|
|
|
141
195
|
/** Go to specific history entry */
|
|
142
196
|
go(delta: number): void;
|
|
143
197
|
|
|
198
|
+
/**
|
|
199
|
+
* Add middleware dynamically
|
|
200
|
+
* @returns Unregister function
|
|
201
|
+
*/
|
|
202
|
+
use(middleware: MiddlewareFn): () => void;
|
|
203
|
+
|
|
144
204
|
/**
|
|
145
205
|
* Add global before-navigation guard
|
|
146
206
|
* @returns Unregister function
|
|
@@ -195,3 +255,32 @@ export declare function createRouter(options?: RouterOptions): Router;
|
|
|
195
255
|
* Quick router setup (creates, starts, and mounts)
|
|
196
256
|
*/
|
|
197
257
|
export declare function simpleRouter(routes: Routes, target?: string): Router;
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Create a lazy-loaded route handler
|
|
261
|
+
* Wraps a dynamic import with loading states and error handling
|
|
262
|
+
*
|
|
263
|
+
* @example
|
|
264
|
+
* const routes = {
|
|
265
|
+
* '/dashboard': lazy(() => import('./Dashboard.js')),
|
|
266
|
+
* '/settings': lazy(() => import('./Settings.js'), {
|
|
267
|
+
* loading: () => el('div.spinner', 'Loading...'),
|
|
268
|
+
* error: (err) => el('div.error', `Failed: ${err.message}`),
|
|
269
|
+
* timeout: 5000
|
|
270
|
+
* })
|
|
271
|
+
* };
|
|
272
|
+
*/
|
|
273
|
+
export declare function lazy(
|
|
274
|
+
importFn: () => Promise<{ default: RouteHandler | (() => Node) }>,
|
|
275
|
+
options?: LazyOptions
|
|
276
|
+
): LazyRouteHandler;
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Preload a lazy component without rendering
|
|
280
|
+
* Useful for prefetching on hover or when likely to navigate
|
|
281
|
+
*
|
|
282
|
+
* @example
|
|
283
|
+
* const DashboardLazy = lazy(() => import('./Dashboard.js'));
|
|
284
|
+
* link.addEventListener('mouseenter', () => preload(DashboardLazy));
|
|
285
|
+
*/
|
|
286
|
+
export declare function preload(lazyHandler: LazyRouteHandler): Promise<void>;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pulse Framework - Source Map Type Definitions
|
|
3
|
+
* @module pulse-js-framework/compiler/sourcemap
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/** Source map position */
|
|
7
|
+
export interface Position {
|
|
8
|
+
line: number;
|
|
9
|
+
column: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Source map mapping */
|
|
13
|
+
export interface Mapping {
|
|
14
|
+
generated: Position;
|
|
15
|
+
original?: Position;
|
|
16
|
+
source?: string;
|
|
17
|
+
name?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** V3 Source Map format */
|
|
21
|
+
export interface SourceMapV3 {
|
|
22
|
+
version: 3;
|
|
23
|
+
file: string;
|
|
24
|
+
sourceRoot: string;
|
|
25
|
+
sources: string[];
|
|
26
|
+
sourcesContent: (string | null)[];
|
|
27
|
+
names: string[];
|
|
28
|
+
mappings: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Original position result from consumer */
|
|
32
|
+
export interface OriginalPosition {
|
|
33
|
+
source: string;
|
|
34
|
+
line: number;
|
|
35
|
+
column: number;
|
|
36
|
+
name: string | null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Source Map Generator
|
|
41
|
+
* Generates V3 source maps for compiled .pulse files
|
|
42
|
+
*/
|
|
43
|
+
export declare class SourceMapGenerator {
|
|
44
|
+
/**
|
|
45
|
+
* Create a new source map generator
|
|
46
|
+
* @param options - Generator options
|
|
47
|
+
*/
|
|
48
|
+
constructor(options?: {
|
|
49
|
+
file?: string;
|
|
50
|
+
sourceRoot?: string;
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Add a source file
|
|
55
|
+
* @param source - Source file path
|
|
56
|
+
* @param content - Source file content (optional, for inline sources)
|
|
57
|
+
* @returns Source index
|
|
58
|
+
*/
|
|
59
|
+
addSource(source: string, content?: string | null): number;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Add a name (identifier) to the names array
|
|
63
|
+
* @param name - Identifier name
|
|
64
|
+
* @returns Name index
|
|
65
|
+
*/
|
|
66
|
+
addName(name: string): number;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Add a mapping between generated and original positions
|
|
70
|
+
* @param mapping - Mapping information
|
|
71
|
+
*/
|
|
72
|
+
addMapping(mapping: Mapping): void;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Generate the source map object
|
|
76
|
+
* @returns V3 source map object
|
|
77
|
+
*/
|
|
78
|
+
toJSON(): SourceMapV3;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Generate source map as JSON string
|
|
82
|
+
*/
|
|
83
|
+
toString(): string;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Generate inline source map comment
|
|
87
|
+
* @returns Comment with base64 encoded source map
|
|
88
|
+
*/
|
|
89
|
+
toComment(): string;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Generate external source map URL comment
|
|
93
|
+
* @param url - URL to source map file
|
|
94
|
+
*/
|
|
95
|
+
static toURLComment(url: string): string;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Source Map Consumer
|
|
100
|
+
* Parse and query source maps for error stack trace translation
|
|
101
|
+
*/
|
|
102
|
+
export declare class SourceMapConsumer {
|
|
103
|
+
/**
|
|
104
|
+
* Create a new source map consumer
|
|
105
|
+
* @param sourceMap - Source map object or JSON string
|
|
106
|
+
*/
|
|
107
|
+
constructor(sourceMap: SourceMapV3 | string);
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Decode VLQ string to numbers
|
|
111
|
+
* @param str - VLQ encoded string
|
|
112
|
+
*/
|
|
113
|
+
static decodeVLQ(str: string): number[];
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Get original position for a generated position
|
|
117
|
+
* @param position - Generated position
|
|
118
|
+
* @returns Original position or null if not found
|
|
119
|
+
*/
|
|
120
|
+
originalPositionFor(position: Position): OriginalPosition | null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Encode a number as VLQ base64
|
|
125
|
+
*/
|
|
126
|
+
export declare function encodeVLQ(value: number): string;
|