@expressive/dom 0.2.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.
- package/README.md +1 -1
- package/dist/chunk-hot-BAqPvKEQ.js +331 -0
- package/dist/chunk-hot-BAqPvKEQ.js.map +1 -0
- package/dist/chunk-loader-kjuM318E.d.ts +58 -0
- package/dist/{chunk-vnode-CzmFSz5_.js → chunk-vnode-BG1Cv8F9.js} +11 -8
- package/dist/chunk-vnode-BG1Cv8F9.js.map +1 -0
- package/dist/index.d.ts +3 -31
- package/dist/index.js +178 -326
- package/dist/index.js.map +1 -1
- package/dist/jsx-dev-runtime.d.ts +2 -3
- package/dist/jsx-dev-runtime.js +3 -3
- package/dist/jsx-dev-runtime.js.map +1 -1
- package/dist/jsx-runtime.d.ts +44 -5
- package/dist/jsx-runtime.js +2 -2
- package/dist/jsx-runtime.js.map +1 -1
- package/dist/vite.js +43 -30
- package/dist/vite.js.map +1 -1
- package/package.json +5 -3
- package/dist/chunk-hot-gq8TyYJV.js +0 -178
- package/dist/chunk-hot-gq8TyYJV.js.map +0 -1
- package/dist/chunk-vnode-BsbDCqd1.d.ts +0 -25
- package/dist/chunk-vnode-CzmFSz5_.js.map +0 -1
package/dist/jsx-runtime.js.map
CHANGED
|
@@ -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 {
|
|
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.js
CHANGED
|
@@ -47,21 +47,8 @@ function scan(body) {
|
|
|
47
47
|
exports
|
|
48
48
|
};
|
|
49
49
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
* refresh. A State class it could not patch reloads the page; after an update,
|
|
53
|
-
* a changed component re-renders in place and any other changed export
|
|
54
|
-
* invalidates importers.
|
|
55
|
-
*/
|
|
56
|
-
function inject(id, body, ssr = false) {
|
|
57
|
-
const { classes, hidden, components, exports } = scan(body);
|
|
58
|
-
if (!classes.length && !components.length) return "";
|
|
59
|
-
const list = classes.join(", ");
|
|
60
|
-
const record = Object.entries(exports).map(([name, local]) => `${JSON.stringify(name)}: ${local}`);
|
|
61
|
-
const refresh = Object.keys(exports).filter((name) => components.includes(exports[name]));
|
|
62
|
-
const effect = ssr ? "replace it instead of patching" : "will trigger a full reload";
|
|
63
|
-
const notes = hidden.map((name) => `${JSON.stringify(name)}: ${JSON.stringify(`[expressive] ${name} (${id}) declares #private members, so edits to its module ${effect}. Use _ properties instead to keep HMR.`)}`);
|
|
64
|
-
const replace = ssr ? ` const __notes = { ${notes.join(", ")} };
|
|
50
|
+
const server = (notes, list) => `\
|
|
51
|
+
const __notes = ${JSON.stringify(notes)};
|
|
65
52
|
const __before = import.meta.hot.data.expressive;
|
|
66
53
|
const __classes = (import.meta.hot.data.expressive = { ${list} });
|
|
67
54
|
const __warned = (import.meta.hot.data.warned ||= {});
|
|
@@ -69,9 +56,10 @@ function inject(id, body, ssr = false) {
|
|
|
69
56
|
if (__before && __classes[key] !== __before[key] && !__warned[key]) {
|
|
70
57
|
__warned[key] = true;
|
|
71
58
|
console.warn(__notes[key]);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const
|
|
59
|
+
}`;
|
|
60
|
+
const browser = (id, notes, list) => `\
|
|
61
|
+
const __notes = ${JSON.stringify(notes)};
|
|
62
|
+
const __flag = (key) => 'expressive:private:' + ${id} + ':' + key;
|
|
75
63
|
for (const key in __notes)
|
|
76
64
|
try {
|
|
77
65
|
if (sessionStorage.getItem(__flag(key)) == 'due') {
|
|
@@ -90,16 +78,19 @@ function inject(id, body, ssr = false) {
|
|
|
90
78
|
} catch {
|
|
91
79
|
console.warn(note);
|
|
92
80
|
}
|
|
93
|
-
dispatchEvent(new CustomEvent('expressive:reload', { detail: { module: ${
|
|
81
|
+
dispatchEvent(new CustomEvent('expressive:reload', { detail: { module: ${id}, class: key, reason: note ? 'private members' : 'class changed shape' } }));
|
|
94
82
|
location.reload();
|
|
95
83
|
break;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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} };
|
|
103
94
|
import.meta.hot.accept((next) => {
|
|
104
95
|
if (!next) return;
|
|
105
96
|
for (const key in __exports) {
|
|
@@ -108,9 +99,31 @@ ${replace} const __exports = { ${record.join(", ")} };
|
|
|
108
99
|
return import.meta.hot.invalidate(\`"\${key}" export cannot be hot-patched.\`);
|
|
109
100
|
}
|
|
110
101
|
});
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
|
|
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`;
|
|
114
127
|
}
|
|
115
128
|
/** Hot-patch classes and refresh function components in place during `vite` dev. */
|
|
116
129
|
function expressive() {
|
|
@@ -126,7 +139,7 @@ function expressive() {
|
|
|
126
139
|
async transform(code, id, options) {
|
|
127
140
|
const [file] = id.split("?");
|
|
128
141
|
if (!SOURCE.test(file) || file.includes("/node_modules/")) return;
|
|
129
|
-
runtime ||= Promise.all(["@expressive/mvc/
|
|
142
|
+
runtime ||= Promise.all(["@expressive/mvc/hot", "@expressive/dom/jsx-dev-runtime"].map((entry) => this.resolve(entry).then((found) => found && dirname(found.id))));
|
|
130
143
|
for (const own of await runtime) if (own && file.startsWith(own)) return;
|
|
131
144
|
const output = inject(file.startsWith(root + "/") ? file.slice(root.length) : file, this.parse(code).body, options?.ssr);
|
|
132
145
|
if (output) return {
|
package/dist/vite.js.map
CHANGED
|
@@ -1 +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\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 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 = hidden.map(\n (name) =>\n `${JSON.stringify(name)}: ${JSON.stringify(`[expressive] ${name} (${id}) declares #private members, so edits to its module ${effect}. Use _ properties instead to keep HMR.`)}`\n );\n const replace = ssr\n ? ` const __notes = { ${notes.join(', ')} };\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`\n : ` const __notes = { ${notes.join(', ')} };\n const __flag = (key) => 'expressive:private:' + ${JSON.stringify(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: ${JSON.stringify(id)}, class: key, reason: note ? 'private members' : 'class changed shape' } }));\n location.reload();\n break;\n }\n`;\n const lines = ['', `import { State as __State } from '@expressive/mvc';`];\n\n if (classes.length)\n lines.push(\n `import { hot as __expressive } from '@expressive/mvc/runtime';`,\n '{',\n ` const __hot = __expressive.accept(${JSON.stringify(id)}, { ${list} });`,\n ...classes.map((name) => ` ${name} = __hot.${name};`),\n '}'\n );\n\n if (components.length)\n lines.push(\n `import { hot as __refresh } from '@expressive/dom/jsx-dev-runtime';`,\n `__refresh(${JSON.stringify(id)}, { ${components.join(', ')} });`\n );\n\n lines.push(`if (import.meta.hot) {\n${replace} const __exports = { ${record.join(', ')} };\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 return lines.join('\\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/runtime', '@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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"}
|
|
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.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "MVC-native DOM renderer.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -50,10 +50,12 @@
|
|
|
50
50
|
},
|
|
51
51
|
"scripts": {
|
|
52
52
|
"build": "tsdown",
|
|
53
|
-
"
|
|
53
|
+
"typecheck": "tsc --noEmit --incremental",
|
|
54
|
+
"coverage": "vitest run --coverage",
|
|
55
|
+
"test": "bun run typecheck && bun run coverage"
|
|
54
56
|
},
|
|
55
57
|
"peerDependencies": {
|
|
56
|
-
"@expressive/mvc": "^0.
|
|
58
|
+
"@expressive/mvc": "^0.88.0",
|
|
57
59
|
"vite": ">=5"
|
|
58
60
|
},
|
|
59
61
|
"peerDependenciesMeta": {
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import { pending } from "@expressive/mvc";
|
|
2
|
-
|
|
3
|
-
//#region src/scheduler.ts
|
|
4
|
-
const urgent = /* @__PURE__ */ new Set();
|
|
5
|
-
const passive = /* @__PURE__ */ new Set();
|
|
6
|
-
const after = [];
|
|
7
|
-
let depth = 0;
|
|
8
|
-
let urgentQueued = false;
|
|
9
|
-
let passiveQueued = false;
|
|
10
|
-
function flush(scopes) {
|
|
11
|
-
for (const scope of scopes) {
|
|
12
|
-
scopes.delete(scope);
|
|
13
|
-
scope.queued = void 0;
|
|
14
|
-
let waiting = void 0;
|
|
15
|
-
try {
|
|
16
|
-
waiting = scope.update(false);
|
|
17
|
-
} catch (error) {
|
|
18
|
-
console.error(error);
|
|
19
|
-
}
|
|
20
|
-
settle(scope);
|
|
21
|
-
if (!waiting) unblock(scope);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
function flushUrgent() {
|
|
25
|
-
urgentQueued = false;
|
|
26
|
-
flush(urgent);
|
|
27
|
-
for (const run of after.splice(0)) run();
|
|
28
|
-
}
|
|
29
|
-
function afterFlush(run) {
|
|
30
|
-
after.push(run);
|
|
31
|
-
if (!urgentQueued) {
|
|
32
|
-
urgentQueued = true;
|
|
33
|
-
queueMicrotask(flushUrgent);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
function flushPassive() {
|
|
37
|
-
passiveQueued = false;
|
|
38
|
-
const batch = [...passive].filter((scope) => scope.queued === "passive");
|
|
39
|
-
passive.clear();
|
|
40
|
-
for (const scope of batch) {
|
|
41
|
-
const waiting = scope.probe?.();
|
|
42
|
-
if (waiting) return defer(batch, waiting, scope);
|
|
43
|
-
}
|
|
44
|
-
batch.sort((a, b) => Number(!!b.empty?.()) - Number(!!a.empty?.()));
|
|
45
|
-
for (let index = 0; index < batch.length; index++) {
|
|
46
|
-
const scope = batch[index];
|
|
47
|
-
if (scope.queued !== "passive") continue;
|
|
48
|
-
scope.queued = void 0;
|
|
49
|
-
let waiting = void 0;
|
|
50
|
-
try {
|
|
51
|
-
waiting = scope.update(true);
|
|
52
|
-
} catch (error) {
|
|
53
|
-
console.error(error);
|
|
54
|
-
}
|
|
55
|
-
settle(scope);
|
|
56
|
-
if (waiting) return defer(batch.slice(index + 1), waiting, scope);
|
|
57
|
-
unblock(scope);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
function defer(scopes, waiting, source) {
|
|
61
|
-
const held = scopes.filter((scope) => scope.queued === "passive");
|
|
62
|
-
for (const scope of held) {
|
|
63
|
-
scope.queued = "deferred";
|
|
64
|
-
scope.probed = void 0;
|
|
65
|
-
}
|
|
66
|
-
const resume = () => {
|
|
67
|
-
for (const scope of held) if (scope.queued === "deferred") {
|
|
68
|
-
scope.queued = void 0;
|
|
69
|
-
transition(() => schedule(scope));
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
(source.blocking ||= []).push(resume);
|
|
73
|
-
waiting.then(resume, resume);
|
|
74
|
-
}
|
|
75
|
-
function unblock(scope) {
|
|
76
|
-
const { blocking } = scope;
|
|
77
|
-
scope.blocking = void 0;
|
|
78
|
-
blocking?.forEach((resume) => resume());
|
|
79
|
-
}
|
|
80
|
-
function release(holds) {
|
|
81
|
-
holds?.forEach((held) => held());
|
|
82
|
-
}
|
|
83
|
-
function settle(scope) {
|
|
84
|
-
const { holds } = scope;
|
|
85
|
-
scope.holds = void 0;
|
|
86
|
-
release(holds);
|
|
87
|
-
}
|
|
88
|
-
function schedule(scope) {
|
|
89
|
-
const held = pending();
|
|
90
|
-
if (held) (scope.holds ||= []).push(held);
|
|
91
|
-
scope.probed = void 0;
|
|
92
|
-
if (!depth) {
|
|
93
|
-
passive.delete(scope);
|
|
94
|
-
scope.queued = "urgent";
|
|
95
|
-
urgent.add(scope);
|
|
96
|
-
if (!urgentQueued) {
|
|
97
|
-
urgentQueued = true;
|
|
98
|
-
queueMicrotask(flushUrgent);
|
|
99
|
-
}
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
if (scope.queued && scope.queued !== "deferred") return;
|
|
103
|
-
scope.queued = "passive";
|
|
104
|
-
passive.add(scope);
|
|
105
|
-
if (!passiveQueued) {
|
|
106
|
-
passiveQueued = true;
|
|
107
|
-
setTimeout(flushPassive);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
function transition(work) {
|
|
111
|
-
depth++;
|
|
112
|
-
try {
|
|
113
|
-
work();
|
|
114
|
-
} finally {
|
|
115
|
-
depth--;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
function claim(scope) {
|
|
119
|
-
urgent.delete(scope);
|
|
120
|
-
passive.delete(scope);
|
|
121
|
-
scope.queued = void 0;
|
|
122
|
-
scope.probed = void 0;
|
|
123
|
-
}
|
|
124
|
-
function unschedule(scope) {
|
|
125
|
-
urgent.delete(scope);
|
|
126
|
-
passive.delete(scope);
|
|
127
|
-
scope.queued = void 0;
|
|
128
|
-
scope.probed = void 0;
|
|
129
|
-
settle(scope);
|
|
130
|
-
unblock(scope);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
//#endregion
|
|
134
|
-
//#region src/hot.ts
|
|
135
|
-
const FAMILIES = /* @__PURE__ */ new Map();
|
|
136
|
-
const FAMILY = /* @__PURE__ */ new WeakMap();
|
|
137
|
-
/** The latest implementation of a component registered for hot refresh. */
|
|
138
|
-
function latest(type) {
|
|
139
|
-
return FAMILY.get(type)?.current || type;
|
|
140
|
-
}
|
|
141
|
-
/** Whether two element types are one component, across hot edits. */
|
|
142
|
-
function same(a, b) {
|
|
143
|
-
if (a === b) return true;
|
|
144
|
-
const family = typeof a == "function" && FAMILY.get(a);
|
|
145
|
-
return !!family && family === FAMILY.get(b);
|
|
146
|
-
}
|
|
147
|
-
function track(type, scope) {
|
|
148
|
-
FAMILY.get(type)?.scopes.add(scope);
|
|
149
|
-
}
|
|
150
|
-
function untrack(type, scope) {
|
|
151
|
-
FAMILY.get(type)?.scopes.delete(scope);
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Register a module's function components under stable ids. A component seen
|
|
155
|
-
* before takes its new implementation and re-renders where it is mounted.
|
|
156
|
-
*/
|
|
157
|
-
function hot(id, components) {
|
|
158
|
-
for (const [name, type] of Object.entries(components)) {
|
|
159
|
-
if (typeof type != "function") continue;
|
|
160
|
-
const key = `${id}#${name}`;
|
|
161
|
-
let family = FAMILIES.get(key);
|
|
162
|
-
if (!family) FAMILIES.set(key, family = {
|
|
163
|
-
current: type,
|
|
164
|
-
scopes: /* @__PURE__ */ new Set()
|
|
165
|
-
});
|
|
166
|
-
FAMILY.set(type, family);
|
|
167
|
-
if (family.current === type) continue;
|
|
168
|
-
family.current = type;
|
|
169
|
-
for (const scope of family.scopes) {
|
|
170
|
-
scope.hot = true;
|
|
171
|
-
schedule(scope);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
//#endregion
|
|
177
|
-
export { untrack as a, release as c, transition as d, unschedule as f, track as i, schedule as l, latest as n, afterFlush as o, same as r, claim as s, hot as t, settle as u };
|
|
178
|
-
//# sourceMappingURL=chunk-hot-gq8TyYJV.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-hot-gq8TyYJV.js","names":[],"sources":["../src/scheduler.ts","../src/hot.ts"],"sourcesContent":["import { pending } from '@expressive/mvc';\n\ninterface Schedulable {\n queued?: 'urgent' | 'passive' | 'deferred';\n holds?: (() => void)[];\n probed?: { output: unknown };\n blocking?: (() => void)[];\n update(passive: boolean): PromiseLike<unknown> | void;\n probe?(): PromiseLike<unknown> | void;\n empty?(): boolean;\n}\n\nconst urgent = new Set<Schedulable>();\nconst passive = new Set<Schedulable>();\nconst after: (() => void)[] = [];\n\nlet depth = 0;\nlet urgentQueued = false;\nlet passiveQueued = false;\n\nfunction flush(scopes: Set<Schedulable>) {\n for (const scope of scopes) {\n scopes.delete(scope);\n scope.queued = undefined;\n\n let waiting: PromiseLike<unknown> | void = undefined;\n\n try {\n waiting = scope.update(false);\n } catch (error) {\n console.error(error);\n }\n\n settle(scope);\n if (!waiting) unblock(scope);\n }\n}\n\nfunction flushUrgent() {\n urgentQueued = false;\n flush(urgent);\n\n for (const run of after.splice(0)) run();\n}\n\nfunction afterFlush(run: () => void) {\n after.push(run);\n\n if (!urgentQueued) {\n urgentQueued = true;\n queueMicrotask(flushUrgent);\n }\n}\n\nfunction flushPassive() {\n passiveQueued = false;\n\n const batch = [...passive].filter((scope) => scope.queued === 'passive');\n passive.clear();\n\n for (const scope of batch) {\n const waiting = scope.probe?.();\n if (waiting) return defer(batch, waiting, scope);\n }\n\n batch.sort((a, b) => Number(!!b.empty?.()) - Number(!!a.empty?.()));\n\n for (let index = 0; index < batch.length; index++) {\n const scope = batch[index];\n\n if (scope.queued !== 'passive') continue;\n\n scope.queued = undefined;\n\n let waiting: PromiseLike<unknown> | void = undefined;\n\n try {\n waiting = scope.update(true);\n } catch (error) {\n console.error(error);\n }\n\n settle(scope);\n\n if (waiting) return defer(batch.slice(index + 1), waiting, scope);\n unblock(scope);\n }\n}\n\nfunction defer(scopes: Schedulable[], waiting: PromiseLike<unknown>, source: Schedulable) {\n const held = scopes.filter((scope) => scope.queued === 'passive');\n\n for (const scope of held) {\n scope.queued = 'deferred';\n scope.probed = undefined;\n }\n\n const resume = () => {\n for (const scope of held)\n if (scope.queued === 'deferred') {\n scope.queued = undefined;\n transition(() => schedule(scope));\n }\n };\n\n (source.blocking ||= []).push(resume);\n waiting.then(resume, resume);\n}\n\nfunction unblock(scope: Schedulable) {\n const { blocking } = scope;\n\n scope.blocking = undefined;\n blocking?.forEach((resume) => resume());\n}\n\nfunction release(holds?: (() => void)[]) {\n holds?.forEach((held) => held());\n}\n\nfunction settle(scope: Schedulable) {\n const { holds } = scope;\n\n scope.holds = undefined;\n release(holds);\n}\n\nfunction schedule(scope: Schedulable) {\n const held = pending();\n\n if (held) (scope.holds ||= []).push(held);\n scope.probed = undefined;\n\n if (!depth) {\n passive.delete(scope);\n scope.queued = 'urgent';\n urgent.add(scope);\n\n if (!urgentQueued) {\n urgentQueued = true;\n queueMicrotask(flushUrgent);\n }\n\n return;\n }\n\n if (scope.queued && scope.queued !== 'deferred') return;\n\n scope.queued = 'passive';\n passive.add(scope);\n\n if (!passiveQueued) {\n passiveQueued = true;\n setTimeout(flushPassive);\n }\n}\n\nfunction transition(work: () => void) {\n depth++;\n\n try {\n work();\n } finally {\n depth--;\n }\n}\n\nfunction claim(scope: Schedulable) {\n urgent.delete(scope);\n passive.delete(scope);\n scope.queued = undefined;\n scope.probed = undefined;\n}\n\nfunction unschedule(scope: Schedulable) {\n urgent.delete(scope);\n passive.delete(scope);\n scope.queued = undefined;\n scope.probed = undefined;\n settle(scope);\n unblock(scope);\n}\n\nexport { afterFlush, claim, release, schedule, settle, transition, unschedule };\nexport type { Schedulable };\n","import type { Scope } from './adapter';\nimport { schedule } from './scheduler';\n\ninterface Family {\n current: Function;\n scopes: Set<Scope>;\n}\n\nconst FAMILIES = new Map<string, Family>();\nconst FAMILY = new WeakMap<Function, Family>();\n\n/** The latest implementation of a component registered for hot refresh. */\nfunction latest(type: Function) {\n return FAMILY.get(type)?.current || type;\n}\n\n/** Whether two element types are one component, across hot edits. */\nfunction same(a: unknown, b: unknown) {\n if (a === b) return true;\n\n const family = typeof a == 'function' && FAMILY.get(a);\n\n return !!family && family === FAMILY.get(b as Function);\n}\n\nfunction track(type: Function, scope: Scope) {\n FAMILY.get(type)?.scopes.add(scope);\n}\n\nfunction untrack(type: Function, scope: Scope) {\n FAMILY.get(type)?.scopes.delete(scope);\n}\n\n/**\n * Register a module's function components under stable ids. A component seen\n * before takes its new implementation and re-renders where it is mounted.\n */\nfunction hot(id: string, components: Record<string, unknown>) {\n for (const [name, type] of Object.entries(components)) {\n if (typeof type != 'function') continue;\n\n const key = `${id}#${name}`;\n let family = FAMILIES.get(key);\n\n if (!family) FAMILIES.set(key, (family = { current: type, scopes: new Set() }));\n\n FAMILY.set(type, family);\n\n if (family.current === type) continue;\n\n family.current = type;\n\n for (const scope of family.scopes) {\n scope.hot = true;\n schedule(scope);\n }\n }\n}\n\nexport { hot, latest, same, track, untrack };\n"],"mappings":"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"}
|
|
@@ -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-BsbDCqd1.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-vnode-CzmFSz5_.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"}
|