@oddsquad/vite-plugin-lit 0.2.3 → 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.
Files changed (210) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/LICENSE +28 -0
  3. package/README.md +153 -0
  4. package/bin.mjs +154 -0
  5. package/client.d.ts +61 -0
  6. package/dist/client/assets/browser-agent-rpc-BXhoSh1z-BvWe4sTJ.js +69 -0
  7. package/dist/client/assets/browser-agent-rpc-BXhoSh1z-BvWe4sTJ.js.map +1 -0
  8. package/dist/client/assets/index-CFrVgNfS.js +9740 -0
  9. package/dist/client/assets/index-CFrVgNfS.js.map +1 -0
  10. package/{panel → dist/client}/index.html +1 -0
  11. package/index.d.ts.map +1 -1
  12. package/index.js +2 -2
  13. package/index.js.map +1 -1
  14. package/lib/color-scheme.d.ts.map +1 -1
  15. package/lib/color-scheme.js +17 -21
  16. package/lib/color-scheme.js.map +1 -1
  17. package/lib/devframe/definition.d.ts +45 -0
  18. package/lib/devframe/definition.d.ts.map +1 -0
  19. package/lib/devframe/definition.js +547 -0
  20. package/lib/devframe/definition.js.map +1 -0
  21. package/lib/devframe/icon.d.ts +8 -0
  22. package/lib/devframe/icon.d.ts.map +1 -0
  23. package/lib/devframe/icon.js +21 -0
  24. package/lib/devframe/icon.js.map +1 -0
  25. package/lib/devframe/paths.d.ts +12 -0
  26. package/lib/devframe/paths.d.ts.map +1 -0
  27. package/lib/devframe/paths.js +38 -0
  28. package/lib/devframe/paths.js.map +1 -0
  29. package/lib/devframe/protocol.d.ts +218 -0
  30. package/lib/devframe/protocol.d.ts.map +1 -0
  31. package/lib/devframe/protocol.js +76 -0
  32. package/lib/devframe/protocol.js.map +1 -0
  33. package/lib/devframe/source.d.ts +49 -0
  34. package/lib/devframe/source.d.ts.map +1 -0
  35. package/lib/devframe/source.js +23 -0
  36. package/lib/devframe/source.js.map +1 -0
  37. package/lib/devframe/vite.d.ts +116 -0
  38. package/lib/devframe/vite.d.ts.map +1 -0
  39. package/lib/devframe/vite.js +291 -0
  40. package/lib/devframe/vite.js.map +1 -0
  41. package/lib/http.d.ts +29 -0
  42. package/lib/http.d.ts.map +1 -0
  43. package/lib/http.js +35 -0
  44. package/lib/http.js.map +1 -0
  45. package/lib/icons.d.ts +2 -0
  46. package/lib/icons.d.ts.map +1 -1
  47. package/lib/icons.js +10 -4
  48. package/lib/icons.js.map +1 -1
  49. package/lib/plugin.d.ts +15 -4
  50. package/lib/plugin.d.ts.map +1 -1
  51. package/lib/plugin.js +640 -574
  52. package/lib/plugin.js.map +1 -1
  53. package/lib/runtime/css.d.ts +2 -2
  54. package/lib/runtime/css.d.ts.map +1 -1
  55. package/lib/runtime/css.js +34 -34
  56. package/lib/runtime/css.js.map +1 -1
  57. package/lib/runtime/edge-panel.d.ts.map +1 -1
  58. package/lib/runtime/edge-panel.js +82 -91
  59. package/lib/runtime/edge-panel.js.map +1 -1
  60. package/lib/runtime/fonts.d.ts.map +1 -1
  61. package/lib/runtime/fonts.js +1 -1
  62. package/lib/runtime/fonts.js.map +1 -1
  63. package/lib/runtime/indicator.d.ts.map +1 -1
  64. package/lib/runtime/indicator.js +71 -74
  65. package/lib/runtime/indicator.js.map +1 -1
  66. package/lib/runtime/inspector/collect.d.ts.map +1 -1
  67. package/lib/runtime/inspector/collect.js +83 -90
  68. package/lib/runtime/inspector/collect.js.map +1 -1
  69. package/lib/runtime/inspector/highlight.d.ts +16 -0
  70. package/lib/runtime/inspector/highlight.d.ts.map +1 -0
  71. package/lib/runtime/inspector/highlight.js +66 -0
  72. package/lib/runtime/inspector/highlight.js.map +1 -0
  73. package/lib/runtime/inspector/install.d.ts.map +1 -1
  74. package/lib/runtime/inspector/install.js +180 -205
  75. package/lib/runtime/inspector/install.js.map +1 -1
  76. package/lib/runtime/inspector/serialize.d.ts.map +1 -1
  77. package/lib/runtime/inspector/serialize.js +86 -107
  78. package/lib/runtime/inspector/serialize.js.map +1 -1
  79. package/lib/runtime/intern.d.ts.map +1 -1
  80. package/lib/runtime/intern.js +31 -29
  81. package/lib/runtime/intern.js.map +1 -1
  82. package/lib/runtime/overrides.d.ts.map +1 -1
  83. package/lib/runtime/overrides.js +14 -13
  84. package/lib/runtime/overrides.js.map +1 -1
  85. package/lib/runtime/patch.d.ts +8 -0
  86. package/lib/runtime/patch.d.ts.map +1 -1
  87. package/lib/runtime/patch.js +321 -282
  88. package/lib/runtime/patch.js.map +1 -1
  89. package/lib/runtime/source-meta.d.ts.map +1 -1
  90. package/lib/runtime/source-meta.js +1 -1
  91. package/lib/runtime/source-meta.js.map +1 -1
  92. package/lib/runtime/source-overlay/editors.d.ts.map +1 -1
  93. package/lib/runtime/source-overlay/editors.js +27 -27
  94. package/lib/runtime/source-overlay/editors.js.map +1 -1
  95. package/lib/runtime/source-overlay/mask-path.d.ts.map +1 -1
  96. package/lib/runtime/source-overlay/mask-path.js +15 -15
  97. package/lib/runtime/source-overlay/mask-path.js.map +1 -1
  98. package/lib/runtime/source-overlay/overlay-element.d.ts.map +1 -1
  99. package/lib/runtime/source-overlay/overlay-element.js +347 -356
  100. package/lib/runtime/source-overlay/overlay-element.js.map +1 -1
  101. package/lib/runtime/source-overlay/source-host.d.ts.map +1 -1
  102. package/lib/runtime/source-overlay/source-host.js +64 -71
  103. package/lib/runtime/source-overlay/source-host.js.map +1 -1
  104. package/lib/runtime/source-overlay/template.d.ts.map +1 -1
  105. package/lib/runtime/source-overlay/template.js +3 -3
  106. package/lib/runtime/source-overlay/template.js.map +1 -1
  107. package/lib/runtime/source-overlay.d.ts.map +1 -1
  108. package/lib/runtime/source-overlay.js +5 -2
  109. package/lib/runtime/source-overlay.js.map +1 -1
  110. package/lib/runtime/timeline/clock.d.ts.map +1 -1
  111. package/lib/runtime/timeline/clock.js +2 -2
  112. package/lib/runtime/timeline/clock.js.map +1 -1
  113. package/lib/runtime/timeline/flash.d.ts +39 -0
  114. package/lib/runtime/timeline/flash.d.ts.map +1 -0
  115. package/lib/runtime/timeline/flash.js +169 -0
  116. package/lib/runtime/timeline/flash.js.map +1 -0
  117. package/lib/runtime/timeline/identity.d.ts.map +1 -1
  118. package/lib/runtime/timeline/identity.js +27 -27
  119. package/lib/runtime/timeline/identity.js.map +1 -1
  120. package/lib/runtime/timeline/input.d.ts.map +1 -1
  121. package/lib/runtime/timeline/input.js +54 -67
  122. package/lib/runtime/timeline/input.js.map +1 -1
  123. package/lib/runtime/timeline/install.d.ts.map +1 -1
  124. package/lib/runtime/timeline/install.js +38 -29
  125. package/lib/runtime/timeline/install.js.map +1 -1
  126. package/lib/runtime/timeline/lifecycle.d.ts +8 -0
  127. package/lib/runtime/timeline/lifecycle.d.ts.map +1 -1
  128. package/lib/runtime/timeline/lifecycle.js +149 -133
  129. package/lib/runtime/timeline/lifecycle.js.map +1 -1
  130. package/lib/runtime/timeline/public-api.d.ts.map +1 -1
  131. package/lib/runtime/timeline/public-api.js +9 -9
  132. package/lib/runtime/timeline/public-api.js.map +1 -1
  133. package/lib/runtime/timeline/render.d.ts.map +1 -1
  134. package/lib/runtime/timeline/render.js +70 -75
  135. package/lib/runtime/timeline/render.js.map +1 -1
  136. package/lib/runtime/timeline/transport.d.ts.map +1 -1
  137. package/lib/runtime/timeline/transport.js +39 -43
  138. package/lib/runtime/timeline/transport.js.map +1 -1
  139. package/lib/segmented-tabs.d.ts +3 -1
  140. package/lib/segmented-tabs.d.ts.map +1 -1
  141. package/lib/segmented-tabs.js +136 -107
  142. package/lib/segmented-tabs.js.map +1 -1
  143. package/lib/snapshot.d.ts +28 -0
  144. package/lib/snapshot.d.ts.map +1 -0
  145. package/lib/snapshot.js +57 -0
  146. package/lib/snapshot.js.map +1 -0
  147. package/lib/source-meta.d.ts.map +1 -1
  148. package/lib/source-meta.js +176 -162
  149. package/lib/source-meta.js.map +1 -1
  150. package/lib/timeline/derive.d.ts +152 -0
  151. package/lib/timeline/derive.d.ts.map +1 -0
  152. package/lib/timeline/derive.js +242 -0
  153. package/lib/timeline/derive.js.map +1 -0
  154. package/lib/timeline-plugin.d.ts.map +1 -1
  155. package/lib/timeline-plugin.js +304 -321
  156. package/lib/timeline-plugin.js.map +1 -1
  157. package/lib/tokens.d.ts.map +1 -1
  158. package/lib/tokens.js +17 -18
  159. package/lib/tokens.js.map +1 -1
  160. package/lib/transform.d.ts.map +1 -1
  161. package/lib/transform.js +62 -57
  162. package/lib/transform.js.map +1 -1
  163. package/lib/types.d.ts.map +1 -1
  164. package/lib/types.js +1 -1
  165. package/lib/types.js.map +1 -1
  166. package/lib/wrap-table.d.ts.map +1 -1
  167. package/lib/wrap-table.js +19 -17
  168. package/lib/wrap-table.js.map +1 -1
  169. package/package.json +77 -13
  170. package/types/hmr-incompatibility.d.ts +59 -0
  171. package/types/hmr-incompatibility.d.ts.map +1 -0
  172. package/types/hmr-incompatibility.js +30 -0
  173. package/types/hmr-incompatibility.js.map +1 -0
  174. package/types/in-page.d.ts +49 -0
  175. package/types/in-page.d.ts.map +1 -0
  176. package/types/in-page.js +33 -0
  177. package/types/in-page.js.map +1 -0
  178. package/types/inspector.d.ts.map +1 -1
  179. package/types/inspector.js.map +1 -1
  180. package/types/snapshot.d.ts +44 -0
  181. package/types/snapshot.d.ts.map +1 -0
  182. package/types/snapshot.js +7 -0
  183. package/types/snapshot.js.map +1 -0
  184. package/types/timeline.d.ts +11 -0
  185. package/types/timeline.d.ts.map +1 -1
  186. package/types/timeline.js.map +1 -1
  187. package/panel/components-view.d.ts +0 -60
  188. package/panel/components-view.d.ts.map +0 -1
  189. package/panel/components-view.js +0 -587
  190. package/panel/components-view.js.map +0 -1
  191. package/panel/devtools-settings.d.ts +0 -41
  192. package/panel/devtools-settings.d.ts.map +0 -1
  193. package/panel/devtools-settings.js +0 -463
  194. package/panel/devtools-settings.js.map +0 -1
  195. package/panel/lit-devtools-panel.d.ts +0 -37
  196. package/panel/lit-devtools-panel.d.ts.map +0 -1
  197. package/panel/lit-devtools-panel.js +0 -185
  198. package/panel/lit-devtools-panel.js.map +0 -1
  199. package/panel/timeline-event-list.d.ts +0 -43
  200. package/panel/timeline-event-list.d.ts.map +0 -1
  201. package/panel/timeline-event-list.js +0 -416
  202. package/panel/timeline-event-list.js.map +0 -1
  203. package/panel/timeline-layers.d.ts +0 -25
  204. package/panel/timeline-layers.d.ts.map +0 -1
  205. package/panel/timeline-layers.js +0 -96
  206. package/panel/timeline-layers.js.map +0 -1
  207. package/panel/timeline-view.d.ts +0 -38
  208. package/panel/timeline-view.d.ts.map +0 -1
  209. package/panel/timeline-view.js +0 -234
  210. package/panel/timeline-view.js.map +0 -1
