@expressive/dom 0.1.0 → 0.3.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.
@@ -1,6 +1,6 @@
1
- import { i as VNode, o as vnode, r as Node } from "./chunk-vnode-DHwzzX6t.js";
2
- import { Fragment } from "@expressive/mvc/runtime";
3
- import { JSX } from "@expressive/mvc/jsx-runtime";
1
+ import { c as vnode, i as Node, n as Module, o as VNode, t as Attributes$1 } from "./chunk-loader-kjuM318E.js";
2
+ import { Component, State } from "@expressive/mvc";
3
+ import { Fragment, JSX as JSX$1 } from "@expressive/mvc/jsx-runtime";
4
4
 
5
5
  //#region src/jsx-runtime.d.ts
6
6
  type Words = 'AnimationCancel' | 'AnimationEnd' | 'AnimationIteration' | 'AnimationStart' | 'AuxClick' | 'BeforeInput' | 'BeforeMatch' | 'BeforeToggle' | 'CanPlay' | 'CanPlayThrough' | 'CompositionEnd' | 'CompositionStart' | 'CompositionUpdate' | 'ContextLost' | 'ContextMenu' | 'ContextRestored' | 'CueChange' | 'DblClick' | 'DragEnd' | 'DragEnter' | 'DragLeave' | 'DragOver' | 'DragStart' | 'DurationChange' | 'FocusIn' | 'FocusOut' | 'FormData' | 'GotPointerCapture' | 'KeyDown' | 'KeyPress' | 'KeyUp' | 'LoadedData' | 'LoadedMetadata' | 'LoadStart' | 'LostPointerCapture' | 'MouseDown' | 'MouseEnter' | 'MouseLeave' | 'MouseMove' | 'MouseOut' | 'MouseOver' | 'MouseUp' | 'PointerCancel' | 'PointerDown' | 'PointerEnter' | 'PointerLeave' | 'PointerMove' | 'PointerOut' | 'PointerOver' | 'PointerRawUpdate' | 'PointerUp' | 'RateChange' | 'ScrollEnd' | 'SecurityPolicyViolation' | 'SelectionChange' | 'SelectStart' | 'SlotChange' | 'TimeUpdate' | 'TouchCancel' | 'TouchEnd' | 'TouchMove' | 'TouchStart' | 'TransitionCancel' | 'TransitionEnd' | 'TransitionRun' | 'TransitionStart' | 'VolumeChange';
