lion/packages-node/babel-plugin-extend-docs/src/babelPluginExtendDocs.js

89 lines
2.9 KiB
JavaScript

/* eslint-disable no-param-reassign */
const {
renameAndStoreImports,
generateImportStatements,
replaceTagImports,
} = require('./handleImports.js');
const { validateOptions } = require('./validateOptions.js');
function replaceTemplateElements({ path, opts }) {
const replaceTag = (value, from, to) =>
value
.replace(new RegExp(`<${from}(?=\\s|>)`, 'g'), `<${to}`) // positive lookahead for '>' or ' ' after the tagName
.replace(new RegExp(`/${from}>`, 'g'), `/${to}>`);
path.node.quasi.quasis.forEach(quasi => {
opts.changes.forEach(change => {
if (change.tag && quasi.value.raw.match(change.tag.from)) {
quasi.value.raw = replaceTag(quasi.value.raw, change.tag.from, change.tag.to);
if (typeof quasi.value.cooked === 'string') {
quasi.value.cooked = replaceTag(quasi.value.cooked, change.tag.from, change.tag.to);
}
}
});
});
}
function replaceTagName(tagName, opts) {
for (const change of opts.changes) {
if (change.tag && change.tag.from === tagName) {
return change.tag.to;
}
}
return tagName;
}
function insertImportStatements({ imports, path }) {
path.node.body = [...imports, ...path.node.body];
}
module.exports = ({ types: t }) => ({
visitor: {
ImportDeclaration(path, state) {
if (path.node.specifiers.length > 0) {
renameAndStoreImports({ path, state, opts: state.opts, types: t });
} else {
replaceTagImports({ path, state, opts: state.opts, types: t });
}
},
ClassMethod(path, state) {
// replace keys (= tag names) in static get scopedElements()
if (path.node.static === true && path.node.key.name === 'scopedElements') {
if (
path.node.body.type === 'BlockStatement' &&
path.node.body.body[0].type === 'ReturnStatement'
) {
const { argument } = path.node.body.body[0];
for (const prop of argument.properties) {
prop.key.value = replaceTagName(prop.key.value, state.opts);
}
}
}
},
ClassProperty(path, state) {
// replace keys (= tag names) in scopedElements =
if (path.node.static === true && path.node.key.name === 'scopedElements') {
if (path.node.value.type === 'ObjectExpression') {
for (const prop of path.node.value.properties) {
prop.key.value = replaceTagName(prop.key.value, state.opts);
}
}
}
},
TaggedTemplateExpression(path, state) {
if (t.isIdentifier(path.node.tag) && path.node.tag.name === 'html') {
replaceTemplateElements({ path, opts: state.opts });
}
},
Program: {
enter: (path, state) => {
validateOptions(state.opts);
state.importedStorage = [];
},
exit: (path, state) => {
const imports = generateImportStatements({ state, types: t });
insertImportStatements({ imports, path });
},
},
},
});