63 lines
1.9 KiB
JavaScript
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),
|
|
),
|
|
);
|
|
},
|
|
},
|
|
};
|
|
};
|