├── .gitignore ├── README.md ├── index.js ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .vscode 3 | yarn.lock -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Babel plugin twin 2 | 3 | Total Downloads 4 | Latest Release 5 | Discord 6 | 7 | This plugin automatically adds the tw prop from [twin.macro](https://github.com/ben-rogerson/twin.macro) - no import required: 8 | 9 | ```diff 10 | - import "twin.macro" 11 | 12 | const Component = () =>
13 | ``` 14 | 15 | You’ll also get the css prop from your css-in-js library: 16 | 17 | ```diff 18 | const Component = () =>
19 | ``` 20 | 21 | ## Installation 22 | 23 | ```shell 24 | npm i -D babel-plugin-twin 25 | # or 26 | yarn add babel-plugin-twin -D 27 | ``` 28 | 29 | Then add the plugin to your babel config: 30 | 31 | ```js 32 | module.exports = { 33 | plugins: [ 34 | "babel-plugin-twin", 35 | "babel-plugin-macros", 36 | // ... 37 | ], 38 | }; 39 | ``` 40 | 41 | Note: You must add `"babel-plugin-twin"` before `"babel-plugin-macros"` in the plugins array. 42 | 43 | ## Options 44 | 45 | Add debug to your config to see some feedback: 46 | 47 | ```js 48 | module.exports = { 49 | plugins: [ 50 | ["babel-plugin-twin", { debug: true }], 51 | "babel-plugin-macros", 52 | // ... 53 | ], 54 | }; 55 | ``` 56 | 57 | To avoid checking files or folders, supply `exclude` with an array of regex patterns: 58 | 59 | ```js 60 | module.exports = { 61 | plugins: [ 62 | ["babel-plugin-twin", { 63 | "exclude": [ 64 | "temp/", 65 | "..." 66 | ] 67 | }, 68 | "babel-plugin-macros", 69 | // ... 70 | ], 71 | }; 72 | ``` 73 | 74 | ## Special thanks 75 | 76 | A big shoutout goes to [@euvs](https://github.com/euvs) for the plugin concept + code and [@mxsbr](https://github.com/mxstbr) for planting [the idea](https://github.com/ben-rogerson/twin.macro/issues/247). 77 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const template = require("@babel/template").default; 2 | 3 | const buildImport = template(` 4 | import 'twin.macro'; 5 | `); 6 | 7 | function importTwinMacroPlugin(babel) { 8 | const importDeclaration = buildImport(); 9 | 10 | return { 11 | visitor: { 12 | Program: (path, state) => { 13 | let shouldAddImport = true; 14 | const hasDebug = state.opts.debug === true; 15 | const matchedExclude = (state.opts.exclude ?? []).find((regex) => 16 | RegExp(regex).test(state.file.opts.filename) 17 | ); 18 | 19 | if (matchedExclude) { 20 | shouldAddImport = false; 21 | hasDebug && 22 | console.log( 23 | `babel-plugin-twin: Matched exclude pattern “${matchedExclude}” on “${state.file.opts.filename}”` 24 | ); 25 | } else { 26 | state.file.path.traverse({ 27 | ImportDeclaration(path) { 28 | // Find the twin import path 29 | if (path.node.source.value !== "twin.macro") return; 30 | shouldAddImport = false; 31 | }, 32 | }); 33 | } 34 | 35 | if (!shouldAddImport) { 36 | hasDebug && 37 | console.log( 38 | `babel-plugin-twin: Skipped injection in “${state.file.opts.filename}”` 39 | ); 40 | return; 41 | } 42 | 43 | hasDebug && 44 | console.log( 45 | `babel-plugin-twin: Injected import in “${state.file.opts.filename}”` 46 | ); 47 | 48 | path.unshiftContainer("body", importDeclaration); 49 | }, 50 | }, 51 | }; 52 | } 53 | 54 | module.exports = importTwinMacroPlugin; 55 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-twin", 3 | "version": "1.1.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "babel-plugin-twin", 9 | "version": "1.1.0", 10 | "license": "MIT", 11 | "dependencies": { 12 | "@babel/template": "^7.12.13" 13 | } 14 | }, 15 | "node_modules/@babel/code-frame": { 16 | "version": "7.12.13", 17 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", 18 | "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", 19 | "dependencies": { 20 | "@babel/highlight": "^7.12.13" 21 | } 22 | }, 23 | "node_modules/@babel/helper-validator-identifier": { 24 | "version": "7.12.11", 25 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", 26 | "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==" 27 | }, 28 | "node_modules/@babel/highlight": { 29 | "version": "7.12.13", 30 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz", 31 | "integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==", 32 | "dependencies": { 33 | "@babel/helper-validator-identifier": "^7.12.11", 34 | "chalk": "^2.0.0", 35 | "js-tokens": "^4.0.0" 36 | } 37 | }, 38 | "node_modules/@babel/parser": { 39 | "version": "7.12.17", 40 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.17.tgz", 41 | "integrity": "sha512-r1yKkiUTYMQ8LiEI0UcQx5ETw5dpTLn9wijn9hk6KkTtOK95FndDN10M+8/s6k/Ymlbivw0Av9q4SlgF80PtHg==", 42 | "bin": { 43 | "parser": "bin/babel-parser.js" 44 | }, 45 | "engines": { 46 | "node": ">=6.0.0" 47 | } 48 | }, 49 | "node_modules/@babel/template": { 50 | "version": "7.12.13", 51 | "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", 52 | "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", 53 | "dependencies": { 54 | "@babel/code-frame": "^7.12.13", 55 | "@babel/parser": "^7.12.13", 56 | "@babel/types": "^7.12.13" 57 | } 58 | }, 59 | "node_modules/@babel/types": { 60 | "version": "7.12.17", 61 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.17.tgz", 62 | "integrity": "sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ==", 63 | "dependencies": { 64 | "@babel/helper-validator-identifier": "^7.12.11", 65 | "lodash": "^4.17.19", 66 | "to-fast-properties": "^2.0.0" 67 | } 68 | }, 69 | "node_modules/ansi-styles": { 70 | "version": "3.2.1", 71 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 72 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 73 | "dependencies": { 74 | "color-convert": "^1.9.0" 75 | }, 76 | "engines": { 77 | "node": ">=4" 78 | } 79 | }, 80 | "node_modules/chalk": { 81 | "version": "2.4.2", 82 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 83 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 84 | "dependencies": { 85 | "ansi-styles": "^3.2.1", 86 | "escape-string-regexp": "^1.0.5", 87 | "supports-color": "^5.3.0" 88 | }, 89 | "engines": { 90 | "node": ">=4" 91 | } 92 | }, 93 | "node_modules/chalk/node_modules/escape-string-regexp": { 94 | "version": "1.0.5", 95 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 96 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 97 | "engines": { 98 | "node": ">=0.8.0" 99 | } 100 | }, 101 | "node_modules/color-convert": { 102 | "version": "1.9.3", 103 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 104 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 105 | "dependencies": { 106 | "color-name": "1.1.3" 107 | } 108 | }, 109 | "node_modules/color-name": { 110 | "version": "1.1.3", 111 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 112 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" 113 | }, 114 | "node_modules/has-flag": { 115 | "version": "3.0.0", 116 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 117 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 118 | "engines": { 119 | "node": ">=4" 120 | } 121 | }, 122 | "node_modules/js-tokens": { 123 | "version": "4.0.0", 124 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 125 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" 126 | }, 127 | "node_modules/lodash": { 128 | "version": "4.17.20", 129 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", 130 | "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" 131 | }, 132 | "node_modules/supports-color": { 133 | "version": "5.5.0", 134 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 135 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 136 | "dependencies": { 137 | "has-flag": "^3.0.0" 138 | }, 139 | "engines": { 140 | "node": ">=4" 141 | } 142 | }, 143 | "node_modules/to-fast-properties": { 144 | "version": "2.0.0", 145 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", 146 | "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", 147 | "engines": { 148 | "node": ">=4" 149 | } 150 | } 151 | }, 152 | "dependencies": { 153 | "@babel/code-frame": { 154 | "version": "7.12.13", 155 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", 156 | "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", 157 | "requires": { 158 | "@babel/highlight": "^7.12.13" 159 | } 160 | }, 161 | "@babel/helper-validator-identifier": { 162 | "version": "7.12.11", 163 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", 164 | "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==" 165 | }, 166 | "@babel/highlight": { 167 | "version": "7.12.13", 168 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz", 169 | "integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==", 170 | "requires": { 171 | "@babel/helper-validator-identifier": "^7.12.11", 172 | "chalk": "^2.0.0", 173 | "js-tokens": "^4.0.0" 174 | } 175 | }, 176 | "@babel/parser": { 177 | "version": "7.12.17", 178 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.17.tgz", 179 | "integrity": "sha512-r1yKkiUTYMQ8LiEI0UcQx5ETw5dpTLn9wijn9hk6KkTtOK95FndDN10M+8/s6k/Ymlbivw0Av9q4SlgF80PtHg==" 180 | }, 181 | "@babel/template": { 182 | "version": "7.12.13", 183 | "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", 184 | "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", 185 | "requires": { 186 | "@babel/code-frame": "^7.12.13", 187 | "@babel/parser": "^7.12.13", 188 | "@babel/types": "^7.12.13" 189 | } 190 | }, 191 | "@babel/types": { 192 | "version": "7.12.17", 193 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.17.tgz", 194 | "integrity": "sha512-tNMDjcv/4DIcHxErTgwB9q2ZcYyN0sUfgGKUK/mm1FJK7Wz+KstoEekxrl/tBiNDgLK1HGi+sppj1An/1DR4fQ==", 195 | "requires": { 196 | "@babel/helper-validator-identifier": "^7.12.11", 197 | "lodash": "^4.17.19", 198 | "to-fast-properties": "^2.0.0" 199 | } 200 | }, 201 | "ansi-styles": { 202 | "version": "3.2.1", 203 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 204 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 205 | "requires": { 206 | "color-convert": "^1.9.0" 207 | } 208 | }, 209 | "chalk": { 210 | "version": "2.4.2", 211 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 212 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 213 | "requires": { 214 | "ansi-styles": "^3.2.1", 215 | "escape-string-regexp": "^1.0.5", 216 | "supports-color": "^5.3.0" 217 | }, 218 | "dependencies": { 219 | "escape-string-regexp": { 220 | "version": "1.0.5", 221 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 222 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" 223 | } 224 | } 225 | }, 226 | "color-convert": { 227 | "version": "1.9.3", 228 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 229 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 230 | "requires": { 231 | "color-name": "1.1.3" 232 | } 233 | }, 234 | "color-name": { 235 | "version": "1.1.3", 236 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 237 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" 238 | }, 239 | "has-flag": { 240 | "version": "3.0.0", 241 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 242 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" 243 | }, 244 | "js-tokens": { 245 | "version": "4.0.0", 246 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 247 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" 248 | }, 249 | "lodash": { 250 | "version": "4.17.20", 251 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", 252 | "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" 253 | }, 254 | "supports-color": { 255 | "version": "5.5.0", 256 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 257 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 258 | "requires": { 259 | "has-flag": "^3.0.0" 260 | } 261 | }, 262 | "to-fast-properties": { 263 | "version": "2.0.0", 264 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", 265 | "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" 266 | } 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-twin", 3 | "version": "1.1.0", 4 | "description": "", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/ben-rogerson/babel-plugin-twin.git" 9 | }, 10 | "files": [ 11 | "index.js" 12 | ], 13 | "keywords": [], 14 | "author": "Evgeny V and Ben Rogerson ", 15 | "license": "MIT", 16 | "bugs": { 17 | "url": "https://github.com/ben-rogerson/babel-plugin-twin/issues" 18 | }, 19 | "homepage": "https://github.com/ben-rogerson/babel-plugin-twin#readme", 20 | "dependencies": { 21 | "@babel/template": "^7.12.13" 22 | } 23 | } 24 | --------------------------------------------------------------------------------