| 102 | * @return {Root|Document} |
| 103 | */ |
| 104 | export const parse: Parser<Root | Document> = ( |
| 105 | source: string | { toString(): string }, |
| 106 | opts?: Pick<ProcessOptions, 'map' | 'from'> |
| 107 | ): Root | Document => { |
| 108 | const doc = new Document(); |
| 109 | const sourceAsString = source.toString(); |
| 110 | |
| 111 | // avoid error spam (and vscode error toasts) if babel can't parse doc |
| 112 | // allows user to type new code without constant warnings |
| 113 | let ast; |
| 114 | try { |
| 115 | ast = babelParse(sourceAsString, { |
| 116 | sourceType: 'unambiguous', |
| 117 | plugins: ['typescript', 'jsx'], |
| 118 | ranges: true, |
| 119 | }); |
| 120 | } catch { |
| 121 | return doc; |
| 122 | } |
| 123 | const extractedStyles = new Set<TaggedTemplateExpression>(); |
| 124 | |
| 125 | traverse(ast, { |
| 126 | TaggedTemplateExpression: ( |
| 127 | path: NodePath<TaggedTemplateExpression> |
| 128 | ): void => { |
| 129 | if ( |
| 130 | path.node.tag.type === 'Identifier' && |
| 131 | path.node.tag.name.includes('css') |
| 132 | ) { |
| 133 | extractedStyles.add(path.node); |
| 134 | } |
| 135 | |
| 136 | if (path.node.tag.type === 'MemberExpression') { |
| 137 | if ((path.node.tag.object as Identifier).name === 'styled') { |
| 138 | extractedStyles.add(path.node); |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | if ( |
| 143 | path.node.tag.type === 'CallExpression' && |
| 144 | path.node.tag.callee.type === 'Identifier' |
| 145 | ) { |
| 146 | if (path.node.tag.callee.name === 'styled') { |
| 147 | extractedStyles.add(path.node); |
| 148 | } |
| 149 | } |
| 150 | }, |
| 151 | }); |
| 152 | |
| 153 | let currentOffset = 0; |
| 154 | |
| 155 | // eslint-disable-next-line no-restricted-syntax |
| 156 | for (const node of extractedStyles) { |
| 157 | if (!node.quasi.range) { |
| 158 | // eslint-disable-next-line no-continue |
| 159 | continue; |
| 160 | } |
| 161 | |