|
| 1 | +import * as acorn from "acorn"; |
| 2 | +import * as walk from "acorn-walk"; |
| 3 | +import jsx from "acorn-jsx"; |
| 4 | +import {extend} from "acorn-jsx-walk"; |
| 5 | + |
| 6 | +extend(walk.base); |
| 7 | + |
| 8 | +function purgeFromJsx(options: acorn.Options) { |
| 9 | + return (content: string): string[] => { |
| 10 | + // Will be filled during walk |
| 11 | + const state = {selectors: []}; |
| 12 | + |
| 13 | + // Parse and walk any JSXElement |
| 14 | + walk.recursive( |
| 15 | + acorn.Parser.extend(jsx()).parse(content, options), |
| 16 | + state, |
| 17 | + { |
| 18 | + JSXOpeningElement(node: any, state: any, callback) { |
| 19 | + // JSXIdentifier | JSXMemberExpression | JSXNamespacedName |
| 20 | + const nameState: any = {}; |
| 21 | + callback(node.name, nameState); |
| 22 | + if (nameState.text) { |
| 23 | + state.selectors.push(nameState.text); |
| 24 | + } |
| 25 | + |
| 26 | + for (let i = 0; i < node.attributes.length; ++i) { |
| 27 | + callback(node.attributes[i], state); |
| 28 | + } |
| 29 | + }, |
| 30 | + JSXAttribute(node: any, state: any, callback) { |
| 31 | + // Literal | JSXExpressionContainer | JSXElement | nil |
| 32 | + if (!node.value) { |
| 33 | + return; |
| 34 | + } |
| 35 | + |
| 36 | + // JSXIdentifier | JSXNamespacedName |
| 37 | + const nameState: any = {}; |
| 38 | + callback(node.name, nameState); |
| 39 | + |
| 40 | + // node.name is id or className |
| 41 | + switch (nameState.text) { |
| 42 | + case "id": |
| 43 | + case "className": |
| 44 | + { |
| 45 | + // Get text in node.value |
| 46 | + const valueState: any = {}; |
| 47 | + callback(node.value, valueState); |
| 48 | + |
| 49 | + // node.value is not empty |
| 50 | + if (valueState.text) { |
| 51 | + state.selectors.push(...valueState.text.split(" ")); |
| 52 | + } |
| 53 | + } |
| 54 | + break; |
| 55 | + default: |
| 56 | + break; |
| 57 | + } |
| 58 | + }, |
| 59 | + JSXIdentifier(node: any, state: any) { |
| 60 | + state.text = node.name; |
| 61 | + }, |
| 62 | + JSXNamespacedName(node: any, state: any) { |
| 63 | + state.text = node.namespace.name + ":" + node.name.name; |
| 64 | + }, |
| 65 | + // Only handle Literal for now, not JSXExpressionContainer | JSXElement |
| 66 | + Literal(node: any, state: any) { |
| 67 | + if (typeof node.value === "string") { |
| 68 | + state.text = node.value; |
| 69 | + } |
| 70 | + } |
| 71 | + }, |
| 72 | + {...walk.base} |
| 73 | + ); |
| 74 | + |
| 75 | + return state.selectors; |
| 76 | + }; |
| 77 | +} |
| 78 | + |
| 79 | +export default purgeFromJsx; |
0 commit comments