Files
f780f31b-fa13-43fb-a74a-208…/vite-plugins/babel-plugin-webild-source.cjs
Nikolay Pecheniev a835343280 Initial commit
2026-04-27 18:07:16 +03:00

63 lines
1.9 KiB
JavaScript

/**
* Injects data-webild-source="relative/path.tsx:line:column" on every JSX opening element
* for visual-edit targeting (stable source location in generated DOM).
*/
const path = require('path');
module.exports = function babelPluginWebildSource(api) {
const { types: t } = api;
return {
name: 'babel-plugin-webild-source',
visitor: {
JSXOpeningElement(openPath, state) {
const opts = state.opts || {};
const rootDir = opts.rootDir ? path.resolve(opts.rootDir) : process.cwd();
const nameNode = openPath.node.name;
if (t.isJSXIdentifier(nameNode) && nameNode.name === 'Fragment') {
return;
}
if (t.isJSXMemberExpression(nameNode)) {
if (
t.isJSXIdentifier(nameNode.property) &&
nameNode.property.name === 'Fragment'
) {
return;
}
}
const hasAttr = openPath.node.attributes.some((attr) => {
if (!t.isJSXAttribute(attr)) return false;
if (!t.isJSXIdentifier(attr.name)) return false;
return attr.name.name === 'data-webild-source';
});
if (hasAttr) return;
const file = openPath.hub.file;
const filename = file.opts.filename || file.opts.sourceFileName;
if (!filename || filename.includes('node_modules')) return;
let rel = path.relative(rootDir, filename);
if (rel.startsWith('..')) return;
rel = rel.split(path.sep).join('/');
const loc = openPath.node.loc?.start;
if (!loc) return;
const line = loc.line;
const column = loc.column + 1;
const sourceValue = `${rel}:${line}:${column}`;
openPath.node.attributes.push(
t.jsxAttribute(
t.jsxIdentifier('data-webild-source'),
t.stringLiteral(sourceValue),
),
);
},
},
};
};