├── .babelrc
├── .eslintrc
├── .github
└── workflows
│ ├── node-pretest.yml
│ ├── node.yml
│ ├── rebase.yml
│ └── require-allow-edits.yml
├── .gitignore
├── .npmrc
├── CHANGELOG.md
├── LICENSE
├── README.md
├── package.json
├── src
├── camelize.js
├── cssToObj.js
├── escapeBraces.js
├── fileExistsWithCaseSync.js
├── index.js
├── optimize.js
└── transformSvg.js
└── test
├── fixtures
├── close-a.svg
├── close.svg
├── close2.svg
├── commented-6.svg
├── commented.svg
├── root-styled.svg
├── test-case-sensitive.jsx
├── test-commented-6.jsx
├── test-commented.jsx
├── test-dynamic-require.jsx
├── test-export-all-as.jsx
├── test-export-default-as.jsx
├── test-export-default.jsx
├── test-import-read-file.jsx
├── test-import.jsx
├── test-multiple-svg.jsx
├── test-no-duplicate-react.jsx
├── test-no-react.jsx
├── test-no-svg-or-react.js
├── test-require.jsx
└── test-root-styled.jsx
└── sanity.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["airbnb"]
3 | }
4 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 |
4 | "root": true,
5 |
6 | "ignorePatterns": [
7 | "lib/",
8 | ],
9 |
10 | "overrides": [
11 | {
12 | "files": "test/**",
13 | "rules": {
14 | "no-console": "off",
15 | },
16 | },
17 | {
18 | "files": "test/fixtures/**",
19 | "rules": {
20 | "import/extensions": "off",
21 | "import/no-unresolved": "off",
22 | },
23 | },
24 | ],
25 | }
26 |
--------------------------------------------------------------------------------
/.github/workflows/node-pretest.yml:
--------------------------------------------------------------------------------
1 | name: 'Tests: pretest/posttest'
2 |
3 | on: [pull_request, push]
4 |
5 | jobs:
6 | pretest:
7 | runs-on: ubuntu-latest
8 |
9 | steps:
10 | - uses: actions/checkout@v2
11 | - uses: ljharb/actions/node/install@main
12 | name: 'nvm install lts/* && npm install'
13 | with:
14 | node-version: 'lts/*'
15 | - run: npm run pretest
16 |
17 | posttest:
18 | runs-on: ubuntu-latest
19 |
20 | steps:
21 | - uses: actions/checkout@v2
22 | - uses: ljharb/actions/node/install@main
23 | name: 'nvm install lts/* && npm install'
24 | with:
25 | node-version: 'lts/*'
26 | - run: npm run posttest
27 |
--------------------------------------------------------------------------------
/.github/workflows/node.yml:
--------------------------------------------------------------------------------
1 | name: 'Tests: node.js'
2 |
3 | on: [pull_request, push]
4 |
5 | jobs:
6 | matrix:
7 | runs-on: ubuntu-latest
8 | outputs:
9 | latest: ${{ steps.set-matrix.outputs.requireds }}
10 | steps:
11 | - uses: ljharb/actions/node/matrix@main
12 | id: set-matrix
13 | with:
14 | versionsAsRoot: true
15 | type: 'majors'
16 | preset: '10.13 || >=10.13'
17 |
18 | test:
19 | needs: [matrix]
20 | name: 'latest majors'
21 | runs-on: ubuntu-latest
22 |
23 | strategy:
24 | fail-fast: false
25 | matrix:
26 | node-version: ${{ fromJson(needs.matrix.outputs.latest) }}
27 |
28 | steps:
29 | - uses: actions/checkout@v3
30 | - uses: ljharb/actions/node/install@main
31 | name: 'nvm install ${{ matrix.node-version }} && npm install'
32 | with:
33 | node-version: ${{ matrix.node-version }}
34 | skip-ls-check: true
35 | - run: npm run tests-only
36 | - uses: codecov/codecov-action@v1
37 |
38 | node:
39 | name: 'node.js'
40 | needs: [test]
41 | runs-on: ubuntu-latest
42 | steps:
43 | - run: 'echo tests completed'
44 |
--------------------------------------------------------------------------------
/.github/workflows/rebase.yml:
--------------------------------------------------------------------------------
1 | name: Automatic Rebase
2 |
3 | on: [pull_request_target]
4 |
5 | jobs:
6 | _:
7 | name: "Automatic Rebase"
8 |
9 | runs-on: ubuntu-latest
10 |
11 | steps:
12 | - uses: actions/checkout@v2
13 | - uses: ljharb/rebase@master
14 | env:
15 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
16 |
--------------------------------------------------------------------------------
/.github/workflows/require-allow-edits.yml:
--------------------------------------------------------------------------------
1 | name: Require “Allow Edits”
2 |
3 | on: [pull_request_target]
4 |
5 | jobs:
6 | _:
7 | name: "Require “Allow Edits”"
8 |
9 | runs-on: ubuntu-latest
10 |
11 | steps:
12 | - uses: ljharb/require-allow-edits@main
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # gitignore
2 | node_modules
3 | lib
4 |
5 | # Only apps should have lockfiles
6 | npm-shrinkwrap.json
7 | package-lock.json
8 | yarn.lock
9 |
10 | .npmignore
11 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
2 | allow-same-version=true
3 | message=v%s
4 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7 |
8 | ## [v2.0.2](https://github.com/airbnb/babel-plugin-inline-react-svg/compare/v2.0.1...v2.0.2) - 2023-02-22
9 |
10 | ### Merged
11 |
12 | - [actions] make a "summary" job, to require for protected branches [`#120`](https://github.com/airbnb/babel-plugin-inline-react-svg/pull/120)
13 | - Tweak some formatting in readme [`#119`](https://github.com/airbnb/babel-plugin-inline-react-svg/pull/119)
14 | - migrate from travis to github actions [`#117`](https://github.com/airbnb/babel-plugin-inline-react-svg/pull/117)
15 |
16 | ### Fixed
17 |
18 | - [Fix] Register export declaration in scope [`#74`](https://github.com/airbnb/babel-plugin-inline-react-svg/issues/74)
19 |
20 | ### Commits
21 |
22 | - [meta] add `auto-changelog` [`0137651`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/0137651421d95db064157f13cc7ac96a2506cfeb)
23 | - [Tests] migrate from travis to github actions [`63611b5`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/63611b5524c5a8cc97d5a21de0ffab86e5627d95)
24 | - [Dev Deps] update `@babel/cli`, `@babel/node`, `@babel/preset-react`, `eslint`, `eslint-config-airbnb`, `eslint-plugin-import`, `eslint-plugin-jsx-a11y`, `eslint-plugin-react` [`b839b94`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/b839b94cb0341da187b2220b69bacb664e5e6891)
25 | - [readme] Update svgo configuration example [`e37c29b`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/e37c29bbea03d8cfcb12503c4924662c7fc1f286)
26 | - [Fix] Fix crash when svg has a style tag in the root element; pass path to SVGO [`a4c1c4c`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/a4c1c4c5d11b088185f8ccc603ac00c352bde45b)
27 | - [meta] use `npmignore` to autogenerate an npmignore file [`aeb3ddf`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/aeb3ddff9cf66927f96226543ac2c5868be23271)
28 | - [Deps] update `resolve`, `svgo` [`b29d6a6`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/b29d6a64de7ffc8f29e91c16e4d7f15044367930)
29 | - [meta] add `safe-publish-latest` and use `prepublishOnly` [`982144b`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/982144bce6bb749885e2d898aa16dc515936a3c2)
30 | - [Dev Deps] update `@babel/cli`, `@babel/plugin-transform-typescript` [`815bb4a`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/815bb4a466c03bce4d9cc6a2b3310fa99fa54d6c)
31 |
32 | ## [v2.0.1](https://github.com/airbnb/babel-plugin-inline-react-svg/compare/v2.0.0...v2.0.1) - 2021-02-23
33 |
34 | ### Commits
35 |
36 | - [Fix] Fix crash when SVGO is turned off [`b8fb637`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/b8fb6377358e132748ad7c62f73226d4d519ccb8)
37 | - [Deps] update `svgo` [`7471408`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/7471408459cf54ec023c8398d85e4d70b11d22e0)
38 |
39 | ## [v2.0.0](https://github.com/airbnb/babel-plugin-inline-react-svg/compare/1.1.2...v2.0.0) - 2021-02-18
40 |
41 | ### Fixed
42 |
43 | - [Tests] add passing test [`#89`](https://github.com/airbnb/babel-plugin-inline-react-svg/issues/89)
44 |
45 | ### Commits
46 |
47 | - [Breaking] update `svgo` to v2; drop node < v10.13 [`90eeedd`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/90eeedda0bf1b380de35d5eb57e2443f1e4987f9)
48 | - [Dev Deps] update `@babel/cli`, `@babel/node`, `@babel/preset-react`, `babel-preset-airbnb`, `eslint`, `eslint-config-airbnb`, `eslint-plugin-import`, `eslint-plugin-jsx-a11y`, `eslint-plugin-react` [`4ed41be`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/4ed41be81dc23ec5ea940225a07b250d17eb40f4)
49 | - [Dev Deps] update `@babel/cli`, `@babel/node`, `@babel/preset-react`, `eslint` [`0b2b119`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/0b2b1191eeeecaa8aef36141a2d8e236aa3bd1b6)
50 | - [Deps] update `resolve` [`c7ae6fd`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/c7ae6fdb9de0bb3c9002d3f5af10d97607ab3222)
51 | - [Deps] update `resolve` [`ca99a79`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/ca99a799a55f8e3dcd4d72852ed5e5a1a996decb)
52 |
53 | ## [1.1.2](https://github.com/airbnb/babel-plugin-inline-react-svg/compare/v1.1.2...1.1.2) - 2020-10-30
54 |
55 | ## [v1.1.2](https://github.com/airbnb/babel-plugin-inline-react-svg/compare/v1.1.1...v1.1.2) - 2021-01-07
56 |
57 | ### Merged
58 |
59 | - Fix crash when export declaration has no local property [`#93`](https://github.com/airbnb/babel-plugin-inline-react-svg/pull/93)
60 |
61 | ### Fixed
62 |
63 | - Fix crash on `export * as foo from "bar"` [`#92`](https://github.com/airbnb/babel-plugin-inline-react-svg/issues/92)
64 |
65 | ### Commits
66 |
67 | - Add failing test for export * as foo from bar [`3fbe8bf`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/3fbe8bf308af7c0df6162093df664da5e766d6de)
68 |
69 | ## [v1.1.1](https://github.com/airbnb/babel-plugin-inline-react-svg/compare/v1.1.0...v1.1.1) - 2020-01-21
70 |
71 | ### Merged
72 |
73 | - [Fix] Register module binding [`#68`](https://github.com/airbnb/babel-plugin-inline-react-svg/pull/68)
74 |
75 | ### Commits
76 |
77 | - Register Module Binding [`266d26a`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/266d26ac514fea3a3cd69eb98c9ce292a3a477b0)
78 |
79 | ## [v1.1.0](https://github.com/airbnb/babel-plugin-inline-react-svg/compare/v1.0.1...v1.1.0) - 2019-04-09
80 |
81 | ### Commits
82 |
83 | - [New] Add support for export default from [`4ed020e`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/4ed020eb9ee2b4784e233a202cdd73076be49974)
84 | - add MIT license file [`a39dfa5`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/a39dfa517563e3b30c631da1bdeba487c6bd21ae)
85 | - [Dev Deps] update `@babel/cli`, `@babel/node`, `babel-preset-airbnb`, `eslint`, `eslint-plugin-import`, `eslint-plugin-jsx-a11y`, `eslint-plugin-react` [`6b39561`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/6b39561f6e608dedd529e884e7491d26b6361648)
86 | - [Deps] update `resolve` [`5e7bb85`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/5e7bb8582e9b50ca5f50424014c9af9fb29198c9)
87 |
88 | ## [v1.0.1](https://github.com/airbnb/babel-plugin-inline-react-svg/compare/v1.0.0...v1.0.1) - 2018-10-22
89 |
90 | ### Merged
91 |
92 | - Fix transforming via API [`#53`](https://github.com/airbnb/babel-plugin-inline-react-svg/pull/53)
93 |
94 | ### Fixed
95 |
96 | - Merge pull request #53 from airbnb/svg_api [`#52`](https://github.com/airbnb/babel-plugin-inline-react-svg/issues/52)
97 | - [Fix] require "filename" option when transforming code [`#52`](https://github.com/airbnb/babel-plugin-inline-react-svg/issues/52)
98 |
99 | ### Commits
100 |
101 | - Add failing test case. [`1525b2e`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/1525b2e409fb5d5b07ca63d2b276d664693c4fef)
102 | - [Dev Deps] update to eslint 5 [`c4fe318`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/c4fe31830abc4143a02c27d075fdaccca6c85162)
103 |
104 | ## [v1.0.0](https://github.com/airbnb/babel-plugin-inline-react-svg/compare/v0.5.4...v1.0.0) - 2018-10-09
105 |
106 | ### Merged
107 |
108 | - [Breaking] Upgrade to babel 7 [`#48`](https://github.com/airbnb/babel-plugin-inline-react-svg/pull/48)
109 |
110 | ### Commits
111 |
112 | - [Refactor] no need to directly depend on babel-template or babel-traverse [`7665543`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/7665543a459045a1e295a34ef6be8fdde57a3b73)
113 | - [Breaking] drop support of node < 6, per babel 7 [`143e8b1`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/143e8b1624dc37d7b60278c16aaed9ea52543c3c)
114 | - Switch to single quotes with curly tick [`83cae6f`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/83cae6fd43f1c297516bc12043c4edb78d7e4dfb)
115 |
116 | ## [v0.5.4](https://github.com/airbnb/babel-plugin-inline-react-svg/compare/v0.5.3...v0.5.4) - 2018-07-20
117 |
118 | ### Fixed
119 |
120 | - [Fix] do not crash on dynamic requires [`#47`](https://github.com/airbnb/babel-plugin-inline-react-svg/issues/47)
121 |
122 | ## [v0.5.3](https://github.com/airbnb/babel-plugin-inline-react-svg/compare/v0.5.2...v0.5.3) - 2018-06-25
123 |
124 | ### Merged
125 |
126 | - [Fix] throw a better error if no svg is found; add tests for multiple SVGs. [`#39`](https://github.com/airbnb/babel-plugin-inline-react-svg/pull/39)
127 | - fix CloseSVG typo in readme [`#37`](https://github.com/airbnb/babel-plugin-inline-react-svg/pull/37)
128 |
129 | ### Commits
130 |
131 | - [New] add support for `require` [`512996e`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/512996e6652dfd1e1de38e6af1bd7bd6408c9045)
132 | - [Dev Deps] update `babel-cli`, `babel-core`, `babel-preset-airbnb`, `eslint`, `eslint-config-airbnb`, `eslint-plugin-import`, `eslint-plugin-jsx-a11y`, `eslint-plugin-react` [`7dc34fa`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/7dc34fa762441265712b4ca98f51963904ea57c9)
133 | - [Tests] add failing tests for multiple React imports [`f380c66`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/f380c664b47c76e062091eadd5e9347517e31d3c)
134 | - [Tests] skip case-sensitive check when on a case-sensitive filesystem [`8f7f42b`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/8f7f42b6006fae4b223a055b9caf73cfb613e67b)
135 | - [Refactor] reduce repeated object lookups [`f9d9613`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/f9d9613d75874c4134145ae4e9374e52b9b4fecd)
136 | - [Tests] add travis [`b6bb7d4`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/b6bb7d4545026ac70aba5dcc67c13f7307814e40)
137 | - [fix] fix linting errors [`49fcb09`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/49fcb09d1e4d4eb59ccce79bbc3affaed9980324)
138 | - Fix invalid JS issue for data attr and cater for aria-* (#33) [`6052866`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/6052866e3888e151cf0dae4ef0cbe470a9b3259f)
139 | - [Dev Deps] update `babel-preset-airbnb`, `eslint-config-airbnb`, `eslint-plugin-import`, `eslint-plugin-react` [`52533c8`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/52533c8c2b474736dd7b471fa17eed2fc7f356d0)
140 | - [Deps] update `babel-template`, `babel-traverse`, `babylon`, `svgo` [`0c5dcdb`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/0c5dcdbf06243c9e0c0408bd7ceda9e7bdeea6a5)
141 | - [Tests] add test scripts [`acf96e2`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/acf96e2a38a022f965fecd291105b778f1c8625f)
142 | - Only apps should have lockfiles [`6b39b21`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/6b39b21cf640303d46e83c2f3326edf840d086e3)
143 | - [Refactor] use `resolve` instead of `resolve-from` [`2696b6b`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/2696b6b0c47625d53203ca42057a2e3a5ea0c62d)
144 | - [Fix] throw a better error if no svg is found [`157bbf0`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/157bbf00db60a15e13e495e7c737c930eaa91273)
145 | - [Fix] ensure that a React import is only added once [`f022c45`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/f022c4560b4584b423cbc6acfcdbbb1efb8d50c4)
146 |
147 | ## [v0.5.2](https://github.com/airbnb/babel-plugin-inline-react-svg/compare/v0.5.1...v0.5.2) - 2017-11-09
148 |
149 | ### Merged
150 |
151 | - [Fix] Only ensure a React import when there’s an svg import in the file. [`#32`](https://github.com/airbnb/babel-plugin-inline-react-svg/pull/32)
152 |
153 | ## [v0.5.1](https://github.com/airbnb/babel-plugin-inline-react-svg/compare/v0.5.0...v0.5.1) - 2017-11-05
154 |
155 | ### Commits
156 |
157 | - Fixing issue with react not trigger module transform [`efe3805`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/efe38059559cf49800f60a87597c15486b25481a)
158 |
159 | ## [v0.5.0](https://github.com/airbnb/babel-plugin-inline-react-svg/compare/v0.4.0...v0.5.0) - 2017-11-05
160 |
161 | ### Merged
162 |
163 | - Add react import [`#29`](https://github.com/airbnb/babel-plugin-inline-react-svg/pull/29)
164 | - Use defaultProps instead of adding props to the svg [`#8`](https://github.com/airbnb/babel-plugin-inline-react-svg/pull/8)
165 | - Implement case-sensitivity check [`#20`](https://github.com/airbnb/babel-plugin-inline-react-svg/pull/20)
166 | - Support data-* attributes [`#22`](https://github.com/airbnb/babel-plugin-inline-react-svg/pull/22)
167 | - Add option to disable optimization. [`#15`](https://github.com/airbnb/babel-plugin-inline-react-svg/pull/15)
168 | - Fix typo in svgo options example in docs [`#11`](https://github.com/airbnb/babel-plugin-inline-react-svg/pull/11)
169 |
170 | ### Fixed
171 |
172 | - [Fix] Add a React import if no React binding exists. [`#24`](https://github.com/airbnb/babel-plugin-inline-react-svg/issues/24)
173 | - Add option to disable optimization. closes #10 [`#10`](https://github.com/airbnb/babel-plugin-inline-react-svg/issues/10)
174 | - Use defaultProps instead of adding props to the svg [`#7`](https://github.com/airbnb/babel-plugin-inline-react-svg/issues/7)
175 |
176 | ### Commits
177 |
178 | - [Tests] minimally transform; add filename to output. [`301681c`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/301681cbfb6ba732ecd6f66ec4de5fd0e94727d3)
179 | - #10 fix bugs and formatting. [`6b6181f`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/6b6181f5fe7b9c28649306d60b7ace7e78beb454)
180 | - #10 update readme [`6b080dc`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/6b080dca6740f3997cbf2d2192dfc0c11f802e8c)
181 |
182 | ## [v0.4.0](https://github.com/airbnb/babel-plugin-inline-react-svg/compare/v0.3.1...v0.4.0) - 2017-03-20
183 |
184 | ### Merged
185 |
186 | - Added svgo options [`#5`](https://github.com/airbnb/babel-plugin-inline-react-svg/pull/5)
187 |
188 | ## [v0.3.1](https://github.com/airbnb/babel-plugin-inline-react-svg/compare/v0.3.0...v0.3.1) - 2017-03-06
189 |
190 | ### Merged
191 |
192 | - Escaping curly braces of SVG's [`#3`](https://github.com/airbnb/babel-plugin-inline-react-svg/pull/3)
193 |
194 | ### Commits
195 |
196 | - escaping curly braces before parsing as JSX [`24e3bef`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/24e3bef2330a1fe651c0a20a3d3bdea81aaf1a91)
197 | - changing names, to avoid confusion/deprecation [`8d17c63`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/8d17c6345764d106ec9fc1f4240688cc716c1cc6)
198 | - reverted version bump [`ceb8968`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/ceb896852f1a0ea012446423aaa62fbdc1b10262)
199 |
200 | ## [v0.3.0](https://github.com/airbnb/babel-plugin-inline-react-svg/compare/v0.2.0...v0.3.0) - 2017-03-06
201 |
202 | ### Merged
203 |
204 | - Add support for .svg paths from 3rd party packages [`#2`](https://github.com/airbnb/babel-plugin-inline-react-svg/pull/2)
205 |
206 | ### Commits
207 |
208 | - Adding docs for the options [`3da7129`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/3da712960d2fe963e209d2cc20e808782b5e2783)
209 |
210 | ## [v0.2.0](https://github.com/airbnb/babel-plugin-inline-react-svg/compare/v0.1.2...v0.2.0) - 2016-09-19
211 |
212 | ### Commits
213 |
214 | - Adding ignorePattern to allow selectively disabling the plugin [`b53fa56`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/b53fa5648e4549a0fb161887e98065bd259b9b9a)
215 |
216 | ## [v0.1.2](https://github.com/airbnb/babel-plugin-inline-react-svg/compare/v0.1.1...v0.1.2) - 2016-09-19
217 |
218 | ### Commits
219 |
220 | - Fixing svg resolution in projects [`0c60955`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/0c609557a5ad37b9c9ed822847dde1955f4b2081)
221 |
222 | ## v0.1.1 - 2016-09-19
223 |
224 | ### Commits
225 |
226 | - First version [`fea1021`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/fea102160b823e3d79b30292c4a406e24256e7a7)
227 | - Better readme [`c8f9e46`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/c8f9e46d862a4594c12022ff40b5b12d2bd54b82)
228 | - svgo isn't really async [`3bb94bc`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/3bb94bca3a0255f609293b9233147118d132ecac)
229 | - More readme cleanu [`d2548c5`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/d2548c5f0ca25a6bda45214053c86686db027634)
230 | - adding npm ignore [`18c6c14`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/18c6c146a2cb37797d80fbcf6f3ec707122f3cce)
231 | - first commit [`15e011a`](https://github.com/airbnb/babel-plugin-inline-react-svg/commit/15e011a6a57060d79a252acd7fa67872437e9c5d)
232 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Jordan Harband
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # babel-plugin-inline-react-svg
2 |
3 | Transforms imports to SVG files into React Components, and optimizes the SVGs with [SVGO](https://github.com/svg/svgo/).
4 |
5 | For example, the following code...
6 |
7 | ```jsx
8 | import React from 'react';
9 | import CloseSVG from './close.svg';
10 |
11 | const MyComponent = () => ;
12 | ```
13 |
14 | will be transformed into...
15 |
16 | ```jsx
17 | import React from 'react';
18 | const CloseSVG = () => ;
19 |
20 | const MyComponent = () => ;
21 | ```
22 |
23 | ## Installation
24 |
25 | ```
26 | npm install --save-dev babel-plugin-inline-react-svg
27 | ```
28 |
29 | ## Usage
30 |
31 | ### Via `.babelrc` (Recommended)
32 |
33 | **.babelrc**
34 |
35 | ```json
36 | {
37 | "plugins": [
38 | "inline-react-svg"
39 | ]
40 | }
41 | ```
42 |
43 | #### Options
44 |
45 | - `ignorePattern` - A pattern that imports will be tested against to selectively ignore imports.
46 | - `caseSensitive` - A boolean value that if true will require file paths to match with case-sensitivity. Useful to ensure consistent behavior if working on both a case-sensitive operating system like Linux and a case-insensitive one like OS X or Windows.
47 | - `svgo` - svgo options (`false` to disable). Example:
48 | ```json
49 | {
50 | "plugins": [
51 | [
52 | "inline-react-svg",
53 | {
54 | "svgo": {
55 | "plugins": [
56 | {
57 | "name": "removeAttrs",
58 | "params": { "attrs": "(data-name)" }
59 | },
60 | "cleanupIDs"
61 | ]
62 | }
63 | }
64 | ]
65 | ]
66 | }
67 |
68 | ```
69 |
70 | **Note:** If `plugins` field is specified the default enabled `svgo` plugins will be overrided. Alternatively, if your Babel config is in JavaScript, the default list of plugins can be extended by making use of the `extendDefaultPlugins` utility provided by `svgo`.
71 |
72 | ```js
73 | const { extendDefaultPlugins } = require('svgo');
74 |
75 | module.exports = {
76 | plugins: [
77 | [
78 | 'inline-react-svg',
79 | {
80 | svgo: {
81 | plugins: extendDefaultPlugins([
82 | {
83 | name: 'removeAttrs',
84 | params: { attrs: '(data-name)' }
85 | },
86 | 'cleanupIDs',
87 | ])
88 | }
89 | }
90 | ]
91 | ]
92 | }
93 | ```
94 |
95 | ### Via CLI
96 |
97 | ```sh
98 | $ babel --plugins inline-react-svg script.js
99 | ```
100 |
101 | ### Via Node API
102 |
103 |
104 | ```javascript
105 | require('@babel/core').transform('code', {
106 | plugins: [
107 | ['inline-react-svg', { filename: 'filename representing the code' }],
108 | ]
109 | }) // => { code, map, ast };
110 | ```
111 |
112 | ---
113 |
114 | Inspired by and code foundation provided by [react-svg-loader](https://github.com/boopathi/react-svg-loader).
115 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "babel-plugin-inline-react-svg",
3 | "version": "2.0.2",
4 | "description": "A babel plugin that optimizes and inlines SVGs for your react components.",
5 | "main": "lib/index.js",
6 | "scripts": {
7 | "prepack": "npmignore --auto --commentLines=autogenerated",
8 | "prepublishOnly": "npm run build && safe-publish-latest",
9 | "prepublish": "not-in-publish || npm run prepublishOnly",
10 | "pretest": "npm run lint",
11 | "lint": "eslint --ext=js,mjs .",
12 | "pretests-only": "npm run build",
13 | "build": "babel src --out-dir lib",
14 | "test": "npm run tests-only",
15 | "tests-only": "babel-node test/sanity.js",
16 | "posttest": "aud --production",
17 | "version": "auto-changelog && git add CHANGELOG.md",
18 | "postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\""
19 | },
20 | "repository": {
21 | "type": "git",
22 | "url": "git+https://github.com/kesne/babel-plugin-inline-react-svg.git"
23 | },
24 | "keywords": [
25 | "babel",
26 | "plugin",
27 | "react",
28 | "svg",
29 | "inline"
30 | ],
31 | "author": "Jordan Gensler ",
32 | "license": "MIT",
33 | "bugs": {
34 | "url": "https://github.com/kesne/babel-plugin-inline-react-svg/issues"
35 | },
36 | "homepage": "https://github.com/kesne/babel-plugin-inline-react-svg#readme",
37 | "devDependencies": {
38 | "@babel/cli": "^7.23.4",
39 | "@babel/core": "^7.0.0",
40 | "@babel/node": "^7.22.19",
41 | "@babel/plugin-transform-typescript": "^7.23.6",
42 | "@babel/preset-react": "^7.23.3",
43 | "aud": "^2.0.4",
44 | "auto-changelog": "^2.4.0",
45 | "babel-preset-airbnb": "^3.3.2",
46 | "eslint": "^8.55.0",
47 | "eslint-config-airbnb": "^19.0.4",
48 | "eslint-plugin-import": "^2.29.1",
49 | "eslint-plugin-jsx-a11y": "^6.8.0",
50 | "eslint-plugin-react": "^7.33.2",
51 | "in-publish": "^2.0.1",
52 | "npmignore": "^0.3.1",
53 | "react": "^15.3.1",
54 | "safe-publish-latest": "^2.0.0"
55 | },
56 | "peerDependencies": {
57 | "@babel/core": "^7.0.0"
58 | },
59 | "dependencies": {
60 | "@babel/helper-plugin-utils": "^7.0.0",
61 | "@babel/parser": "^7.0.0",
62 | "lodash.isplainobject": "^4.0.6",
63 | "resolve": "^2.0.0-next.5",
64 | "svgo": "^2.8.0"
65 | },
66 | "engines": {
67 | "node": ">=10.13"
68 | },
69 | "auto-changelog": {
70 | "output": "CHANGELOG.md",
71 | "template": "keepachangelog",
72 | "unreleased": false,
73 | "commitLimit": false,
74 | "backfillLimit": false,
75 | "hideCredit": true
76 | },
77 | "publishConfig": {
78 | "ignore": [
79 | "!lib",
80 | "src",
81 | ".github/workflows"
82 | ]
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/camelize.js:
--------------------------------------------------------------------------------
1 | export function hyphenToCamel(name) {
2 | return name.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
3 | }
4 |
5 | export function namespaceToCamel(namespace, name) {
6 | return namespace + name.charAt(0).toUpperCase() + name.slice(1);
7 | }
8 |
--------------------------------------------------------------------------------
/src/cssToObj.js:
--------------------------------------------------------------------------------
1 | export default function cssToObj(css) {
2 | const o = {};
3 | css.split(';')
4 | .filter((el) => !!el)
5 | .forEach((el) => {
6 | const s = el.split(':');
7 | const key = s.shift().trim();
8 | const value = s.join(':').trim();
9 | o[key] = value;
10 | });
11 |
12 | return o;
13 | }
14 |
--------------------------------------------------------------------------------
/src/escapeBraces.js:
--------------------------------------------------------------------------------
1 | /* If the SVG has text that has curly braces, or
2 | if there is a
8 | // to
9 | //
10 | return { ...raw, data: raw.data.replace(/(\{|\})/g, '{`$1`}') };
11 | }
12 |
--------------------------------------------------------------------------------
/src/fileExistsWithCaseSync.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 |
4 | // Based on https://stackoverflow.com/questions/27367261/check-if-file-exists-case-sensitive
5 | export default function fileExistsWithCaseSync(filepath) {
6 | const dir = path.dirname(filepath);
7 | if (dir === '/' || dir === '.') return true;
8 | const filenames = fs.readdirSync(dir);
9 | return filenames.indexOf(path.basename(filepath)) !== -1;
10 | }
11 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import { extname, dirname, parse as parseFilename } from 'path';
2 | import { readFileSync } from 'fs';
3 | import { parse } from '@babel/parser';
4 | import { declare } from '@babel/helper-plugin-utils';
5 | import resolve from 'resolve/sync';
6 |
7 | import optimize from './optimize';
8 | import escapeBraces from './escapeBraces';
9 | import transformSvg from './transformSvg';
10 | import fileExistsWithCaseSync from './fileExistsWithCaseSync';
11 |
12 | let ignoreRegex;
13 |
14 | export default declare(({
15 | assertVersion,
16 | template,
17 | traverse,
18 | types: t,
19 | }) => {
20 | assertVersion(7);
21 |
22 | const buildSvg = ({
23 | IS_EXPORT,
24 | EXPORT_FILENAME,
25 | SVG_NAME,
26 | SVG_CODE,
27 | SVG_DEFAULT_PROPS_CODE,
28 | }) => {
29 | const namedTemplate = `
30 | var SVG_NAME = function SVG_NAME(props) { return SVG_CODE; };
31 | ${SVG_DEFAULT_PROPS_CODE ? 'SVG_NAME.defaultProps = SVG_DEFAULT_PROPS_CODE;' : ''}
32 | ${IS_EXPORT ? 'export { SVG_NAME };' : ''}
33 | `;
34 | const anonymousTemplate = `
35 | var Component = function (props) { return SVG_CODE; };
36 | ${SVG_DEFAULT_PROPS_CODE ? 'Component.defaultProps = SVG_DEFAULT_PROPS_CODE;' : ''}
37 | Component.displayName = 'EXPORT_FILENAME';
38 | export default Component;
39 | `;
40 |
41 | if (SVG_NAME !== 'default') {
42 | return template(namedTemplate)({ SVG_NAME, SVG_CODE, SVG_DEFAULT_PROPS_CODE });
43 | }
44 | return template(anonymousTemplate)({ SVG_CODE, SVG_DEFAULT_PROPS_CODE, EXPORT_FILENAME });
45 | };
46 |
47 | function applyPlugin(importIdentifier, importPath, path, state, isExport, exportFilename) {
48 | if (typeof importPath !== 'string') {
49 | throw new TypeError('`applyPlugin` `importPath` must be a string');
50 | }
51 | const { ignorePattern, caseSensitive, filename: providedFilename } = state.opts;
52 | const { file, filename } = state;
53 | let newPath;
54 | if (ignorePattern) {
55 | // Only set the ignoreRegex once:
56 | ignoreRegex = ignoreRegex || new RegExp(ignorePattern);
57 | // Test if we should ignore this:
58 | if (ignoreRegex.test(importPath)) {
59 | return undefined;
60 | }
61 | }
62 | // This plugin only applies for SVGs:
63 | if (extname(importPath) === '.svg') {
64 | const iconPath = filename || providedFilename;
65 | const svgPath = resolve(importPath, {
66 | basedir: dirname(iconPath),
67 | preserveSymlinks: true,
68 | });
69 | if (caseSensitive && !fileExistsWithCaseSync(svgPath)) {
70 | throw new Error(`File path didn't match case of file on disk: ${svgPath}`);
71 | }
72 | if (!svgPath) {
73 | throw new Error(`File path does not exist: ${importPath}`);
74 | }
75 | const rawSource = readFileSync(svgPath, 'utf8');
76 | const optimizedSource = state.opts.svgo === false
77 | ? { data: rawSource }
78 | : optimize(rawSource, { ...state.opts.svgo, path: svgPath });
79 |
80 | const escapeSvgSource = escapeBraces(optimizedSource);
81 |
82 | const parsedSvgAst = parse(escapeSvgSource.data, {
83 | sourceType: 'module',
84 | plugins: ['jsx'],
85 | });
86 |
87 | traverse(parsedSvgAst, transformSvg(t));
88 |
89 | const svgCode = traverse.removeProperties(parsedSvgAst.program.body[0].expression);
90 |
91 | const opts = {
92 | SVG_NAME: importIdentifier,
93 | SVG_CODE: svgCode,
94 | IS_EXPORT: isExport,
95 | EXPORT_FILENAME: exportFilename,
96 | };
97 |
98 | // Move props off of element and into defaultProps
99 | if (svgCode.openingElement.attributes.length > 1) {
100 | const keepProps = [];
101 | const defaultProps = [];
102 |
103 | svgCode.openingElement.attributes.forEach((prop) => {
104 | if (prop.type === 'JSXSpreadAttribute') {
105 | keepProps.push(prop);
106 | } else if (prop.value.type === 'JSXExpressionContainer') {
107 | const objectExpression = t.objectExpression(prop.value.expression.properties);
108 | defaultProps.push(t.objectProperty(t.identifier(prop.name.name), objectExpression));
109 | } else {
110 | defaultProps.push(t.objectProperty(t.identifier(prop.name.name), prop.value));
111 | }
112 | });
113 |
114 | svgCode.openingElement.attributes = keepProps;
115 | opts.SVG_DEFAULT_PROPS_CODE = t.objectExpression(defaultProps);
116 | }
117 |
118 | const svgReplacement = buildSvg(opts);
119 | if (opts.SVG_DEFAULT_PROPS_CODE) {
120 | [newPath] = path.replaceWithMultiple(svgReplacement);
121 | } else {
122 | newPath = path.replaceWith(svgReplacement);
123 | }
124 |
125 | file.get('ensureReact')();
126 | file.set('ensureReact', () => {});
127 | }
128 | return newPath;
129 | }
130 |
131 | return {
132 | visitor: {
133 | Program: {
134 | enter(path, { file, opts, filename }) {
135 | if (typeof filename === 'string' && typeof opts.filename !== 'undefined') {
136 | throw new TypeError('the "filename" option may only be provided when transforming code');
137 | }
138 | if (typeof filename === 'undefined' && typeof opts.filename !== 'string') {
139 | throw new TypeError('the "filename" option is required when transforming code');
140 | }
141 | if (!path.scope.hasBinding('React')) {
142 | const reactImportDeclaration = t.importDeclaration([
143 | t.importDefaultSpecifier(t.identifier('React')),
144 | ], t.stringLiteral('react'));
145 |
146 | file.set('ensureReact', () => {
147 | const [newPath] = path.unshiftContainer('body', reactImportDeclaration);
148 | newPath.get('specifiers').forEach((specifier) => { path.scope.registerBinding('module', specifier); });
149 | });
150 | } else {
151 | file.set('ensureReact', () => {});
152 | }
153 | },
154 | },
155 | CallExpression(path, state) {
156 | const { node } = path;
157 | const requireArg = node.arguments.length > 0 ? node.arguments[0] : null;
158 | const filePath = t.isStringLiteral(requireArg) ? requireArg.value : null;
159 | if (node.callee.name === 'require' && t.isVariableDeclarator(path.parent) && filePath) {
160 | applyPlugin(path.parent.id, filePath, path.parentPath.parentPath, state);
161 | }
162 | },
163 | ImportDeclaration(path, state) {
164 | const { node } = path;
165 | if (node.specifiers.length > 0) {
166 | applyPlugin(node.specifiers[0].local, node.source.value, path, state);
167 | }
168 | },
169 | ExportNamedDeclaration(path, state) {
170 | const { node, scope } = path;
171 | if (node.specifiers.length > 0 && node.specifiers[0].local && node.specifiers[0].local.name === 'default') {
172 | const exportName = node.specifiers[0].exported.name;
173 | const filename = parseFilename(node.source.value).name;
174 | const newPath = applyPlugin(exportName, node.source.value, path, state, true, filename);
175 | if (newPath) {
176 | scope.registerDeclaration(newPath);
177 | }
178 | }
179 | },
180 | },
181 | };
182 | });
183 |
--------------------------------------------------------------------------------
/src/optimize.js:
--------------------------------------------------------------------------------
1 | // validates svgo opts
2 | // to contain minimal set of plugins that will strip some stuff
3 | // for the babylon JSX parser to work
4 | import * as SVGO from 'svgo';
5 | import isPlainObject from 'lodash.isplainobject';
6 |
7 | const essentialPlugins = ['removeDoctype', 'removeComments'];
8 |
9 | function isEssentialPlugin(p) {
10 | return essentialPlugins.indexOf(p) !== -1;
11 | }
12 |
13 | function validateAndFix(opts) {
14 | if (!isPlainObject(opts)) return;
15 |
16 | if (opts.full) {
17 | if (
18 | typeof opts.plugins === 'undefined'
19 | || (Array.isArray(opts.plugins) && opts.plugins.length === 0)
20 | ) {
21 | /* eslint no-param-reassign: 1 */
22 | opts.plugins = [...essentialPlugins];
23 | return;
24 | }
25 | }
26 |
27 | // opts.full is false, plugins can be empty
28 | if (typeof opts.plugins === 'undefined') return;
29 | if (Array.isArray(opts.plugins) && opts.plugins.length === 0) return;
30 |
31 | // track whether its defined in opts.plugins
32 | const state = essentialPlugins.reduce((p, c) => Object.assign(p, { [c]: false }), {});
33 |
34 | opts.plugins.forEach((p) => {
35 | if (typeof p === 'string' && isEssentialPlugin(p)) {
36 | state[p] = true;
37 | } else if (typeof p === 'object') {
38 | Object.keys(p).forEach((k) => {
39 | if (isEssentialPlugin(k)) {
40 | // make it essential
41 | if (!p[k]) p[k] = true;
42 | // and update state
43 | /* eslint no-param-reassign: 1 */
44 | state[k] = true;
45 | }
46 | });
47 | }
48 | });
49 |
50 | Object.keys(state)
51 | .filter((key) => !state[key])
52 | .forEach((key) => opts.plugins.push(key));
53 | }
54 |
55 | export default function optimize(content, opts = {}) {
56 | validateAndFix(opts);
57 |
58 | return SVGO.optimize(content, opts);
59 | }
60 |
--------------------------------------------------------------------------------
/src/transformSvg.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-param-reassign */
2 | //
3 | // These visitors normalize the SVG into something React understands:
4 | //
5 |
6 | import { namespaceToCamel, hyphenToCamel } from './camelize';
7 | import cssToObj from './cssToObj';
8 |
9 | export default (t) => ({
10 | JSXAttribute({ node }) {
11 | const { name: originalName } = node;
12 | if (t.isJSXNamespacedName(originalName)) {
13 | // converts
14 | //