@@ -36,10 +36,26 @@ type Attributes<T extends Element> = EventAttributes<T> & { [K in keyof T as K e
36
36
  [attribute: `aria-${string}`]: unknown;
37
37
  };
38
38
  type Intrinsics = { [K in keyof HTMLElementTagNameMap]: Attributes<HTMLElementTagNameMap[K]> } & { [K in keyof SVGElementTagNameMap]: Attributes<SVGElementTagNameMap[K]> & SVGAttributes };
39
- declare module '@expressive/mvc/runtime' {
39
+ declare module '@expressive/mvc/jsx-runtime' {
40
40
  interface Host {
41
41
  node: Node;
42
42
  intrinsics: Intrinsics;
43
+ element: () => PromiseLike<Module>;
44
+ elementClass: State;
45
+ }
46
+ }
47
+ declare module '@expressive/mvc' {
48
+ namespace State {
49
+ /** JSX attributes of a State with no `props` member: its settable fields, `is`, a boundary, and what `render` accepts. */
50
+ type Props<T extends State> = Component.StateProps<T> & {
51
+ is?: (instance: T) => void; /** Shown while this element's content is suspended or recovering. `false` opts out. */
52
+ fallback?: Reserved<T, 'fallback', Component.Node | false>; /** Called when this element's content throws. A returned promise retries once settled. */
53
+ catch?: Reserved<T, 'catch', (error: Error, instance: T) => Promise<void> | void>;
54
+ } & Component.RenderProps<T extends {
55
+ render: infer R;
56
+ } ? R : never>;
57
+ /** Boundary attribute type, narrowed by a member of the same name so a mismatch fails at the element. */
58
+ type Reserved<T, K extends string, V> = K extends keyof T ? T[K] & V : V;
43
59
  }
44
60
  }
45
61
  declare module '@expressive/mvc/jsx-runtime' {
@@ -52,6 +68,29 @@ declare module '@expressive/mvc/jsx-runtime' {
52
68
  }
53
69
  declare const jsx: typeof vnode;
54
70
  declare const jsxs: typeof vnode;
71
+ declare namespace JSX {
72
+ type Element = JSX$1.Element;
73
+ type ElementType = keyof IntrinsicElements | ((props: any) => Component.Node) | (() => PromiseLike<Module>) | (abstract new (...args: any[]) => ElementClass);
74
+ /**
75
+ * Any State renders as a class element - one with `render` produces content,
76
+ * one without passes children through and provides itself.
77
+ */
78
+ interface ElementClass extends State {
79
+ render?(props?: any): Component.Node;
80
+ }
81
+ /**
82
+ * Empty, so a class element's attributes resolve from its instance type and
83
+ * {@link LibraryManagedAttributes} picks `props` when declared, else derives
84
+ * them from the State.
85
+ */
86
+ interface ElementAttributesProperty {}
87
+ type LibraryManagedAttributes<C, P> = C extends (abstract new (...args: any[]) => infer I) ? P extends {
88
+ props: infer Q;
89
+ } ? Q : I extends State ? State.Props<I> : P : C extends (() => PromiseLike<Module<infer T>>) ? Attributes$1<T> : P;
90
+ interface ElementChildrenAttribute extends JSX$1.ElementChildrenAttribute {}
91
+ interface IntrinsicAttributes extends JSX$1.IntrinsicAttributes {}
92
+ type IntrinsicElements = JSX$1.IntrinsicElements;
93
+ }
55
94
  //#endregion
56
- export { Fragment, type JSX, type VNode as JSXElement, jsx, jsxs };
95
+ export { Fragment, JSX, type VNode as JSXElement, jsx, jsxs };
57
96
  //# sourceMappingURL=jsx-runtime.d.ts.map
@@ -1,5 +1,5 @@
1
- import { a as vnode, i as isVNode, n as childrenOf } from "./chunk-vnode-DA7cLTKP.js";
2
- import { Fragment, host } from "@expressive/mvc/runtime";
1
+ import { i as childrenOf, o as isVNode, s as vnode } from "./chunk-vnode-BG1Cv8F9.js";
2
+ import { Fragment, host } from "@expressive/mvc/jsx-runtime";
3
3
 
4
4
  //#region src/jsx-runtime.ts
5
5
  host({
@@ -1 +1 @@
1
- {"version":3,"file":"jsx-runtime.js","names":[],"sources":["../src/jsx-runtime.ts"],"sourcesContent":["import { Fragment, host } from '@expressive/mvc/runtime';\n\nimport { childrenOf, isVNode, vnode } from './vnode';\nimport type { Node, VNode } from './vnode';\n\ntype Words =\n | 'AnimationCancel' | 'AnimationEnd' | 'AnimationIteration' | 'AnimationStart'\n | 'AuxClick' | 'BeforeInput' | 'BeforeMatch' | 'BeforeToggle' | 'CanPlay' | 'CanPlayThrough'\n | 'CompositionEnd' | 'CompositionStart' | 'CompositionUpdate'\n | 'ContextLost' | 'ContextMenu' | 'ContextRestored' | 'CueChange' | 'DblClick'\n | 'DragEnd' | 'DragEnter' | 'DragLeave' | 'DragOver' | 'DragStart' | 'DurationChange'\n | 'FocusIn' | 'FocusOut' | 'FormData' | 'GotPointerCapture' | 'KeyDown' | 'KeyPress' | 'KeyUp'\n | 'LoadedData' | 'LoadedMetadata' | 'LoadStart' | 'LostPointerCapture'\n | 'MouseDown' | 'MouseEnter' | 'MouseLeave' | 'MouseMove' | 'MouseOut' | 'MouseOver' | 'MouseUp'\n | 'PointerCancel' | 'PointerDown' | 'PointerEnter' | 'PointerLeave' | 'PointerMove'\n | 'PointerOut' | 'PointerOver' | 'PointerRawUpdate' | 'PointerUp'\n | 'RateChange' | 'ScrollEnd' | 'SecurityPolicyViolation' | 'SelectionChange' | 'SelectStart'\n | 'SlotChange' | 'TimeUpdate' | 'TouchCancel' | 'TouchEnd' | 'TouchMove' | 'TouchStart'\n | 'TransitionCancel' | 'TransitionEnd' | 'TransitionRun' | 'TransitionStart' | 'VolumeChange';\n\ntype Cased = { [W in Words as Lowercase<W>]: W };\ntype EventName<K> = K extends keyof Cased ? Cased[K] : Capitalize<K & string>;\n\ntype EventAttributes<T extends Element> = {\n [K in keyof GlobalEventHandlersEventMap as `on${EventName<K>}`]?:\n (event: GlobalEventHandlersEventMap[K] & { currentTarget: T }) => unknown;\n} & {\n [K in keyof GlobalEventHandlersEventMap as `on${EventName<K>}Capture`]?:\n (event: GlobalEventHandlersEventMap[K] & { currentTarget: T }) => unknown;\n};\n\ntype Declarations = Partial<Record<keyof CSSStyleDeclaration, string | number | null>> & {\n [property: `--${string}`]: string | number | null | undefined;\n};\ntype Style = string | Declarations | false | null | undefined | readonly Style[];\n\ntype SVGAttributes = {\n [K in\n | 'clipPathUnits' | 'cx' | 'cy' | 'd' | 'dx' | 'dy' | 'fill' | 'filter' | 'fx' | 'fy'\n | 'gradientTransform' | 'gradientUnits' | 'height' | 'href' | 'in' | 'in2' | 'mask'\n | 'markerHeight' | 'markerUnits' | 'markerWidth' | 'maskUnits' | 'offset' | 'opacity'\n | 'orient' | 'pathLength' | 'patternUnits' | 'points' | 'preserveAspectRatio' | 'r'\n | 'refX' | 'refY' | 'result' | 'rotate' | 'rx' | 'ry' | 'stdDeviation' | 'stroke'\n | 'textLength' | 'transform' | 'type' | 'values' | 'version' | 'viewBox' | 'width'\n | 'x' | 'x1' | 'x2' | 'xmlns' | 'y' | 'y1' | 'y2']?: string | number;\n};\n\ntype Attributes<T extends Element> = EventAttributes<T> & {\n [K in keyof T as K extends 'children' | 'className' | 'style'\n ? never\n : T[K] extends Function\n ? never\n : K]?: T[K] | string | number | boolean;\n} & {\n children?: Node;\n className?: string;\n autoFocus?: boolean;\n onDoubleClick?: (event: MouseEvent & { currentTarget: T }) => unknown;\n dangerouslySetInnerHTML?: { __html: string };\n key?: string | number | null;\n ref?: ((node: T | null) => unknown) | { current: T | null };\n style?: Style;\n [attribute: `_${string}`]: unknown;\n [attribute: `data-${string}`]: unknown;\n [attribute: `aria-${string}`]: unknown;\n};\n\ntype Intrinsics = {\n [K in keyof HTMLElementTagNameMap]: Attributes<HTMLElementTagNameMap[K]>;\n} & {\n [K in keyof SVGElementTagNameMap]: Attributes<SVGElementTagNameMap[K]> & SVGAttributes;\n};\n\ndeclare module '@expressive/mvc/runtime' {\n interface Host {\n node: Node;\n intrinsics: Intrinsics;\n }\n}\n\ndeclare module '@expressive/mvc/jsx-runtime' {\n namespace JSX {\n interface IntrinsicAttributes {\n style?: Style;\n [attribute: `_${string}`]: unknown;\n }\n }\n}\n\nhost({\n jsx: vnode,\n jsxs: vnode,\n Fragment,\n childrenOf,\n isElement: isVNode,\n typeOf(node: unknown) {\n return isVNode(node) ? node.type : undefined;\n },\n propsOf(node: unknown) {\n return isVNode(node) ? node.props : {};\n }\n});\n\nconst jsx = vnode;\nconst jsxs = vnode;\n\nexport { Fragment, jsx, jsxs };\nexport type { VNode as JSXElement };\nexport type { JSX } from '@expressive/mvc/jsx-runtime';\n"],"mappings":";;;;AAyFA,KAAK;CACH,KAAK;CACL,MAAM;CACN;CACA;CACA,WAAW;CACX,OAAO,MAAe;AACpB,SAAO,QAAQ,KAAK,GAAG,KAAK,OAAO;;CAErC,QAAQ,MAAe;AACrB,SAAO,QAAQ,KAAK,GAAG,KAAK,QAAQ,EAAE;;CAEzC,CAAC;AAEF,MAAM,MAAM;AACZ,MAAM,OAAO"}
1
+ {"version":3,"file":"jsx-runtime.js","names":[],"sources":["../src/jsx-runtime.ts"],"sourcesContent":["import { Fragment, host } from '@expressive/mvc/jsx-runtime';\nimport type { Component, State } from '@expressive/mvc';\nimport type { JSX as Base } from '@expressive/mvc/jsx-runtime';\n\nimport { childrenOf, isVNode, vnode } from './vnode';\nimport type { Node, VNode } from './vnode';\nimport type { Attributes as Loaded, Module } from './loader';\n\ntype Words =\n | 'AnimationCancel' | 'AnimationEnd' | 'AnimationIteration' | 'AnimationStart'\n | 'AuxClick' | 'BeforeInput' | 'BeforeMatch' | 'BeforeToggle' | 'CanPlay' | 'CanPlayThrough'\n | 'CompositionEnd' | 'CompositionStart' | 'CompositionUpdate'\n | 'ContextLost' | 'ContextMenu' | 'ContextRestored' | 'CueChange' | 'DblClick'\n | 'DragEnd' | 'DragEnter' | 'DragLeave' | 'DragOver' | 'DragStart' | 'DurationChange'\n | 'FocusIn' | 'FocusOut' | 'FormData' | 'GotPointerCapture' | 'KeyDown' | 'KeyPress' | 'KeyUp'\n | 'LoadedData' | 'LoadedMetadata' | 'LoadStart' | 'LostPointerCapture'\n | 'MouseDown' | 'MouseEnter' | 'MouseLeave' | 'MouseMove' | 'MouseOut' | 'MouseOver' | 'MouseUp'\n | 'PointerCancel' | 'PointerDown' | 'PointerEnter' | 'PointerLeave' | 'PointerMove'\n | 'PointerOut' | 'PointerOver' | 'PointerRawUpdate' | 'PointerUp'\n | 'RateChange' | 'ScrollEnd' | 'SecurityPolicyViolation' | 'SelectionChange' | 'SelectStart'\n | 'SlotChange' | 'TimeUpdate' | 'TouchCancel' | 'TouchEnd' | 'TouchMove' | 'TouchStart'\n | 'TransitionCancel' | 'TransitionEnd' | 'TransitionRun' | 'TransitionStart' | 'VolumeChange';\n\ntype Cased = { [W in Words as Lowercase<W>]: W };\ntype EventName<K> = K extends keyof Cased ? Cased[K] : Capitalize<K & string>;\n\ntype EventAttributes<T extends Element> = {\n [K in keyof GlobalEventHandlersEventMap as `on${EventName<K>}`]?:\n (event: GlobalEventHandlersEventMap[K] & { currentTarget: T }) => unknown;\n} & {\n [K in keyof GlobalEventHandlersEventMap as `on${EventName<K>}Capture`]?:\n (event: GlobalEventHandlersEventMap[K] & { currentTarget: T }) => unknown;\n};\n\ntype Declarations = Partial<Record<keyof CSSStyleDeclaration, string | number | null>> & {\n [property: `--${string}`]: string | number | null | undefined;\n};\ntype Style = string | Declarations | false | null | undefined | readonly Style[];\n\ntype SVGAttributes = {\n [K in\n | 'clipPathUnits' | 'cx' | 'cy' | 'd' | 'dx' | 'dy' | 'fill' | 'filter' | 'fx' | 'fy'\n | 'gradientTransform' | 'gradientUnits' | 'height' | 'href' | 'in' | 'in2' | 'mask'\n | 'markerHeight' | 'markerUnits' | 'markerWidth' | 'maskUnits' | 'offset' | 'opacity'\n | 'orient' | 'pathLength' | 'patternUnits' | 'points' | 'preserveAspectRatio' | 'r'\n | 'refX' | 'refY' | 'result' | 'rotate' | 'rx' | 'ry' | 'stdDeviation' | 'stroke'\n | 'textLength' | 'transform' | 'type' | 'values' | 'version' | 'viewBox' | 'width'\n | 'x' | 'x1' | 'x2' | 'xmlns' | 'y' | 'y1' | 'y2']?: string | number;\n};\n\ntype Attributes<T extends Element> = EventAttributes<T> & {\n [K in keyof T as K extends 'children' | 'className' | 'style'\n ? never\n : T[K] extends Function\n ? never\n : K]?: T[K] | string | number | boolean;\n} & {\n children?: Node;\n className?: string;\n autoFocus?: boolean;\n onDoubleClick?: (event: MouseEvent & { currentTarget: T }) => unknown;\n dangerouslySetInnerHTML?: { __html: string };\n key?: string | number | null;\n ref?: ((node: T | null) => unknown) | { current: T | null };\n style?: Style;\n [attribute: `_${string}`]: unknown;\n [attribute: `data-${string}`]: unknown;\n [attribute: `aria-${string}`]: unknown;\n};\n\ntype Intrinsics = {\n [K in keyof HTMLElementTagNameMap]: Attributes<HTMLElementTagNameMap[K]>;\n} & {\n [K in keyof SVGElementTagNameMap]: Attributes<SVGElementTagNameMap[K]> & SVGAttributes;\n};\n\ndeclare module '@expressive/mvc/jsx-runtime' {\n interface Host {\n node: Node;\n intrinsics: Intrinsics;\n element: () => PromiseLike<Module>;\n elementClass: State;\n }\n}\n\ndeclare module '@expressive/mvc' {\n namespace State {\n /** JSX attributes of a State with no `props` member: its settable fields, `is`, a boundary, and what `render` accepts. */\n type Props<T extends State> =\n & Component.StateProps<T>\n & {\n is?: (instance: T) => void;\n /** Shown while this element's content is suspended or recovering. `false` opts out. */\n fallback?: Reserved<T, 'fallback', Component.Node | false>;\n /** Called when this element's content throws. A returned promise retries once settled. */\n catch?: Reserved<T, 'catch', (error: Error, instance: T) => Promise<void> | void>;\n }\n & Component.RenderProps<T extends { render: infer R } ? R : never>;\n\n /** Boundary attribute type, narrowed by a member of the same name so a mismatch fails at the element. */\n type Reserved<T, K extends string, V> = K extends keyof T ? T[K] & V : V;\n }\n}\n\ndeclare module '@expressive/mvc/jsx-runtime' {\n namespace JSX {\n interface IntrinsicAttributes {\n style?: Style;\n [attribute: `_${string}`]: unknown;\n }\n }\n}\n\nhost({\n jsx: vnode,\n jsxs: vnode,\n Fragment,\n childrenOf,\n isElement: isVNode,\n typeOf(node: unknown) {\n return isVNode(node) ? node.type : undefined;\n },\n propsOf(node: unknown) {\n return isVNode(node) ? node.props : {};\n }\n});\n\nconst jsx = vnode;\nconst jsxs = vnode;\n\nexport { Fragment, jsx, jsxs };\nexport type { VNode as JSXElement };\nexport declare namespace JSX {\n type Element = Base.Element;\n type ElementType =\n | keyof IntrinsicElements\n | ((props: any) => Component.Node)\n | (() => PromiseLike<Module>)\n | (abstract new (...args: any[]) => ElementClass);\n /**\n * Any State renders as a class element - one with `render` produces content,\n * one without passes children through and provides itself.\n */\n interface ElementClass extends State { render?(props?: any): Component.Node }\n /**\n * Empty, so a class element's attributes resolve from its instance type and\n * {@link LibraryManagedAttributes} picks `props` when declared, else derives\n * them from the State.\n */\n interface ElementAttributesProperty {}\n type LibraryManagedAttributes<C, P> =\n C extends abstract new (...args: any[]) => infer I\n ? P extends { props: infer Q } ? Q\n : I extends State ? State.Props<I>\n : P\n : C extends () => PromiseLike<Module<infer T>>\n ? Loaded<T>\n : P;\n interface ElementChildrenAttribute extends Base.ElementChildrenAttribute {}\n interface IntrinsicAttributes extends Base.IntrinsicAttributes {}\n type IntrinsicElements = Base.IntrinsicElements;\n}\n"],"mappings":";;;;AAiHA,KAAK;CACH,KAAK;CACL,MAAM;CACN;CACA;CACA,WAAW;CACX,OAAO,MAAe;AACpB,SAAO,QAAQ,KAAK,GAAG,KAAK,OAAO;;CAErC,QAAQ,MAAe;AACrB,SAAO,QAAQ,KAAK,GAAG,KAAK,QAAQ,EAAE;;CAEzC,CAAC;AAEF,MAAM,MAAM;AACZ,MAAM,OAAO"}
package/dist/vite.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ import { Plugin } from "vite";
2
+
3
+ //#region src/vite.d.ts
4
+ /** Hot-patch classes and refresh function components in place during `vite` dev. */
5
+ declare function expressive(): Plugin;
6
+ //#endregion
7
+ export { expressive as default };
8
+ //# sourceMappingURL=vite.d.ts.map
package/dist/vite.js ADDED
@@ -0,0 +1,155 @@
1
+ import { dirname } from "node:path";
2
+
3
+ //#region src/vite.ts
4
+ const SOURCE = /\.[cm]?[jt]sx?$/;
5
+ const COMPONENT = /^[A-Z]/;
6
+ const FUNCTION = ["ArrowFunctionExpression", "FunctionExpression"];
7
+ /**
8
+ * Top-level classes a module can reassign, those declaring private members,
9
+ * function components by name, and its exports by local binding.
10
+ */
11
+ function scan(body) {
12
+ const classes = [];
13
+ const hidden = [];
14
+ const components = [];
15
+ const exports = {};
16
+ function add(name, node) {
17
+ classes.push(name);
18
+ if (node.body.body.some((member) => member.key?.type == "PrivateIdentifier")) hidden.push(name);
19
+ }
20
+ function collect(node) {
21
+ if (node.type == "ClassDeclaration" && node.id) add(node.id.name, node);
22
+ else if (node.type == "FunctionDeclaration" && COMPONENT.test(node.id?.name)) components.push(node.id.name);
23
+ else if (node.type == "VariableDeclaration") for (const { id, init } of node.declarations) {
24
+ if (id.type != "Identifier") continue;
25
+ if (init?.type == "ClassExpression" && node.kind != "const") add(id.name, init);
26
+ else if (FUNCTION.includes(init?.type) && COMPONENT.test(id.name)) components.push(id.name);
27
+ }
28
+ }
29
+ function names(node) {
30
+ if (node.type == "VariableDeclaration") return node.declarations.flatMap(({ id }) => id.type == "Identifier" ? [id.name] : []);
31
+ return [node.id.name];
32
+ }
33
+ for (const node of body) if (node.type == "ExportNamedDeclaration") {
34
+ if (node.declaration) {
35
+ collect(node.declaration);
36
+ for (const name of names(node.declaration)) exports[name] = name;
37
+ } else if (!node.source) for (const { local, exported } of node.specifiers) exports[exported.name ?? exported.value] = local.name;
38
+ } else if (node.type == "ExportDefaultDeclaration") {
39
+ const { declaration } = node;
40
+ collect(declaration);
41
+ if (declaration.id) exports.default = declaration.id.name;
42
+ } else collect(node);
43
+ return {
44
+ classes,
45
+ hidden,
46
+ components,
47
+ exports
48
+ };
49
+ }
50
+ const server = (notes, list) => `\
51
+ const __notes = ${JSON.stringify(notes)};
52
+ const __before = import.meta.hot.data.expressive;
53
+ const __classes = (import.meta.hot.data.expressive = { ${list} });
54
+ const __warned = (import.meta.hot.data.warned ||= {});
55
+ for (const key in __notes)
56
+ if (__before && __classes[key] !== __before[key] && !__warned[key]) {
57
+ __warned[key] = true;
58
+ console.warn(__notes[key]);
59
+ }`;
60
+ const browser = (id, notes, list) => `\
61
+ const __notes = ${JSON.stringify(notes)};
62
+ const __flag = (key) => 'expressive:private:' + ${id} + ':' + key;
63
+ for (const key in __notes)
64
+ try {
65
+ if (sessionStorage.getItem(__flag(key)) == 'due') {
66
+ console.warn(__notes[key]);
67
+ sessionStorage.setItem(__flag(key), 'shown');
68
+ }
69
+ } catch {}
70
+ const __before = import.meta.hot.data.expressive;
71
+ const __classes = (import.meta.hot.data.expressive = { ${list} });
72
+ for (const key in __before)
73
+ if (__classes[key] !== __before[key] && __classes[key]?.prototype instanceof __State) {
74
+ const note = __notes[key];
75
+ if (note)
76
+ try {
77
+ if (!sessionStorage.getItem(__flag(key))) sessionStorage.setItem(__flag(key), 'due');
78
+ } catch {
79
+ console.warn(note);
80
+ }
81
+ dispatchEvent(new CustomEvent('expressive:reload', { detail: { module: ${id}, class: key, reason: note ? 'private members' : 'class changed shape' } }));
82
+ location.reload();
83
+ break;
84
+ }`;
85
+ const patchClasses = (id, classes) => `\
86
+ {
87
+ const __hot = __accept(${id}, { ${classes.join(", ")} });
88
+ ${classes.map((name) => `${name} = __hot.${name};`).join("\n ")}
89
+ }`;
90
+ const acceptUpdates = (replace, record, refresh) => `\
91
+ if (import.meta.hot) {
92
+ ${replace}
93
+ const __exports = { ${record} };
94
+ import.meta.hot.accept((next) => {
95
+ if (!next) return;
96
+ for (const key in __exports) {
97
+ const after = next[key];
98
+ if (after !== __exports[key] && !(after?.prototype instanceof __State) && !${JSON.stringify(refresh)}.includes(key))
99
+ return import.meta.hot.invalidate(\`"\${key}" export cannot be hot-patched.\`);
100
+ }
101
+ });
102
+ }`;
103
+ /**
104
+ * Bind a module's classes to `hot.accept` and its function components to dom's
105
+ * refresh. A State class it could not patch reloads the page; after an update,
106
+ * a changed component re-renders in place and any other changed export
107
+ * invalidates importers.
108
+ */
109
+ function inject(id, body, ssr = false) {
110
+ const { classes, hidden, components, exports } = scan(body);
111
+ if (!classes.length && !components.length) return "";
112
+ const key = JSON.stringify(id);
113
+ const list = classes.join(", ");
114
+ const record = Object.entries(exports).map(([name, local]) => `${JSON.stringify(name)}: ${local}`);
115
+ const refresh = Object.keys(exports).filter((name) => components.includes(exports[name]));
116
+ const effect = ssr ? "replace it instead of patching" : "will trigger a full reload";
117
+ const notes = Object.fromEntries(hidden.map((name) => [name, `[expressive] ${name} (${id}) declares #private members, so edits to its module ${effect}. Use _ properties instead to keep HMR.`]));
118
+ const replace = ssr ? server(notes, list) : browser(key, notes, list);
119
+ return `\n${[
120
+ `import { State as __State } from '@expressive/mvc';`,
121
+ classes.length && `import { accept as __accept } from '@expressive/mvc/hot';`,
122
+ components.length && `import { hot as __refresh } from '@expressive/dom/jsx-dev-runtime';`,
123
+ classes.length && patchClasses(key, classes),
124
+ components.length && `__refresh(${key}, { ${components.join(", ")} });`,
125
+ acceptUpdates(replace, record.join(", "), refresh)
126
+ ].filter(Boolean).join("\n")}\n`;
127
+ }
128
+ /** Hot-patch classes and refresh function components in place during `vite` dev. */
129
+ function expressive() {
130
+ let root = "";
131
+ let runtime;
132
+ return {
133
+ name: "@expressive/dom:hot",
134
+ apply: "serve",
135
+ enforce: "post",
136
+ configResolved(config) {
137
+ root = config.root;
138
+ },
139
+ async transform(code, id, options) {
140
+ const [file] = id.split("?");
141
+ if (!SOURCE.test(file) || file.includes("/node_modules/")) return;
142
+ runtime ||= Promise.all(["@expressive/mvc/hot", "@expressive/dom/jsx-dev-runtime"].map((entry) => this.resolve(entry).then((found) => found && dirname(found.id))));
143
+ for (const own of await runtime) if (own && file.startsWith(own)) return;
144
+ const output = inject(file.startsWith(root + "/") ? file.slice(root.length) : file, this.parse(code).body, options?.ssr);
145
+ if (output) return {
146
+ code: code + output,
147
+ map: null
148
+ };
149
+ }
150
+ };
151
+ }
152
+
153
+ //#endregion
154
+ export { expressive as default };
155
+ //# sourceMappingURL=vite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite.js","names":[],"sources":["../src/vite.ts"],"sourcesContent":["import { dirname } from 'node:path';\nimport type { Plugin } from 'vite';\n\ntype Node = { type: string; [key: string]: any };\n\nconst SOURCE = /\\.[cm]?[jt]sx?$/;\n\nconst COMPONENT = /^[A-Z]/;\nconst FUNCTION = ['ArrowFunctionExpression', 'FunctionExpression'];\n\n/**\n * Top-level classes a module can reassign, those declaring private members,\n * function components by name, and its exports by local binding.\n */\nfunction scan(body: Node[]) {\n const classes: string[] = [];\n const hidden: string[] = [];\n const components: string[] = [];\n const exports: Record<string, string> = {};\n\n function add(name: string, node: Node) {\n classes.push(name);\n\n if (node.body.body.some((member: Node) => member.key?.type == 'PrivateIdentifier')) hidden.push(name);\n }\n\n function collect(node: Node) {\n if (node.type == 'ClassDeclaration' && node.id) add(node.id.name, node);\n else if (node.type == 'FunctionDeclaration' && COMPONENT.test(node.id?.name)) components.push(node.id.name);\n else if (node.type == 'VariableDeclaration')\n for (const { id, init } of node.declarations) {\n if (id.type != 'Identifier') continue;\n if (init?.type == 'ClassExpression' && node.kind != 'const') add(id.name, init);\n else if (FUNCTION.includes(init?.type) && COMPONENT.test(id.name)) components.push(id.name);\n }\n }\n\n function names(node: Node): string[] {\n if (node.type == 'VariableDeclaration')\n return node.declarations.flatMap(({ id }: Node) => (id.type == 'Identifier' ? [id.name] : []));\n\n return [node.id.name];\n }\n\n for (const node of body) {\n if (node.type == 'ExportNamedDeclaration') {\n if (node.declaration) {\n collect(node.declaration);\n for (const name of names(node.declaration)) exports[name] = name;\n } else if (!node.source)\n for (const { local, exported } of node.specifiers)\n exports[exported.name ?? exported.value] = local.name;\n } else if (node.type == 'ExportDefaultDeclaration') {\n const { declaration } = node;\n\n collect(declaration);\n\n if (declaration.id) exports.default = declaration.id.name;\n } else collect(node);\n }\n\n return { classes, hidden, components, exports };\n}\n\nconst server = (notes: Record<string, string>, list: string) => `\\\n const __notes = ${JSON.stringify(notes)};\n const __before = import.meta.hot.data.expressive;\n const __classes = (import.meta.hot.data.expressive = { ${list} });\n const __warned = (import.meta.hot.data.warned ||= {});\n for (const key in __notes)\n if (__before && __classes[key] !== __before[key] && !__warned[key]) {\n __warned[key] = true;\n console.warn(__notes[key]);\n }`;\n\nconst browser = (id: string, notes: Record<string, string>, list: string) => `\\\n const __notes = ${JSON.stringify(notes)};\n const __flag = (key) => 'expressive:private:' + ${id} + ':' + key;\n for (const key in __notes)\n try {\n if (sessionStorage.getItem(__flag(key)) == 'due') {\n console.warn(__notes[key]);\n sessionStorage.setItem(__flag(key), 'shown');\n }\n } catch {}\n const __before = import.meta.hot.data.expressive;\n const __classes = (import.meta.hot.data.expressive = { ${list} });\n for (const key in __before)\n if (__classes[key] !== __before[key] && __classes[key]?.prototype instanceof __State) {\n const note = __notes[key];\n if (note)\n try {\n if (!sessionStorage.getItem(__flag(key))) sessionStorage.setItem(__flag(key), 'due');\n } catch {\n console.warn(note);\n }\n dispatchEvent(new CustomEvent('expressive:reload', { detail: { module: ${id}, class: key, reason: note ? 'private members' : 'class changed shape' } }));\n location.reload();\n break;\n }`;\n\nconst patchClasses = (id: string, classes: string[]) => `\\\n{\n const __hot = __accept(${id}, { ${classes.join(', ')} });\n ${classes.map((name) => `${name} = __hot.${name};`).join('\\n ')}\n}`;\n\nconst acceptUpdates = (replace: string, record: string, refresh: string[]) => `\\\nif (import.meta.hot) {\n${replace}\n const __exports = { ${record} };\n import.meta.hot.accept((next) => {\n if (!next) return;\n for (const key in __exports) {\n const after = next[key];\n if (after !== __exports[key] && !(after?.prototype instanceof __State) && !${JSON.stringify(refresh)}.includes(key))\n return import.meta.hot.invalidate(\\`\"\\${key}\" export cannot be hot-patched.\\`);\n }\n });\n}`;\n\n/**\n * Bind a module's classes to `hot.accept` and its function components to dom's\n * refresh. A State class it could not patch reloads the page; after an update,\n * a changed component re-renders in place and any other changed export\n * invalidates importers.\n */\nfunction inject(id: string, body: Node[], ssr = false) {\n const { classes, hidden, components, exports } = scan(body);\n\n if (!classes.length && !components.length) return '';\n\n const key = JSON.stringify(id);\n const list = classes.join(', ');\n const record = Object.entries(exports).map(([name, local]) => `${JSON.stringify(name)}: ${local}`);\n const refresh = Object.keys(exports).filter((name) => components.includes(exports[name]));\n const effect = ssr ? 'replace it instead of patching' : 'will trigger a full reload';\n const notes = Object.fromEntries(\n hidden.map((name) => [name, `[expressive] ${name} (${id}) declares #private members, so edits to its module ${effect}. Use _ properties instead to keep HMR.`])\n );\n const replace = ssr ? server(notes, list) : browser(key, notes, list);\n const lines = [\n `import { State as __State } from '@expressive/mvc';`,\n classes.length && `import { accept as __accept } from '@expressive/mvc/hot';`,\n components.length && `import { hot as __refresh } from '@expressive/dom/jsx-dev-runtime';`,\n classes.length && patchClasses(key, classes),\n components.length && `__refresh(${key}, { ${components.join(', ')} });`,\n acceptUpdates(replace, record.join(', '), refresh)\n ];\n\n return `\\n${lines.filter(Boolean).join('\\n')}\\n`;\n}\n\n/** Hot-patch classes and refresh function components in place during `vite` dev. */\nexport default function expressive(): Plugin {\n let root = '';\n let runtime: Promise<(string | null | undefined)[]> | undefined;\n\n return {\n name: '@expressive/dom:hot',\n apply: 'serve',\n enforce: 'post',\n configResolved(config) {\n root = config.root;\n },\n async transform(code, id, options) {\n const [file] = id.split('?');\n\n if (!SOURCE.test(file) || file.includes('/node_modules/')) return;\n\n runtime ||= Promise.all(\n ['@expressive/mvc/hot', '@expressive/dom/jsx-dev-runtime'].map((entry) =>\n this.resolve(entry).then((found) => found && dirname(found.id))\n )\n );\n\n for (const own of await runtime) if (own && file.startsWith(own)) return;\n\n const output = inject(file.startsWith(root + '/') ? file.slice(root.length) : file, this.parse(code).body as Node[], options?.ssr);\n\n if (output) return { code: code + output, map: null };\n }\n };\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expressive/dom",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "MVC-native DOM renderer.",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -36,6 +36,10 @@
36
36
  "./jsx-dev-runtime": {
37
37
  "types": "./dist/jsx-dev-runtime.d.ts",
38
38
  "default": "./dist/jsx-dev-runtime.js"
39
+ },
40
+ "./vite": {
41
+ "types": "./dist/vite.d.ts",
42
+ "default": "./dist/vite.js"
39
43
  }
40
44
  },
41
45
  "engines": {
@@ -46,14 +50,23 @@
46
50
  },
47
51
  "scripts": {
48
52
  "build": "tsdown",
49
- "test": "tsc --noEmit && vitest run --coverage"
53
+ "typecheck": "tsc --noEmit --incremental",
54
+ "coverage": "vitest run --coverage",
55
+ "test": "bun run typecheck && bun run coverage"
50
56
  },
51
57
  "peerDependencies": {
52
- "@expressive/mvc": "^0.86.0"
58
+ "@expressive/mvc": "^0.88.0",
59
+ "vite": ">=5"
60
+ },
61
+ "peerDependenciesMeta": {
62
+ "vite": {
63
+ "optional": true
64
+ }
53
65
  },
54
66
  "devDependencies": {
55
67
  "@expressive/mvc": "workspace:^",
56
68
  "@types/node": "^25.2.0",
57
- "tsdown": "^0.20.1"
69
+ "tsdown": "^0.20.1",
70
+ "vite": "^7.3.1"
58
71
  }
59
72
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"chunk-vnode-DA7cLTKP.js","names":[],"sources":["../src/vnode.ts"],"sourcesContent":["import type { has, map } from '@expressive/mvc';\n\nconst VNODE = Symbol('@expressive/dom.vnode');\nconst PORTAL = Symbol('@expressive/dom.portal');\n\ntype Key = string | number | null | undefined;\ntype FunctionComponent<P = any> = (props: P) => Node;\ninterface ComponentInstance {\n readonly props: any;\n render(props?: any): Node;\n}\ntype ComponentType<P = any> = FunctionComponent<P> | (new (props: P) => ComponentInstance);\n\ntype Node =\n | VNode\n | ComponentInstance\n | string\n | number\n | bigint\n | boolean\n | null\n | undefined\n | readonly Node[]\n | has.List<Node>\n | has.Pool<Node, any, any>\n | map.Managed<unknown, Node>;\n\ninterface VNode<P = any> {\n readonly [VNODE]: true;\n readonly type: string | symbol | ComponentType<P>;\n readonly props: P & { children?: Node };\n readonly key?: Key;\n}\n\nfunction vnode<P>(type: VNode<P>['type'], props: P, key?: unknown): VNode<P> {\n return {\n [VNODE]: true,\n type,\n props: (props || {}) as VNode<P>['props'],\n key: key as Key\n };\n}\n\nfunction isVNode(value: unknown): value is VNode {\n return !!value && typeof value == 'object' && (value as VNode)[VNODE] === true;\n}\n\nfunction childrenOf(value: unknown): Node[] {\n const output: Node[] = [];\n\n function add(child: unknown) {\n if (Array.isArray(child)) child.forEach(add);\n else if (child !== null && child !== undefined && typeof child != 'boolean')\n output.push(child as Node);\n }\n\n add(value);\n return output;\n}\n\nfunction createPortal(children: Node, container: Element | DocumentFragment, key?: Key): VNode {\n return vnode(PORTAL, { children, container }, key);\n}\n\nexport {\n VNODE,\n PORTAL,\n childrenOf,\n createPortal,\n isVNode,\n vnode\n};\n\nexport type { ComponentInstance, ComponentType, FunctionComponent, Key, Node, VNode };\n"],"mappings":";AAEA,MAAM,QAAQ,OAAO,wBAAwB;AAC7C,MAAM,SAAS,OAAO,yBAAyB;AA+B/C,SAAS,MAAS,MAAwB,OAAU,KAAyB;AAC3E,QAAO;GACJ,QAAQ;EACT;EACA,OAAQ,SAAS,EAAE;EACd;EACN;;AAGH,SAAS,QAAQ,OAAgC;AAC/C,QAAO,CAAC,CAAC,SAAS,OAAO,SAAS,YAAa,MAAgB,WAAW;;AAG5E,SAAS,WAAW,OAAwB;CAC1C,MAAM,SAAiB,EAAE;CAEzB,SAAS,IAAI,OAAgB;AAC3B,MAAI,MAAM,QAAQ,MAAM,CAAE,OAAM,QAAQ,IAAI;WACnC,UAAU,QAAQ,UAAU,UAAa,OAAO,SAAS,UAChE,QAAO,KAAK,MAAc;;AAG9B,KAAI,MAAM;AACV,QAAO;;AAGT,SAAS,aAAa,UAAgB,WAAuC,KAAkB;AAC7F,QAAO,MAAM,QAAQ;EAAE;EAAU;EAAW,EAAE,IAAI"}
@@ -1,25 +0,0 @@
1
- import { has, map } from "@expressive/mvc";
2
-
3
- //#region src/vnode.d.ts
4
- declare const VNODE: unique symbol;
5
- type Key = string | number | null | undefined;
6
- type FunctionComponent<P = any> = (props: P) => Node;
7
- interface ComponentInstance {
8
- readonly props: any;
9
- render(props?: any): Node;
10
- }
11
- type ComponentType<P = any> = FunctionComponent<P> | (new (props: P) => ComponentInstance);
12
- type Node = VNode | ComponentInstance | string | number | bigint | boolean | null | undefined | readonly Node[] | has.List<Node> | has.Pool<Node, any, any> | map.Managed<unknown, Node>;
13
- interface VNode<P = any> {
14
- readonly [VNODE]: true;
15
- readonly type: string | symbol | ComponentType<P>;
16
- readonly props: P & {
17
- children?: Node;
18
- };
19
- readonly key?: Key;
20
- }
21
- declare function vnode<P>(type: VNode<P>['type'], props: P, key?: unknown): VNode<P>;
22
- declare function createPortal(children: Node, container: Element | DocumentFragment, key?: Key): VNode;
23
- //#endregion
24
- export { createPortal as a, VNode as i, FunctionComponent as n, vnode as o, Node as r, ComponentType as t };
25
- //# sourceMappingURL=chunk-vnode-DHwzzX6t.d.ts.map