@@ -18,7 +18,11 @@
18
18
  * it never imports lit (keeps it version-agnostic and safe for non-Lit
19
19
  * custom elements, which get prototype/static patching only).
20
20
  */
21
- import { subscribeOverride } from './overrides.js';
21
+ import {subscribeOverride} from './overrides.js';
22
+ import {
23
+ HMR_INCOMPATIBLE_CHANNEL,
24
+ describeHmrReason,
25
+ } from '../../types/hmr-incompatibility.js';
22
26
  // Exactly one patch state per page, even if this module loads twice.
23
27
  const STATE_KEY = Symbol.for('@lit-labs/vite-plugin-lit#patch');
24
28
  // Brands our lifecycle wrappers so re-instrumentation is idempotent.
@@ -26,8 +30,8 @@ const RECORD_BRAND = Symbol.for('@lit-labs/vite-plugin-lit#wrapperRecord');
26
30
  const PROTO_SKIP = ['constructor'];
27
31
  const STATIC_SKIP = ['prototype', 'name', 'length'];
28
32
  const ownKeys = (o) => [
29
- ...Object.getOwnPropertyNames(o),
30
- ...Object.getOwnPropertySymbols(o),
33
+ ...Object.getOwnPropertyNames(o),
34
+ ...Object.getOwnPropertySymbols(o),
31
35
  ];
