@reticlehq/babel-plugin 2.13.1 → 2.14.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/dist/dom-tags.d.ts +37 -0
- package/dist/dom-tags.js +274 -0
- package/dist/index.js +9 -1
- package/package.json +2 -2
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The lowercase JSX tags that are actually DOM elements.
|
|
3
|
+
*
|
|
4
|
+
* "Lowercase means host element" was the rule, and it is true only for React DOM. React is a
|
|
5
|
+
* reconciler interface, not a renderer: react-three-fiber, react-pdf, ink and friends define their
|
|
6
|
+
* own lowercase intrinsics, and those host instances are not nodes and do not take attributes.
|
|
7
|
+
*
|
|
8
|
+
* R3F is the case that bit. Its `applyProps` treats any prop containing a dash as a PIERCED
|
|
9
|
+
* PROPERTY PATH, so `data-reticle-source` is walked as `data` -> `reticle` -> `source`; there is no
|
|
10
|
+
* `data` object on a three.js instance, and it throws from inside the commit phase. Unhandled there,
|
|
11
|
+
* the whole React tree unmounts to a white screen — and because it needs an element UPDATE rather
|
|
12
|
+
* than a mount, it fires long after the app looked fine.
|
|
13
|
+
*
|
|
14
|
+
* So the check is an ALLOWLIST, not a heuristic. The set of custom-reconciler intrinsics is
|
|
15
|
+
* unbounded and cannot be enumerated; the set of HTML and SVG tags can. Getting it wrong in the
|
|
16
|
+
* conservative direction costs one source pointer on an exotic element. Getting it wrong the other
|
|
17
|
+
* way costs the user their entire app.
|
|
18
|
+
*
|
|
19
|
+
* WHAT THIS DOES NOT COVER, stated rather than implied: a handful of three.js class names collide
|
|
20
|
+
* with real DOM tags — `line` is both `<line>` in SVG and `THREE.Line`, and `audio` is both. A tag
|
|
21
|
+
* name alone cannot separate them, and a lexical "is it under a <Canvas>" walk only sees the file
|
|
22
|
+
* it is transforming, so a scene component in its own file would still slip through. The complete
|
|
23
|
+
* answer for a three.js app is `reticle({ sourceMapping: false })` — which `reticle init` writes on
|
|
24
|
+
* its own when it finds one of these renderers in the manifest (see `Detection.customReconciler`).
|
|
25
|
+
*
|
|
26
|
+
* This paragraph described that as already true for a release in which it was not: nothing read the
|
|
27
|
+
* manifest, and the crash reached new installs anyway. The allowlist below is a mitigation, not the
|
|
28
|
+
* remedy; the manifest check is the remedy.
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* Whether `tag` names a DOM element that will accept an arbitrary `data-*` attribute.
|
|
32
|
+
*
|
|
33
|
+
* Custom elements are deliberately included: a tag containing a dash is a valid custom element per
|
|
34
|
+
* the HTML spec, it IS a DOM node, and `data-*` on it is ordinary. That rule cannot collide with a
|
|
35
|
+
* custom reconciler's intrinsics, which are bare identifiers (`mesh`, `group`, `box`).
|
|
36
|
+
*/
|
|
37
|
+
export declare function isDomTag(tag: string): boolean;
|
package/dist/dom-tags.js
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The lowercase JSX tags that are actually DOM elements.
|
|
4
|
+
*
|
|
5
|
+
* "Lowercase means host element" was the rule, and it is true only for React DOM. React is a
|
|
6
|
+
* reconciler interface, not a renderer: react-three-fiber, react-pdf, ink and friends define their
|
|
7
|
+
* own lowercase intrinsics, and those host instances are not nodes and do not take attributes.
|
|
8
|
+
*
|
|
9
|
+
* R3F is the case that bit. Its `applyProps` treats any prop containing a dash as a PIERCED
|
|
10
|
+
* PROPERTY PATH, so `data-reticle-source` is walked as `data` -> `reticle` -> `source`; there is no
|
|
11
|
+
* `data` object on a three.js instance, and it throws from inside the commit phase. Unhandled there,
|
|
12
|
+
* the whole React tree unmounts to a white screen — and because it needs an element UPDATE rather
|
|
13
|
+
* than a mount, it fires long after the app looked fine.
|
|
14
|
+
*
|
|
15
|
+
* So the check is an ALLOWLIST, not a heuristic. The set of custom-reconciler intrinsics is
|
|
16
|
+
* unbounded and cannot be enumerated; the set of HTML and SVG tags can. Getting it wrong in the
|
|
17
|
+
* conservative direction costs one source pointer on an exotic element. Getting it wrong the other
|
|
18
|
+
* way costs the user their entire app.
|
|
19
|
+
*
|
|
20
|
+
* WHAT THIS DOES NOT COVER, stated rather than implied: a handful of three.js class names collide
|
|
21
|
+
* with real DOM tags — `line` is both `<line>` in SVG and `THREE.Line`, and `audio` is both. A tag
|
|
22
|
+
* name alone cannot separate them, and a lexical "is it under a <Canvas>" walk only sees the file
|
|
23
|
+
* it is transforming, so a scene component in its own file would still slip through. The complete
|
|
24
|
+
* answer for a three.js app is `reticle({ sourceMapping: false })` — which `reticle init` writes on
|
|
25
|
+
* its own when it finds one of these renderers in the manifest (see `Detection.customReconciler`).
|
|
26
|
+
*
|
|
27
|
+
* This paragraph described that as already true for a release in which it was not: nothing read the
|
|
28
|
+
* manifest, and the crash reached new installs anyway. The allowlist below is a mitigation, not the
|
|
29
|
+
* remedy; the manifest check is the remedy.
|
|
30
|
+
*/
|
|
31
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
|
+
exports.isDomTag = isDomTag;
|
|
33
|
+
/** Every HTML element name, including the deprecated ones a real codebase still contains. */
|
|
34
|
+
const HTML_TAGS = [
|
|
35
|
+
'a',
|
|
36
|
+
'abbr',
|
|
37
|
+
'address',
|
|
38
|
+
'area',
|
|
39
|
+
'article',
|
|
40
|
+
'aside',
|
|
41
|
+
'audio',
|
|
42
|
+
'b',
|
|
43
|
+
'base',
|
|
44
|
+
'bdi',
|
|
45
|
+
'bdo',
|
|
46
|
+
'big',
|
|
47
|
+
'blockquote',
|
|
48
|
+
'body',
|
|
49
|
+
'br',
|
|
50
|
+
'button',
|
|
51
|
+
'canvas',
|
|
52
|
+
'caption',
|
|
53
|
+
'center',
|
|
54
|
+
'cite',
|
|
55
|
+
'code',
|
|
56
|
+
'col',
|
|
57
|
+
'colgroup',
|
|
58
|
+
'data',
|
|
59
|
+
'datalist',
|
|
60
|
+
'dd',
|
|
61
|
+
'del',
|
|
62
|
+
'details',
|
|
63
|
+
'dfn',
|
|
64
|
+
'dialog',
|
|
65
|
+
'div',
|
|
66
|
+
'dl',
|
|
67
|
+
'dt',
|
|
68
|
+
'em',
|
|
69
|
+
'embed',
|
|
70
|
+
'fieldset',
|
|
71
|
+
'figcaption',
|
|
72
|
+
'figure',
|
|
73
|
+
'font',
|
|
74
|
+
'footer',
|
|
75
|
+
'form',
|
|
76
|
+
'frame',
|
|
77
|
+
'frameset',
|
|
78
|
+
'h1',
|
|
79
|
+
'h2',
|
|
80
|
+
'h3',
|
|
81
|
+
'h4',
|
|
82
|
+
'h5',
|
|
83
|
+
'h6',
|
|
84
|
+
'head',
|
|
85
|
+
'header',
|
|
86
|
+
'hgroup',
|
|
87
|
+
'hr',
|
|
88
|
+
'html',
|
|
89
|
+
'i',
|
|
90
|
+
'iframe',
|
|
91
|
+
'img',
|
|
92
|
+
'input',
|
|
93
|
+
'ins',
|
|
94
|
+
'kbd',
|
|
95
|
+
'keygen',
|
|
96
|
+
'label',
|
|
97
|
+
'legend',
|
|
98
|
+
'li',
|
|
99
|
+
'link',
|
|
100
|
+
'main',
|
|
101
|
+
'map',
|
|
102
|
+
'mark',
|
|
103
|
+
'marquee',
|
|
104
|
+
'menu',
|
|
105
|
+
'menuitem',
|
|
106
|
+
'meta',
|
|
107
|
+
'meter',
|
|
108
|
+
'nav',
|
|
109
|
+
'nobr',
|
|
110
|
+
'noframes',
|
|
111
|
+
'noscript',
|
|
112
|
+
'object',
|
|
113
|
+
'ol',
|
|
114
|
+
'optgroup',
|
|
115
|
+
'option',
|
|
116
|
+
'output',
|
|
117
|
+
'p',
|
|
118
|
+
'param',
|
|
119
|
+
'picture',
|
|
120
|
+
'pre',
|
|
121
|
+
'progress',
|
|
122
|
+
'q',
|
|
123
|
+
'rp',
|
|
124
|
+
'rt',
|
|
125
|
+
'ruby',
|
|
126
|
+
's',
|
|
127
|
+
'samp',
|
|
128
|
+
'script',
|
|
129
|
+
'search',
|
|
130
|
+
'section',
|
|
131
|
+
'select',
|
|
132
|
+
'slot',
|
|
133
|
+
'small',
|
|
134
|
+
'source',
|
|
135
|
+
'span',
|
|
136
|
+
'strike',
|
|
137
|
+
'strong',
|
|
138
|
+
'style',
|
|
139
|
+
'sub',
|
|
140
|
+
'summary',
|
|
141
|
+
'sup',
|
|
142
|
+
'table',
|
|
143
|
+
'tbody',
|
|
144
|
+
'td',
|
|
145
|
+
'template',
|
|
146
|
+
'textarea',
|
|
147
|
+
'tfoot',
|
|
148
|
+
'th',
|
|
149
|
+
'thead',
|
|
150
|
+
'time',
|
|
151
|
+
'title',
|
|
152
|
+
'tr',
|
|
153
|
+
'track',
|
|
154
|
+
'u',
|
|
155
|
+
'ul',
|
|
156
|
+
'var',
|
|
157
|
+
'video',
|
|
158
|
+
'wbr',
|
|
159
|
+
];
|
|
160
|
+
/**
|
|
161
|
+
* SVG element names. Included because SVG is DOM — a `data-*` attribute on `<path>` is as valid as
|
|
162
|
+
* one on `<div>`, and an app whose UI is a chart would otherwise lose every source pointer in it.
|
|
163
|
+
*
|
|
164
|
+
* The camelCase members (`clipPath`, `linearGradient`, …) are real JSX intrinsics in React DOM and
|
|
165
|
+
* are matched exactly, so the lookup below cannot be case-folded.
|
|
166
|
+
*/
|
|
167
|
+
const SVG_TAGS = [
|
|
168
|
+
'animate',
|
|
169
|
+
'animateMotion',
|
|
170
|
+
'animateTransform',
|
|
171
|
+
'circle',
|
|
172
|
+
'clipPath',
|
|
173
|
+
'defs',
|
|
174
|
+
'desc',
|
|
175
|
+
'ellipse',
|
|
176
|
+
'feBlend',
|
|
177
|
+
'feColorMatrix',
|
|
178
|
+
'feComponentTransfer',
|
|
179
|
+
'feComposite',
|
|
180
|
+
'feConvolveMatrix',
|
|
181
|
+
'feDiffuseLighting',
|
|
182
|
+
'feDisplacementMap',
|
|
183
|
+
'feDistantLight',
|
|
184
|
+
'feDropShadow',
|
|
185
|
+
'feFlood',
|
|
186
|
+
'feFuncA',
|
|
187
|
+
'feFuncB',
|
|
188
|
+
'feFuncG',
|
|
189
|
+
'feFuncR',
|
|
190
|
+
'feGaussianBlur',
|
|
191
|
+
'feImage',
|
|
192
|
+
'feMerge',
|
|
193
|
+
'feMergeNode',
|
|
194
|
+
'feMorphology',
|
|
195
|
+
'feOffset',
|
|
196
|
+
'fePointLight',
|
|
197
|
+
'feSpecularLighting',
|
|
198
|
+
'feSpotLight',
|
|
199
|
+
'feTile',
|
|
200
|
+
'feTurbulence',
|
|
201
|
+
'filter',
|
|
202
|
+
'foreignObject',
|
|
203
|
+
'g',
|
|
204
|
+
'image',
|
|
205
|
+
'line',
|
|
206
|
+
'linearGradient',
|
|
207
|
+
'marker',
|
|
208
|
+
'mask',
|
|
209
|
+
'metadata',
|
|
210
|
+
'mpath',
|
|
211
|
+
'path',
|
|
212
|
+
'pattern',
|
|
213
|
+
'polygon',
|
|
214
|
+
'polyline',
|
|
215
|
+
'radialGradient',
|
|
216
|
+
'rect',
|
|
217
|
+
'set',
|
|
218
|
+
'stop',
|
|
219
|
+
'svg',
|
|
220
|
+
'switch',
|
|
221
|
+
'symbol',
|
|
222
|
+
'text',
|
|
223
|
+
'textPath',
|
|
224
|
+
'tspan',
|
|
225
|
+
'use',
|
|
226
|
+
'view',
|
|
227
|
+
];
|
|
228
|
+
/**
|
|
229
|
+
* MathML, for completeness: also DOM, also takes `data-*`. Small enough that omitting it would be a
|
|
230
|
+
* deliberate blind spot rather than a saving.
|
|
231
|
+
*/
|
|
232
|
+
const MATHML_TAGS = [
|
|
233
|
+
'annotation',
|
|
234
|
+
'annotation-xml',
|
|
235
|
+
'maction',
|
|
236
|
+
'math',
|
|
237
|
+
'merror',
|
|
238
|
+
'mfrac',
|
|
239
|
+
'mi',
|
|
240
|
+
'mmultiscripts',
|
|
241
|
+
'mn',
|
|
242
|
+
'mo',
|
|
243
|
+
'mover',
|
|
244
|
+
'mpadded',
|
|
245
|
+
'mphantom',
|
|
246
|
+
'mprescripts',
|
|
247
|
+
'mroot',
|
|
248
|
+
'mrow',
|
|
249
|
+
'ms',
|
|
250
|
+
'mspace',
|
|
251
|
+
'msqrt',
|
|
252
|
+
'mstyle',
|
|
253
|
+
'msub',
|
|
254
|
+
'msubsup',
|
|
255
|
+
'msup',
|
|
256
|
+
'mtable',
|
|
257
|
+
'mtd',
|
|
258
|
+
'mtext',
|
|
259
|
+
'mtr',
|
|
260
|
+
'munder',
|
|
261
|
+
'munderover',
|
|
262
|
+
'semantics',
|
|
263
|
+
];
|
|
264
|
+
const DOM_TAGS = new Set([...HTML_TAGS, ...SVG_TAGS, ...MATHML_TAGS]);
|
|
265
|
+
/**
|
|
266
|
+
* Whether `tag` names a DOM element that will accept an arbitrary `data-*` attribute.
|
|
267
|
+
*
|
|
268
|
+
* Custom elements are deliberately included: a tag containing a dash is a valid custom element per
|
|
269
|
+
* the HTML spec, it IS a DOM node, and `data-*` on it is ordinary. That rule cannot collide with a
|
|
270
|
+
* custom reconciler's intrinsics, which are bare identifiers (`mesh`, `group`, `box`).
|
|
271
|
+
*/
|
|
272
|
+
function isDomTag(tag) {
|
|
273
|
+
return DOM_TAGS.has(tag) || (tag.includes('-') && !tag.startsWith('-'));
|
|
274
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const node_path_1 = require("node:path");
|
|
3
3
|
const source_constants_1 = require("@reticlehq/core/source-constants");
|
|
4
|
+
const dom_tags_js_1 = require("./dom-tags.js");
|
|
4
5
|
const SOURCE_ATTR = source_constants_1.DATA_RETICLE_SOURCE_ATTR;
|
|
5
6
|
/**
|
|
6
7
|
* Stamps `data-reticle-source="relativeFile:line:col"` on every JSX host element (lowercase
|
|
@@ -22,9 +23,16 @@ function reticleSourcePlugin({ types: t }) {
|
|
|
22
23
|
// Host elements only (e.g. <div>, <button>) — skip components (<App />).
|
|
23
24
|
if (node.name.type !== 'JSXIdentifier')
|
|
24
25
|
return;
|
|
25
|
-
const
|
|
26
|
+
const tag = node.name.name;
|
|
27
|
+
const first = tag[0];
|
|
26
28
|
if (first === undefined || first !== first.toLowerCase())
|
|
27
29
|
return;
|
|
30
|
+
// ...and only host elements that are DOM. React is a reconciler interface, so a lowercase
|
|
31
|
+
// intrinsic can belong to react-three-fiber, react-pdf or ink, whose host instances are not
|
|
32
|
+
// nodes. R3F reads a dashed prop as a pierced property path and throws from the commit
|
|
33
|
+
// phase, which unmounts the entire app to a white screen. See dom-tags.ts.
|
|
34
|
+
if (!(0, dom_tags_js_1.isDomTag)(tag))
|
|
35
|
+
return;
|
|
28
36
|
const alreadyStamped = node.attributes.some((attr) => 'JSXAttribute' === attr.type &&
|
|
29
37
|
'JSXIdentifier' === attr.name.type &&
|
|
30
38
|
attr.name.name === SOURCE_ATTR);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reticlehq/babel-plugin",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.14.0",
|
|
4
4
|
"description": "Babel plugin that stamps data-reticle-source=\"file:line:col\" on JSX host elements so @reticlehq/react can map a DOM node to its source (works on React 19, which dropped _debugSource).",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"NOTICE"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@reticlehq/core": "2.
|
|
38
|
+
"@reticlehq/core": "2.14.0"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"@babel/core": "^7"
|