@subbly/swc-plugin-add-element-source
v0.3.0
Published
An SWC plugin to add source code location to JSX elements.
Downloads
307
Readme
@subbly/swc-plugin-add-element-source
Automatically add JSX element source information.
<!-- Before -->
<div>Hello</div>
<!-- After -->
<div
data-sbly-id="src/components/Component.tsx:16:5"
data-sbly-component-path="src/components/Component.tsx"
data-sbly-component-line="16"
data-sbly-text-kind="jsx-text"
data-sbly-text-loc="16:10"
>Hello</div>Text source attributes
When an element's children form a recognizable text source, the plugin emits
data-sbly-text-kind describing where the rendered text comes from:
| Kind | Source example |
| --- | --- |
| jsx-text | <p>Hello</p> |
| string-literal | <p>{'Hello'}</p> |
| numeric-literal | <p>{42}</p> |
| template-literal | <p>{`It's new`}</p> |
| template-expression | <p>{`Hi ${name}`}</p> |
| identifier | <p>{title}</p> |
| member-expr | <p>{item.title}</p> |
| conditional | <p>{isNew ? 'New' : 'Old'}</p> |
| call-expr | <p>{t('key')}</p> |
| mixed | <p>Hello <b>world</b></p> |
| dynamic | anything else |
For the deterministically editable kinds (jsx-text, string-literal,
numeric-literal, template-literal) the plugin also emits
data-sbly-text-loc="line:col" pointing at the literal node itself
(1-based line, 0-based column — same convention as data-sbly-id).
Rich-text containers
The plugin emits data-sbly-richtext="true" on a container whose children are
round-trippable — i.e. a mixed-children element the visual editor can rebuild
faithfully from the JSX source. Children are round-trippable when every meaningful
child is one of:
- a text run (
JSXText, or{…}wrapping a string/numeric/expression-less template literal), - an inline formatting element —
<b> <strong> <i> <em> <s> <u> <span> <a> <small> <mark> <br>with static attributes whose own children are round-trippable (recursively), or - an opaque atom — a component/icon element (
<ChevronLeft/>), a dynamic expression ({product.name},{count}, conditionals, calls), or an inline element carrying dynamic/computed attributes.
The attribute is not emitted when any child is a block-level element
(<div> <p> <ul> …), a .map() call, a JSX spread child, or a fragment, nor on
single-text-run containers (those already covered by data-sbly-text-kind).
It is also not emitted when the container has no editable text — text
either directly (a text run) or inside an inline formatting element. A container
made entirely of opaque atoms (e.g. a grid of <motion.div> cells) is not
inline-editable, so it is skipped even though its children are round-trippable.
| Example | data-sbly-richtext |
| --- | --- |
| <h1>Join us <span className="text-orange-500">today!</span></h1> | true |
| <div><ChevronLeft />Go back</div> | true |
| <span>{product.name} on sale</span> | true |
| <h3><span className="font-bold">Always</span> <span className="italic">Available</span></h3> | true (text in spans) |
| <p>Hello world</p> | — (single text run) |
| <div><p>block</p>text</div> | — (block child) |
| <ul>{items.map(i => <li>{i}</li>)}</ul> | — (.map()) |
| <div><Card /><Card /><Card /></div> | — (no editable text) |
Installation
Install as devDependency with your preferred package manager.
npm i -D @subbly/swc-plugin-add-element-sourceAdd plugin to SWC config. Here is an example how to use the plugin with Next.js
// next.config.ts
const nextConfig: NextConfig = {
experimental: {
swcPlugins: [
// Pass an empty object to satisfy SWC's API schema.
['@subbly/swc-plugin-add-element-source', {}]
]
}
};Configuration
No configuration options.
License
MIT