32
36
  /**
33
37
  * Syncs own members `source` → `target`: deletes own keys of `target` that
@@ -36,30 +40,32 @@ const ownKeys = (o) => [
36
40
  */
37
41
  // Exported for unit testing; otherwise module-internal.
38
42
  export const syncOwnMembers = (target, source, skip) => {
39
- for (const key of ownKeys(target)) {
40
- if (skip.includes(key)) {
41
- continue;
42
- }
43
- if (Object.getOwnPropertyDescriptor(source, key) === undefined) {
44
- try {
45
- delete target[key];
46
- }
47
- catch {
48
- // Non-configurable; leave it.
49
- }
50
- }
43
+ for (const key of ownKeys(target)) {
44
+ if (skip.includes(key)) {
45
+ continue;
51
46
  }
52
- for (const key of ownKeys(source)) {
53
- if (skip.includes(key)) {
54
- continue;
55
- }
56
- try {
57
- Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
58
- }
59
- catch {
60
- // Non-configurable; leave it.
61
- }
47
+ if (Object.getOwnPropertyDescriptor(source, key) === undefined) {
48
+ try {
49
+ delete target[key];
50
+ } catch {
51
+ // Non-configurable; leave it.
52
+ }
53
+ }
54
+ }
55
+ for (const key of ownKeys(source)) {
56
+ if (skip.includes(key)) {
57
+ continue;
62
58
  }
59
+ try {
60
+ Object.defineProperty(
61
+ target,
62
+ key,
63
+ Object.getOwnPropertyDescriptor(source, key)
64
+ );
65
+ } catch {
66
+ // Non-configurable; leave it.
67
+ }
68
+ }
63
69
  };
64
70
  /**
65
71
  * Defines branded `connectedCallback`/`disconnectedCallback` wrappers on the
@@ -68,44 +74,41 @@ export const syncOwnMembers = (target, source, skip) => {
68
74
  * deletes the wrappers).
69
75
  */
70
76
  const instrument = (state, proto, record) => {
71
- for (const name of [
72
- 'connectedCallback',
73
- 'disconnectedCallback',
74
- ]) {
75
- const own = Object.getOwnPropertyDescriptor(proto, name);
76
- if (own?.value?.[RECORD_BRAND] === record) {
77
- continue;
78
- }
79
- // May be an own raw function (just copied from the new class), an
80
- // inherited base implementation, or absent entirely.
81
- const original = proto[name];
82
- const wrapper = name === 'connectedCallback'
83
- ? function () {
84
- record.instances.add(this);
85
- const stamp = state.generationOf.get(this);
86
- if (stamp !== undefined && stamp !== record.generation) {
87
- // Was detached during one or more patches; catch up.
88
- this.requestUpdate?.();
89
- }
90
- state.generationOf.set(this, record.generation);
91
- original?.call(this);
77
+ for (const name of ['connectedCallback', 'disconnectedCallback']) {
78
+ const own = Object.getOwnPropertyDescriptor(proto, name);
79
+ if (own?.value?.[RECORD_BRAND] === record) {
80
+ continue;
81
+ }
82
+ // May be an own raw function (just copied from the new class), an
83
+ // inherited base implementation, or absent entirely.
84
+ const original = proto[name];
85
+ const wrapper =
86
+ name === 'connectedCallback'
87
+ ? function () {
88
+ record.instances.add(this);
89
+ const stamp = state.generationOf.get(this);
90
+ if (stamp !== undefined && stamp !== record.generation) {
91
+ // Was detached during one or more patches; catch up.
92
+ this.requestUpdate?.();
92
93
  }
93
- : function () {
94
- record.instances.delete(this);
95
- original?.call(this);
96
- };
97
- wrapper[RECORD_BRAND] = record;
98
- try {
99
- Object.defineProperty(proto, name, {
100
- value: wrapper,
101
- writable: true,
102
- configurable: true,
103
- });
104
- }
105
- catch {
106
- // Non-configurable lifecycle slot; tracking degrades gracefully.
107
- }
94
+ state.generationOf.set(this, record.generation);
95
+ original?.call(this);
96
+ }
97
+ : function () {
98
+ record.instances.delete(this);
99
+ original?.call(this);
100
+ };
101
+ wrapper[RECORD_BRAND] = record;
102
+ try {
103
+ Object.defineProperty(proto, name, {
104
+ value: wrapper,
105
+ writable: true,
106
+ configurable: true,
107
+ });
108
+ } catch {
109
+ // Non-configurable lifecycle slot; tracking degrades gracefully.
108
110
  }
111
+ }
109
112
  };
110
113
  /**
111
114
  * Detects standard-decorator (`accessor`) reactive properties on the new
@@ -113,26 +116,24 @@ const instrument = (state, proto, record) => {
113
116
  * accessors would brand-check-throw — in-place patching is impossible.
114
117
  */
115
118
  const usesStandardDecorators = (ctor) => {
116
- const metadataSymbol = Symbol.metadata;
117
- if (metadataSymbol === undefined) {
118
- return false;
119
- }
120
- const metadata = Object.getOwnPropertyDescriptor(ctor, metadataSymbol)
121
- ?.value;
122
- if (metadata === undefined || metadata === null) {
123
- return false;
124
- }
125
- // litPropertyMetadata is a Lit internal (not public API). Guard against
126
- // rename, removal, or shape changes — a false negative here means we try
127
- // to hot-patch and crash, which is handled by the outer catch in hotPatch.
128
- try {
129
- const litPropertyMetadata = globalThis.litPropertyMetadata;
130
- const properties = litPropertyMetadata?.get(metadata);
131
- return properties !== undefined && properties.size > 0;
132
- }
133
- catch {
134
- return false;
135
- }
119
+ const metadataSymbol = Symbol.metadata;
120
+ if (metadataSymbol === undefined) {
121
+ return false;
122
+ }
123
+ const metadata = Object.getOwnPropertyDescriptor(ctor, metadataSymbol)?.value;
124
+ if (metadata === undefined || metadata === null) {
125
+ return false;
126
+ }
127
+ // litPropertyMetadata is a Lit internal (not public API). Guard against
128
+ // rename, removal, or shape changes — a false negative here means we try
129
+ // to hot-patch and crash, which is handled by the outer catch in hotPatch.
130
+ try {
131
+ const litPropertyMetadata = globalThis.litPropertyMetadata;
132
+ const properties = litPropertyMetadata?.get(metadata);
133
+ return properties !== undefined && properties.size > 0;
134
+ } catch {
135
+ return false;
136
+ }
136
137
  };
137
138
  /**
138
139
  * Resolves a static `elementStyles` array to its constructed `CSSStyleSheet`s.
@@ -140,19 +141,15 @@ const usesStandardDecorators = (ctor) => {
140
141
  * stylesheet support), so callers can bail rather than adopt a partial list.
141
142
  */
142
143
  const stylesToSheets = (styles) => {
143
- if (!Array.isArray(styles))
144
- return null;
145
- const sheets = [];
146
- for (const style of styles) {
147
- const sheet = style instanceof CSSStyleSheet
148
- ? style
149
- : (style?.styleSheet ??
150
- undefined);
151
- if (!(sheet instanceof CSSStyleSheet))
152
- return null;
153
- sheets.push(sheet);
154
- }
155
- return sheets;
144
+ if (!Array.isArray(styles)) return null;
145
+ const sheets = [];
146
+ for (const style of styles) {
147
+ const sheet =
148
+ style instanceof CSSStyleSheet ? style : (style?.styleSheet ?? undefined);
149
+ if (!(sheet instanceof CSSStyleSheet)) return null;
150
+ sheets.push(sheet);
151
+ }
152
+ return sheets;
156
153
  };
157
154
  /**
158
155
  * Re-adopts constructed stylesheets on an instance's shadow root from the
@@ -165,211 +162,253 @@ const stylesToSheets = (styles) => {
165
162
  * whole list.
166
163
  */
167
164
  const readoptStyles = (el, oldSheets) => {
168
- const root = el.renderRoot;
169
- if (typeof ShadowRoot === 'undefined' || !(root instanceof ShadowRoot)) {
170
- return;
171
- }
172
- const sheets = stylesToSheets(el.constructor.elementStyles);
173
- if (sheets === null) {
174
- return;
175
- }
176
- const drop = new Set(oldSheets);
177
- const ours = new Set(sheets);
178
- // Our styles go first, matching Lit's own order (extra sheets appended).
179
- const preserved = [...root.adoptedStyleSheets].filter((s) => !drop.has(s) && !ours.has(s));
180
- root.adoptedStyleSheets = [...sheets, ...preserved];
165
+ const root = el.renderRoot;
166
+ if (typeof ShadowRoot === 'undefined' || !(root instanceof ShadowRoot)) {
167
+ return;
168
+ }
169
+ const sheets = stylesToSheets(el.constructor.elementStyles);
170
+ if (sheets === null) {
171
+ return;
172
+ }
173
+ const drop = new Set(oldSheets);
174
+ const ours = new Set(sheets);
175
+ // Our styles go first, matching Lit's own order (extra sheets appended).
176
+ const preserved = [...root.adoptedStyleSheets].filter(
177
+ (s) => !drop.has(s) && !ours.has(s)
178
+ );
179
+ root.adoptedStyleSheets = [...sheets, ...preserved];
181
180
  };
181
+ /**
182
+ * Builds the structured event reported over {@link HMR_INCOMPATIBLE_CHANNEL}.
183
+ * Exported for unit testing; otherwise module-internal. Whether the send
184
+ * survives the `location.reload()` that may follow it can only be checked by
185
+ * hand against a real dev server.
186
+ */
187
+ export const buildHmrIncompatibleEvent = (tagName, reason, action) => ({
188
+ tagName,
189
+ time: Date.now(),
190
+ reason,
191
+ action,
192
+ });
182
193
  const incompatible = (state, tagName, reason) => {
183
- if (state.options.onIncompatible === 'warn') {
184
- console.warn(`[lit-plugin] <${tagName}> can't be hot-patched (${reason}). ` +
185
- `Reload the page to pick up the change.`);
186
- }
187
- else {
188
- console.info(`[lit-plugin] <${tagName}>: ${reason} — performing full reload.`);
189
- location.reload();
190
- }
194
+ const message = describeHmrReason(reason);
195
+ const action = state.options.onIncompatible === 'warn' ? 'warn' : 'reload';
196
+ state.hot?.send(
197
+ HMR_INCOMPATIBLE_CHANNEL,
198
+ buildHmrIncompatibleEvent(tagName, reason, action)
199
+ );
200
+ if (state.options.onIncompatible === 'warn') {
201
+ console.warn(
202
+ `[lit-plugin] <${tagName}> can't be hot-patched (${message}). ` +
203
+ `Reload the page to pick up the change.`
204
+ );
205
+ } else {
206
+ console.info(
207
+ `[lit-plugin] <${tagName}>: ${message} — performing full reload.`
208
+ );
209
+ location.reload();
210
+ }
191
211
  };
192
212
  /**
193
213
  * Patches the originally-registered class for `record.tagName` in place
194
214
  * from the freshly evaluated `NewClass`, then updates live instances.
195
215
  */
196
216
  const hotPatch = (state, record, NewClass) => {
197
- const OldClass = record.canonical;
198
- try {
199
- // 1. Materialize finalized/elementProperties/elementStyles/
200
- // __attributeToPropertyMap on the new class before we copy statics.
201
- if (typeof NewClass.finalize === 'function') {
202
- NewClass.finalize();
203
- }
204
- // 2. Standard-decorator `accessor` properties can't be patched in place.
205
- if (usesStandardDecorators(NewClass)) {
206
- incompatible(state, record.tagName, 'standard accessor decorators');
207
- return;
208
- }
209
- // The platform snapshots observedAttributes at define time; new
210
- // attribute observations can't take effect without a reload.
211
- const oldObserved = [...(OldClass.observedAttributes ?? [])];
212
- const newObserved = [...(NewClass.observedAttributes ?? [])];
213
- // 3. Snapshot reactive property values per live instance through the
214
- // OLD accessors. Vite serves prod lit in dev (no `development`
215
- // export condition), where accessor storage keys are unique
216
- // Symbol()s per class evaluation — without this, state resets.
217
- const propertyKeys = new Set([
218
- ...(OldClass.elementProperties?.keys() ?? []),
219
- ...(NewClass.elementProperties?.keys() ?? []),
220
- ]);
221
- const snapshots = new Map();
222
- for (const el of record.instances) {
223
- const values = new Map();
224
- for (const key of propertyKeys) {
225
- values.set(key, el[key]);
226
- }
227
- snapshots.set(el, values);
228
- }
229
- // 4. Re-parent prototype chains. Mixins regenerate intermediate classes
230
- // on every module evaluation, so the parents usually differ.
231
- const newProtoParent = Object.getPrototypeOf(NewClass.prototype);
232
- if (Object.getPrototypeOf(OldClass.prototype) !== newProtoParent) {
233
- Object.setPrototypeOf(OldClass.prototype, newProtoParent);
234
- }
235
- const newStaticParent = Object.getPrototypeOf(NewClass);
236
- if (Object.getPrototypeOf(OldClass) !== newStaticParent) {
237
- Object.setPrototypeOf(OldClass, newStaticParent);
238
- }
239
- // Capture the sheets the OLD class contributed before the static sync
240
- // overwrites `elementStyles`, so readoptStyles can drop exactly those and
241
- // leave imperatively-adopted sheets in place.
242
- const oldSheets = stylesToSheets(OldClass.elementStyles) ?? [];
243
- // 5. Sync own members new → old on the prototype and on statics.
244
- syncOwnMembers(OldClass.prototype, NewClass.prototype, PROTO_SKIP);
245
- syncOwnMembers(OldClass, NewClass, STATIC_SKIP);
246
- // 6. The sync replaced/removed our lifecycle wrappers; re-instrument.
247
- instrument(state, OldClass.prototype, record);
248
- record.generation++;
249
- // Module-local `instanceof NewClass` checks keep working against
250
- // instances of the canonical class.
251
- Object.defineProperty(NewClass, Symbol.hasInstance, {
252
- value: (instance) => typeof instance === 'object' &&
253
- instance !== null &&
254
- OldClass.prototype.isPrototypeOf(instance),
255
- configurable: true,
256
- });
257
- if (oldObserved.length !== newObserved.length ||
258
- oldObserved.some((attr, i) => attr !== newObserved[i])) {
259
- console.info(`[lit-plugin] <${record.tagName}> changed observedAttributes; the ` +
260
- `platform registry can't pick this up — reload recommended.`);
217
+ const OldClass = record.canonical;
218
+ try {
219
+ // 1. Materialize finalized/elementProperties/elementStyles/
220
+ // __attributeToPropertyMap on the new class before we copy statics.
221
+ if (typeof NewClass.finalize === 'function') {
222
+ NewClass.finalize();
223
+ }
224
+ // 2. Standard-decorator `accessor` properties can't be patched in place.
225
+ if (usesStandardDecorators(NewClass)) {
226
+ incompatible(state, record.tagName, {code: 'accessor-decorators'});
227
+ return;
228
+ }
229
+ // The platform snapshots observedAttributes at define time; new
230
+ // attribute observations can't take effect without a reload.
231
+ const oldObserved = [...(OldClass.observedAttributes ?? [])];
232
+ const newObserved = [...(NewClass.observedAttributes ?? [])];
233
+ // 3. Snapshot reactive property values per live instance through the
234
+ // OLD accessors. Vite serves prod lit in dev (no `development`
235
+ // export condition), where accessor storage keys are unique
236
+ // Symbol()s per class evaluation — without this, state resets.
237
+ const propertyKeys = new Set([
238
+ ...(OldClass.elementProperties?.keys() ?? []),
239
+ ...(NewClass.elementProperties?.keys() ?? []),
240
+ ]);
241
+ const snapshots = new Map();
242
+ for (const el of record.instances) {
243
+ const values = new Map();
244
+ for (const key of propertyKeys) {
245
+ values.set(key, el[key]);
246
+ }
247
+ snapshots.set(el, values);
248
+ }
249
+ // 4. Re-parent prototype chains. Mixins regenerate intermediate classes
250
+ // on every module evaluation, so the parents usually differ.
251
+ const newProtoParent = Object.getPrototypeOf(NewClass.prototype);
252
+ if (Object.getPrototypeOf(OldClass.prototype) !== newProtoParent) {
253
+ Object.setPrototypeOf(OldClass.prototype, newProtoParent);
254
+ }
255
+ const newStaticParent = Object.getPrototypeOf(NewClass);
256
+ if (Object.getPrototypeOf(OldClass) !== newStaticParent) {
257
+ Object.setPrototypeOf(OldClass, newStaticParent);
258
+ }
259
+ // Capture the sheets the OLD class contributed before the static sync
260
+ // overwrites `elementStyles`, so readoptStyles can drop exactly those and
261
+ // leave imperatively-adopted sheets in place.
262
+ const oldSheets = stylesToSheets(OldClass.elementStyles) ?? [];
263
+ // 5. Sync own members new → old on the prototype and on statics.
264
+ syncOwnMembers(OldClass.prototype, NewClass.prototype, PROTO_SKIP);
265
+ syncOwnMembers(OldClass, NewClass, STATIC_SKIP);
266
+ // 6. The sync replaced/removed our lifecycle wrappers; re-instrument.
267
+ instrument(state, OldClass.prototype, record);
268
+ record.generation++;
269
+ // Module-local `instanceof NewClass` checks keep working against
270
+ // instances of the canonical class.
271
+ Object.defineProperty(NewClass, Symbol.hasInstance, {
272
+ value: (instance) =>
273
+ typeof instance === 'object' &&
274
+ instance !== null &&
275
+ OldClass.prototype.isPrototypeOf(instance),
276
+ configurable: true,
277
+ });
278
+ if (
279
+ oldObserved.length !== newObserved.length ||
280
+ oldObserved.some((attr, i) => attr !== newObserved[i])
281
+ ) {
282
+ console.info(
283
+ `[lit-plugin] <${record.tagName}> changed observedAttributes; the ` +
284
+ `platform registry can't pick this up — reload recommended.`
285
+ );
286
+ state.hot?.send(
287
+ HMR_INCOMPATIBLE_CHANNEL,
288
+ buildHmrIncompatibleEvent(
289
+ record.tagName,
290
+ {code: 'observed-attributes-changed'},
291
+ 'none'
292
+ )
293
+ );
294
+ }
295
+ // 7. Update live instances.
296
+ const newPropertyKeys = NewClass.elementProperties?.keys() ?? [];
297
+ // After the static sync this is the NEW class's initializer list.
298
+ const initializers = OldClass._initializers;
299
+ // Snapshot: the reconnect below mutates record.instances mid-iteration.
300
+ // oxlint-disable-next-line unicorn/no-useless-spread
301
+ for (const el of [...record.instances]) {
302
+ if (state.options.reconnect) {
303
+ el.disconnectedCallback?.();
304
+ el.connectedCallback?.();
305
+ }
306
+ // Decorator-created reactive controllers (e.g. @lit/context's
307
+ // @provide/@consume) live in per-class-evaluation closures keyed by
308
+ // instance via addInitializer. Re-running the initializers enrolls
309
+ // live instances in the new closures — without this, the first
310
+ // assignment through a copied accessor throws and we'd full-reload.
311
+ // Controllers from previous evaluations stay attached but inert
312
+ // (everything flows through the newest closures); that's bounded by
313
+ // edit count and dev-only. Runs before the value restore so e.g. a
314
+ // re-created ContextProvider exists when the restore pushes into it.
315
+ if (Array.isArray(initializers)) {
316
+ for (const initialize of initializers) {
317
+ initialize(el);
261
318
  }
262
- // 7. Update live instances.
263
- const newPropertyKeys = NewClass.elementProperties?.keys() ?? [];
264
- // After the static sync this is the NEW class's initializer list.
265
- const initializers = OldClass._initializers;
266
- for (const el of [...record.instances]) {
267
- if (state.options.reconnect) {
268
- el.disconnectedCallback?.();
269
- el.connectedCallback?.();
270
- }
271
- // Decorator-created reactive controllers (e.g. @lit/context's
272
- // @provide/@consume) live in per-class-evaluation closures keyed by
273
- // instance via addInitializer. Re-running the initializers enrolls
274
- // live instances in the new closures — without this, the first
275
- // assignment through a copied accessor throws and we'd full-reload.
276
- // Controllers from previous evaluations stay attached but inert
277
- // (everything flows through the newest closures); that's bounded by
278
- // edit count and dev-only. Runs before the value restore so e.g. a
279
- // re-created ContextProvider exists when the restore pushes into it.
280
- if (Array.isArray(initializers)) {
281
- for (const initialize of initializers) {
282
- initialize(el);
283
- }
284
- }
285
- const values = snapshots.get(el);
286
- if (values !== undefined) {
287
- // Restore through the new accessors — only keys the new class
288
- // still declares.
289
- for (const key of newPropertyKeys) {
290
- if (values.has(key)) {
291
- el[key] =
292
- values.get(key);
293
- }
294
- }
295
- }
296
- readoptStyles(el, oldSheets);
297
- state.generationOf.set(el, record.generation);
298
- el.requestUpdate?.();
319
+ }
320
+ const values = snapshots.get(el);
321
+ if (values !== undefined) {
322
+ // Restore through the new accessors — only keys the new class
323
+ // still declares.
324
+ for (const key of newPropertyKeys) {
325
+ if (values.has(key)) {
326
+ el[key] = values.get(key);
327
+ }
299
328
  }
329
+ }
330
+ readoptStyles(el, oldSheets);
331
+ state.generationOf.set(el, record.generation);
332
+ el.requestUpdate?.();
300
333
  }
301
- catch (e) {
302
- incompatible(state, record.tagName, `patching failed: ${e instanceof Error ? e.message : String(e)}`);
303
- }
334
+ } catch (e) {
335
+ incompatible(state, record.tagName, {
336
+ code: 'patch-failed',
337
+ detail: e instanceof Error ? e.message : String(e),
338
+ });
339
+ }
304
340
  };
305
341
  /**
306
342
  * Installs the `customElements.define` interceptor. Idempotent (per-page
307
343
  * global guard); no-ops in environments without `customElements` (SSR).
308
344
  */
309
345
  export const install = (options = {}) => {
310
- if (typeof customElements === 'undefined') {
311
- return;
346
+ if (typeof customElements === 'undefined') {
347
+ return;
348
+ }
349
+ const g = globalThis;
350
+ const existing = g[STATE_KEY];
351
+ if (existing !== undefined) {
352
+ // Already installed; refresh explicitly-provided options only.
353
+ if (options.reconnect !== undefined) {
354
+ existing.options.reconnect = options.reconnect;
312
355
  }
313
- const g = globalThis;
314
- const existing = g[STATE_KEY];
315
- if (existing !== undefined) {
316
- // Already installed; refresh explicitly-provided options only.
317
- if (options.reconnect !== undefined) {
318
- existing.options.reconnect = options.reconnect;
319
- }
320
- if (options.onIncompatible !== undefined) {
321
- existing.options.onIncompatible = options.onIncompatible;
322
- }
323
- return;
356
+ if (options.onIncompatible !== undefined) {
357
+ existing.options.onIncompatible = options.onIncompatible;
324
358
  }
325
- const state = {
326
- records: new Map(),
327
- generationOf: new WeakMap(),
328
- options: {
329
- reconnect: options.reconnect ?? false,
330
- onIncompatible: options.onIncompatible ?? 'reload',
331
- },
332
- };
333
- g[STATE_KEY] = state;
334
- // Let the DevTools panel override these behaviours live (and persist across
335
- // reloads) on top of the config-time defaults above.
336
- subscribeOverride(import.meta.hot, (o) => {
337
- if (o.hmrReconnect !== undefined)
338
- state.options.reconnect = o.hmrReconnect;
339
- if (o.hmrOnIncompatible !== undefined) {
340
- state.options.onIncompatible = o.hmrOnIncompatible;
341
- }
342
- });
343
- const nativeDefine = customElements.define;
344
- customElements.define = function (name, ctor, defineOptions) {
345
- let record = state.records.get(name);
346
- if (record === undefined && this.get(name) !== undefined) {
347
- // Defined before install() ran (shouldn't happen — the installer is
348
- // import-hoisted — but recover gracefully without instance tracking).
349
- record = {
350
- tagName: name,
351
- canonical: this.get(name),
352
- instances: new Set(),
353
- generation: 0,
354
- };
355
- state.records.set(name, record);
356
- }
357
- if (record === undefined) {
358
- record = {
359
- tagName: name,
360
- canonical: ctor,
361
- instances: new Set(),
362
- generation: 0,
363
- };
364
- state.records.set(name, record);
365
- instrument(state, ctor.prototype, record);
366
- return nativeDefine.call(this, name, ctor, defineOptions);
367
- }
368
- if (ctor === record.canonical) {
369
- // Same class object re-defined; nothing to patch.
370
- return;
371
- }
372
- hotPatch(state, record, ctor);
373
- };
359
+ return;
360
+ }
361
+ const hot = import.meta.hot;
362
+ const state = {
363
+ records: new Map(),
364
+ generationOf: new WeakMap(),
365
+ options: {
366
+ reconnect: options.reconnect ?? false,
367
+ onIncompatible: options.onIncompatible ?? 'reload',
368
+ },
369
+ hot,
370
+ };
371
+ g[STATE_KEY] = state;
372
+ // Let the DevTools panel override these behaviours live (and persist across
373
+ // reloads) on top of the config-time defaults above.
374
+ subscribeOverride(hot, (o) => {
375
+ if (o.hmrReconnect !== undefined) state.options.reconnect = o.hmrReconnect;
376
+ if (o.hmrOnIncompatible !== undefined) {
377
+ state.options.onIncompatible = o.hmrOnIncompatible;
378
+ }
379
+ });
380
+ // Captured to re-invoke below as nativeDefine.call(this, ...).
381
+ // oxlint-disable-next-line typescript/unbound-method
382
+ const nativeDefine = customElements.define;
383
+ customElements.define = function (name, ctor, defineOptions) {
384
+ let record = state.records.get(name);
385
+ if (record === undefined && this.get(name) !== undefined) {
386
+ // Defined before install() ran (shouldn't happen — the installer is
387
+ // import-hoisted — but recover gracefully without instance tracking).
388
+ record = {
389
+ tagName: name,
390
+ canonical: this.get(name),
391
+ instances: new Set(),
392
+ generation: 0,
393
+ };
394
+ state.records.set(name, record);
395
+ }
396
+ if (record === undefined) {
397
+ record = {
398
+ tagName: name,
399
+ canonical: ctor,
400
+ instances: new Set(),
401
+ generation: 0,
402
+ };
403
+ state.records.set(name, record);
404
+ instrument(state, ctor.prototype, record);
405
+ return nativeDefine.call(this, name, ctor, defineOptions);
406
+ }
407
+ if (ctor === record.canonical) {
408
+ // Same class object re-defined; nothing to patch.
409
+ return;
410
+ }
411
+ hotPatch(state, record, ctor);
412
+ };
374
413
  };
375
- //# sourceMappingURL=patch.js.map
414
+ //# sourceMappingURL=patch.js.map