-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
85 lines (75 loc) · 2.21 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/**
* @typedef {import('./index.js').Predicate} Predicate
* @typedef {import('@babel/core').types} types
* @typedef {import('@babel/core').types.MemberExpression} MemberExpression
* @typedef {import('@babel/core').types.JSXMemberExpression} JSXMemberExpression
* @typedef {import('@babel/core').types.JSXIdentifier} JSXIdentifier
*/
/**
* @type {import('./index.js').default}
*/
export default function babelPluginSolidMdx(ctx) {
const t = /** @type {types} */ (ctx.types);
return {
visitor: {
Program(path, state) {
const extensions = /** @type {Predicate[]} */ (
'extensions' in state.opts ? state.opts.extensions : /[.]mdx?$/
);
if (!state.filename || !predicate(state.filename, extensions)) {
return;
}
path.traverse({
JSXOpeningElement(path) {
const { node } = path;
if (t.isJSXMemberExpression(node.name)) {
const component = t.jsxAttribute(
t.jsxIdentifier('component'),
t.jsxExpressionContainer(toMemberExpression(node.name)),
);
const attributes = [component, ...node.attributes];
const dynamic = t.jsxOpeningElement(
t.jsxIdentifier('Dynamic'),
attributes,
);
path.replaceWith(dynamic);
}
},
});
},
},
};
/**
* @param {JSXMemberExpression} expr
* @returns {MemberExpression}
*/
function toMemberExpression(expr) {
return t.memberExpression(
expr.object.type === 'JSXIdentifier'
? toIdentifier(expr.object)
: toMemberExpression(expr.object),
toIdentifier(expr.property),
);
}
/**
* @param {JSXIdentifier} expr
*/
function toIdentifier(expr) {
return t.identifier(expr.name);
}
}
/**
* @param {string} filename
* @param {Predicate} pred
*/
function predicate(filename, pred) {
if (typeof pred === 'function') {
return pred(filename);
} else if (Array.isArray(pred)) {
return pred.some((pred) => predicate(filename, pred));
} else if (pred instanceof RegExp) {
return pred.test(filename);
} else {
return filename.endsWith(String(pred));
}
}