mirror of
https://github.com/gosticks/svgr.git
synced 2025-10-16 11:55:43 +00:00
feat(typescript): add types everywhere (#611)
The whole codebase has been rewritten to TypeScript. BREAKING CHANGE: template signature has changed
This commit is contained in:
parent
5decc9448e
commit
16664327ab
21
.babelrc
21
.babelrc
@ -1,21 +0,0 @@
|
||||
{
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"targets": {
|
||||
"node": "10"
|
||||
},
|
||||
"loose": true
|
||||
},
|
||||
"preset-env"
|
||||
]
|
||||
],
|
||||
"plugins": [
|
||||
[
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
{ "loose": true },
|
||||
"class-properties"
|
||||
]
|
||||
]
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
node_modules/
|
||||
lib/
|
||||
__fixtures__/
|
||||
__fixtures_build__/
|
||||
coverage/
|
||||
examples/
|
||||
svgr.now.sh/
|
||||
/website/
|
||||
/website/
|
||||
dist/
|
||||
@ -1,26 +1,26 @@
|
||||
{
|
||||
"root": true,
|
||||
"parser": "babel-eslint",
|
||||
"extends": ["airbnb", "prettier"],
|
||||
"env": {
|
||||
"jest": true
|
||||
"node": true
|
||||
},
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:react-hooks/recommended",
|
||||
"plugin:react/recommended"
|
||||
],
|
||||
"rules": {
|
||||
"no-plusplus": "off",
|
||||
"no-shadow": "off",
|
||||
"class-methods-use-this": "off",
|
||||
"no-param-reassign": "off",
|
||||
"no-use-before-define": "off",
|
||||
"import/prefer-default-export": "off",
|
||||
"import/no-extraneous-dependencies": "off",
|
||||
"import/extensions": "off",
|
||||
"react/jsx-filename-extension": ["error", { "extensions": [".js"] }],
|
||||
"react/jsx-wrap-multilines": "off",
|
||||
"react/no-unused-state": "off",
|
||||
"react/destructuring-assignment": "off",
|
||||
"react/prop-types": "off",
|
||||
"react/sort-comp": "off",
|
||||
"react/jsx-props-no-spreading": "off",
|
||||
"react/state-in-constructor": "off"
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-empty-function": "warn",
|
||||
"@typescript-eslint/ban-types": "warn",
|
||||
"react/prop-types": "off"
|
||||
},
|
||||
"settings": {
|
||||
"react": {
|
||||
"version": "detect"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
7
.github/workflows/ci.yml
vendored
7
.github/workflows/ci.yml
vendored
@ -25,8 +25,8 @@ jobs:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'npm'
|
||||
|
||||
- name: Use npm v7
|
||||
run: npm i -g npm@7 --registry=https://registry.npmjs.org
|
||||
- name: Use latest npm
|
||||
run: npm i -g npm@latest --registry=https://registry.npmjs.org
|
||||
if: ${{ matrix.node-version == '12.x' || matrix.node-version == '14.x' }}
|
||||
|
||||
- name: Install dependencies
|
||||
@ -38,9 +38,6 @@ jobs:
|
||||
- name: Lint
|
||||
run: npm run lint
|
||||
|
||||
- name: Check DTS
|
||||
run: npx check-dts
|
||||
|
||||
- name: Test
|
||||
run: npm run test -- --ci --coverage
|
||||
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
node_modules/
|
||||
lib/
|
||||
dist/
|
||||
!svgr.now.sh/lib/
|
||||
__fixtures_build__/
|
||||
src/__fixtures__/dist/
|
||||
|
||||
23
.gitpod.yml
23
.gitpod.yml
@ -1,23 +0,0 @@
|
||||
tasks:
|
||||
- command: gp await-port 8000 && sleep 3 && gp preview $(gp url 8000)
|
||||
- name: Docs
|
||||
before: cd website
|
||||
init: |
|
||||
npm install
|
||||
gp sync-done boot
|
||||
command: npm run dev
|
||||
|
||||
- name: Dev
|
||||
init: |
|
||||
gp sync-await boot
|
||||
npm install
|
||||
command: npm run dev
|
||||
openMode: split-right
|
||||
|
||||
ports:
|
||||
- port: 8000
|
||||
onOpen: ignore
|
||||
|
||||
vscode:
|
||||
extensions:
|
||||
- esbenp.prettier-vscode@5.7.1:4Zx39KyQMoIz7x94PSmDmQ==
|
||||
@ -3,7 +3,7 @@ __fixtures__/
|
||||
CHANGELOG.md
|
||||
package.json
|
||||
lerna.json
|
||||
lib/
|
||||
dist/
|
||||
.next/
|
||||
/website/.cache/
|
||||
/website/public/
|
||||
@ -37,7 +37,7 @@ _Before_ submitting a pull request, please make sure the following is done…
|
||||
|
||||
Note: Replace `<your_username>` with your GitHub username
|
||||
|
||||
2. Run `npm install`.
|
||||
2. Run `npm install` and `npm run build`.
|
||||
|
||||
3. If you've added code that should be tested, add tests. You can use watch mode that continuously transforms changed files to make your life easier.
|
||||
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
const indexTemplate = require('./custom-index-template.js')
|
||||
|
||||
function template(
|
||||
{ template },
|
||||
opts,
|
||||
{ imports, componentName, props, jsx, exports },
|
||||
{ tpl }
|
||||
) {
|
||||
return template.ast`${imports}
|
||||
return tpl`${imports}
|
||||
export function ${componentName}(${props}) {
|
||||
return ${jsx};
|
||||
}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
/* eslint-disable import/no-unresolved */
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const { default: svgr } = require('@svgr/core')
|
||||
const { default: jsx } = require('@svgr/plugin-jsx')
|
||||
const { default: svgo } = require('@svgr/plugin-svgo')
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
module.exports = (api) => {
|
||||
api.cache(true)
|
||||
|
||||
const config = fs.readFileSync(path.join(__dirname, '.babelrc'))
|
||||
|
||||
module.exports = JSON.parse(config)
|
||||
return {
|
||||
presets: [
|
||||
['@babel/preset-env', { targets: { node: '12' }, loose: true }],
|
||||
'@babel/preset-typescript',
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
20
build/build.sh
Executable file
20
build/build.sh
Executable file
@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
npm run build --workspace @svgr/babel-plugin-add-jsx-attribute
|
||||
npm run build --workspace @svgr/babel-plugin-remove-jsx-attribute
|
||||
npm run build --workspace @svgr/babel-plugin-remove-jsx-empty-expression
|
||||
npm run build --workspace @svgr/babel-plugin-replace-jsx-attribute-value
|
||||
npm run build --workspace @svgr/babel-plugin-svg-dynamic-title
|
||||
npm run build --workspace @svgr/babel-plugin-svg-em-dimensions
|
||||
npm run build --workspace @svgr/babel-plugin-transform-react-native-svg
|
||||
npm run build --workspace @svgr/babel-plugin-transform-svg-component
|
||||
npm run build --workspace @svgr/babel-preset
|
||||
npm run build --workspace @svgr/core
|
||||
npm run build --workspace @svgr/hast-util-to-babel-ast
|
||||
npm run build --workspace @svgr/plugin-jsx
|
||||
npm run build --workspace @svgr/plugin-prettier
|
||||
npm run build --workspace @svgr/plugin-svgo
|
||||
npm run build --workspace @svgr/cli
|
||||
npm run build --workspace @svgr/rollup
|
||||
npm run build --workspace @svgr/webpack
|
||||
39
build/rollup.config.js
Normal file
39
build/rollup.config.js
Normal file
@ -0,0 +1,39 @@
|
||||
import path from 'path'
|
||||
import json from '@rollup/plugin-json'
|
||||
import dts from 'rollup-plugin-dts'
|
||||
import esbuild from 'rollup-plugin-esbuild'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const pkg = require(path.resolve(process.cwd(), './package.json'))
|
||||
const name = pkg.main ? pkg.main.replace(/\.js$/, '') : './dist/index'
|
||||
|
||||
const bundle = (config) => ({
|
||||
...config,
|
||||
input: 'src/index.ts',
|
||||
external: (id) => !/^[./]/.test(id),
|
||||
})
|
||||
|
||||
export default [
|
||||
bundle({
|
||||
plugins: [json(), esbuild()],
|
||||
output: [
|
||||
{
|
||||
file: `${name}.js`,
|
||||
format: 'cjs',
|
||||
sourcemap: Boolean(pkg.main),
|
||||
exports: 'auto',
|
||||
},
|
||||
],
|
||||
}),
|
||||
...(pkg.main
|
||||
? [
|
||||
bundle({
|
||||
plugins: [dts()],
|
||||
output: {
|
||||
file: `${name}.d.ts`,
|
||||
format: 'es',
|
||||
},
|
||||
}),
|
||||
]
|
||||
: []),
|
||||
]
|
||||
@ -1,4 +1,4 @@
|
||||
/* eslint-disable no-console, import/no-unresolved */
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const githubCurrentUser = require('github-current-user')
|
||||
|
||||
githubCurrentUser.verify((err, verified, username) => {
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
module.exports = {
|
||||
watchPathIgnorePatterns: ['__fixtures__', '__fixtures__build__'],
|
||||
rootDir: 'packages',
|
||||
transform: {
|
||||
'^.+\\.(j|t)sx?$': 'babel-jest',
|
||||
},
|
||||
}
|
||||
|
||||
19585
package-lock.json
generated
19585
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
40
package.json
40
package.json
@ -4,7 +4,7 @@
|
||||
"packages/*"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "lerna run build",
|
||||
"build": "build/build.sh",
|
||||
"dev": "lerna run build --parallel -- --watch",
|
||||
"format": "prettier --write \"**/*.{js,json,md}\"",
|
||||
"lint": "eslint .",
|
||||
@ -12,28 +12,26 @@
|
||||
"test": "jest --runInBand"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.15.4",
|
||||
"@babel/core": "^7.15.5",
|
||||
"@babel/generator": "^7.15.4",
|
||||
"@babel/node": "^7.15.4",
|
||||
"@babel/plugin-proposal-class-properties": "^7.14.5",
|
||||
"@babel/plugin-syntax-typescript": "^7.14.5",
|
||||
"@babel/preset-env": "^7.15.6",
|
||||
"babel-core": "^7.0.0-bridge.0",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"babel-jest": "^27.1.1",
|
||||
"babel-loader": "^8.2.2",
|
||||
"check-dts": "^0.4.4",
|
||||
"@babel/core": "^7.16.0",
|
||||
"@babel/preset-env": "^7.16.0",
|
||||
"@babel/preset-typescript": "^7.16.0",
|
||||
"@rollup/plugin-json": "^4.1.0",
|
||||
"@types/jest": "^27.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^5.2.0",
|
||||
"@typescript-eslint/parser": "^5.2.0",
|
||||
"babel-jest": "^27.3.1",
|
||||
"codecov": "^3.8.3",
|
||||
"conventional-github-releaser": "^3.1.5",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-airbnb": "^18.2.1",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-import": "^2.24.2",
|
||||
"eslint-plugin-jsx-a11y": "^6.4.1",
|
||||
"eslint-plugin-react": "^7.25.1",
|
||||
"jest": "^27.1.1",
|
||||
"esbuild": "^0.13.12",
|
||||
"eslint": "^8.1.0",
|
||||
"eslint-plugin-react": "^7.26.1",
|
||||
"eslint-plugin-react-hooks": "^4.2.0",
|
||||
"jest": "^27.3.1",
|
||||
"lerna": "^4.0.0",
|
||||
"react": "^17.0.2"
|
||||
"react": "^17.0.2",
|
||||
"rollup": "^2.58.3",
|
||||
"rollup-plugin-dts": "^4.0.0",
|
||||
"rollup-plugin-esbuild": "^4.6.0",
|
||||
"typescript": "^4.4.4"
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,9 @@
|
||||
"name": "@svgr/babel-plugin-add-jsx-attribute",
|
||||
"description": "Add JSX attribute",
|
||||
"version": "5.4.0",
|
||||
"main": "lib/index.js",
|
||||
"main": "./dist/index.js",
|
||||
"exports": "./dist/index.js",
|
||||
"typings": "./dist/index.d.ts",
|
||||
"repository": "https://github.com/gregberge/svgr/tree/master/packages/babel-plugin-add-jsx-attribute",
|
||||
"author": "Greg Bergé <berge.greg@gmail.com>",
|
||||
"publishConfig": {
|
||||
@ -20,9 +22,12 @@
|
||||
"url": "https://github.com/sponsors/gregberge"
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0-0"
|
||||
},
|
||||
"scripts": {
|
||||
"prebuild": "rm -rf lib/",
|
||||
"build": "babel --config-file ../../babel.config.js -d lib --ignore \"**/*.test.js\" src",
|
||||
"prepublishOnly": "npm run build"
|
||||
"reset": "rm -rf dist",
|
||||
"build": "rollup -c ../../build/rollup.config.js",
|
||||
"prepublishOnly": "npm run reset && npm run build"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { transform } from '@babel/core'
|
||||
import plugin from '.'
|
||||
import plugin, { Options } from '.'
|
||||
|
||||
const testPlugin = (code, options) => {
|
||||
const testPlugin = (code: string, options: Options) => {
|
||||
const result = transform(code, {
|
||||
plugins: ['@babel/plugin-syntax-jsx', [plugin, options]],
|
||||
configFile: false,
|
||||
})
|
||||
|
||||
return result.code
|
||||
return result?.code
|
||||
}
|
||||
|
||||
describe('plugin', () => {
|
||||
@ -1,10 +1,32 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { ConfigAPI, types as t, NodePath, template } from '@babel/core'
|
||||
|
||||
export interface Attribute {
|
||||
name: string
|
||||
value?: boolean | number | string | null
|
||||
spread?: boolean
|
||||
literal?: boolean
|
||||
position?: 'start' | 'end'
|
||||
}
|
||||
|
||||
export interface Options {
|
||||
elements: string[]
|
||||
attributes: Attribute[]
|
||||
}
|
||||
|
||||
const positionMethod = {
|
||||
start: 'unshiftContainer',
|
||||
end: 'pushContainer',
|
||||
}
|
||||
} as const
|
||||
|
||||
const addJSXAttribute = ({ types: t, template }, opts) => {
|
||||
function getAttributeValue({ literal, value }) {
|
||||
const addJSXAttribute = (_: ConfigAPI, opts: Options) => {
|
||||
function getAttributeValue({
|
||||
literal,
|
||||
value,
|
||||
}: {
|
||||
literal?: Attribute['literal']
|
||||
value: Attribute['value']
|
||||
}) {
|
||||
if (typeof value === 'boolean') {
|
||||
return t.jsxExpressionContainer(t.booleanLiteral(value))
|
||||
}
|
||||
@ -14,7 +36,9 @@ const addJSXAttribute = ({ types: t, template }, opts) => {
|
||||
}
|
||||
|
||||
if (typeof value === 'string' && literal) {
|
||||
return t.jsxExpressionContainer(template.ast(value).expression)
|
||||
return t.jsxExpressionContainer(
|
||||
(template.ast(value) as t.ExpressionStatement).expression,
|
||||
)
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
@ -24,7 +48,7 @@ const addJSXAttribute = ({ types: t, template }, opts) => {
|
||||
return null
|
||||
}
|
||||
|
||||
function getAttribute({ spread, name, value, literal }) {
|
||||
function getAttribute({ spread, name, value, literal }: Attribute) {
|
||||
if (spread) {
|
||||
return t.jsxSpreadAttribute(t.identifier(name))
|
||||
}
|
||||
@ -37,7 +61,8 @@ const addJSXAttribute = ({ types: t, template }, opts) => {
|
||||
|
||||
return {
|
||||
visitor: {
|
||||
JSXOpeningElement(path) {
|
||||
JSXOpeningElement(path: NodePath<t.JSXOpeningElement>) {
|
||||
if (!t.isJSXIdentifier(path.node.name)) return
|
||||
if (!opts.elements.includes(path.node.name.name)) return
|
||||
|
||||
opts.attributes.forEach(
|
||||
@ -52,12 +77,18 @@ const addJSXAttribute = ({ types: t, template }, opts) => {
|
||||
const newAttribute = getAttribute({ spread, name, value, literal })
|
||||
const attributes = path.get('attributes')
|
||||
|
||||
const isEqualAttribute = (attribute) => {
|
||||
if (spread) {
|
||||
return attribute.get('argument').isIdentifier({ name })
|
||||
}
|
||||
|
||||
return attribute.get('name').isJSXIdentifier({ name })
|
||||
const isEqualAttribute = (
|
||||
attribute: NodePath<t.JSXSpreadAttribute | t.JSXAttribute>,
|
||||
) => {
|
||||
if (spread)
|
||||
return (
|
||||
attribute.isJSXSpreadAttribute() &&
|
||||
attribute.get('argument').isIdentifier({ name })
|
||||
)
|
||||
return (
|
||||
attribute.isJSXAttribute() &&
|
||||
attribute.get('name').isJSXIdentifier({ name })
|
||||
)
|
||||
}
|
||||
|
||||
const replaced = attributes.some((attribute) => {
|
||||
4
packages/babel-plugin-add-jsx-attribute/tsconfig.json
Normal file
4
packages/babel-plugin-add-jsx-attribute/tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"include": ["src"]
|
||||
}
|
||||
@ -1,2 +1,4 @@
|
||||
src/
|
||||
.*
|
||||
/*
|
||||
/dist/*
|
||||
!/dist/index.{d.ts,js}
|
||||
!/dist/index.js.map
|
||||
@ -2,7 +2,9 @@
|
||||
"name": "@svgr/babel-plugin-remove-jsx-attribute",
|
||||
"description": "Remove JSX attribute",
|
||||
"version": "5.4.0",
|
||||
"main": "lib/index.js",
|
||||
"main": "./dist/index.js",
|
||||
"exports": "./dist/index.js",
|
||||
"typings": "./dist/index.d.ts",
|
||||
"repository": "https://github.com/gregberge/svgr/tree/master/packages/babel-plugin-remove-jsx-attribute",
|
||||
"author": "Greg Bergé <berge.greg@gmail.com>",
|
||||
"publishConfig": {
|
||||
@ -20,9 +22,12 @@
|
||||
"url": "https://github.com/sponsors/gregberge"
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0-0"
|
||||
},
|
||||
"scripts": {
|
||||
"prebuild": "rm -rf lib/",
|
||||
"build": "babel --config-file ../../babel.config.js -d lib --ignore \"**/*.test.js\" src",
|
||||
"prepublishOnly": "npm run build"
|
||||
"reset": "rm -rf dist",
|
||||
"build": "rollup -c ../../build/rollup.config.js",
|
||||
"prepublishOnly": "npm run reset && npm run build"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
const removeJSXAttribute = (api, opts) => ({
|
||||
visitor: {
|
||||
JSXOpeningElement(path) {
|
||||
if (!opts.elements.includes(path.node.name.name)) return
|
||||
|
||||
path.get('attributes').forEach((attribute) => {
|
||||
const nodeName = attribute.node.name
|
||||
if (nodeName && opts.attributes.includes(nodeName.name)) {
|
||||
attribute.remove()
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export default removeJSXAttribute
|
||||
@ -1,13 +1,13 @@
|
||||
import { transform } from '@babel/core'
|
||||
import plugin from '.'
|
||||
import plugin, { Options } from '.'
|
||||
|
||||
const testPlugin = (code, options) => {
|
||||
const testPlugin = (code: string, options: Options) => {
|
||||
const result = transform(code, {
|
||||
plugins: ['@babel/plugin-syntax-jsx', [plugin, options]],
|
||||
configFile: false,
|
||||
})
|
||||
|
||||
return result.code
|
||||
return result?.code
|
||||
}
|
||||
|
||||
describe('plugin', () => {
|
||||
29
packages/babel-plugin-remove-jsx-attribute/src/index.ts
Normal file
29
packages/babel-plugin-remove-jsx-attribute/src/index.ts
Normal file
@ -0,0 +1,29 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { ConfigAPI, types as t, NodePath } from '@babel/core'
|
||||
|
||||
export interface Options {
|
||||
elements: string[]
|
||||
attributes: string[]
|
||||
}
|
||||
|
||||
const removeJSXAttribute = (_: ConfigAPI, opts: Options) => ({
|
||||
visitor: {
|
||||
JSXOpeningElement(path: NodePath<t.JSXOpeningElement>) {
|
||||
if (!t.isJSXIdentifier(path.node.name)) return
|
||||
if (!opts.elements.includes(path.node.name.name)) return
|
||||
|
||||
// @ts-ignore
|
||||
path.get('attributes').forEach((attribute) => {
|
||||
if (
|
||||
t.isJSXAttribute(attribute.node) &&
|
||||
t.isJSXIdentifier(attribute.node.name) &&
|
||||
opts.attributes.includes(attribute.node.name.name)
|
||||
) {
|
||||
attribute.remove()
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export default removeJSXAttribute
|
||||
4
packages/babel-plugin-remove-jsx-attribute/tsconfig.json
Normal file
4
packages/babel-plugin-remove-jsx-attribute/tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"include": ["src"]
|
||||
}
|
||||
@ -1,2 +1,4 @@
|
||||
src/
|
||||
.*
|
||||
/*
|
||||
/dist/*
|
||||
!/dist/index.{d.ts,js}
|
||||
!/dist/index.js.map
|
||||
@ -2,7 +2,9 @@
|
||||
"name": "@svgr/babel-plugin-remove-jsx-empty-expression",
|
||||
"description": "Remove JSX empty expression",
|
||||
"version": "5.0.1",
|
||||
"main": "lib/index.js",
|
||||
"main": "./dist/index.js",
|
||||
"exports": "./dist/index.js",
|
||||
"typings": "./dist/index.d.ts",
|
||||
"repository": "https://github.com/gregberge/svgr/tree/master/packages/babel-plugin-remove-jsx-empty-expression",
|
||||
"author": "Greg Bergé <berge.greg@gmail.com>",
|
||||
"publishConfig": {
|
||||
@ -20,9 +22,12 @@
|
||||
"url": "https://github.com/sponsors/gregberge"
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0-0"
|
||||
},
|
||||
"scripts": {
|
||||
"prebuild": "rm -rf lib/",
|
||||
"build": "babel --config-file ../../babel.config.js -d lib --ignore \"**/*.test.js\" src",
|
||||
"prepublishOnly": "npm run build"
|
||||
"reset": "rm -rf dist",
|
||||
"build": "rollup -c ../../build/rollup.config.js",
|
||||
"prepublishOnly": "npm run reset && npm run build"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
const removeJSXEmptyExpression = () => ({
|
||||
visitor: {
|
||||
JSXExpressionContainer(path) {
|
||||
if (!path.get('expression').isJSXEmptyExpression()) return
|
||||
path.remove()
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export default removeJSXEmptyExpression
|
||||
@ -1,19 +0,0 @@
|
||||
import { transform } from '@babel/core'
|
||||
import plugin from '.'
|
||||
|
||||
const testPlugin = (code, options) => {
|
||||
const result = transform(code, {
|
||||
plugins: ['@babel/plugin-syntax-jsx', [plugin, options]],
|
||||
configFile: false,
|
||||
})
|
||||
|
||||
return result.code
|
||||
}
|
||||
|
||||
describe('plugin', () => {
|
||||
it('should remove empty expression', () => {
|
||||
expect(
|
||||
testPlugin('<div>{/* Hello */}<a /></div>', { attribute: 'foo' }),
|
||||
).toMatchInlineSnapshot(`"<div><a /></div>;"`)
|
||||
})
|
||||
})
|
||||
@ -0,0 +1,19 @@
|
||||
import { transform } from '@babel/core'
|
||||
import plugin from '.'
|
||||
|
||||
const testPlugin = (code: string) => {
|
||||
const result = transform(code, {
|
||||
plugins: ['@babel/plugin-syntax-jsx', plugin],
|
||||
configFile: false,
|
||||
})
|
||||
|
||||
return result?.code
|
||||
}
|
||||
|
||||
describe('plugin', () => {
|
||||
it('should remove empty expression', () => {
|
||||
expect(testPlugin('<div>{/* Hello */}<a /></div>')).toMatchInlineSnapshot(
|
||||
`"<div><a /></div>;"`,
|
||||
)
|
||||
})
|
||||
})
|
||||
@ -0,0 +1,14 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { types as t, NodePath } from '@babel/core'
|
||||
|
||||
const removeJSXEmptyExpression = () => ({
|
||||
visitor: {
|
||||
JSXExpressionContainer(path: NodePath<t.JSXExpressionContainer>) {
|
||||
if (t.isJSXEmptyExpression(path.get('expression'))) {
|
||||
path.remove()
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export default removeJSXEmptyExpression
|
||||
@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"include": ["src"]
|
||||
}
|
||||
@ -1,2 +1,6 @@
|
||||
src/
|
||||
.*
|
||||
/*
|
||||
/dist/*
|
||||
!/dist/index.{d.ts,js}
|
||||
!/dist/index.js.map
|
||||
@ -2,7 +2,9 @@
|
||||
"name": "@svgr/babel-plugin-replace-jsx-attribute-value",
|
||||
"description": "Replace JSX attribute value",
|
||||
"version": "5.0.1",
|
||||
"main": "lib/index.js",
|
||||
"main": "./dist/index.js",
|
||||
"exports": "./dist/index.js",
|
||||
"typings": "./dist/index.d.ts",
|
||||
"repository": "https://github.com/gregberge/svgr/tree/master/packages/babel-plugin-replace-jsx-attribute-value",
|
||||
"author": "Greg Bergé <berge.greg@gmail.com>",
|
||||
"publishConfig": {
|
||||
@ -20,9 +22,12 @@
|
||||
"url": "https://github.com/sponsors/gregberge"
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0-0"
|
||||
},
|
||||
"scripts": {
|
||||
"prebuild": "rm -rf lib/",
|
||||
"build": "babel --config-file ../../babel.config.js -d lib --ignore \"**/*.test.js\" src",
|
||||
"prepublishOnly": "npm run build"
|
||||
"reset": "rm -rf dist",
|
||||
"build": "rollup -c ../../build/rollup.config.js",
|
||||
"prepublishOnly": "npm run reset && npm run build"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,37 +0,0 @@
|
||||
const addJSXAttribute = ({ types: t, template }, opts) => {
|
||||
function getAttributeValue(value, literal) {
|
||||
if (typeof value === 'string' && literal) {
|
||||
return t.jsxExpressionContainer(template.ast(value).expression)
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
return t.stringLiteral(value)
|
||||
}
|
||||
|
||||
if (typeof value === 'boolean') {
|
||||
return t.jsxExpressionContainer(t.booleanLiteral(value))
|
||||
}
|
||||
|
||||
if (typeof value === 'number') {
|
||||
return t.jsxExpressionContainer(t.numericLiteral(value))
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
visitor: {
|
||||
JSXAttribute(path) {
|
||||
const valuePath = path.get('value')
|
||||
if (!valuePath.isStringLiteral()) return
|
||||
|
||||
opts.values.forEach(({ value, newValue, literal }) => {
|
||||
if (!valuePath.isStringLiteral({ value })) return
|
||||
valuePath.replaceWith(getAttributeValue(newValue, literal))
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export default addJSXAttribute
|
||||
@ -1,13 +1,13 @@
|
||||
import { transform } from '@babel/core'
|
||||
import plugin from '.'
|
||||
import plugin, { Options } from '.'
|
||||
|
||||
const testPlugin = (code, options) => {
|
||||
const testPlugin = (code: string, options: Options) => {
|
||||
const result = transform(code, {
|
||||
plugins: ['@babel/plugin-syntax-jsx', [plugin, options]],
|
||||
configFile: false,
|
||||
})
|
||||
|
||||
return result.code
|
||||
return result?.code
|
||||
}
|
||||
|
||||
describe('plugin', () => {
|
||||
@ -0,0 +1,58 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { ConfigAPI, types as t, NodePath, template } from '@babel/core'
|
||||
|
||||
export interface Value {
|
||||
value: string
|
||||
newValue: string | boolean | number
|
||||
literal?: boolean
|
||||
}
|
||||
|
||||
export interface Options {
|
||||
values: Value[]
|
||||
}
|
||||
|
||||
const addJSXAttribute = (api: ConfigAPI, opts: Options) => {
|
||||
const getAttributeValue = (
|
||||
value: string | boolean | number,
|
||||
literal?: boolean,
|
||||
) => {
|
||||
if (typeof value === 'string' && literal) {
|
||||
return t.jsxExpressionContainer(
|
||||
(template.ast(value) as t.ExpressionStatement).expression,
|
||||
)
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
return t.stringLiteral(value)
|
||||
}
|
||||
|
||||
if (typeof value === 'boolean') {
|
||||
return t.jsxExpressionContainer(t.booleanLiteral(value))
|
||||
}
|
||||
|
||||
if (typeof value === 'number') {
|
||||
return t.jsxExpressionContainer(t.numericLiteral(value))
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
visitor: {
|
||||
JSXAttribute(path: NodePath<t.JSXAttribute>) {
|
||||
const valuePath = path.get('value')
|
||||
if (!valuePath.isStringLiteral()) return
|
||||
|
||||
opts.values.forEach(({ value, newValue, literal }) => {
|
||||
if (!valuePath.isStringLiteral({ value })) return
|
||||
const attributeValue = getAttributeValue(newValue, literal)
|
||||
if (attributeValue) {
|
||||
valuePath.replaceWith(attributeValue)
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export default addJSXAttribute
|
||||
@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"include": ["src"]
|
||||
}
|
||||
@ -1,2 +1,4 @@
|
||||
src/
|
||||
.*
|
||||
/*
|
||||
/dist/*
|
||||
!/dist/index.{d.ts,js}
|
||||
!/dist/index.js.map
|
||||
@ -2,7 +2,9 @@
|
||||
"name": "@svgr/babel-plugin-svg-dynamic-title",
|
||||
"description": "Transform SVG by adding a dynamic title element",
|
||||
"version": "5.4.0",
|
||||
"main": "lib/index.js",
|
||||
"main": "./dist/index.js",
|
||||
"exports": "./dist/index.js",
|
||||
"typings": "./dist/index.d.ts",
|
||||
"repository": "https://github.com/gregberge/svgr/tree/master/packages/babel-plugin-svg-dynamic-title",
|
||||
"author": "Greg Bergé <berge.greg@gmail.com>",
|
||||
"publishConfig": {
|
||||
@ -20,9 +22,12 @@
|
||||
"url": "https://github.com/sponsors/gregberge"
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0-0"
|
||||
},
|
||||
"scripts": {
|
||||
"prebuild": "rm -rf lib/",
|
||||
"build": "babel --config-file ../../babel.config.js -d lib --ignore \"**/*.test.js\" src",
|
||||
"prepublishOnly": "npm run build"
|
||||
"reset": "rm -rf dist",
|
||||
"build": "rollup -c ../../build/rollup.config.js",
|
||||
"prepublishOnly": "npm run reset && npm run build"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,113 +0,0 @@
|
||||
const elements = ['svg', 'Svg']
|
||||
|
||||
const plugin = ({ types: t }) => ({
|
||||
visitor: {
|
||||
JSXElement(path) {
|
||||
if (
|
||||
!elements.some((element) =>
|
||||
path.get('openingElement.name').isJSXIdentifier({ name: element }),
|
||||
)
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
function createTitle(children = [], attributes = []) {
|
||||
return t.jsxElement(
|
||||
t.jsxOpeningElement(t.jsxIdentifier('title'), attributes),
|
||||
t.jsxClosingElement(t.jsxIdentifier('title')),
|
||||
children,
|
||||
)
|
||||
}
|
||||
|
||||
function createTitleIdAttribute() {
|
||||
return t.jsxAttribute(
|
||||
t.jsxIdentifier('id'),
|
||||
t.jsxExpressionContainer(t.identifier('titleId')),
|
||||
)
|
||||
}
|
||||
|
||||
function enhanceAttributes(attributes) {
|
||||
const existingId = attributes.find(
|
||||
(attribute) => attribute.name.name === 'id',
|
||||
)
|
||||
if (!existingId) {
|
||||
return [...attributes, createTitleIdAttribute()]
|
||||
}
|
||||
existingId.value = t.jsxExpressionContainer(
|
||||
t.logicalExpression('||', t.identifier('titleId'), existingId.value),
|
||||
)
|
||||
return attributes
|
||||
}
|
||||
|
||||
function getTitleElement(existingTitle) {
|
||||
const titleExpression = t.identifier('title')
|
||||
if (existingTitle) {
|
||||
existingTitle.openingElement.attributes = enhanceAttributes(
|
||||
existingTitle.openingElement.attributes,
|
||||
)
|
||||
}
|
||||
let titleElement = t.conditionalExpression(
|
||||
titleExpression,
|
||||
createTitle(
|
||||
[t.jsxExpressionContainer(titleExpression)],
|
||||
existingTitle
|
||||
? existingTitle.openingElement.attributes
|
||||
: [
|
||||
t.jsxAttribute(
|
||||
t.jsxIdentifier('id'),
|
||||
t.jsxExpressionContainer(t.identifier('titleId')),
|
||||
),
|
||||
],
|
||||
),
|
||||
t.nullLiteral(),
|
||||
)
|
||||
if (
|
||||
existingTitle &&
|
||||
existingTitle.children &&
|
||||
existingTitle.children.length
|
||||
) {
|
||||
// if title already exists
|
||||
// render as follows
|
||||
const fallbackTitleElement = existingTitle
|
||||
// {title === undefined ? fallbackTitleElement : titleElement}
|
||||
const conditionalExpressionForTitle = t.conditionalExpression(
|
||||
t.binaryExpression(
|
||||
'===',
|
||||
titleExpression,
|
||||
t.identifier('undefined'),
|
||||
),
|
||||
fallbackTitleElement,
|
||||
titleElement,
|
||||
)
|
||||
titleElement = t.jsxExpressionContainer(conditionalExpressionForTitle)
|
||||
} else {
|
||||
titleElement = t.jsxExpressionContainer(titleElement)
|
||||
}
|
||||
return titleElement
|
||||
}
|
||||
|
||||
// store the title element
|
||||
let titleElement
|
||||
|
||||
const hasTitle = path.get('children').some((childPath) => {
|
||||
if (!childPath.isJSXElement()) return false
|
||||
if (childPath.node === titleElement) return false
|
||||
if (childPath.node.openingElement.name.name !== 'title') return false
|
||||
titleElement = getTitleElement(childPath.node)
|
||||
childPath.replaceWith(titleElement)
|
||||
return true
|
||||
})
|
||||
|
||||
// create a title element if not already create
|
||||
titleElement = titleElement || getTitleElement()
|
||||
if (!hasTitle) {
|
||||
// path.unshiftContainer is not working well :(
|
||||
// path.unshiftContainer('children', titleElement)
|
||||
path.node.children.unshift(titleElement)
|
||||
path.replaceWith(path.node)
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export default plugin
|
||||
@ -1,13 +1,13 @@
|
||||
import { transform } from '@babel/core'
|
||||
import plugin from '.'
|
||||
|
||||
const testPlugin = (code, options) => {
|
||||
const testPlugin = (code: string) => {
|
||||
const result = transform(code, {
|
||||
plugins: ['@babel/plugin-syntax-jsx', [plugin, options]],
|
||||
plugins: ['@babel/plugin-syntax-jsx', plugin],
|
||||
configFile: false,
|
||||
})
|
||||
|
||||
return result.code
|
||||
return result?.code
|
||||
}
|
||||
|
||||
describe('plugin', () => {
|
||||
120
packages/babel-plugin-svg-dynamic-title/src/index.ts
Normal file
120
packages/babel-plugin-svg-dynamic-title/src/index.ts
Normal file
@ -0,0 +1,120 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { NodePath, types as t } from '@babel/core'
|
||||
|
||||
const elements = ['svg', 'Svg']
|
||||
|
||||
const createTitleElement = (
|
||||
children: t.JSXExpressionContainer[] = [],
|
||||
attributes: (t.JSXAttribute | t.JSXSpreadAttribute)[] = [],
|
||||
) => {
|
||||
const title = t.jsxIdentifier('title')
|
||||
return t.jsxElement(
|
||||
t.jsxOpeningElement(title, attributes),
|
||||
t.jsxClosingElement(title),
|
||||
children,
|
||||
)
|
||||
}
|
||||
|
||||
const createTitleIdAttribute = () =>
|
||||
t.jsxAttribute(
|
||||
t.jsxIdentifier('id'),
|
||||
t.jsxExpressionContainer(t.identifier('titleId')),
|
||||
)
|
||||
|
||||
const addTitleIdAttribute = (
|
||||
attributes: (t.JSXAttribute | t.JSXSpreadAttribute)[],
|
||||
) => {
|
||||
const existingId = attributes.find(
|
||||
(attribute) => t.isJSXAttribute(attribute) && attribute.name.name === 'id',
|
||||
) as t.JSXAttribute | undefined
|
||||
|
||||
if (!existingId) {
|
||||
return [...attributes, createTitleIdAttribute()]
|
||||
}
|
||||
existingId.value = t.jsxExpressionContainer(
|
||||
t.isStringLiteral(existingId.value)
|
||||
? t.logicalExpression('||', t.identifier('titleId'), existingId.value)
|
||||
: t.identifier('titleId'),
|
||||
)
|
||||
return attributes
|
||||
}
|
||||
|
||||
const plugin = () => ({
|
||||
visitor: {
|
||||
JSXElement(path: NodePath<t.JSXElement>) {
|
||||
if (!elements.length) return
|
||||
|
||||
const openingElement = path.get('openingElement')
|
||||
const openingElementName = openingElement.get('name')
|
||||
if (
|
||||
!elements.some((element) =>
|
||||
openingElementName.isJSXIdentifier({ name: element }),
|
||||
)
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
const getTitleElement = (
|
||||
existingTitle?: t.JSXElement,
|
||||
): t.JSXExpressionContainer => {
|
||||
const titleExpression = t.identifier('title')
|
||||
if (existingTitle) {
|
||||
existingTitle.openingElement.attributes = addTitleIdAttribute(
|
||||
existingTitle.openingElement.attributes,
|
||||
)
|
||||
}
|
||||
const conditionalTitle = t.conditionalExpression(
|
||||
titleExpression,
|
||||
createTitleElement(
|
||||
[t.jsxExpressionContainer(titleExpression)],
|
||||
existingTitle
|
||||
? existingTitle.openingElement.attributes
|
||||
: [createTitleIdAttribute()],
|
||||
),
|
||||
t.nullLiteral(),
|
||||
)
|
||||
if (existingTitle?.children?.length) {
|
||||
// If title already exists render as follows
|
||||
// `{title === undefined ? fallbackTitleElement : titleElement}`
|
||||
return t.jsxExpressionContainer(
|
||||
t.conditionalExpression(
|
||||
t.binaryExpression(
|
||||
'===',
|
||||
titleExpression,
|
||||
t.identifier('undefined'),
|
||||
),
|
||||
existingTitle,
|
||||
conditionalTitle,
|
||||
),
|
||||
)
|
||||
}
|
||||
return t.jsxExpressionContainer(conditionalTitle)
|
||||
}
|
||||
|
||||
// store the title element
|
||||
let titleElement: t.JSXExpressionContainer | null = null
|
||||
|
||||
const hasTitle = path.get('children').some((childPath) => {
|
||||
if (childPath.node === titleElement) return false
|
||||
if (!childPath.isJSXElement()) return false
|
||||
const name = childPath.get('openingElement').get('name')
|
||||
if (!name.isJSXIdentifier()) return false
|
||||
if (name.node.name !== 'title') return false
|
||||
titleElement = getTitleElement(childPath.node)
|
||||
childPath.replaceWith(titleElement)
|
||||
return true
|
||||
})
|
||||
|
||||
// create a title element if not already create
|
||||
titleElement = titleElement || getTitleElement()
|
||||
if (!hasTitle) {
|
||||
// path.unshiftContainer is not working well :(
|
||||
// path.unshiftContainer('children', titleElement)
|
||||
path.node.children.unshift(titleElement)
|
||||
path.replaceWith(path.node)
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export default plugin
|
||||
4
packages/babel-plugin-svg-dynamic-title/tsconfig.json
Normal file
4
packages/babel-plugin-svg-dynamic-title/tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"include": ["src"]
|
||||
}
|
||||
@ -1,2 +1,6 @@
|
||||
src/
|
||||
.*
|
||||
/*
|
||||
/dist/*
|
||||
!/dist/index.{d.ts,js}
|
||||
!/dist/index.js.map
|
||||
@ -2,7 +2,9 @@
|
||||
"name": "@svgr/babel-plugin-svg-em-dimensions",
|
||||
"description": "Transform SVG to use em-based dimensions",
|
||||
"version": "5.4.0",
|
||||
"main": "lib/index.js",
|
||||
"main": "./dist/index.js",
|
||||
"exports": "./dist/index.js",
|
||||
"typings": "./dist/index.d.ts",
|
||||
"repository": "https://github.com/gregberge/svgr/tree/master/packages/babel-plugin-svg-em-dimensions",
|
||||
"author": "Greg Bergé <berge.greg@gmail.com>",
|
||||
"publishConfig": {
|
||||
@ -20,9 +22,12 @@
|
||||
"url": "https://github.com/sponsors/gregberge"
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0-0"
|
||||
},
|
||||
"scripts": {
|
||||
"prebuild": "rm -rf lib/",
|
||||
"build": "babel --config-file ../../babel.config.js -d lib --ignore \"**/*.test.js\" src",
|
||||
"prepublishOnly": "npm run build"
|
||||
"reset": "rm -rf dist",
|
||||
"build": "rollup -c ../../build/rollup.config.js",
|
||||
"prepublishOnly": "npm run reset && npm run build"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,42 +0,0 @@
|
||||
const elements = ['svg', 'Svg']
|
||||
|
||||
const plugin = ({ types: t }) => ({
|
||||
visitor: {
|
||||
JSXOpeningElement: {
|
||||
enter(path) {
|
||||
if (
|
||||
!elements.some((element) =>
|
||||
path.get('name').isJSXIdentifier({ name: element }),
|
||||
)
|
||||
)
|
||||
return
|
||||
|
||||
const requiredAttributes = ['width', 'height']
|
||||
const attributeValue = '1em'
|
||||
|
||||
path.get('attributes').forEach((attributePath) => {
|
||||
if (!attributePath.isJSXAttribute()) return
|
||||
const index = requiredAttributes.indexOf(attributePath.node.name.name)
|
||||
|
||||
if (index === -1) return
|
||||
|
||||
const value = attributePath.get('value')
|
||||
value.replaceWith(t.stringLiteral(attributeValue))
|
||||
requiredAttributes.splice(index, 1)
|
||||
})
|
||||
|
||||
requiredAttributes.forEach((attribute) => {
|
||||
path.pushContainer(
|
||||
'attributes',
|
||||
t.jsxAttribute(
|
||||
t.jsxIdentifier(attribute),
|
||||
t.stringLiteral(attributeValue),
|
||||
),
|
||||
)
|
||||
})
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export default plugin
|
||||
@ -1,13 +1,13 @@
|
||||
import { transform } from '@babel/core'
|
||||
import plugin from '.'
|
||||
|
||||
const testPlugin = (code, options) => {
|
||||
const testPlugin = (code: string) => {
|
||||
const result = transform(code, {
|
||||
plugins: ['@babel/plugin-syntax-jsx', [plugin, options]],
|
||||
plugins: ['@babel/plugin-syntax-jsx', plugin],
|
||||
configFile: false,
|
||||
})
|
||||
|
||||
return result.code
|
||||
return result?.code
|
||||
}
|
||||
|
||||
describe('plugin', () => {
|
||||
42
packages/babel-plugin-svg-em-dimensions/src/index.ts
Normal file
42
packages/babel-plugin-svg-em-dimensions/src/index.ts
Normal file
@ -0,0 +1,42 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { types as t, NodePath } from '@babel/core'
|
||||
|
||||
const elements = ['svg', 'Svg']
|
||||
const value = t.stringLiteral('1em')
|
||||
|
||||
const plugin = () => ({
|
||||
visitor: {
|
||||
JSXOpeningElement(path: NodePath<t.JSXOpeningElement>) {
|
||||
if (
|
||||
!elements.some((element) =>
|
||||
path.get('name').isJSXIdentifier({ name: element }),
|
||||
)
|
||||
)
|
||||
return
|
||||
|
||||
const requiredAttributes = ['width', 'height']
|
||||
|
||||
path.get('attributes').forEach((attributePath) => {
|
||||
if (!attributePath.isJSXAttribute()) return
|
||||
const namePath = attributePath.get('name')
|
||||
if (!namePath.isJSXIdentifier()) return
|
||||
const index = requiredAttributes.indexOf(namePath.node.name)
|
||||
|
||||
if (index === -1) return
|
||||
|
||||
const valuePath = attributePath.get('value')
|
||||
valuePath.replaceWith(value)
|
||||
requiredAttributes.splice(index, 1)
|
||||
})
|
||||
|
||||
path.pushContainer(
|
||||
'attributes',
|
||||
requiredAttributes.map((attr) =>
|
||||
t.jsxAttribute(t.jsxIdentifier(attr), value),
|
||||
),
|
||||
)
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export default plugin
|
||||
4
packages/babel-plugin-svg-em-dimensions/tsconfig.json
Normal file
4
packages/babel-plugin-svg-em-dimensions/tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"include": ["src"]
|
||||
}
|
||||
@ -1,2 +1,6 @@
|
||||
src/
|
||||
.*
|
||||
/*
|
||||
/dist/*
|
||||
!/dist/index.{d.ts,js}
|
||||
!/dist/index.js.map
|
||||
@ -2,7 +2,9 @@
|
||||
"name": "@svgr/babel-plugin-transform-react-native-svg",
|
||||
"description": "Transform DOM elements into react-native-svg components",
|
||||
"version": "5.4.0",
|
||||
"main": "lib/index.js",
|
||||
"main": "./dist/index.js",
|
||||
"exports": "./dist/index.js",
|
||||
"typings": "./dist/index.d.ts",
|
||||
"repository": "https://github.com/gregberge/svgr/tree/master/packages/babel-plugin-transform-react-native-svg",
|
||||
"author": "Greg Bergé <berge.greg@gmail.com>",
|
||||
"publishConfig": {
|
||||
@ -20,9 +22,12 @@
|
||||
"url": "https://github.com/sponsors/gregberge"
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0-0"
|
||||
},
|
||||
"scripts": {
|
||||
"prebuild": "rm -rf lib/",
|
||||
"build": "babel --config-file ../../babel.config.js -d lib --ignore \"**/*.test.js\" src",
|
||||
"prepublishOnly": "npm run build"
|
||||
"reset": "rm -rf dist",
|
||||
"build": "rollup -c ../../build/rollup.config.js",
|
||||
"prepublishOnly": "npm run reset && npm run build"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,23 +1,23 @@
|
||||
import { transform } from '@babel/core'
|
||||
import plugin from '.'
|
||||
|
||||
const testPlugin = (code, options) => {
|
||||
const testPlugin = (code: string) => {
|
||||
const result = transform(code, {
|
||||
plugins: ['@babel/plugin-syntax-jsx', [plugin, options]],
|
||||
plugins: ['@babel/plugin-syntax-jsx', plugin],
|
||||
configFile: false,
|
||||
})
|
||||
|
||||
return result
|
||||
return result?.code
|
||||
}
|
||||
|
||||
describe('plugin', () => {
|
||||
it('should transform elements', () => {
|
||||
const { code } = testPlugin('<svg><div /></svg>')
|
||||
const code = testPlugin('<svg><div /></svg>')
|
||||
expect(code).toMatchInlineSnapshot(`"<Svg></Svg>;"`)
|
||||
})
|
||||
|
||||
it('should add import', () => {
|
||||
const { code } = testPlugin(
|
||||
const code = testPlugin(
|
||||
`import Svg from 'react-native-svg'; <svg><g /><div /></svg>;`,
|
||||
)
|
||||
expect(code).toMatchInlineSnapshot(`
|
||||
@ -25,19 +25,6 @@ describe('plugin', () => {
|
||||
/* SVGR has dropped some elements not supported by react-native-svg: div */
|
||||
|
||||
<Svg><G /></Svg>;"
|
||||
`)
|
||||
})
|
||||
|
||||
it('should transform for expo import', () => {
|
||||
const { code } = testPlugin(`import 'expo'; <svg><g /><div /></svg>;`, {
|
||||
expo: true,
|
||||
})
|
||||
|
||||
expect(code).toMatchInlineSnapshot(`
|
||||
"import { Svg } from 'expo';
|
||||
/* SVGR has dropped some elements not supported by react-native-svg: div */
|
||||
|
||||
<Svg><Svg.G /></Svg>;"
|
||||
`)
|
||||
})
|
||||
})
|
||||
@ -1,4 +1,12 @@
|
||||
const elementToComponent = {
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { NodePath, types as t } from '@babel/core'
|
||||
|
||||
interface State {
|
||||
replacedComponents: Set<string>
|
||||
unsupportedComponents: Set<string>
|
||||
}
|
||||
|
||||
const elementToComponent: { [key: string]: string } = {
|
||||
svg: 'Svg',
|
||||
circle: 'Circle',
|
||||
clipPath: 'ClipPath',
|
||||
@ -24,30 +32,24 @@ const elementToComponent = {
|
||||
foreignObject: 'ForeignObject',
|
||||
}
|
||||
|
||||
const expoPrefix = (component, expo) => {
|
||||
// Prefix with 'Svg.' in the case we're transforming for Expo
|
||||
if (!expo) {
|
||||
return component
|
||||
}
|
||||
return (component !== 'Svg' ? 'Svg.' : '') + component
|
||||
}
|
||||
|
||||
const plugin = ({ types: t }, { expo }) => {
|
||||
function replaceElement(path, state) {
|
||||
const { name } = path.node.openingElement.name
|
||||
const plugin = () => {
|
||||
function replaceElement(path: NodePath<t.JSXElement>, state: State) {
|
||||
const namePath = path.get('openingElement').get('name')
|
||||
if (!namePath.isJSXIdentifier()) return
|
||||
const { name } = namePath.node
|
||||
|
||||
// Replace element by react-native-svg components
|
||||
const component = elementToComponent[name]
|
||||
|
||||
if (component) {
|
||||
const prefixedComponent = expoPrefix(component, expo)
|
||||
const openingElementName = path.get('openingElement.name')
|
||||
openingElementName.replaceWith(t.jsxIdentifier(prefixedComponent))
|
||||
namePath.replaceWith(t.jsxIdentifier(component))
|
||||
if (path.has('closingElement')) {
|
||||
const closingElementName = path.get('closingElement.name')
|
||||
closingElementName.replaceWith(t.jsxIdentifier(prefixedComponent))
|
||||
const closingNamePath = path
|
||||
.get('closingElement')
|
||||
.get('name') as NodePath<t.JSXIdentifier>
|
||||
closingNamePath.replaceWith(t.jsxIdentifier(component))
|
||||
}
|
||||
state.replacedComponents.add(prefixedComponent)
|
||||
state.replacedComponents.add(component)
|
||||
return
|
||||
}
|
||||
|
||||
@ -57,8 +59,10 @@ const plugin = ({ types: t }, { expo }) => {
|
||||
}
|
||||
|
||||
const svgElementVisitor = {
|
||||
JSXElement(path, state) {
|
||||
if (!path.get('openingElement.name').isJSXIdentifier({ name: 'svg' })) {
|
||||
JSXElement(path: NodePath<t.JSXElement>, state: State) {
|
||||
if (
|
||||
!path.get('openingElement').get('name').isJSXIdentifier({ name: 'svg' })
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -68,13 +72,13 @@ const plugin = ({ types: t }, { expo }) => {
|
||||
}
|
||||
|
||||
const jsxElementVisitor = {
|
||||
JSXElement(path, state) {
|
||||
JSXElement(path: NodePath<t.JSXElement>, state: State) {
|
||||
replaceElement(path, state)
|
||||
},
|
||||
}
|
||||
|
||||
const importDeclarationVisitor = {
|
||||
ImportDeclaration(path, state) {
|
||||
ImportDeclaration(path: NodePath<t.ImportDeclaration>, state: State) {
|
||||
if (path.get('source').isStringLiteral({ value: 'react-native-svg' })) {
|
||||
state.replacedComponents.forEach((component) => {
|
||||
if (
|
||||
@ -113,12 +117,12 @@ const plugin = ({ types: t }, { expo }) => {
|
||||
|
||||
return {
|
||||
visitor: {
|
||||
Program(path, state) {
|
||||
Program(path: NodePath<t.Program>, state: Partial<State>) {
|
||||
state.replacedComponents = new Set()
|
||||
state.unsupportedComponents = new Set()
|
||||
|
||||
path.traverse(svgElementVisitor, state)
|
||||
path.traverse(importDeclarationVisitor, state)
|
||||
path.traverse(svgElementVisitor, state as State)
|
||||
path.traverse(importDeclarationVisitor, state as State)
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"include": ["src"]
|
||||
}
|
||||
@ -1,2 +1,4 @@
|
||||
src/
|
||||
.*
|
||||
/*
|
||||
/dist/*
|
||||
!/dist/index.{d.ts,js}
|
||||
!/dist/index.js.map
|
||||
@ -2,7 +2,9 @@
|
||||
"name": "@svgr/babel-plugin-transform-svg-component",
|
||||
"description": "Transform SVG into component",
|
||||
"version": "6.0.0-alpha.0",
|
||||
"main": "lib/index.js",
|
||||
"main": "./dist/index.js",
|
||||
"exports": "./dist/index.js",
|
||||
"typings": "./dist/index.d.ts",
|
||||
"repository": "https://github.com/gregberge/svgr/tree/master/packages/babel-plugin-transform-svg-component",
|
||||
"author": "Greg Bergé <berge.greg@gmail.com>",
|
||||
"publishConfig": {
|
||||
@ -12,7 +14,7 @@
|
||||
"babel-plugin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
"node": ">=12"
|
||||
},
|
||||
"homepage": "https://react-svgr.com",
|
||||
"funding": {
|
||||
@ -20,9 +22,12 @@
|
||||
"url": "https://github.com/sponsors/gregberge"
|
||||
},
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0-0"
|
||||
},
|
||||
"scripts": {
|
||||
"prebuild": "rm -rf lib/",
|
||||
"build": "babel --config-file ../../babel.config.js -d lib --ignore \"**/*.test.js\" src",
|
||||
"prepublishOnly": "npm run build"
|
||||
"reset": "rm -rf dist",
|
||||
"build": "rollup -c ../../build/rollup.config.js",
|
||||
"prepublishOnly": "npm run reset && npm run build"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,21 +1,5 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[` 1`] = `
|
||||
"import * as React from 'react';
|
||||
|
||||
const MyComponent = () => <main>{<svg><g /></svg>}</main>;
|
||||
|
||||
export default MyComponent;"
|
||||
`;
|
||||
|
||||
exports[` 2`] = `
|
||||
"import * as React from 'react';
|
||||
|
||||
const MyComponent = () => <main>{<svg><g /></svg>}</main>;
|
||||
|
||||
export default MyComponent;"
|
||||
`;
|
||||
|
||||
exports[`plugin javascript custom templates support basic template 1`] = `
|
||||
"import * as React from 'react';
|
||||
|
||||
@ -24,6 +8,14 @@ const MyComponent = () => <svg><g /></svg>;
|
||||
export default MyComponent;"
|
||||
`;
|
||||
|
||||
exports[`plugin javascript custom templates supports JSX template 1`] = `
|
||||
"import * as React from 'react';
|
||||
|
||||
const MyComponent = () => <main>{<svg><g /></svg>}</main>;
|
||||
|
||||
export default MyComponent;"
|
||||
`;
|
||||
|
||||
exports[`plugin javascript custom templates supports TypeScript template 1`] = `
|
||||
"import * as React from 'react';
|
||||
|
||||
@ -37,9 +29,7 @@ exports[`plugin javascript custom templates supports template that does not retu
|
||||
exports[`plugin javascript transforms whole program 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
|
||||
function SvgComponent() {
|
||||
return <svg><g /></svg>;
|
||||
}
|
||||
const SvgComponent = () => <svg><g /></svg>;
|
||||
|
||||
export default SvgComponent;"
|
||||
`;
|
||||
@ -47,30 +37,25 @@ export default SvgComponent;"
|
||||
exports[`plugin javascript with "expandProps" add props 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
|
||||
function SvgComponent(props) {
|
||||
return <svg><g /></svg>;
|
||||
}
|
||||
const SvgComponent = props => <svg><g /></svg>;
|
||||
|
||||
export default SvgComponent;"
|
||||
`;
|
||||
|
||||
exports[`plugin javascript with "memo" option wrap component in "React.memo" 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
import { memo } from \\"react\\";
|
||||
|
||||
function SvgComponent() {
|
||||
return <svg><g /></svg>;
|
||||
}
|
||||
const SvgComponent = () => <svg><g /></svg>;
|
||||
|
||||
const MemoSvgComponent = React.memo(SvgComponent);
|
||||
export default MemoSvgComponent;"
|
||||
const Memo = memo(SvgComponent);
|
||||
export default Memo;"
|
||||
`;
|
||||
|
||||
exports[`plugin javascript with "namedExport" and "exportType" option and without "previousExport" state exports via named export 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
|
||||
function SvgComponent() {
|
||||
return <svg><g /></svg>;
|
||||
}
|
||||
const SvgComponent = () => <svg><g /></svg>;
|
||||
|
||||
export { SvgComponent as ReactComponent };"
|
||||
`;
|
||||
@ -78,11 +63,8 @@ export { SvgComponent as ReactComponent };"
|
||||
exports[`plugin javascript with "namedExport" option and "previousExport" state has custom named export 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
|
||||
function SvgComponent() {
|
||||
return <svg><g /></svg>;
|
||||
}
|
||||
const SvgComponent = () => <svg><g /></svg>;
|
||||
|
||||
export default \\"logo.svg\\";
|
||||
export { SvgComponent as Component };"
|
||||
`;
|
||||
|
||||
@ -90,9 +72,7 @@ exports[`plugin javascript with "native" and "expandProps" option adds import fr
|
||||
"import * as React from \\"react\\";
|
||||
import Svg from \\"react-native-svg\\";
|
||||
|
||||
function SvgComponent(props) {
|
||||
return <Svg><g /></Svg>;
|
||||
}
|
||||
const SvgComponent = props => <Svg><g /></Svg>;
|
||||
|
||||
export default SvgComponent;"
|
||||
`;
|
||||
@ -101,9 +81,7 @@ exports[`plugin javascript with "native" option adds import from "react-native-s
|
||||
"import * as React from \\"react\\";
|
||||
import Svg from \\"react-native-svg\\";
|
||||
|
||||
function SvgComponent() {
|
||||
return <Svg><g /></Svg>;
|
||||
}
|
||||
const SvgComponent = () => <Svg><g /></Svg>;
|
||||
|
||||
export default SvgComponent;"
|
||||
`;
|
||||
@ -111,69 +89,52 @@ export default SvgComponent;"
|
||||
exports[`plugin javascript with "native", "ref" and "expandProps" option adds import from "react-native-svg" and adds props and adds ForwardRef component 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
import Svg from \\"react-native-svg\\";
|
||||
import { forwardRef } from \\"react\\";
|
||||
|
||||
function SvgComponent(props, svgRef) {
|
||||
return <Svg><g /></Svg>;
|
||||
}
|
||||
const SvgComponent = (props, ref) => <Svg><g /></Svg>;
|
||||
|
||||
const ForwardRef = React.forwardRef(SvgComponent);
|
||||
const ForwardRef = forwardRef(SvgComponent);
|
||||
export default ForwardRef;"
|
||||
`;
|
||||
|
||||
exports[`plugin javascript with "native", "ref" option adds import from "react-native-svg" and adds ForwardRef component 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
import Svg from \\"react-native-svg\\";
|
||||
import { forwardRef } from \\"react\\";
|
||||
|
||||
function SvgComponent(props, svgRef) {
|
||||
return <Svg><g /></Svg>;
|
||||
}
|
||||
const SvgComponent = (_, ref) => <Svg><g /></Svg>;
|
||||
|
||||
const ForwardRef = React.forwardRef(SvgComponent);
|
||||
const ForwardRef = forwardRef(SvgComponent);
|
||||
export default ForwardRef;"
|
||||
`;
|
||||
|
||||
exports[`plugin javascript with "native.expo" option adds import from "react-native-svg" & from "expo" 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
import \\"expo\\";
|
||||
|
||||
function SvgComponent() {
|
||||
return <Svg><g /></Svg>;
|
||||
}
|
||||
|
||||
export default SvgComponent;"
|
||||
`;
|
||||
|
||||
exports[`plugin javascript with "ref" and "expandProps" option expands props 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
import { forwardRef } from \\"react\\";
|
||||
|
||||
function SvgComponent(props, svgRef) {
|
||||
return <svg><g /></svg>;
|
||||
}
|
||||
const SvgComponent = (props, ref) => <svg><g /></svg>;
|
||||
|
||||
const ForwardRef = React.forwardRef(SvgComponent);
|
||||
const ForwardRef = forwardRef(SvgComponent);
|
||||
export default ForwardRef;"
|
||||
`;
|
||||
|
||||
exports[`plugin javascript with "ref" option adds ForwardRef component 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
import { forwardRef } from \\"react\\";
|
||||
|
||||
function SvgComponent(props, svgRef) {
|
||||
return <svg><g /></svg>;
|
||||
}
|
||||
const SvgComponent = (_, ref) => <svg><g /></svg>;
|
||||
|
||||
const ForwardRef = React.forwardRef(SvgComponent);
|
||||
const ForwardRef = forwardRef(SvgComponent);
|
||||
export default ForwardRef;"
|
||||
`;
|
||||
|
||||
exports[`plugin javascript with "titleProp" adds "titleProp" and "titleId" prop 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
|
||||
function SvgComponent({
|
||||
const SvgComponent = ({
|
||||
title,
|
||||
titleId
|
||||
}) {
|
||||
return <svg><g /></svg>;
|
||||
}
|
||||
}) => <svg><g /></svg>;
|
||||
|
||||
export default SvgComponent;"
|
||||
`;
|
||||
@ -181,27 +142,24 @@ export default SvgComponent;"
|
||||
exports[`plugin javascript with "titleProp" and "expandProps" adds "titleProp", "titleId" props and expands props 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
|
||||
function SvgComponent({
|
||||
const SvgComponent = ({
|
||||
title,
|
||||
titleId,
|
||||
...props
|
||||
}) {
|
||||
return <svg><g /></svg>;
|
||||
}
|
||||
}) => <svg><g /></svg>;
|
||||
|
||||
export default SvgComponent;"
|
||||
`;
|
||||
|
||||
exports[`plugin javascript with both "memo" and "ref" option wrap component in "React.memo" and "React.forwardRef" 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
import { forwardRef, memo } from \\"react\\";
|
||||
|
||||
function SvgComponent(props, svgRef) {
|
||||
return <svg><g /></svg>;
|
||||
}
|
||||
const SvgComponent = (_, ref) => <svg><g /></svg>;
|
||||
|
||||
const ForwardRef = React.forwardRef(SvgComponent);
|
||||
const MemoForwardRef = React.memo(ForwardRef);
|
||||
export default MemoForwardRef;"
|
||||
const ForwardRef = forwardRef(SvgComponent);
|
||||
const Memo = memo(ForwardRef);
|
||||
export default Memo;"
|
||||
`;
|
||||
|
||||
exports[`plugin typescript custom templates support basic template 1`] = `
|
||||
@ -212,6 +170,14 @@ const MyComponent = () => <svg><g /></svg>;
|
||||
export default MyComponent;"
|
||||
`;
|
||||
|
||||
exports[`plugin typescript custom templates supports JSX template 1`] = `
|
||||
"import * as React from 'react';
|
||||
|
||||
const MyComponent = () => <main>{<svg><g /></svg>}</main>;
|
||||
|
||||
export default MyComponent;"
|
||||
`;
|
||||
|
||||
exports[`plugin typescript custom templates supports TypeScript template 1`] = `
|
||||
"import * as React from 'react';
|
||||
|
||||
@ -225,40 +191,34 @@ exports[`plugin typescript custom templates supports template that does not retu
|
||||
exports[`plugin typescript transforms whole program 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
|
||||
function SvgComponent() {
|
||||
return <svg><g /></svg>;
|
||||
}
|
||||
const SvgComponent = () => <svg><g /></svg>;
|
||||
|
||||
export default SvgComponent;"
|
||||
`;
|
||||
|
||||
exports[`plugin typescript with "expandProps" add props 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
import { SVGProps } from \\"react\\";
|
||||
|
||||
function SvgComponent(props: React.SVGProps<SVGSVGElement>) {
|
||||
return <svg><g /></svg>;
|
||||
}
|
||||
const SvgComponent = (props: SVGProps<SVGSVGElement>) => <svg><g /></svg>;
|
||||
|
||||
export default SvgComponent;"
|
||||
`;
|
||||
|
||||
exports[`plugin typescript with "memo" option wrap component in "React.memo" 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
import { memo } from \\"react\\";
|
||||
|
||||
function SvgComponent() {
|
||||
return <svg><g /></svg>;
|
||||
}
|
||||
const SvgComponent = () => <svg><g /></svg>;
|
||||
|
||||
const MemoSvgComponent = React.memo(SvgComponent);
|
||||
export default MemoSvgComponent;"
|
||||
const Memo = memo(SvgComponent);
|
||||
export default Memo;"
|
||||
`;
|
||||
|
||||
exports[`plugin typescript with "namedExport" and "exportType" option and without "previousExport" state exports via named export 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
|
||||
function SvgComponent() {
|
||||
return <svg><g /></svg>;
|
||||
}
|
||||
const SvgComponent = () => <svg><g /></svg>;
|
||||
|
||||
export { SvgComponent as ReactComponent };"
|
||||
`;
|
||||
@ -266,11 +226,8 @@ export { SvgComponent as ReactComponent };"
|
||||
exports[`plugin typescript with "namedExport" option and "previousExport" state has custom named export 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
|
||||
function SvgComponent() {
|
||||
return <svg><g /></svg>;
|
||||
}
|
||||
const SvgComponent = () => <svg><g /></svg>;
|
||||
|
||||
export default \\"logo.svg\\";
|
||||
export { SvgComponent as Component };"
|
||||
`;
|
||||
|
||||
@ -278,9 +235,7 @@ exports[`plugin typescript with "native" and "expandProps" option adds import fr
|
||||
"import * as React from \\"react\\";
|
||||
import Svg, { SvgProps } from \\"react-native-svg\\";
|
||||
|
||||
function SvgComponent(props: SvgProps) {
|
||||
return <Svg><g /></Svg>;
|
||||
}
|
||||
const SvgComponent = (props: SvgProps) => <Svg><g /></Svg>;
|
||||
|
||||
export default SvgComponent;"
|
||||
`;
|
||||
@ -289,9 +244,7 @@ exports[`plugin typescript with "native" option adds import from "react-native-s
|
||||
"import * as React from \\"react\\";
|
||||
import Svg from \\"react-native-svg\\";
|
||||
|
||||
function SvgComponent() {
|
||||
return <Svg><g /></Svg>;
|
||||
}
|
||||
const SvgComponent = () => <Svg><g /></Svg>;
|
||||
|
||||
export default SvgComponent;"
|
||||
`;
|
||||
@ -299,103 +252,84 @@ export default SvgComponent;"
|
||||
exports[`plugin typescript with "native", "ref" and "expandProps" option adds import from "react-native-svg" and adds props and adds ForwardRef component 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
import Svg, { SvgProps } from \\"react-native-svg\\";
|
||||
import { Ref, forwardRef } from \\"react\\";
|
||||
|
||||
function SvgComponent(props: SvgProps, svgRef?: React.Ref<React.Component<SvgProps>>) {
|
||||
return <Svg><g /></Svg>;
|
||||
}
|
||||
const SvgComponent = (props: SvgProps, ref: Ref<SVGSVGElement>) => <Svg><g /></Svg>;
|
||||
|
||||
const ForwardRef = React.forwardRef(SvgComponent);
|
||||
const ForwardRef = forwardRef(SvgComponent);
|
||||
export default ForwardRef;"
|
||||
`;
|
||||
|
||||
exports[`plugin typescript with "native", "ref" option adds import from "react-native-svg" and adds ForwardRef component 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
import Svg from \\"react-native-svg\\";
|
||||
import { Ref, forwardRef } from \\"react\\";
|
||||
|
||||
function SvgComponent(props: {}, svgRef?: React.Ref<React.Component<SvgProps>>) {
|
||||
return <Svg><g /></Svg>;
|
||||
}
|
||||
const SvgComponent = (_, ref: Ref<SVGSVGElement>) => <Svg><g /></Svg>;
|
||||
|
||||
const ForwardRef = React.forwardRef(SvgComponent);
|
||||
const ForwardRef = forwardRef(SvgComponent);
|
||||
export default ForwardRef;"
|
||||
`;
|
||||
|
||||
exports[`plugin typescript with "native.expo" option adds import from "react-native-svg" & from "expo" 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
import \\"expo\\";
|
||||
|
||||
function SvgComponent() {
|
||||
return <Svg><g /></Svg>;
|
||||
}
|
||||
|
||||
export default SvgComponent;"
|
||||
`;
|
||||
|
||||
exports[`plugin typescript with "ref" and "expandProps" option expands props 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
import { SVGProps, Ref, forwardRef } from \\"react\\";
|
||||
|
||||
function SvgComponent(props: React.SVGProps<SVGSVGElement>, svgRef?: React.Ref<SVGSVGElement>) {
|
||||
return <svg><g /></svg>;
|
||||
}
|
||||
const SvgComponent = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => <svg><g /></svg>;
|
||||
|
||||
const ForwardRef = React.forwardRef(SvgComponent);
|
||||
const ForwardRef = forwardRef(SvgComponent);
|
||||
export default ForwardRef;"
|
||||
`;
|
||||
|
||||
exports[`plugin typescript with "ref" option adds ForwardRef component 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
import { Ref, forwardRef } from \\"react\\";
|
||||
|
||||
function SvgComponent(props: {}, svgRef?: React.Ref<SVGSVGElement>) {
|
||||
return <svg><g /></svg>;
|
||||
}
|
||||
const SvgComponent = (_, ref: Ref<SVGSVGElement>) => <svg><g /></svg>;
|
||||
|
||||
const ForwardRef = React.forwardRef(SvgComponent);
|
||||
const ForwardRef = forwardRef(SvgComponent);
|
||||
export default ForwardRef;"
|
||||
`;
|
||||
|
||||
exports[`plugin typescript with "titleProp" adds "titleProp" and "titleId" prop 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
interface SVGRProps {
|
||||
title?: string,
|
||||
titleId?: string,
|
||||
title?: string;
|
||||
titleId?: string;
|
||||
}
|
||||
|
||||
function SvgComponent({
|
||||
const SvgComponent = ({
|
||||
title,
|
||||
titleId
|
||||
}: SVGRProps) {
|
||||
return <svg><g /></svg>;
|
||||
}
|
||||
}: SVGRProps) => <svg><g /></svg>;
|
||||
|
||||
export default SvgComponent;"
|
||||
`;
|
||||
|
||||
exports[`plugin typescript with "titleProp" and "expandProps" adds "titleProp", "titleId" props and expands props 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
import { SVGProps } from \\"react\\";
|
||||
interface SVGRProps {
|
||||
title?: string,
|
||||
titleId?: string,
|
||||
title?: string;
|
||||
titleId?: string;
|
||||
}
|
||||
|
||||
function SvgComponent({
|
||||
const SvgComponent = ({
|
||||
title,
|
||||
titleId,
|
||||
...props
|
||||
}: React.SVGProps<SVGSVGElement> & SVGRProps) {
|
||||
return <svg><g /></svg>;
|
||||
}
|
||||
}: SVGProps<SVGSVGElement> & SVGRProps) => <svg><g /></svg>;
|
||||
|
||||
export default SvgComponent;"
|
||||
`;
|
||||
|
||||
exports[`plugin typescript with both "memo" and "ref" option wrap component in "React.memo" and "React.forwardRef" 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
import { Ref, forwardRef, memo } from \\"react\\";
|
||||
|
||||
function SvgComponent(props: {}, svgRef?: React.Ref<SVGSVGElement>) {
|
||||
return <svg><g /></svg>;
|
||||
}
|
||||
const SvgComponent = (_, ref: Ref<SVGSVGElement>) => <svg><g /></svg>;
|
||||
|
||||
const ForwardRef = React.forwardRef(SvgComponent);
|
||||
const MemoForwardRef = React.memo(ForwardRef);
|
||||
export default MemoForwardRef;"
|
||||
const ForwardRef = forwardRef(SvgComponent);
|
||||
const Memo = memo(ForwardRef);
|
||||
export default Memo;"
|
||||
`;
|
||||
@ -0,0 +1,15 @@
|
||||
import type { Template } from './types'
|
||||
|
||||
export const defaultTemplate: Template = (variables, { tpl }) => {
|
||||
return tpl`
|
||||
${variables.imports};
|
||||
|
||||
${variables.interfaces};
|
||||
|
||||
const ${variables.componentName} = (${variables.props}) => (
|
||||
${variables.jsx}
|
||||
);
|
||||
|
||||
${variables.exports};
|
||||
`
|
||||
}
|
||||
@ -1,47 +0,0 @@
|
||||
import { getProps, getImport, getExport, getInterface } from './util'
|
||||
|
||||
function defaultTemplate(
|
||||
{ template },
|
||||
opts,
|
||||
{ imports, interfaces, componentName, props, jsx, exports },
|
||||
) {
|
||||
const plugins = ['jsx']
|
||||
if (opts.typescript) {
|
||||
plugins.push('typescript')
|
||||
}
|
||||
const typeScriptTpl = template.smart({ plugins })
|
||||
return typeScriptTpl.ast`${imports}
|
||||
|
||||
${interfaces}
|
||||
|
||||
function ${componentName}(${props}) {
|
||||
return ${jsx};
|
||||
}
|
||||
${exports}
|
||||
`
|
||||
}
|
||||
|
||||
const plugin = (api, opts) => ({
|
||||
visitor: {
|
||||
Program(path) {
|
||||
const { types: t } = api
|
||||
const template = opts.template || defaultTemplate
|
||||
const body = template(api, opts, {
|
||||
componentName: t.identifier(opts.state.componentName),
|
||||
interfaces: getInterface(api, opts),
|
||||
props: getProps(api, opts),
|
||||
imports: getImport(api, opts),
|
||||
exports: getExport(api, opts),
|
||||
jsx: path.node.body[0].expression,
|
||||
})
|
||||
if (Array.isArray(body)) {
|
||||
path.node.body = body
|
||||
} else {
|
||||
path.node.body = [body]
|
||||
}
|
||||
path.replaceWith(path.node)
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export default plugin
|
||||
@ -1,51 +1,55 @@
|
||||
import { transform } from '@babel/core'
|
||||
import plugin from '.'
|
||||
import plugin, { Options } from '.'
|
||||
|
||||
const testPlugin = (language) => (code, options) => {
|
||||
const result = transform(code, {
|
||||
plugins: [
|
||||
'@babel/plugin-syntax-jsx',
|
||||
[plugin, { ...options, typescript: language === 'typescript' }],
|
||||
],
|
||||
configFile: false,
|
||||
})
|
||||
|
||||
return result
|
||||
const defaultOptions = {
|
||||
namedExport: 'ReactComponent',
|
||||
state: { componentName: 'SvgComponent' },
|
||||
}
|
||||
|
||||
const testPlugin =
|
||||
(language: string) =>
|
||||
(code: string, options: Partial<Options> = {}) => {
|
||||
const result = transform(code, {
|
||||
plugins: [
|
||||
'@babel/plugin-syntax-jsx',
|
||||
[
|
||||
plugin,
|
||||
{
|
||||
typescript: language === 'typescript',
|
||||
...defaultOptions,
|
||||
...options,
|
||||
},
|
||||
],
|
||||
],
|
||||
configFile: false,
|
||||
})
|
||||
|
||||
if (!result) {
|
||||
throw new Error(`No result`)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
describe('plugin', () => {
|
||||
describe.each(['javascript', 'typescript'])('%s', (language) => {
|
||||
it('transforms whole program', () => {
|
||||
const { code } = testPlugin(language)('<svg><g /></svg>', {
|
||||
state: { componentName: 'SvgComponent' },
|
||||
})
|
||||
const { code } = testPlugin(language)('<svg><g /></svg>')
|
||||
expect(code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
describe('with "native" option', () => {
|
||||
it('adds import from "react-native-svg"', () => {
|
||||
const { code } = testPlugin(language)('<Svg><g /></Svg>', {
|
||||
state: { componentName: 'SvgComponent' },
|
||||
native: true,
|
||||
})
|
||||
expect(code).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
|
||||
describe('with "native.expo" option', () => {
|
||||
it('adds import from "react-native-svg" & from "expo"', () => {
|
||||
const { code } = testPlugin(language)('<Svg><g /></Svg>', {
|
||||
state: { componentName: 'SvgComponent' },
|
||||
native: { expo: true },
|
||||
})
|
||||
expect(code).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
|
||||
describe('with "ref" option', () => {
|
||||
it('adds ForwardRef component', () => {
|
||||
const { code } = testPlugin(language)('<svg><g /></svg>', {
|
||||
state: { componentName: 'SvgComponent' },
|
||||
ref: true,
|
||||
})
|
||||
expect(code).toMatchSnapshot()
|
||||
@ -55,7 +59,6 @@ describe('plugin', () => {
|
||||
describe('with "titleProp"', () => {
|
||||
it('adds "titleProp" and "titleId" prop', () => {
|
||||
const { code } = testPlugin(language)('<svg><g /></svg>', {
|
||||
state: { componentName: 'SvgComponent' },
|
||||
titleProp: true,
|
||||
})
|
||||
expect(code).toMatchSnapshot()
|
||||
@ -65,7 +68,7 @@ describe('plugin', () => {
|
||||
describe('with "titleProp" and "expandProps"', () => {
|
||||
it('adds "titleProp", "titleId" props and expands props', () => {
|
||||
const { code } = testPlugin(language)('<svg><g /></svg>', {
|
||||
state: { componentName: 'SvgComponent' },
|
||||
...defaultOptions,
|
||||
expandProps: true,
|
||||
titleProp: true,
|
||||
})
|
||||
@ -76,6 +79,7 @@ describe('plugin', () => {
|
||||
describe('with "expandProps"', () => {
|
||||
it('add props', () => {
|
||||
const { code } = testPlugin(language)('<svg><g /></svg>', {
|
||||
...defaultOptions,
|
||||
state: { componentName: 'SvgComponent' },
|
||||
expandProps: true,
|
||||
})
|
||||
@ -179,24 +183,19 @@ describe('plugin', () => {
|
||||
describe('custom templates', () => {
|
||||
it('support basic template', () => {
|
||||
const { code } = testPlugin(language)('<svg><g /></svg>', {
|
||||
template: (
|
||||
{ template },
|
||||
opts,
|
||||
{ jsx },
|
||||
) => template.ast`import * as React from 'react';
|
||||
const MyComponent = () => ${jsx}
|
||||
export default MyComponent
|
||||
`,
|
||||
template: ({ jsx }, { tpl }) => tpl`import * as React from 'react';
|
||||
const MyComponent = () => ${jsx}
|
||||
export default MyComponent
|
||||
`,
|
||||
state: { componentName: 'SvgComponent' },
|
||||
})
|
||||
expect(code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
describe('it supports JSX template', () => {
|
||||
it('supports JSX template', () => {
|
||||
const { code } = testPlugin(language)('<svg><g /></svg>', {
|
||||
template: ({ template }, opts, { jsx }) => {
|
||||
const jsxTemplate = template.smart({ plugins: ['jsx'] })
|
||||
return jsxTemplate.ast`import * as React from 'react';
|
||||
template: ({ jsx }, { tpl }) => {
|
||||
return tpl`import * as React from 'react';
|
||||
const MyComponent = () => <main>{${jsx}}</main>
|
||||
export default MyComponent
|
||||
`
|
||||
@ -208,16 +207,14 @@ describe('plugin', () => {
|
||||
|
||||
it('supports TypeScript template', () => {
|
||||
const { code } = testPlugin(language)('<svg><g /></svg>', {
|
||||
template: ({ template }, opts, { jsx }) => {
|
||||
const typescriptTemplate = template.smart({
|
||||
plugins: ['typescript'],
|
||||
})
|
||||
return typescriptTemplate.ast`
|
||||
template: ({ jsx }, { tpl }) => {
|
||||
return tpl`
|
||||
import * as React from 'react';
|
||||
const MyComponent = (props: React.SVGProps<SVGSVGElement>) => ${jsx};
|
||||
export default MyComponent;
|
||||
`
|
||||
},
|
||||
typescript: true,
|
||||
state: { componentName: 'SvgComponent' },
|
||||
})
|
||||
expect(code).toMatchSnapshot()
|
||||
@ -225,7 +222,7 @@ describe('plugin', () => {
|
||||
|
||||
it('supports template that does not return an array', () => {
|
||||
const { code } = testPlugin(language)('<svg><g /></svg>', {
|
||||
template: ({ template }, opts, { jsx }) => template.ast`${jsx}`,
|
||||
template: ({ jsx }, { tpl }) => tpl`${jsx}`,
|
||||
state: { componentName: 'SvgComponent' },
|
||||
})
|
||||
expect(code).toMatchSnapshot()
|
||||
38
packages/babel-plugin-transform-svg-component/src/index.ts
Normal file
38
packages/babel-plugin-transform-svg-component/src/index.ts
Normal file
@ -0,0 +1,38 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import {
|
||||
ConfigAPI,
|
||||
NodePath,
|
||||
types as t,
|
||||
template as babelTemplate,
|
||||
ParserOptions,
|
||||
} from '@babel/core'
|
||||
import type { Options } from './types'
|
||||
import { defaultTemplate } from './defaultTemplate'
|
||||
import { getVariables } from './variables'
|
||||
|
||||
export type { Options } from './types'
|
||||
|
||||
const plugin = (_: ConfigAPI, opts: Options) => {
|
||||
const template = opts.template || defaultTemplate
|
||||
const plugins: ParserOptions['plugins'] = opts.typescript
|
||||
? ['jsx', 'typescript']
|
||||
: ['jsx']
|
||||
const tpl = babelTemplate.smart({ plugins }).ast
|
||||
return {
|
||||
visitor: {
|
||||
Program(path: NodePath<t.Program>) {
|
||||
const jsx = (path.node.body[0] as t.ExpressionStatement)
|
||||
.expression as t.JSXElement
|
||||
const variables = getVariables({
|
||||
opts,
|
||||
jsx,
|
||||
})
|
||||
const body = template(variables, { options: opts, tpl })
|
||||
path.node.body = Array.isArray(body) ? body : [body]
|
||||
path.replaceWith(path.node)
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export default plugin
|
||||
40
packages/babel-plugin-transform-svg-component/src/types.ts
Normal file
40
packages/babel-plugin-transform-svg-component/src/types.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import type { types as t } from '@babel/core'
|
||||
import type { TemplateBuilder } from '@babel/template'
|
||||
|
||||
export interface TemplateVariables {
|
||||
componentName: t.Identifier
|
||||
interfaces: t.TSInterfaceDeclaration[]
|
||||
props: (t.ObjectPattern | t.Identifier)[]
|
||||
imports: t.ImportDeclaration[]
|
||||
exports: (t.VariableDeclaration | t.ExportDeclaration)[]
|
||||
jsx: t.JSXElement
|
||||
}
|
||||
|
||||
interface TemplateContext {
|
||||
options: Options
|
||||
tpl: TemplateBuilder<t.Statement | t.Statement[]>['ast']
|
||||
}
|
||||
|
||||
export interface Template {
|
||||
(variables: TemplateVariables, context: TemplateContext):
|
||||
| t.Statement
|
||||
| t.Statement[]
|
||||
}
|
||||
|
||||
interface State {
|
||||
componentName: string
|
||||
caller?: { previousExport?: string | null }
|
||||
}
|
||||
|
||||
export interface Options {
|
||||
typescript?: boolean
|
||||
titleProp?: boolean
|
||||
expandProps?: boolean | 'start' | 'end'
|
||||
ref?: boolean
|
||||
template?: Template
|
||||
state: State
|
||||
native?: boolean
|
||||
memo?: boolean
|
||||
exportType?: 'named' | 'default'
|
||||
namedExport: string
|
||||
}
|
||||
@ -1,242 +0,0 @@
|
||||
function typeAnnotation(typeAnnotation) {
|
||||
return {
|
||||
type: 'TypeAnnotation',
|
||||
typeAnnotation,
|
||||
}
|
||||
}
|
||||
|
||||
function genericTypeAnnotation(id, typeParameters = null) {
|
||||
return { type: 'GenericTypeAnnotation', id, typeParameters }
|
||||
}
|
||||
|
||||
function typeParameters(params) {
|
||||
return {
|
||||
type: 'TypeParameterInstantiation',
|
||||
params,
|
||||
}
|
||||
}
|
||||
|
||||
function qualifiedTypeIdentifier(qualification, id) {
|
||||
return { type: 'QualifiedTypeIdentifier', qualification, id }
|
||||
}
|
||||
|
||||
function intersectionTypeAnnotation(types) {
|
||||
return { type: 'IntersectionTypeAnnotation', types }
|
||||
}
|
||||
|
||||
function interfaceDeclaration(id, body) {
|
||||
return {
|
||||
type: 'InterfaceDeclaration',
|
||||
id,
|
||||
typeParameters: null,
|
||||
extends: [],
|
||||
implements: [],
|
||||
mixins: [],
|
||||
body,
|
||||
}
|
||||
}
|
||||
|
||||
function objectTypeAnnotation(properties) {
|
||||
return {
|
||||
type: 'ObjectTypeAnnotation',
|
||||
properties,
|
||||
}
|
||||
}
|
||||
|
||||
function objectTypeProperty(key, value, optional = false) {
|
||||
return {
|
||||
type: 'ObjectTypeProperty',
|
||||
key,
|
||||
static: false,
|
||||
proto: false,
|
||||
kind: 'init',
|
||||
method: false,
|
||||
value,
|
||||
variance: null,
|
||||
optional,
|
||||
}
|
||||
}
|
||||
|
||||
function addTypeAnotation(obj, typeAnnotation, opts) {
|
||||
if (!opts.typescript) return obj
|
||||
return { ...obj, typeAnnotation }
|
||||
}
|
||||
|
||||
function getSvgPropsTypeAnnotation(t, opts) {
|
||||
if (opts.native) {
|
||||
return t.genericTypeAnnotation(t.identifier('SvgProps'))
|
||||
}
|
||||
return genericTypeAnnotation(
|
||||
qualifiedTypeIdentifier(t.identifier('React'), t.identifier('SVGProps')),
|
||||
typeParameters([genericTypeAnnotation(t.identifier('SVGSVGElement'))]),
|
||||
)
|
||||
}
|
||||
|
||||
export const getProps = ({ types: t }, opts) => {
|
||||
const props = []
|
||||
|
||||
if (opts.titleProp) {
|
||||
props.push(
|
||||
t.objectProperty(
|
||||
t.identifier('title'),
|
||||
t.identifier('title'),
|
||||
false,
|
||||
true,
|
||||
),
|
||||
)
|
||||
|
||||
props.push(
|
||||
t.objectProperty(
|
||||
t.identifier('titleId'),
|
||||
t.identifier('titleId'),
|
||||
false,
|
||||
true,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if (opts.expandProps && props.length > 0) {
|
||||
props.push(t.restElement(t.identifier('props')))
|
||||
}
|
||||
|
||||
const propsArgument =
|
||||
props.length > 0 ? t.objectPattern(props) : t.identifier('props')
|
||||
let propsTypeAnnotation
|
||||
if (props.length > 0) {
|
||||
propsTypeAnnotation = genericTypeAnnotation(t.identifier('SVGRProps'))
|
||||
|
||||
if (opts.expandProps) {
|
||||
propsTypeAnnotation = intersectionTypeAnnotation([
|
||||
getSvgPropsTypeAnnotation(t, opts),
|
||||
propsTypeAnnotation,
|
||||
])
|
||||
}
|
||||
} else {
|
||||
propsTypeAnnotation = opts.expandProps
|
||||
? getSvgPropsTypeAnnotation(t, opts)
|
||||
: t.objectPattern([])
|
||||
}
|
||||
|
||||
const typedPropsArgument = addTypeAnotation(
|
||||
propsArgument,
|
||||
typeAnnotation(propsTypeAnnotation),
|
||||
opts,
|
||||
)
|
||||
|
||||
const args = []
|
||||
if (opts.expandProps || props.length > 0 || opts.ref)
|
||||
args.push(typedPropsArgument)
|
||||
|
||||
if (opts.ref) {
|
||||
const refArgument = t.identifier(opts.typescript ? 'svgRef?' : 'svgRef')
|
||||
const typedRefArgument = addTypeAnotation(
|
||||
refArgument,
|
||||
typeAnnotation(
|
||||
genericTypeAnnotation(
|
||||
qualifiedTypeIdentifier(t.identifier('React'), t.identifier('Ref')),
|
||||
typeParameters([
|
||||
opts.native
|
||||
? genericTypeAnnotation(
|
||||
qualifiedTypeIdentifier(
|
||||
t.identifier('React'),
|
||||
t.identifier('Component'),
|
||||
),
|
||||
typeParameters([
|
||||
genericTypeAnnotation(t.identifier('SvgProps')),
|
||||
]),
|
||||
)
|
||||
: genericTypeAnnotation(t.identifier('SVGSVGElement')),
|
||||
]),
|
||||
),
|
||||
),
|
||||
opts,
|
||||
)
|
||||
|
||||
args.push(typedRefArgument)
|
||||
}
|
||||
|
||||
return args
|
||||
}
|
||||
|
||||
export const getInterface = ({ types: t }, opts) => {
|
||||
if (!opts.typescript) return null
|
||||
const properties = []
|
||||
if (opts.titleProp) {
|
||||
properties.push(
|
||||
objectTypeProperty(t.identifier('title'), t.identifier('string'), true),
|
||||
)
|
||||
properties.push(
|
||||
objectTypeProperty(t.identifier('titleId'), t.identifier('string'), true),
|
||||
)
|
||||
}
|
||||
if (properties.length === 0) return null
|
||||
return interfaceDeclaration(
|
||||
t.identifier('SVGRProps'),
|
||||
objectTypeAnnotation(properties),
|
||||
)
|
||||
}
|
||||
|
||||
export const getImport = ({ types: t }, opts) => {
|
||||
const importDeclarations = [
|
||||
t.importDeclaration(
|
||||
[t.importNamespaceSpecifier(t.identifier('React'))],
|
||||
t.stringLiteral('react'),
|
||||
),
|
||||
]
|
||||
|
||||
if (opts.native) {
|
||||
if (opts.native.expo) {
|
||||
importDeclarations.push(t.importDeclaration([], t.stringLiteral('expo')))
|
||||
} else {
|
||||
const imports = [t.importDefaultSpecifier(t.identifier('Svg'))]
|
||||
if (opts.typescript && opts.expandProps) {
|
||||
imports.push(
|
||||
t.importSpecifier(t.identifier('SvgProps'), t.identifier('SvgProps')),
|
||||
)
|
||||
}
|
||||
importDeclarations.push(
|
||||
t.importDeclaration(imports, t.stringLiteral('react-native-svg')),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return importDeclarations
|
||||
}
|
||||
|
||||
export const getExport = ({ template }, opts) => {
|
||||
let result = ''
|
||||
let exportName = opts.state.componentName
|
||||
const plugins = ['jsx']
|
||||
|
||||
if (opts.typescript) {
|
||||
plugins.push('typescript')
|
||||
}
|
||||
|
||||
if (opts.ref) {
|
||||
const nextExportName = `ForwardRef`
|
||||
result += `const ${nextExportName} = React.forwardRef(${exportName})\n\n`
|
||||
exportName = nextExportName
|
||||
}
|
||||
|
||||
if (opts.memo) {
|
||||
const nextExportName = `Memo${exportName}`
|
||||
result += `const ${nextExportName} = React.memo(${exportName})\n\n`
|
||||
exportName = nextExportName
|
||||
}
|
||||
|
||||
if (opts.state.caller && opts.state.caller.previousExport) {
|
||||
result += `${opts.state.caller.previousExport}\n`
|
||||
result += `export { ${exportName} as ${opts.namedExport} }`
|
||||
return template.ast(result, {
|
||||
plugins,
|
||||
})
|
||||
}
|
||||
|
||||
result +=
|
||||
opts.exportType === 'named'
|
||||
? `export { ${exportName} as ${opts.namedExport} }`
|
||||
: `export default ${exportName}`
|
||||
return template.ast(result, {
|
||||
plugins,
|
||||
})
|
||||
}
|
||||
215
packages/babel-plugin-transform-svg-component/src/variables.ts
Normal file
215
packages/babel-plugin-transform-svg-component/src/variables.ts
Normal file
@ -0,0 +1,215 @@
|
||||
import { types as t } from '@babel/core'
|
||||
import type { Options, TemplateVariables } from './types'
|
||||
|
||||
const tsOptionalPropertySignature = (
|
||||
...args: Parameters<typeof t.tsPropertySignature>
|
||||
) => {
|
||||
return {
|
||||
...t.tsPropertySignature(...args),
|
||||
optional: true,
|
||||
} as t.TSPropertySignature
|
||||
}
|
||||
|
||||
interface Context {
|
||||
opts: Options
|
||||
interfaces: t.TSInterfaceDeclaration[]
|
||||
props: (t.Identifier | t.ObjectPattern)[]
|
||||
imports: t.ImportDeclaration[]
|
||||
}
|
||||
|
||||
const getOrCreateImport = ({ imports }: Context, sourceValue: string) => {
|
||||
const existing = imports.find(
|
||||
(imp) =>
|
||||
imp.source.value === sourceValue &&
|
||||
!imp.specifiers.some(
|
||||
(specifier) => specifier.type === 'ImportNamespaceSpecifier',
|
||||
),
|
||||
)
|
||||
if (existing) return existing
|
||||
const imp = t.importDeclaration([], t.stringLiteral(sourceValue))
|
||||
imports.push(imp)
|
||||
return imp
|
||||
}
|
||||
|
||||
const tsTypeReferenceSVGProps = (ctx: Context) => {
|
||||
if (ctx.opts.native) {
|
||||
const identifier = t.identifier('SvgProps')
|
||||
getOrCreateImport(ctx, 'react-native-svg').specifiers.push(
|
||||
t.importSpecifier(identifier, identifier),
|
||||
)
|
||||
return t.tsTypeReference(identifier)
|
||||
}
|
||||
const identifier = t.identifier('SVGProps')
|
||||
getOrCreateImport(ctx, 'react').specifiers.push(
|
||||
t.importSpecifier(identifier, identifier),
|
||||
)
|
||||
return t.tsTypeReference(
|
||||
identifier,
|
||||
t.tsTypeParameterInstantiation([
|
||||
t.tsTypeReference(t.identifier('SVGSVGElement')),
|
||||
]),
|
||||
)
|
||||
}
|
||||
|
||||
const tsTypeReferenceSVGRef = (ctx: Context) => {
|
||||
const identifier = t.identifier('Ref')
|
||||
getOrCreateImport(ctx, 'react').specifiers.push(
|
||||
t.importSpecifier(identifier, identifier),
|
||||
)
|
||||
return t.tsTypeReference(
|
||||
identifier,
|
||||
t.tsTypeParameterInstantiation([
|
||||
t.tsTypeReference(t.identifier('SVGSVGElement')),
|
||||
]),
|
||||
)
|
||||
}
|
||||
|
||||
export const getVariables = ({
|
||||
opts,
|
||||
jsx,
|
||||
}: {
|
||||
opts: Options
|
||||
jsx: t.JSXElement
|
||||
}): TemplateVariables => {
|
||||
const componentName = t.identifier(opts.state.componentName)
|
||||
const interfaces: t.TSInterfaceDeclaration[] = []
|
||||
const props: (t.Identifier | t.ObjectPattern)[] = []
|
||||
const imports: t.ImportDeclaration[] = []
|
||||
const exports: (t.VariableDeclaration | t.ExportDeclaration)[] = []
|
||||
const ctx = {
|
||||
exportIdentifier: componentName,
|
||||
opts,
|
||||
interfaces,
|
||||
props,
|
||||
imports,
|
||||
exports,
|
||||
}
|
||||
|
||||
imports.push(
|
||||
t.importDeclaration(
|
||||
[t.importNamespaceSpecifier(t.identifier('React'))],
|
||||
t.stringLiteral('react'),
|
||||
),
|
||||
)
|
||||
|
||||
if (opts.native) {
|
||||
getOrCreateImport(ctx, 'react-native-svg').specifiers.push(
|
||||
t.importDefaultSpecifier(t.identifier('Svg')),
|
||||
)
|
||||
}
|
||||
|
||||
if (opts.titleProp) {
|
||||
const prop = t.objectPattern([
|
||||
t.objectProperty(
|
||||
t.identifier('title'),
|
||||
t.identifier('title'),
|
||||
false,
|
||||
true,
|
||||
),
|
||||
t.objectProperty(
|
||||
t.identifier('titleId'),
|
||||
t.identifier('titleId'),
|
||||
false,
|
||||
true,
|
||||
),
|
||||
])
|
||||
props.push(prop)
|
||||
if (opts.typescript) {
|
||||
interfaces.push(
|
||||
t.tsInterfaceDeclaration(
|
||||
t.identifier('SVGRProps'),
|
||||
null,
|
||||
null,
|
||||
t.tSInterfaceBody([
|
||||
tsOptionalPropertySignature(
|
||||
t.identifier('title'),
|
||||
t.tsTypeAnnotation(t.tsStringKeyword()),
|
||||
),
|
||||
tsOptionalPropertySignature(
|
||||
t.identifier('titleId'),
|
||||
t.tsTypeAnnotation(t.tsStringKeyword()),
|
||||
),
|
||||
]),
|
||||
),
|
||||
)
|
||||
prop.typeAnnotation = t.tsTypeAnnotation(
|
||||
t.tsTypeReference(t.identifier('SVGRProps')),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.expandProps) {
|
||||
const identifier = t.identifier('props')
|
||||
if (t.isObjectPattern(props[0])) {
|
||||
props[0].properties.push(t.restElement(identifier))
|
||||
if (opts.typescript) {
|
||||
props[0].typeAnnotation = t.tsTypeAnnotation(
|
||||
t.tsIntersectionType([
|
||||
tsTypeReferenceSVGProps(ctx),
|
||||
(props[0].typeAnnotation as t.TSTypeAnnotation).typeAnnotation,
|
||||
]),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
props.push(identifier)
|
||||
if (opts.typescript) {
|
||||
identifier.typeAnnotation = t.tsTypeAnnotation(
|
||||
tsTypeReferenceSVGProps(ctx),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.ref) {
|
||||
if (props.length === 0) {
|
||||
props.push(t.identifier('_'))
|
||||
}
|
||||
const prop = t.identifier('ref')
|
||||
props.push(prop)
|
||||
if (opts.typescript) {
|
||||
prop.typeAnnotation = t.tsTypeAnnotation(tsTypeReferenceSVGRef(ctx))
|
||||
}
|
||||
const forwardRef = t.identifier('forwardRef')
|
||||
const ForwardRef = t.identifier('ForwardRef')
|
||||
getOrCreateImport(ctx, 'react').specifiers.push(
|
||||
t.importSpecifier(forwardRef, forwardRef),
|
||||
)
|
||||
exports.push(
|
||||
t.variableDeclaration('const', [
|
||||
t.variableDeclarator(
|
||||
ForwardRef,
|
||||
t.callExpression(forwardRef, [ctx.exportIdentifier]),
|
||||
),
|
||||
]),
|
||||
)
|
||||
ctx.exportIdentifier = ForwardRef
|
||||
}
|
||||
|
||||
if (opts.memo) {
|
||||
const memo = t.identifier('memo')
|
||||
const Memo = t.identifier('Memo')
|
||||
getOrCreateImport(ctx, 'react').specifiers.push(
|
||||
t.importSpecifier(memo, memo),
|
||||
)
|
||||
exports.push(
|
||||
t.variableDeclaration('const', [
|
||||
t.variableDeclarator(
|
||||
Memo,
|
||||
t.callExpression(memo, [ctx.exportIdentifier]),
|
||||
),
|
||||
]),
|
||||
)
|
||||
ctx.exportIdentifier = Memo
|
||||
}
|
||||
|
||||
if (opts.state.caller?.previousExport || opts.exportType === 'named') {
|
||||
exports.push(
|
||||
t.exportNamedDeclaration(null, [
|
||||
t.exportSpecifier(ctx.exportIdentifier, t.identifier(opts.namedExport)),
|
||||
]),
|
||||
)
|
||||
} else {
|
||||
exports.push(t.exportDefaultDeclaration(ctx.exportIdentifier))
|
||||
}
|
||||
return { componentName, props, interfaces, imports, exports, jsx }
|
||||
}
|
||||
@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"include": ["src"]
|
||||
}
|
||||
@ -1,2 +1,4 @@
|
||||
src/
|
||||
.*
|
||||
/*
|
||||
/dist/*
|
||||
!/dist/index.{d.ts,js}
|
||||
!/dist/index.js.map
|
||||
@ -2,7 +2,9 @@
|
||||
"name": "@svgr/babel-preset",
|
||||
"description": "SVGR preset that apply transformations from config",
|
||||
"version": "6.0.0-alpha.0",
|
||||
"main": "lib/index.js",
|
||||
"main": "./dist/index.js",
|
||||
"exports": "./dist/index.js",
|
||||
"typings": "./dist/index.d.ts",
|
||||
"repository": "https://github.com/gregberge/svgr/tree/master/packages/babel-preset",
|
||||
"author": "Greg Bergé <berge.greg@gmail.com>",
|
||||
"publishConfig": {
|
||||
@ -21,11 +23,6 @@
|
||||
"url": "https://github.com/sponsors/gregberge"
|
||||
},
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"prebuild": "rm -rf lib/",
|
||||
"build": "babel --config-file ../../babel.config.js -d lib --ignore \"**/*.test.js\" src",
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@svgr/babel-plugin-add-jsx-attribute": "^5.4.0",
|
||||
"@svgr/babel-plugin-remove-jsx-attribute": "^5.4.0",
|
||||
@ -35,5 +32,13 @@
|
||||
"@svgr/babel-plugin-svg-em-dimensions": "^5.4.0",
|
||||
"@svgr/babel-plugin-transform-react-native-svg": "^5.4.0",
|
||||
"@svgr/babel-plugin-transform-svg-component": "^6.0.0-alpha.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0-0"
|
||||
},
|
||||
"scripts": {
|
||||
"reset": "rm -rf dist",
|
||||
"build": "rollup -c ../../build/rollup.config.js",
|
||||
"prepublishOnly": "npm run reset && npm run build"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,14 +1,19 @@
|
||||
import { transform } from '@babel/core'
|
||||
import preset from '.'
|
||||
import preset, { Options } from '.'
|
||||
|
||||
const testPreset = (code, options) => {
|
||||
const defaultOptions = {
|
||||
namedExport: 'ReactComponent',
|
||||
state: { componentName: 'SvgComponent' },
|
||||
}
|
||||
|
||||
const testPreset = (code: string, options: Partial<Options>) => {
|
||||
const result = transform(code, {
|
||||
plugins: ['@babel/plugin-syntax-jsx'],
|
||||
presets: [[preset, options]],
|
||||
presets: [[preset, { ...defaultOptions, ...options }]],
|
||||
configFile: false,
|
||||
})
|
||||
|
||||
return result.code
|
||||
return result?.code
|
||||
}
|
||||
|
||||
describe('preset', () => {
|
||||
@ -19,36 +24,11 @@ describe('preset', () => {
|
||||
foo: 'bar',
|
||||
x: '{y}',
|
||||
},
|
||||
state: {
|
||||
componentName: 'SvgComponent',
|
||||
},
|
||||
}),
|
||||
).toMatchInlineSnapshot(`
|
||||
"import * as React from \\"react\\";
|
||||
|
||||
function SvgComponent() {
|
||||
return <svg foo=\\"bar\\" x={y} />;
|
||||
}
|
||||
|
||||
export default SvgComponent;"
|
||||
`)
|
||||
})
|
||||
|
||||
it('should handle native expo option', () => {
|
||||
expect(
|
||||
testPreset('<svg><g><path d="M0 0h48v1H0z" /></g></svg>', {
|
||||
native: { expo: true },
|
||||
state: {
|
||||
componentName: 'SvgComponent',
|
||||
},
|
||||
}),
|
||||
).toMatchInlineSnapshot(`
|
||||
"import * as React from \\"react\\";
|
||||
import { Svg } from \\"expo\\";
|
||||
|
||||
function SvgComponent() {
|
||||
return <Svg><Svg.G><Svg.Path d=\\"M0 0h48v1H0z\\" /></Svg.G></Svg>;
|
||||
}
|
||||
const SvgComponent = () => <svg foo=\\"bar\\" x={y} />;
|
||||
|
||||
export default SvgComponent;"
|
||||
`)
|
||||
@ -58,19 +38,14 @@ describe('preset', () => {
|
||||
expect(
|
||||
testPreset('<svg></svg>', {
|
||||
titleProp: true,
|
||||
state: {
|
||||
componentName: 'SvgComponent',
|
||||
},
|
||||
}),
|
||||
).toMatchInlineSnapshot(`
|
||||
"import * as React from \\"react\\";
|
||||
|
||||
function SvgComponent({
|
||||
const SvgComponent = ({
|
||||
title,
|
||||
titleId
|
||||
}) {
|
||||
return <svg aria-labelledby={titleId}>{title ? <title id={titleId}>{title}</title> : null}</svg>;
|
||||
}
|
||||
}) => <svg aria-labelledby={titleId}>{title ? <title id={titleId}>{title}</title> : null}</svg>;
|
||||
|
||||
export default SvgComponent;"
|
||||
`)
|
||||
@ -80,19 +55,14 @@ describe('preset', () => {
|
||||
expect(
|
||||
testPreset(`<svg><title>Hello</title></svg>`, {
|
||||
titleProp: true,
|
||||
state: {
|
||||
componentName: 'SvgComponent',
|
||||
},
|
||||
}),
|
||||
).toMatchInlineSnapshot(`
|
||||
"import * as React from \\"react\\";
|
||||
|
||||
function SvgComponent({
|
||||
const SvgComponent = ({
|
||||
title,
|
||||
titleId
|
||||
}) {
|
||||
return <svg aria-labelledby={titleId}>{title === undefined ? <title id={titleId}>Hello</title> : title ? <title id={titleId}>{title}</title> : null}</svg>;
|
||||
}
|
||||
}) => <svg aria-labelledby={titleId}>{title === undefined ? <title id={titleId}>Hello</title> : title ? <title id={titleId}>{title}</title> : null}</svg>;
|
||||
|
||||
export default SvgComponent;"
|
||||
`)
|
||||
@ -100,19 +70,14 @@ describe('preset', () => {
|
||||
expect(
|
||||
testPreset(`<svg><title>{"Hello"}</title></svg>`, {
|
||||
titleProp: true,
|
||||
state: {
|
||||
componentName: 'SvgComponent',
|
||||
},
|
||||
}),
|
||||
).toMatchInlineSnapshot(`
|
||||
"import * as React from \\"react\\";
|
||||
|
||||
function SvgComponent({
|
||||
const SvgComponent = ({
|
||||
title,
|
||||
titleId
|
||||
}) {
|
||||
return <svg aria-labelledby={titleId}>{title === undefined ? <title id={titleId}>{\\"Hello\\"}</title> : title ? <title id={titleId}>{title}</title> : null}</svg>;
|
||||
}
|
||||
}) => <svg aria-labelledby={titleId}>{title === undefined ? <title id={titleId}>{\\"Hello\\"}</title> : title ? <title id={titleId}>{title}</title> : null}</svg>;
|
||||
|
||||
export default SvgComponent;"
|
||||
`)
|
||||
@ -125,16 +90,11 @@ describe('preset', () => {
|
||||
'#000': 'black',
|
||||
'#fff': '{props.white}',
|
||||
},
|
||||
state: {
|
||||
componentName: 'SvgComponent',
|
||||
},
|
||||
}),
|
||||
).toMatchInlineSnapshot(`
|
||||
"import * as React from \\"react\\";
|
||||
|
||||
function SvgComponent() {
|
||||
return <svg a=\\"black\\" b={props.white} />;
|
||||
}
|
||||
const SvgComponent = () => <svg a=\\"black\\" b={props.white} />;
|
||||
|
||||
export default SvgComponent;"
|
||||
`)
|
||||
@ -146,16 +106,11 @@ describe('preset', () => {
|
||||
expandProps: 'end',
|
||||
icon: true,
|
||||
dimensions: true,
|
||||
state: {
|
||||
componentName: 'SvgComponent',
|
||||
},
|
||||
}),
|
||||
).toMatchInlineSnapshot(`
|
||||
"import * as React from \\"react\\";
|
||||
|
||||
function SvgComponent(props) {
|
||||
return <svg a=\\"#000\\" b=\\"#fff\\" width=\\"1em\\" height=\\"1em\\" {...props} />;
|
||||
}
|
||||
const SvgComponent = props => <svg a=\\"#000\\" b=\\"#fff\\" width=\\"1em\\" height=\\"1em\\" {...props} />;
|
||||
|
||||
export default SvgComponent;"
|
||||
`)
|
||||
@ -1,35 +1,54 @@
|
||||
import addJSXAttribute from '@svgr/babel-plugin-add-jsx-attribute'
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { ConfigAPI } from '@babel/core'
|
||||
import addJSXAttribute, {
|
||||
Attribute,
|
||||
} from '@svgr/babel-plugin-add-jsx-attribute'
|
||||
import removeJSXAttribute from '@svgr/babel-plugin-remove-jsx-attribute'
|
||||
import removeJSXEmptyExpression from '@svgr/babel-plugin-remove-jsx-empty-expression'
|
||||
import replaceJSXAttributeValue from '@svgr/babel-plugin-replace-jsx-attribute-value'
|
||||
import replaceJSXAttributeValue, {
|
||||
Value,
|
||||
} from '@svgr/babel-plugin-replace-jsx-attribute-value'
|
||||
import svgDynamicTitle from '@svgr/babel-plugin-svg-dynamic-title'
|
||||
import svgEmDimensions from '@svgr/babel-plugin-svg-em-dimensions'
|
||||
import transformReactNativeSVG from '@svgr/babel-plugin-transform-react-native-svg'
|
||||
import transformSvgComponent from '@svgr/babel-plugin-transform-svg-component'
|
||||
import transformSvgComponent, {
|
||||
Options as TransformOptions,
|
||||
} from '@svgr/babel-plugin-transform-svg-component'
|
||||
|
||||
function getAttributeValue(value) {
|
||||
export interface Options extends TransformOptions {
|
||||
ref?: boolean
|
||||
titleProp?: boolean
|
||||
expandProps?: boolean | 'start' | 'end'
|
||||
dimensions?: boolean
|
||||
icon?: boolean
|
||||
native?: boolean
|
||||
svgProps?: { [key: string]: string }
|
||||
replaceAttrValues?: { [key: string]: string }
|
||||
}
|
||||
|
||||
const getAttributeValue = (value: string) => {
|
||||
const literal =
|
||||
typeof value === 'string' && value.startsWith('{') && value.endsWith('}')
|
||||
return { value: literal ? value.slice(1, -1) : value, literal }
|
||||
}
|
||||
|
||||
function propsToAttributes(props) {
|
||||
const propsToAttributes = (props: { [key: string]: string }): Attribute[] => {
|
||||
return Object.keys(props).map((name) => {
|
||||
const { literal, value } = getAttributeValue(props[name])
|
||||
return { name, literal, value }
|
||||
})
|
||||
}
|
||||
|
||||
function replaceMapToValues(replaceMap) {
|
||||
function replaceMapToValues(replaceMap: { [key: string]: string }): Value[] {
|
||||
return Object.keys(replaceMap).map((value) => {
|
||||
const { literal, value: newValue } = getAttributeValue(replaceMap[value])
|
||||
return { value, newValue, literal }
|
||||
})
|
||||
}
|
||||
|
||||
const plugin = (api, opts) => {
|
||||
const plugin = (_: ConfigAPI, opts: Options) => {
|
||||
let toRemoveAttributes = ['version']
|
||||
let toAddAttributes = []
|
||||
let toAddAttributes: Attribute[] = []
|
||||
|
||||
if (opts.svgProps) {
|
||||
toAddAttributes = [...toAddAttributes, ...propsToAttributes(opts.svgProps)]
|
||||
@ -63,7 +82,10 @@ const plugin = (api, opts) => {
|
||||
{
|
||||
name: 'props',
|
||||
spread: true,
|
||||
position: opts.expandProps,
|
||||
position:
|
||||
opts.expandProps === 'start' || opts.expandProps === 'end'
|
||||
? opts.expandProps
|
||||
: undefined,
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -72,7 +94,7 @@ const plugin = (api, opts) => {
|
||||
toRemoveAttributes = [...toRemoveAttributes, 'width', 'height']
|
||||
}
|
||||
|
||||
const plugins = [
|
||||
const plugins: any[] = [
|
||||
[transformSvgComponent, opts],
|
||||
...(opts.icon && opts.dimensions ? [svgEmDimensions] : []),
|
||||
[
|
||||
@ -98,11 +120,7 @@ const plugin = (api, opts) => {
|
||||
}
|
||||
|
||||
if (opts.native) {
|
||||
if (opts.native.expo) {
|
||||
plugins.push([transformReactNativeSVG, opts.native])
|
||||
} else {
|
||||
plugins.push(transformReactNativeSVG)
|
||||
}
|
||||
plugins.push(transformReactNativeSVG)
|
||||
}
|
||||
|
||||
return { plugins }
|
||||
4
packages/babel-preset/tsconfig.json
Normal file
4
packages/babel-preset/tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"include": ["src"]
|
||||
}
|
||||
@ -1,2 +1,5 @@
|
||||
src/
|
||||
.*
|
||||
/*
|
||||
/dist/*
|
||||
!/dist/index.{d.ts,js}
|
||||
!/dist/index.js.map
|
||||
!/bin/svgr
|
||||
@ -1,3 +1,3 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
require('../lib/index')
|
||||
require('../dist/index')
|
||||
|
||||
@ -26,9 +26,9 @@
|
||||
"svgr": "./bin/svgr"
|
||||
},
|
||||
"scripts": {
|
||||
"prebuild": "rm -rf lib/",
|
||||
"build": "babel --config-file ../../babel.config.js -d lib --ignore \"**/*.test.js\" src",
|
||||
"prepublishOnly": "npm run build"
|
||||
"reset": "rm -rf dist",
|
||||
"build": "rollup -c ../../build/rollup.config.js",
|
||||
"prepublishOnly": "npm run reset && npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@svgr/core": "^6.0.0-alpha.0",
|
||||
@ -42,6 +42,7 @@
|
||||
"glob": "^7.1.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/glob": "^7.2.0",
|
||||
"del": "^6.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,607 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`cli should add Svg prefix to index.js exports staring with number 1`] = `
|
||||
"export { default as Svg2File } from './2File'
|
||||
export { default as File } from './File'"
|
||||
`;
|
||||
|
||||
exports[`cli should not override config with cli defaults 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
|
||||
function SvgFile() {
|
||||
return <svg viewBox=\\"0 0 48 1\\" xmlns=\\"http://www.w3.org/2000/svg\\" xmlnsXlink=\\"http://www.w3.org/1999/xlink\\"><title>{\\"Rectangle 5\\"}</title><desc>{\\"Created with Sketch.\\"}</desc><defs /><g id=\\"Page-1\\" stroke=\\"none\\" strokeWidth={1} fill=\\"none\\" fillRule=\\"evenodd\\"><g id=\\"19-Separator\\" transform=\\"translate(-129.000000, -156.000000)\\" fill=\\"#063855\\"><g id=\\"Controls/Settings\\" transform=\\"translate(80.000000, 0.000000)\\"><g id=\\"Content\\" transform=\\"translate(0.000000, 64.000000)\\"><g id=\\"Group\\" transform=\\"translate(24.000000, 56.000000)\\"><g id=\\"Group-2\\"><rect id=\\"Rectangle-5\\" x={25} y={36} width={48} height={1} /></g></g></g></g></g></g></svg>;
|
||||
}
|
||||
|
||||
export default SvgFile;
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support --index-template in cli 1`] = `"export { File } from './File'"`;
|
||||
|
||||
exports[`cli should support --no-index 1`] = `
|
||||
Array [
|
||||
"File.js",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`cli should support --prettier-config as file 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgFile(props) {
|
||||
return (
|
||||
<svg
|
||||
width={48}
|
||||
height={1}
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
{...props}
|
||||
>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support --prettier-config as json 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgFile(props) {
|
||||
return (
|
||||
<svg
|
||||
width={48}
|
||||
height={1}
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
{...props}
|
||||
>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support --svgo-config as file 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgFile(props) {
|
||||
return (
|
||||
<svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<title>{'Rectangle 5'}</title>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support --svgo-config as json 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgFile(props) {
|
||||
return (
|
||||
<svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<title>{'Rectangle 5'}</title>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support custom file extension 1`] = `
|
||||
Array [
|
||||
"File.ts",
|
||||
"index.ts",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`cli should support custom index.js with directory output 1`] = `"export { File } from './File'"`;
|
||||
|
||||
exports[`cli should support different filename cases with directory output 1`] = `
|
||||
Array [
|
||||
"CamelCase.js",
|
||||
"KebabCase.js",
|
||||
"MultipleDashes.js",
|
||||
"PascalCase.js",
|
||||
"index.js",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`cli should support different filename cases with directory output: --filename-case=camel 1`] = `
|
||||
Array [
|
||||
"camelCase.js",
|
||||
"index.js",
|
||||
"kebabCase.js",
|
||||
"multipleDashes.js",
|
||||
"pascalCase.js",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`cli should support different filename cases with directory output: --filename-case=kebab 1`] = `
|
||||
Array [
|
||||
"camel-case.js",
|
||||
"index.js",
|
||||
"kebab-case.js",
|
||||
"multiple-dashes.js",
|
||||
"pascal-case.js",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`cli should support different filename cases with directory output: --filename-case=pascal 1`] = `
|
||||
Array [
|
||||
"CamelCase.js",
|
||||
"KebabCase.js",
|
||||
"MultipleDashes.js",
|
||||
"PascalCase.js",
|
||||
"index.js",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`cli should support stdin filepath 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgFile(props) {
|
||||
return (
|
||||
<svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --expand-props none 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgFile() {
|
||||
return (
|
||||
<svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\">
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --expand-props start 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgFile(props) {
|
||||
return (
|
||||
<svg {...props} width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\">
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --icon 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgFile(props) {
|
||||
return (
|
||||
<svg
|
||||
width=\\"1em\\"
|
||||
height=\\"1em\\"
|
||||
viewBox=\\"0 0 48 1\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
{...props}
|
||||
>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --native --expand-props none 1`] = `
|
||||
"import * as React from 'react'
|
||||
import Svg, { Path } from 'react-native-svg'
|
||||
|
||||
function SvgFile() {
|
||||
return (
|
||||
<Svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\">
|
||||
<Path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</Svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --native --icon 1`] = `
|
||||
"import * as React from 'react'
|
||||
import Svg, { Path } from 'react-native-svg'
|
||||
|
||||
function SvgFile(props) {
|
||||
return (
|
||||
<Svg
|
||||
width=\\"1em\\"
|
||||
height=\\"1em\\"
|
||||
viewBox=\\"0 0 48 1\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
{...props}
|
||||
>
|
||||
<Path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</Svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --native --ref 1`] = `
|
||||
"import * as React from 'react'
|
||||
import Svg, { Path } from 'react-native-svg'
|
||||
|
||||
function SvgFile(props, svgRef) {
|
||||
return (
|
||||
<Svg
|
||||
width={48}
|
||||
height={1}
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
ref={svgRef}
|
||||
{...props}
|
||||
>
|
||||
<Path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</Svg>
|
||||
)
|
||||
}
|
||||
|
||||
const ForwardRef = React.forwardRef(SvgFile)
|
||||
export default ForwardRef
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --native 1`] = `
|
||||
"import * as React from 'react'
|
||||
import Svg, { Path } from 'react-native-svg'
|
||||
|
||||
function SvgFile(props) {
|
||||
return (
|
||||
<Svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<Path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</Svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --no-dimensions 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgFile(props) {
|
||||
return (
|
||||
<svg viewBox=\\"0 0 48 1\\" xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --no-prettier 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
|
||||
function SvgFile(props) {
|
||||
return <svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}><path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" /></svg>;
|
||||
}
|
||||
|
||||
export default SvgFile;
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --no-svgo 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgFile(props) {
|
||||
return (
|
||||
<svg
|
||||
width=\\"48px\\"
|
||||
height=\\"1px\\"
|
||||
viewBox=\\"0 0 48 1\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
xmlnsXlink=\\"http://www.w3.org/1999/xlink\\"
|
||||
{...props}
|
||||
>
|
||||
<title>{'Rectangle 5'}</title>
|
||||
<desc>{'Created with Sketch.'}</desc>
|
||||
<defs />
|
||||
<g
|
||||
id=\\"Page-1\\"
|
||||
stroke=\\"none\\"
|
||||
strokeWidth={1}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
>
|
||||
<g
|
||||
id=\\"19-Separator\\"
|
||||
transform=\\"translate(-129.000000, -156.000000)\\"
|
||||
fill=\\"#063855\\"
|
||||
>
|
||||
<g id=\\"Controls/Settings\\" transform=\\"translate(80.000000, 0.000000)\\">
|
||||
<g id=\\"Content\\" transform=\\"translate(0.000000, 64.000000)\\">
|
||||
<g id=\\"Group\\" transform=\\"translate(24.000000, 56.000000)\\">
|
||||
<g id=\\"Group-2\\">
|
||||
<rect id=\\"Rectangle-5\\" x={25} y={36} width={48} height={1} />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --ref 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgFile(props, svgRef) {
|
||||
return (
|
||||
<svg
|
||||
width={48}
|
||||
height={1}
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
ref={svgRef}
|
||||
{...props}
|
||||
>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
const ForwardRef = React.forwardRef(SvgFile)
|
||||
export default ForwardRef
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --replace-attr-values "#063855=currentColor" 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgFile(props) {
|
||||
return (
|
||||
<svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"currentColor\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --svg-props "hidden={true},id=hello" 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgFile(props) {
|
||||
return (
|
||||
<svg
|
||||
width={48}
|
||||
height={1}
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
hidden={true}
|
||||
id=\\"hello\\"
|
||||
{...props}
|
||||
>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --title-prop 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgFile({ title, titleId, ...props }) {
|
||||
return (
|
||||
<svg
|
||||
width={48}
|
||||
height={1}
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
aria-labelledby={titleId}
|
||||
{...props}
|
||||
>
|
||||
{title ? <title id={titleId}>{title}</title> : null}
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --typescript --ref --title-prop 1`] = `
|
||||
"import * as React from 'react'
|
||||
interface SVGRProps {
|
||||
title?: string;
|
||||
titleId?: string;
|
||||
}
|
||||
|
||||
function SvgFile(
|
||||
{ title, titleId, ...props }: React.SVGProps<SVGSVGElement> & SVGRProps,
|
||||
svgRef?: React.Ref<SVGSVGElement>,
|
||||
) {
|
||||
return (
|
||||
<svg
|
||||
width={48}
|
||||
height={1}
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
ref={svgRef}
|
||||
aria-labelledby={titleId}
|
||||
{...props}
|
||||
>
|
||||
{title ? <title id={titleId}>{title}</title> : null}
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
const ForwardRef = React.forwardRef(SvgFile)
|
||||
export default ForwardRef
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --typescript --ref 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgFile(
|
||||
props: React.SVGProps<SVGSVGElement>,
|
||||
svgRef?: React.Ref<SVGSVGElement>,
|
||||
) {
|
||||
return (
|
||||
<svg
|
||||
width={48}
|
||||
height={1}
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
ref={svgRef}
|
||||
{...props}
|
||||
>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
const ForwardRef = React.forwardRef(SvgFile)
|
||||
export default ForwardRef
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --typescript 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgFile(props: React.SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should suppress output when transforming a directory with a --silent option 1`] = `""`;
|
||||
|
||||
exports[`cli should transform a whole directory and output relative destination paths 1`] = `
|
||||
"
|
||||
__fixtures__/cased/pascalcase.svg -> __fixtures_build__/whole/cased/pascalcase.js
|
||||
__fixtures__/cased/camelcase.svg -> __fixtures_build__/whole/cased/camelcase.js
|
||||
__fixtures__/cased/kebab-case.svg -> __fixtures_build__/whole/cased/kebabcase.js
|
||||
__fixtures__/cased/multiple---dashes.svg -> __fixtures_build__/whole/cased/multipledashes.js
|
||||
__fixtures__/complex/skype.svg -> __fixtures_build__/whole/complex/skype.js
|
||||
__fixtures__/complex/telegram.svg -> __fixtures_build__/whole/complex/telegram.js
|
||||
__fixtures__/nesting/a/c/three.svg -> __fixtures_build__/whole/nesting/a/c/three.js
|
||||
__fixtures__/nesting/a/two.svg -> __fixtures_build__/whole/nesting/a/two.js
|
||||
__fixtures__/nesting/one.svg -> __fixtures_build__/whole/nesting/one.js
|
||||
__fixtures__/numeric/2.file.svg -> __fixtures_build__/whole/numeric/2file.js
|
||||
__fixtures__/numeric/file.svg -> __fixtures_build__/whole/numeric/file.js
|
||||
__fixtures__/simple/file.svg -> __fixtures_build__/whole/simple/file.js
|
||||
__fixtures__/withprettierrc/file.svg -> __fixtures_build__/whole/withprettierrc/file.js
|
||||
__fixtures__/withsvgoconfig/file.svg -> __fixtures_build__/whole/withsvgoconfig/file.js
|
||||
__fixtures__/withsvgrrc/file.svg -> __fixtures_build__/whole/withsvgrrc/file.js"
|
||||
`;
|
||||
|
||||
exports[`cli should transform a whole directory with --typescript 1`] = `
|
||||
"
|
||||
__fixtures__/cased/pascalcase.svg -> __fixtures_build__/whole/cased/pascalcase.tsx
|
||||
__fixtures__/cased/camelcase.svg -> __fixtures_build__/whole/cased/camelcase.tsx
|
||||
__fixtures__/cased/kebab-case.svg -> __fixtures_build__/whole/cased/kebabcase.tsx
|
||||
__fixtures__/cased/multiple---dashes.svg -> __fixtures_build__/whole/cased/multipledashes.tsx
|
||||
__fixtures__/complex/skype.svg -> __fixtures_build__/whole/complex/skype.tsx
|
||||
__fixtures__/complex/telegram.svg -> __fixtures_build__/whole/complex/telegram.tsx
|
||||
__fixtures__/nesting/a/c/three.svg -> __fixtures_build__/whole/nesting/a/c/three.tsx
|
||||
__fixtures__/nesting/a/two.svg -> __fixtures_build__/whole/nesting/a/two.tsx
|
||||
__fixtures__/nesting/one.svg -> __fixtures_build__/whole/nesting/one.tsx
|
||||
__fixtures__/numeric/2.file.svg -> __fixtures_build__/whole/numeric/2file.tsx
|
||||
__fixtures__/numeric/file.svg -> __fixtures_build__/whole/numeric/file.tsx
|
||||
__fixtures__/simple/file.svg -> __fixtures_build__/whole/simple/file.tsx
|
||||
__fixtures__/withprettierrc/file.svg -> __fixtures_build__/whole/withprettierrc/file.tsx
|
||||
__fixtures__/withsvgoconfig/file.svg -> __fixtures_build__/whole/withsvgoconfig/file.tsx
|
||||
__fixtures__/withsvgrrc/file.svg -> __fixtures_build__/whole/withsvgrrc/file.tsx"
|
||||
`;
|
||||
|
||||
exports[`cli should work with a simple file 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgFile(props) {
|
||||
return (
|
||||
<svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should work with stdin 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgComponent(props) {
|
||||
return (
|
||||
<svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgComponent
|
||||
|
||||
"
|
||||
`;
|
||||
548
packages/cli/src/__snapshots__/index.test.ts.snap
Normal file
548
packages/cli/src/__snapshots__/index.test.ts.snap
Normal file
@ -0,0 +1,548 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`cli should add Svg prefix to index.js exports staring with number 1`] = `
|
||||
"export { default as Svg2File } from './2File'
|
||||
export { default as File } from './File'"
|
||||
`;
|
||||
|
||||
exports[`cli should not override config with cli defaults 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgFile = () => (
|
||||
<svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\">
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support --index-template in cli 1`] = `"export { File } from './File'"`;
|
||||
|
||||
exports[`cli should support --no-index 1`] = `
|
||||
Array [
|
||||
"File.js",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`cli should support --prettier-config as file 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgFile = (props) => (
|
||||
<svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support --prettier-config as json 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgFile = (props) => (
|
||||
<svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support --svgo-config as file 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgFile = (props) => (
|
||||
<svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<title>{'Rectangle 5'}</title>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support --svgo-config as json 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgFile = (props) => (
|
||||
<svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<title>{'Rectangle 5'}</title>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support custom file extension 1`] = `
|
||||
Array [
|
||||
"File.ts",
|
||||
"index.ts",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`cli should support custom index.js with directory output 1`] = `"export { default as File } from './File'"`;
|
||||
|
||||
exports[`cli should support different filename cases with directory output 1`] = `
|
||||
Array [
|
||||
"CamelCase.js",
|
||||
"KebabCase.js",
|
||||
"MultipleDashes.js",
|
||||
"PascalCase.js",
|
||||
"index.js",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`cli should support different filename cases with directory output: --filename-case=camel 1`] = `
|
||||
Array [
|
||||
"camelCase.js",
|
||||
"index.js",
|
||||
"kebabCase.js",
|
||||
"multipleDashes.js",
|
||||
"pascalCase.js",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`cli should support different filename cases with directory output: --filename-case=kebab 1`] = `
|
||||
Array [
|
||||
"camel-case.js",
|
||||
"index.js",
|
||||
"kebab-case.js",
|
||||
"multiple-dashes.js",
|
||||
"pascal-case.js",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`cli should support different filename cases with directory output: --filename-case=pascal 1`] = `
|
||||
Array [
|
||||
"CamelCase.js",
|
||||
"KebabCase.js",
|
||||
"MultipleDashes.js",
|
||||
"PascalCase.js",
|
||||
"index.js",
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`cli should support stdin filepath 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgFile = (props) => (
|
||||
<svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --expand-props none 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgFile = () => (
|
||||
<svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\">
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --expand-props start 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgFile = (props) => (
|
||||
<svg {...props} width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\">
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --icon 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgFile = (props) => (
|
||||
<svg
|
||||
width=\\"1em\\"
|
||||
height=\\"1em\\"
|
||||
viewBox=\\"0 0 48 1\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
{...props}
|
||||
>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --native --expand-props none 1`] = `
|
||||
"import * as React from 'react'
|
||||
import Svg, { Path } from 'react-native-svg'
|
||||
|
||||
const SvgFile = () => (
|
||||
<Svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\">
|
||||
<Path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</Svg>
|
||||
)
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --native --icon 1`] = `
|
||||
"import * as React from 'react'
|
||||
import Svg, { Path } from 'react-native-svg'
|
||||
|
||||
const SvgFile = (props) => (
|
||||
<Svg
|
||||
width=\\"1em\\"
|
||||
height=\\"1em\\"
|
||||
viewBox=\\"0 0 48 1\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
{...props}
|
||||
>
|
||||
<Path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</Svg>
|
||||
)
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --native --ref 1`] = `
|
||||
"import * as React from 'react'
|
||||
import Svg, { Path } from 'react-native-svg'
|
||||
import { forwardRef } from 'react'
|
||||
|
||||
const SvgFile = (props, ref) => (
|
||||
<Svg
|
||||
width={48}
|
||||
height={1}
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
ref={svgRef}
|
||||
{...props}
|
||||
>
|
||||
<Path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</Svg>
|
||||
)
|
||||
|
||||
const ForwardRef = forwardRef(SvgFile)
|
||||
export default ForwardRef
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --native 1`] = `
|
||||
"import * as React from 'react'
|
||||
import Svg, { Path } from 'react-native-svg'
|
||||
|
||||
const SvgFile = (props) => (
|
||||
<Svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<Path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</Svg>
|
||||
)
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --no-dimensions 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgFile = (props) => (
|
||||
<svg viewBox=\\"0 0 48 1\\" xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --no-prettier 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
|
||||
const SvgFile = props => <svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}><path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" /></svg>;
|
||||
|
||||
export default SvgFile;
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --no-svgo 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgFile = (props) => (
|
||||
<svg
|
||||
width=\\"48px\\"
|
||||
height=\\"1px\\"
|
||||
viewBox=\\"0 0 48 1\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
xmlnsXlink=\\"http://www.w3.org/1999/xlink\\"
|
||||
{...props}
|
||||
>
|
||||
<title>{'Rectangle 5'}</title>
|
||||
<desc>{'Created with Sketch.'}</desc>
|
||||
<defs />
|
||||
<g id=\\"Page-1\\" stroke=\\"none\\" strokeWidth={1} fill=\\"none\\" fillRule=\\"evenodd\\">
|
||||
<g
|
||||
id=\\"19-Separator\\"
|
||||
transform=\\"translate(-129.000000, -156.000000)\\"
|
||||
fill=\\"#063855\\"
|
||||
>
|
||||
<g id=\\"Controls/Settings\\" transform=\\"translate(80.000000, 0.000000)\\">
|
||||
<g id=\\"Content\\" transform=\\"translate(0.000000, 64.000000)\\">
|
||||
<g id=\\"Group\\" transform=\\"translate(24.000000, 56.000000)\\">
|
||||
<g id=\\"Group-2\\">
|
||||
<rect id=\\"Rectangle-5\\" x={25} y={36} width={48} height={1} />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --ref 1`] = `
|
||||
"import * as React from 'react'
|
||||
import { forwardRef } from 'react'
|
||||
|
||||
const SvgFile = (props, ref) => (
|
||||
<svg
|
||||
width={48}
|
||||
height={1}
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
ref={svgRef}
|
||||
{...props}
|
||||
>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
const ForwardRef = forwardRef(SvgFile)
|
||||
export default ForwardRef
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --replace-attr-values "#063855=currentColor" 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgFile = (props) => (
|
||||
<svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"currentColor\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --svg-props "hidden={true},id=hello" 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgFile = (props) => (
|
||||
<svg
|
||||
width={48}
|
||||
height={1}
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
hidden={true}
|
||||
id=\\"hello\\"
|
||||
{...props}
|
||||
>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --title-prop 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgFile = ({ title, titleId, ...props }) => (
|
||||
<svg
|
||||
width={48}
|
||||
height={1}
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
aria-labelledby={titleId}
|
||||
{...props}
|
||||
>
|
||||
{title ? <title id={titleId}>{title}</title> : null}
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --typescript --ref --title-prop 1`] = `
|
||||
"import * as React from 'react'
|
||||
import { SVGProps, Ref, forwardRef } from 'react'
|
||||
interface SVGRProps {
|
||||
title?: string;
|
||||
titleId?: string;
|
||||
}
|
||||
|
||||
const SvgFile = (
|
||||
{ title, titleId, ...props }: SVGProps<SVGSVGElement> & SVGRProps,
|
||||
ref: Ref<SVGSVGElement>,
|
||||
) => (
|
||||
<svg
|
||||
width={48}
|
||||
height={1}
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
ref={svgRef}
|
||||
aria-labelledby={titleId}
|
||||
{...props}
|
||||
>
|
||||
{title ? <title id={titleId}>{title}</title> : null}
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
const ForwardRef = forwardRef(SvgFile)
|
||||
export default ForwardRef
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --typescript --ref 1`] = `
|
||||
"import * as React from 'react'
|
||||
import { SVGProps, Ref, forwardRef } from 'react'
|
||||
|
||||
const SvgFile = (props: SVGProps<SVGSVGElement>, ref: Ref<SVGSVGElement>) => (
|
||||
<svg
|
||||
width={48}
|
||||
height={1}
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
ref={svgRef}
|
||||
{...props}
|
||||
>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
const ForwardRef = forwardRef(SvgFile)
|
||||
export default ForwardRef
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should support various args: --typescript 1`] = `
|
||||
"import * as React from 'react'
|
||||
import { SVGProps } from 'react'
|
||||
|
||||
const SvgFile = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should suppress output when transforming a directory with a --silent option 1`] = `""`;
|
||||
|
||||
exports[`cli should transform a whole directory and output relative destination paths 1`] = `
|
||||
"
|
||||
__fixtures__/cased/pascalcase.svg -> __fixtures_build__/whole/cased/pascalcase.js
|
||||
__fixtures__/cased/camelcase.svg -> __fixtures_build__/whole/cased/camelcase.js
|
||||
__fixtures__/cased/kebab-case.svg -> __fixtures_build__/whole/cased/kebabcase.js
|
||||
__fixtures__/cased/multiple---dashes.svg -> __fixtures_build__/whole/cased/multipledashes.js
|
||||
__fixtures__/complex/skype.svg -> __fixtures_build__/whole/complex/skype.js
|
||||
__fixtures__/complex/telegram.svg -> __fixtures_build__/whole/complex/telegram.js
|
||||
__fixtures__/nesting/a/c/three.svg -> __fixtures_build__/whole/nesting/a/c/three.js
|
||||
__fixtures__/nesting/a/two.svg -> __fixtures_build__/whole/nesting/a/two.js
|
||||
__fixtures__/nesting/one.svg -> __fixtures_build__/whole/nesting/one.js
|
||||
__fixtures__/numeric/2.file.svg -> __fixtures_build__/whole/numeric/2file.js
|
||||
__fixtures__/numeric/file.svg -> __fixtures_build__/whole/numeric/file.js
|
||||
__fixtures__/simple/file.svg -> __fixtures_build__/whole/simple/file.js
|
||||
__fixtures__/withprettierrc/file.svg -> __fixtures_build__/whole/withprettierrc/file.js
|
||||
__fixtures__/withsvgoconfig/file.svg -> __fixtures_build__/whole/withsvgoconfig/file.js
|
||||
__fixtures__/withsvgrrc/file.svg -> __fixtures_build__/whole/withsvgrrc/file.js"
|
||||
`;
|
||||
|
||||
exports[`cli should transform a whole directory with --typescript 1`] = `
|
||||
"
|
||||
__fixtures__/cased/pascalcase.svg -> __fixtures_build__/whole/cased/pascalcase.tsx
|
||||
__fixtures__/cased/camelcase.svg -> __fixtures_build__/whole/cased/camelcase.tsx
|
||||
__fixtures__/cased/kebab-case.svg -> __fixtures_build__/whole/cased/kebabcase.tsx
|
||||
__fixtures__/cased/multiple---dashes.svg -> __fixtures_build__/whole/cased/multipledashes.tsx
|
||||
__fixtures__/complex/skype.svg -> __fixtures_build__/whole/complex/skype.tsx
|
||||
__fixtures__/complex/telegram.svg -> __fixtures_build__/whole/complex/telegram.tsx
|
||||
__fixtures__/nesting/a/c/three.svg -> __fixtures_build__/whole/nesting/a/c/three.tsx
|
||||
__fixtures__/nesting/a/two.svg -> __fixtures_build__/whole/nesting/a/two.tsx
|
||||
__fixtures__/nesting/one.svg -> __fixtures_build__/whole/nesting/one.tsx
|
||||
__fixtures__/numeric/2.file.svg -> __fixtures_build__/whole/numeric/2file.tsx
|
||||
__fixtures__/numeric/file.svg -> __fixtures_build__/whole/numeric/file.tsx
|
||||
__fixtures__/simple/file.svg -> __fixtures_build__/whole/simple/file.tsx
|
||||
__fixtures__/withprettierrc/file.svg -> __fixtures_build__/whole/withprettierrc/file.tsx
|
||||
__fixtures__/withsvgoconfig/file.svg -> __fixtures_build__/whole/withsvgoconfig/file.tsx
|
||||
__fixtures__/withsvgrrc/file.svg -> __fixtures_build__/whole/withsvgrrc/file.tsx"
|
||||
`;
|
||||
|
||||
exports[`cli should work with a simple file 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgFile = (props) => (
|
||||
<svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgFile
|
||||
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`cli should work with stdin 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgComponent = (props) => (
|
||||
<svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgComponent
|
||||
|
||||
"
|
||||
`;
|
||||
@ -1,37 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`util #convertFile should convert a file 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgFile(props) {
|
||||
return (
|
||||
<svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgFile
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`util #convertFile should support a custom config path 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgFile(props) {
|
||||
return (
|
||||
<svg
|
||||
width=\\"1em\\"
|
||||
height=\\"1em\\"
|
||||
viewBox=\\"0 0 48 1\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
{...props}
|
||||
>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgFile
|
||||
"
|
||||
`;
|
||||
33
packages/cli/src/__snapshots__/util.test.ts.snap
Normal file
33
packages/cli/src/__snapshots__/util.test.ts.snap
Normal file
@ -0,0 +1,33 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`util #convertFile should convert a file 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgFile = (props) => (
|
||||
<svg width={48} height={1} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgFile
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`util #convertFile should support a custom config path 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgFile = (props) => (
|
||||
<svg
|
||||
width=\\"1em\\"
|
||||
height=\\"1em\\"
|
||||
viewBox=\\"0 0 48 1\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
{...props}
|
||||
>
|
||||
<path d=\\"M0 0h48v1H0z\\" fill=\\"#063855\\" fillRule=\\"evenodd\\" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgFile
|
||||
"
|
||||
`;
|
||||
@ -1,119 +0,0 @@
|
||||
/* eslint-disable no-underscore-dangle, no-console */
|
||||
import { promises as fs } from 'fs'
|
||||
import path from 'path'
|
||||
import chalk from 'chalk'
|
||||
import { loadConfig } from '@svgr/core'
|
||||
import {
|
||||
convertFile,
|
||||
transformFilename,
|
||||
CASE,
|
||||
politeWrite,
|
||||
formatExportName,
|
||||
} from './util'
|
||||
|
||||
async function exists(file) {
|
||||
try {
|
||||
await fs.access(file)
|
||||
return true
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function rename(relative, ext, filenameCase) {
|
||||
const relativePath = path.parse(relative)
|
||||
relativePath.ext = `.${ext}`
|
||||
relativePath.base = null
|
||||
relativePath.name = transformFilename(relativePath.name, filenameCase)
|
||||
|
||||
return path.format(relativePath)
|
||||
}
|
||||
|
||||
const COMPILABLE_EXTENSIONS = ['.svg', '.SVG']
|
||||
|
||||
export function isCompilable(filename) {
|
||||
const ext = path.extname(filename)
|
||||
return COMPILABLE_EXTENSIONS.includes(ext)
|
||||
}
|
||||
|
||||
function defaultIndexTemplate(filePaths) {
|
||||
const exportEntries = filePaths.map((filePath) => {
|
||||
const basename = path.basename(filePath, path.extname(filePath))
|
||||
const exportName = formatExportName(basename)
|
||||
return `export { default as ${exportName} } from './${basename}'`
|
||||
})
|
||||
return exportEntries.join('\n')
|
||||
}
|
||||
|
||||
function getDefaultExtension(options) {
|
||||
return options.typescript ? 'tsx' : 'js'
|
||||
}
|
||||
|
||||
export default async function dirCommand(
|
||||
opts,
|
||||
program,
|
||||
filenames,
|
||||
{ ext, filenameCase = CASE.PASCAL, ...options },
|
||||
) {
|
||||
async function write(src, dest) {
|
||||
if (!isCompilable(src)) return { transformed: false, dest: null }
|
||||
|
||||
ext = ext || getDefaultExtension(options)
|
||||
dest = rename(dest, ext, filenameCase)
|
||||
const code = await convertFile(src, options)
|
||||
const cwdRelative = path.relative(process.cwd(), dest)
|
||||
const logOutput = `${src} -> ${cwdRelative}\n`
|
||||
|
||||
if (opts.ignoreExisting && (await exists(dest))) {
|
||||
politeWrite(opts, chalk.grey(logOutput))
|
||||
return { transformed: false, dest }
|
||||
}
|
||||
|
||||
await fs.mkdir(path.dirname(dest), { recursive: true })
|
||||
await fs.writeFile(dest, code)
|
||||
politeWrite(opts, chalk.white(logOutput))
|
||||
return { transformed: true, dest }
|
||||
}
|
||||
|
||||
async function generateIndex(dest, files, config) {
|
||||
const indexFile = path.join(dest, `index.${ext}`)
|
||||
const indexTemplate = config.indexTemplate || defaultIndexTemplate
|
||||
await fs.writeFile(indexFile, indexTemplate(files))
|
||||
}
|
||||
|
||||
async function handle(filename, root) {
|
||||
const stats = await fs.stat(filename)
|
||||
|
||||
if (stats.isDirectory()) {
|
||||
const dirname = filename
|
||||
const files = await fs.readdir(dirname)
|
||||
const results = await Promise.all(
|
||||
files.map(async (relativeFile) => {
|
||||
const absFile = path.join(dirname, relativeFile)
|
||||
return handle(absFile, root)
|
||||
}),
|
||||
)
|
||||
const transformed = results.filter((result) => result.transformed)
|
||||
if (transformed.length) {
|
||||
const destFiles = results.map((result) => result.dest).filter(Boolean)
|
||||
const dest = path.resolve(opts.outDir, path.relative(root, dirname))
|
||||
const config = loadConfig.sync(options, { filePath: dest })
|
||||
if (config.index) {
|
||||
await generateIndex(dest, destFiles, config)
|
||||
}
|
||||
}
|
||||
return { transformed: false, dest: null }
|
||||
}
|
||||
|
||||
const dest = path.resolve(opts.outDir, path.relative(root, filename))
|
||||
return write(filename, dest)
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
filenames.map(async (file) => {
|
||||
const stats = await fs.stat(file)
|
||||
const root = stats.isDirectory() ? file : path.dirname(file)
|
||||
await handle(file, root)
|
||||
}),
|
||||
)
|
||||
}
|
||||
138
packages/cli/src/dirCommand.ts
Normal file
138
packages/cli/src/dirCommand.ts
Normal file
@ -0,0 +1,138 @@
|
||||
/* eslint-disable no-underscore-dangle, no-console */
|
||||
import { promises as fs } from 'fs'
|
||||
import * as path from 'path'
|
||||
import { grey, white } from 'chalk'
|
||||
import { loadConfig, Config } from '@svgr/core'
|
||||
import {
|
||||
convertFile,
|
||||
transformFilename,
|
||||
politeWrite,
|
||||
formatExportName,
|
||||
} from './util'
|
||||
import type { SvgrCommand } from './index'
|
||||
|
||||
const exists = async (filepath: string) => {
|
||||
try {
|
||||
await fs.access(filepath)
|
||||
return true
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const rename = (relative: string, ext: string, filenameCase: string) => {
|
||||
const relativePath = path.parse(relative)
|
||||
relativePath.ext = `.${ext}`
|
||||
relativePath.base = ''
|
||||
relativePath.name = transformFilename(relativePath.name, filenameCase)
|
||||
return path.format(relativePath)
|
||||
}
|
||||
|
||||
export const isCompilable = (filename: string): boolean => {
|
||||
const ext = path.extname(filename)
|
||||
return ext === '.svg' || ext == '.SVG'
|
||||
}
|
||||
|
||||
export interface IndexTemplate {
|
||||
(paths: string[]): string
|
||||
}
|
||||
|
||||
const defaultIndexTemplate: IndexTemplate = (paths) => {
|
||||
const exportEntries = paths.map((filePath) => {
|
||||
const basename = path.basename(filePath, path.extname(filePath))
|
||||
const exportName = formatExportName(basename)
|
||||
return `export { default as ${exportName} } from './${basename}'`
|
||||
})
|
||||
return exportEntries.join('\n')
|
||||
}
|
||||
|
||||
const resolveExtension = (config: Config, ext?: string) =>
|
||||
ext || (config.typescript ? 'tsx' : 'js')
|
||||
|
||||
export const dirCommand: SvgrCommand = async (
|
||||
{
|
||||
ext: extOpt,
|
||||
filenameCase = 'pascal',
|
||||
ignoreExisting,
|
||||
silent,
|
||||
indexTemplate: indexTemplateOpt,
|
||||
configFile,
|
||||
outDir,
|
||||
},
|
||||
_,
|
||||
filenames,
|
||||
config,
|
||||
): Promise<void> => {
|
||||
const ext = resolveExtension(config, extOpt)
|
||||
|
||||
const write = async (src: string, dest: string) => {
|
||||
if (!isCompilable(src)) {
|
||||
return { transformed: false, dest: null }
|
||||
}
|
||||
|
||||
dest = rename(dest, ext, filenameCase)
|
||||
const code = await convertFile(src, config)
|
||||
const cwdRelative = path.relative(process.cwd(), dest)
|
||||
const logOutput = `${src} -> ${cwdRelative}\n`
|
||||
|
||||
if (ignoreExisting && (await exists(dest))) {
|
||||
politeWrite(grey(logOutput), silent)
|
||||
return { transformed: false, dest }
|
||||
}
|
||||
|
||||
await fs.mkdir(path.dirname(dest), { recursive: true })
|
||||
await fs.writeFile(dest, code)
|
||||
politeWrite(white(logOutput), silent)
|
||||
return { transformed: true, dest }
|
||||
}
|
||||
|
||||
const generateIndex = async (dest: string, files: string[]) => {
|
||||
const indexFile = path.join(dest, `index.${ext}`)
|
||||
const indexTemplate = indexTemplateOpt || defaultIndexTemplate
|
||||
await fs.writeFile(indexFile, indexTemplate(files))
|
||||
}
|
||||
|
||||
async function handle(filename: string, root: string) {
|
||||
const stats = await fs.stat(filename)
|
||||
|
||||
if (stats.isDirectory()) {
|
||||
const dirname = filename
|
||||
const files = await fs.readdir(dirname)
|
||||
const results = await Promise.all(
|
||||
files.map(async (relativeFile) => {
|
||||
const absFile = path.join(dirname, relativeFile)
|
||||
return handle(absFile, root)
|
||||
}),
|
||||
)
|
||||
const transformed = results.filter((result) => result.transformed)
|
||||
if (transformed.length) {
|
||||
const destFiles = results
|
||||
.map((result) => result.dest)
|
||||
.filter(Boolean) as string[]
|
||||
const dest = path.resolve(
|
||||
outDir as string,
|
||||
path.relative(root, dirname),
|
||||
)
|
||||
const resolvedConfig = loadConfig.sync(
|
||||
{ configFile, ...config },
|
||||
{ filePath: dest },
|
||||
)
|
||||
if (resolvedConfig.index) {
|
||||
await generateIndex(dest, destFiles)
|
||||
}
|
||||
}
|
||||
return { transformed: false, dest: null }
|
||||
}
|
||||
|
||||
const dest = path.resolve(outDir as string, path.relative(root, filename))
|
||||
return write(filename, dest)
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
filenames.map(async (file) => {
|
||||
const stats = await fs.stat(file)
|
||||
const root = stats.isDirectory() ? file : path.dirname(file)
|
||||
await handle(file, root)
|
||||
}),
|
||||
)
|
||||
}
|
||||
@ -1,41 +1,42 @@
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
import { promises as fs } from 'fs'
|
||||
import { convert, convertFile, exitError } from './util'
|
||||
import type { SvgrCommand } from './index'
|
||||
|
||||
async function output(promise) {
|
||||
process.stdout.write(`${await promise}\n`)
|
||||
}
|
||||
|
||||
async function fileCommand(opts, program, filenames, config) {
|
||||
function stdin() {
|
||||
const readStdin = async () => {
|
||||
return new Promise<string>((resolve) => {
|
||||
let code = ''
|
||||
|
||||
process.stdin.setEncoding('utf8')
|
||||
|
||||
process.stdin.on('readable', () => {
|
||||
const chunk = process.stdin.read()
|
||||
if (chunk !== null) code += chunk
|
||||
})
|
||||
|
||||
process.stdin.on('end', () => {
|
||||
output(convert(code, config, { filePath: opts.stdinFilepath }))
|
||||
resolve(code)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const fileCommand: SvgrCommand = async (
|
||||
opts,
|
||||
program,
|
||||
filenames,
|
||||
config,
|
||||
): Promise<void> => {
|
||||
if (opts.stdin || (filenames.length === 0 && !process.stdin.isTTY)) {
|
||||
stdin()
|
||||
const input = await readStdin()
|
||||
const output = convert(input, config, { filePath: opts.stdinFilepath })
|
||||
process.stdout.write(`${output}\n`)
|
||||
return
|
||||
}
|
||||
|
||||
if (filenames.length === 0) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(program.helpInformation())
|
||||
process.stdout.write(`${program.helpInformation()}\n`)
|
||||
return
|
||||
}
|
||||
|
||||
if (filenames.length > 1) {
|
||||
exitError('Please specify only one filename or use `--out-dir` option.')
|
||||
return
|
||||
}
|
||||
|
||||
const [filename] = filenames
|
||||
@ -45,7 +46,6 @@ async function fileCommand(opts, program, filenames, config) {
|
||||
exitError('Directory are not supported without `--out-dir` option instead.')
|
||||
}
|
||||
|
||||
output(convertFile(filename, config))
|
||||
const output = await convertFile(filename, config)
|
||||
process.stdout.write(`${output}\n`)
|
||||
}
|
||||
|
||||
export default fileCommand
|
||||
@ -1,17 +1,17 @@
|
||||
import { promises as fs } from 'fs'
|
||||
import path from 'path'
|
||||
import childProcess from 'child_process'
|
||||
import util from 'util'
|
||||
import * as path from 'path'
|
||||
import { exec as execCb } from 'child_process'
|
||||
import { promisify } from 'util'
|
||||
// @ts-ignore
|
||||
import del from 'del'
|
||||
|
||||
const exec = util.promisify(childProcess.exec)
|
||||
const exec = promisify(execCb)
|
||||
|
||||
const svgr = path.join(__dirname, 'index.js')
|
||||
const babelNode = path.join(__dirname, '../../../node_modules/.bin/babel-node')
|
||||
const svgr = path.join(__dirname, '../bin/svgr')
|
||||
|
||||
describe('cli', () => {
|
||||
const cli = async (args) => {
|
||||
const { stdout } = await exec(`${babelNode} -- ${svgr} ${args}`)
|
||||
const cli = async (args: string) => {
|
||||
const { stdout } = await exec(`${svgr} ${args}`)
|
||||
return stdout
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ describe('cli', () => {
|
||||
expect.assertions(1)
|
||||
try {
|
||||
await cli('__fixtures__/nesting')
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
expect(error.message).toMatch(
|
||||
'Directory are not supported without `--out-dir` option instead',
|
||||
)
|
||||
@ -35,7 +35,7 @@ describe('cli', () => {
|
||||
expect.assertions(1)
|
||||
try {
|
||||
await cli('__fixtures__/simple/file.svg __fixtures__/nesting/one.svg')
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
expect(error.message).toMatch(
|
||||
'Please specify only one filename or use `--out-dir` option',
|
||||
)
|
||||
@ -1,43 +1,44 @@
|
||||
/* eslint-disable no-console */
|
||||
import program from 'commander'
|
||||
import path from 'path'
|
||||
import glob from 'glob'
|
||||
import fs, { promises as fsPromises } from 'fs'
|
||||
import { loadConfig } from '@svgr/core'
|
||||
import pkg from '../package.json'
|
||||
import fileCommand from './fileCommand'
|
||||
import dirCommand from './dirCommand'
|
||||
import { program, Command } from 'commander'
|
||||
import * as path from 'path'
|
||||
import { glob } from 'glob'
|
||||
import { readFileSync, promises as fsPromises } from 'fs'
|
||||
import { loadConfig, Config } from '@svgr/core'
|
||||
import { fileCommand } from './fileCommand'
|
||||
import { dirCommand } from './dirCommand'
|
||||
import { exitError } from './util'
|
||||
import type { IndexTemplate } from './dirCommand'
|
||||
import { version } from '../package.json'
|
||||
|
||||
function noUndefinedKeys(obj) {
|
||||
const noUndefinedKeys = <T extends Record<string, any>>(obj: T): T => {
|
||||
return Object.entries(obj).reduce((obj, [key, value]) => {
|
||||
if (value !== undefined) {
|
||||
// @ts-ignore
|
||||
obj[key] = value
|
||||
}
|
||||
return obj
|
||||
}, {})
|
||||
}, {} as T)
|
||||
}
|
||||
|
||||
function parseObject(arg, accumulation = {}) {
|
||||
const parseObject = (arg: string, accumulation = {}) => {
|
||||
const [name, value] = arg.split('=')
|
||||
return { ...accumulation, [name]: value }
|
||||
}
|
||||
|
||||
function parseObjectList(arg, accumulation = {}) {
|
||||
const parseObjectList = (arg: string, accumulation = {}) => {
|
||||
const args = arg.split(',').map((str) => str.trim())
|
||||
return args.reduce((acc, arg) => parseObject(arg, acc), accumulation)
|
||||
}
|
||||
|
||||
const parseConfig = (name) => (arg) => {
|
||||
const parseConfig = (name: string) => (arg: string) => {
|
||||
try {
|
||||
if (arg.endsWith('rc')) {
|
||||
const content = fs.readFileSync(arg, 'utf-8')
|
||||
const content = readFileSync(arg, 'utf-8')
|
||||
return JSON.parse(content)
|
||||
}
|
||||
|
||||
const ext = path.extname(arg)
|
||||
if (ext === '.js' || ext === '.json') {
|
||||
// eslint-disable-next-line import/no-dynamic-require, global-require
|
||||
return require(path.join(process.cwd(), arg))
|
||||
}
|
||||
|
||||
@ -46,12 +47,51 @@ const parseConfig = (name) => (arg) => {
|
||||
exitError(
|
||||
`"${name}" is not valid, please specify a valid file or use a inline JSON.`,
|
||||
)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const parseExpandProps = (arg: string) => (arg === 'none' ? false : arg)
|
||||
|
||||
const parseTemplate = (name: string) => (arg: string) => {
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const template = require(path.join(process.cwd(), arg))
|
||||
const resolved = template.default || template
|
||||
if (typeof resolved !== 'function') {
|
||||
throw new Error(`${name} file must export a function`)
|
||||
}
|
||||
return resolved
|
||||
} catch (error: any) {
|
||||
console.error(`Error when loading "${name}": ${arg}\n`)
|
||||
console.error(error.stack)
|
||||
process.exit(2)
|
||||
}
|
||||
}
|
||||
|
||||
interface ProgramOpts extends Config {
|
||||
configFile?: string
|
||||
runtimeConfig?: boolean
|
||||
outDir?: string
|
||||
ignoreExisting?: boolean
|
||||
ext?: string
|
||||
filenameCase?: string
|
||||
silent?: boolean
|
||||
stdin?: boolean
|
||||
stdinFilepath?: string
|
||||
indexTemplate?: IndexTemplate
|
||||
}
|
||||
|
||||
export interface SvgrCommand {
|
||||
(
|
||||
opts: ProgramOpts,
|
||||
program: Command,
|
||||
filenames: string[],
|
||||
config: Config,
|
||||
): Promise<void>
|
||||
}
|
||||
|
||||
program
|
||||
.version(pkg.version)
|
||||
.version(version)
|
||||
.usage('[options] <file|directory>')
|
||||
.option('--config-file <file>', 'specify the path of the svgr config')
|
||||
.option(
|
||||
@ -74,6 +114,7 @@ program
|
||||
.option(
|
||||
'--expand-props [position]',
|
||||
'disable props expanding ("start", "end", "none") (default: "end")',
|
||||
parseExpandProps,
|
||||
)
|
||||
.option(
|
||||
'--svg-props <property=value>',
|
||||
@ -85,10 +126,15 @@ program
|
||||
'replace an attribute value',
|
||||
parseObjectList,
|
||||
)
|
||||
.option('--template <file>', 'specify a custom template to use')
|
||||
.option(
|
||||
'--template <file>',
|
||||
'specify a custom template to use',
|
||||
parseTemplate('--template'),
|
||||
)
|
||||
.option(
|
||||
'--index-template <file>',
|
||||
'specify a custom index.js template to use',
|
||||
parseTemplate('--index-template'),
|
||||
)
|
||||
.option('--no-index', 'disable index file generation')
|
||||
.option('--title-prop', 'create a title element linked with props')
|
||||
@ -121,12 +167,12 @@ program.on('--help', () => {
|
||||
program.parse(process.argv)
|
||||
|
||||
async function run() {
|
||||
const errors = []
|
||||
const errors: string[] = []
|
||||
const filenames = program.args.reduce((globbed, input) => {
|
||||
let files = glob.sync(input)
|
||||
if (!files.length) files = [input]
|
||||
return globbed.concat(files)
|
||||
}, [])
|
||||
return [...globbed, ...files]
|
||||
}, [] as string[])
|
||||
|
||||
await Promise.all(
|
||||
filenames.map(async (filename) => {
|
||||
@ -143,17 +189,10 @@ async function run() {
|
||||
process.exit(2)
|
||||
}
|
||||
|
||||
const opts = noUndefinedKeys(program.opts())
|
||||
const opts = noUndefinedKeys(program.opts<ProgramOpts>())
|
||||
|
||||
const config = await loadConfig(opts, { filePath: process.cwd() })
|
||||
|
||||
// Back config file
|
||||
config.configFile = opts.configFile
|
||||
|
||||
if (opts.expandProps === 'none') {
|
||||
config.expandProps = false
|
||||
}
|
||||
|
||||
if (opts.dimensions === true) {
|
||||
delete config.dimensions
|
||||
}
|
||||
@ -166,47 +205,11 @@ async function run() {
|
||||
delete config.prettier
|
||||
}
|
||||
|
||||
if (opts.template) {
|
||||
try {
|
||||
// eslint-disable-next-line global-require, import/no-dynamic-require
|
||||
const template = require(path.join(process.cwd(), opts.template))
|
||||
if (template.default) config.template = template.default
|
||||
else config.template = template
|
||||
|
||||
if (typeof config.template !== 'function')
|
||||
throw new Error('Template must be a function')
|
||||
} catch (error) {
|
||||
console.error(`Error when loading template: ${opts.template}\n`)
|
||||
console.error(error.stack)
|
||||
process.exit(2)
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.indexTemplate) {
|
||||
try {
|
||||
// eslint-disable-next-line global-require, import/no-dynamic-require
|
||||
const indexTemplate = require(path.join(
|
||||
process.cwd(),
|
||||
opts.indexTemplate,
|
||||
))
|
||||
if (indexTemplate.default) config.indexTemplate = indexTemplate.default
|
||||
else config.indexTemplate = indexTemplate
|
||||
|
||||
if (typeof config.indexTemplate !== 'function')
|
||||
throw new Error('indexTemplate must be a function')
|
||||
} catch (error) {
|
||||
console.error(`Error when loading indexTemplate: ${opts.indexTemplate}\n`)
|
||||
console.error(error.stack)
|
||||
process.exit(2)
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.index === false) {
|
||||
delete config.index
|
||||
}
|
||||
|
||||
const command = opts.outDir ? dirCommand : fileCommand
|
||||
|
||||
await command(opts, program, filenames, config)
|
||||
}
|
||||
|
||||
@ -1,66 +0,0 @@
|
||||
/* eslint-disable no-console */
|
||||
import { promises as fs } from 'fs'
|
||||
import chalk from 'chalk'
|
||||
import svgrConvert from '@svgr/core'
|
||||
import svgo from '@svgr/plugin-svgo'
|
||||
import jsx from '@svgr/plugin-jsx'
|
||||
import prettier from '@svgr/plugin-prettier'
|
||||
import camelcase from 'camelcase'
|
||||
import dashify from 'dashify'
|
||||
|
||||
export const CASE = {
|
||||
KEBAB: 'kebab', // kebab-case
|
||||
CAMEL: 'camel', // camelCase
|
||||
PASCAL: 'pascal', // PascalCase
|
||||
}
|
||||
|
||||
export function transformFilename(filename, filenameCase) {
|
||||
switch (filenameCase) {
|
||||
case CASE.KEBAB:
|
||||
return dashify(filename.replace(/_/g, '-'), { condense: true })
|
||||
case CASE.CAMEL:
|
||||
return camelcase(filename)
|
||||
case CASE.PASCAL:
|
||||
return camelcase(filename, { pascalCase: true })
|
||||
default:
|
||||
throw new Error(`Unknown --filename-case ${filenameCase}`)
|
||||
}
|
||||
}
|
||||
|
||||
export function convert(code, config, state) {
|
||||
return svgrConvert.sync(code, config, {
|
||||
...state,
|
||||
caller: {
|
||||
name: '@svgr/cli',
|
||||
defaultPlugins: [svgo, jsx, prettier],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export async function convertFile(filePath, config = {}) {
|
||||
const code = await fs.readFile(filePath, 'utf-8')
|
||||
return convert(code, config, { filePath })
|
||||
}
|
||||
|
||||
export function exitError(error) {
|
||||
console.error(chalk.red(error))
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
export function politeWrite(opts, data) {
|
||||
if (!opts.silent) {
|
||||
process.stdout.write(data)
|
||||
}
|
||||
}
|
||||
|
||||
export function formatExportName(name) {
|
||||
if (/[-]/g.test(name) && /^\d/.test(name)) {
|
||||
return `Svg${camelcase(name, { pascalCase: true })}`
|
||||
}
|
||||
|
||||
if (/^\d/.test(name)) {
|
||||
return `Svg${name}`
|
||||
}
|
||||
|
||||
return camelcase(name, { pascalCase: true })
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
import path from 'path'
|
||||
import { convertFile, transformFilename, CASE, formatExportName } from './util'
|
||||
import * as path from 'path'
|
||||
import { convertFile, transformFilename, formatExportName } from './util'
|
||||
|
||||
const FIXTURES = path.join(__dirname, '../../../__fixtures__')
|
||||
|
||||
@ -22,13 +22,13 @@ describe('util', () => {
|
||||
|
||||
describe('#transformFilename', () => {
|
||||
it('should transform filename', () => {
|
||||
expect(transformFilename('FooBar', CASE.CAMEL)).toBe('fooBar')
|
||||
expect(transformFilename('FooBar', CASE.KEBAB)).toBe('foo-bar')
|
||||
expect(transformFilename('FooBar', CASE.PASCAL)).toBe('FooBar')
|
||||
expect(transformFilename('FooBar', 'camel')).toBe('fooBar')
|
||||
expect(transformFilename('FooBar', 'kebab')).toBe('foo-bar')
|
||||
expect(transformFilename('FooBar', 'pascal')).toBe('FooBar')
|
||||
|
||||
expect(transformFilename('foo_bar', CASE.CAMEL)).toBe('fooBar')
|
||||
expect(transformFilename('foo_bar', CASE.KEBAB)).toBe('foo-bar')
|
||||
expect(transformFilename('foo_bar', CASE.PASCAL)).toBe('FooBar')
|
||||
expect(transformFilename('foo_bar', 'camel')).toBe('fooBar')
|
||||
expect(transformFilename('foo_bar', 'kebab')).toBe('foo-bar')
|
||||
expect(transformFilename('foo_bar', 'pascal')).toBe('FooBar')
|
||||
})
|
||||
})
|
||||
|
||||
72
packages/cli/src/util.ts
Normal file
72
packages/cli/src/util.ts
Normal file
@ -0,0 +1,72 @@
|
||||
/* eslint-disable no-console */
|
||||
import { promises as fs } from 'fs'
|
||||
import { red } from 'chalk'
|
||||
import svgrConvert, { Config, State } from '@svgr/core'
|
||||
import svgo from '@svgr/plugin-svgo'
|
||||
import jsx from '@svgr/plugin-jsx'
|
||||
import prettier from '@svgr/plugin-prettier'
|
||||
// @ts-ignore
|
||||
import camelCase from 'camelcase'
|
||||
// @ts-ignore
|
||||
import dashify from 'dashify'
|
||||
|
||||
export function transformFilename(
|
||||
filename: string,
|
||||
filenameCase: string,
|
||||
): string {
|
||||
switch (filenameCase) {
|
||||
case 'kebab':
|
||||
return dashify(filename.replace(/_/g, '-'), { condense: true })
|
||||
case 'camel':
|
||||
return camelCase(filename)
|
||||
case 'pascal':
|
||||
return camelCase(filename, { pascalCase: true })
|
||||
default:
|
||||
throw new Error(`Unknown --filename-case ${filenameCase}`)
|
||||
}
|
||||
}
|
||||
|
||||
export const convert = (
|
||||
code: string,
|
||||
config: Config,
|
||||
state: Partial<State>,
|
||||
): string => {
|
||||
return svgrConvert.sync(code, config, {
|
||||
...state,
|
||||
caller: {
|
||||
name: '@svgr/cli',
|
||||
defaultPlugins: [svgo, jsx, prettier],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const convertFile = async (
|
||||
filePath: string,
|
||||
config: Config = {},
|
||||
): Promise<string> => {
|
||||
const code = await fs.readFile(filePath, 'utf-8')
|
||||
return convert(code, config, { filePath })
|
||||
}
|
||||
|
||||
export const exitError = (error: string): never => {
|
||||
console.error(red(error))
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
export const politeWrite = (data: string, silent?: boolean): void => {
|
||||
if (!silent) {
|
||||
process.stdout.write(data)
|
||||
}
|
||||
}
|
||||
|
||||
export const formatExportName = (name: string): string => {
|
||||
if (/[-]/g.test(name) && /^\d/.test(name)) {
|
||||
return `Svg${camelCase(name, { pascalCase: true })}`
|
||||
}
|
||||
|
||||
if (/^\d/.test(name)) {
|
||||
return `Svg${name}`
|
||||
}
|
||||
|
||||
return camelCase(name, { pascalCase: true })
|
||||
}
|
||||
4
packages/cli/tsconfig.json
Normal file
4
packages/cli/tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"include": ["src"]
|
||||
}
|
||||
@ -1,2 +1,4 @@
|
||||
src/
|
||||
.*
|
||||
/*
|
||||
/dist/*
|
||||
!/dist/index.{d.ts,js}
|
||||
!/dist/index.js.map
|
||||
@ -2,7 +2,9 @@
|
||||
"name": "@svgr/core",
|
||||
"description": "Transform SVG into React Components.",
|
||||
"version": "6.0.0-alpha.0",
|
||||
"main": "lib/index.js",
|
||||
"main": "./dist/index.js",
|
||||
"exports": "./dist/index.js",
|
||||
"typings": "./dist/index.d.ts",
|
||||
"repository": "https://github.com/gregberge/svgr/tree/master/packages/core",
|
||||
"author": "Greg Bergé <berge.greg@gmail.com>",
|
||||
"publishConfig": {
|
||||
@ -26,13 +28,16 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"prebuild": "rm -rf lib/",
|
||||
"build": "babel --config-file ../../babel.config.js -d lib --ignore \"**/*.test.js\" src && cp src/index.d.ts lib/index.d.ts",
|
||||
"prepublishOnly": "npm run build"
|
||||
"reset": "rm -rf dist",
|
||||
"build": "rollup -c ../../build/rollup.config.js",
|
||||
"prepublishOnly": "npm run reset && npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@svgr/plugin-jsx": "^6.0.0-alpha.0",
|
||||
"camelcase": "^6.2.0",
|
||||
"cosmiconfig": "^7.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/svgo": "^2.6.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,9 +11,8 @@ Object {
|
||||
"namedExport": "ReactComponent",
|
||||
"native": false,
|
||||
"noSemi": true,
|
||||
"plugins": null,
|
||||
"prettier": true,
|
||||
"prettierConfig": null,
|
||||
"prettierConfig": undefined,
|
||||
"ref": false,
|
||||
"replaceAttrValues": Array [
|
||||
Array [
|
||||
@ -22,10 +21,10 @@ Object {
|
||||
],
|
||||
],
|
||||
"runtimeConfig": true,
|
||||
"svgProps": null,
|
||||
"svgProps": undefined,
|
||||
"svgo": true,
|
||||
"svgoConfig": null,
|
||||
"template": null,
|
||||
"svgoConfig": undefined,
|
||||
"template": undefined,
|
||||
"titleProp": false,
|
||||
"typescript": false,
|
||||
}
|
||||
@ -42,9 +41,8 @@ Object {
|
||||
"namedExport": "ReactComponent",
|
||||
"native": false,
|
||||
"noSemi": true,
|
||||
"plugins": null,
|
||||
"prettier": true,
|
||||
"prettierConfig": null,
|
||||
"prettierConfig": undefined,
|
||||
"ref": false,
|
||||
"replaceAttrValues": Array [
|
||||
Array [
|
||||
@ -53,10 +51,10 @@ Object {
|
||||
],
|
||||
],
|
||||
"runtimeConfig": true,
|
||||
"svgProps": null,
|
||||
"svgProps": undefined,
|
||||
"svgo": true,
|
||||
"svgoConfig": null,
|
||||
"template": null,
|
||||
"svgoConfig": undefined,
|
||||
"template": undefined,
|
||||
"titleProp": false,
|
||||
"typescript": false,
|
||||
"useRuntimeConfig": false,
|
||||
@ -73,16 +71,15 @@ Object {
|
||||
"memo": false,
|
||||
"namedExport": "ReactComponent",
|
||||
"native": false,
|
||||
"plugins": null,
|
||||
"prettier": true,
|
||||
"prettierConfig": null,
|
||||
"prettierConfig": undefined,
|
||||
"ref": false,
|
||||
"replaceAttrValues": null,
|
||||
"replaceAttrValues": undefined,
|
||||
"runtimeConfig": true,
|
||||
"svgProps": null,
|
||||
"svgProps": undefined,
|
||||
"svgo": true,
|
||||
"svgoConfig": null,
|
||||
"template": null,
|
||||
"svgoConfig": undefined,
|
||||
"template": undefined,
|
||||
"titleProp": false,
|
||||
"typescript": false,
|
||||
}
|
||||
@ -99,9 +96,8 @@ Object {
|
||||
"namedExport": "ReactComponent",
|
||||
"native": false,
|
||||
"noSemi": true,
|
||||
"plugins": null,
|
||||
"prettier": true,
|
||||
"prettierConfig": null,
|
||||
"prettierConfig": undefined,
|
||||
"ref": false,
|
||||
"replaceAttrValues": Array [
|
||||
Array [
|
||||
@ -110,10 +106,10 @@ Object {
|
||||
],
|
||||
],
|
||||
"runtimeConfig": true,
|
||||
"svgProps": null,
|
||||
"svgProps": undefined,
|
||||
"svgo": true,
|
||||
"svgoConfig": null,
|
||||
"template": null,
|
||||
"svgoConfig": undefined,
|
||||
"template": undefined,
|
||||
"titleProp": false,
|
||||
"typescript": false,
|
||||
}
|
||||
@ -130,9 +126,8 @@ Object {
|
||||
"namedExport": "ReactComponent",
|
||||
"native": false,
|
||||
"noSemi": true,
|
||||
"plugins": null,
|
||||
"prettier": true,
|
||||
"prettierConfig": null,
|
||||
"prettierConfig": undefined,
|
||||
"ref": false,
|
||||
"replaceAttrValues": Array [
|
||||
Array [
|
||||
@ -141,10 +136,10 @@ Object {
|
||||
],
|
||||
],
|
||||
"runtimeConfig": true,
|
||||
"svgProps": null,
|
||||
"svgProps": undefined,
|
||||
"svgo": true,
|
||||
"svgoConfig": null,
|
||||
"template": null,
|
||||
"svgoConfig": undefined,
|
||||
"template": undefined,
|
||||
"titleProp": false,
|
||||
"typescript": false,
|
||||
}
|
||||
@ -161,9 +156,8 @@ Object {
|
||||
"namedExport": "ReactComponent",
|
||||
"native": false,
|
||||
"noSemi": true,
|
||||
"plugins": null,
|
||||
"prettier": true,
|
||||
"prettierConfig": null,
|
||||
"prettierConfig": undefined,
|
||||
"ref": false,
|
||||
"replaceAttrValues": Array [
|
||||
Array [
|
||||
@ -172,10 +166,10 @@ Object {
|
||||
],
|
||||
],
|
||||
"runtimeConfig": true,
|
||||
"svgProps": null,
|
||||
"svgProps": undefined,
|
||||
"svgo": true,
|
||||
"svgoConfig": null,
|
||||
"template": null,
|
||||
"svgoConfig": undefined,
|
||||
"template": undefined,
|
||||
"titleProp": false,
|
||||
"typescript": false,
|
||||
"useRuntimeConfig": false,
|
||||
@ -192,16 +186,15 @@ Object {
|
||||
"memo": false,
|
||||
"namedExport": "ReactComponent",
|
||||
"native": false,
|
||||
"plugins": null,
|
||||
"prettier": true,
|
||||
"prettierConfig": null,
|
||||
"prettierConfig": undefined,
|
||||
"ref": false,
|
||||
"replaceAttrValues": null,
|
||||
"replaceAttrValues": undefined,
|
||||
"runtimeConfig": true,
|
||||
"svgProps": null,
|
||||
"svgProps": undefined,
|
||||
"svgo": true,
|
||||
"svgoConfig": null,
|
||||
"template": null,
|
||||
"svgoConfig": undefined,
|
||||
"template": undefined,
|
||||
"titleProp": false,
|
||||
"typescript": false,
|
||||
}
|
||||
@ -218,9 +211,8 @@ Object {
|
||||
"namedExport": "ReactComponent",
|
||||
"native": false,
|
||||
"noSemi": true,
|
||||
"plugins": null,
|
||||
"prettier": true,
|
||||
"prettierConfig": null,
|
||||
"prettierConfig": undefined,
|
||||
"ref": false,
|
||||
"replaceAttrValues": Array [
|
||||
Array [
|
||||
@ -229,10 +221,10 @@ Object {
|
||||
],
|
||||
],
|
||||
"runtimeConfig": true,
|
||||
"svgProps": null,
|
||||
"svgProps": undefined,
|
||||
"svgo": true,
|
||||
"svgoConfig": null,
|
||||
"template": null,
|
||||
"svgoConfig": undefined,
|
||||
"template": undefined,
|
||||
"titleProp": false,
|
||||
"typescript": false,
|
||||
}
|
||||
@ -1,710 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`convert config should support options {"dimensions":false} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgComponent(props) {
|
||||
return (
|
||||
<svg viewBox=\\"0 0 88 88\\" xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"expandProps":"start"} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgComponent(props) {
|
||||
return (
|
||||
<svg {...props} width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\">
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"expandProps":false} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgComponent() {
|
||||
return (
|
||||
<svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\">
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"exportType":"named"} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgComponent(props) {
|
||||
return (
|
||||
<svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export { SvgComponent as ReactComponent }
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"icon":true} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgComponent(props) {
|
||||
return (
|
||||
<svg
|
||||
width=\\"1em\\"
|
||||
height=\\"1em\\"
|
||||
viewBox=\\"0 0 88 88\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
{...props}
|
||||
>
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"memo":true} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgComponent(props) {
|
||||
return (
|
||||
<svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
const MemoSvgComponent = React.memo(SvgComponent)
|
||||
export default MemoSvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"namedExport":"Component","state":{"caller":{"previousExport":"export default \\"logo.svg\\";"}}} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgComponent(props) {
|
||||
return (
|
||||
<svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"native":{"expo":true}} 1`] = `
|
||||
"import * as React from 'react'
|
||||
import { Svg } from 'expo'
|
||||
|
||||
function SvgComponent(props) {
|
||||
return (
|
||||
<Svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<Svg.G
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<Svg.Path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</Svg.G>
|
||||
</Svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"native":true,"expandProps":false} 1`] = `
|
||||
"import * as React from 'react'
|
||||
import Svg, { G, Path } from 'react-native-svg'
|
||||
|
||||
function SvgComponent() {
|
||||
return (
|
||||
<Svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\">
|
||||
<G
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<Path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</G>
|
||||
</Svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"native":true,"icon":true} 1`] = `
|
||||
"import * as React from 'react'
|
||||
import Svg, { G, Path } from 'react-native-svg'
|
||||
|
||||
function SvgComponent(props) {
|
||||
return (
|
||||
<Svg
|
||||
width=\\"1em\\"
|
||||
height=\\"1em\\"
|
||||
viewBox=\\"0 0 88 88\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
{...props}
|
||||
>
|
||||
<G
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<Path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</G>
|
||||
</Svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"native":true,"ref":true} 1`] = `
|
||||
"import * as React from 'react'
|
||||
import Svg, { G, Path } from 'react-native-svg'
|
||||
|
||||
function SvgComponent(props, svgRef) {
|
||||
return (
|
||||
<Svg
|
||||
width={88}
|
||||
height={88}
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
ref={svgRef}
|
||||
{...props}
|
||||
>
|
||||
<G
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<Path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</G>
|
||||
</Svg>
|
||||
)
|
||||
}
|
||||
|
||||
const ForwardRef = React.forwardRef(SvgComponent)
|
||||
export default ForwardRef
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"native":true} 1`] = `
|
||||
"import * as React from 'react'
|
||||
import Svg, { G, Path } from 'react-native-svg'
|
||||
|
||||
function SvgComponent(props) {
|
||||
return (
|
||||
<Svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<G
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<Path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</G>
|
||||
</Svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"prettier":false} 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
|
||||
function SvgComponent(props) {
|
||||
return <svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}><g stroke=\\"#063855\\" strokeWidth={2} fill=\\"none\\" fillRule=\\"evenodd\\" strokeLinecap=\\"square\\"><path d=\\"M51 37 37 51M51 51 37 37\\" /></g></svg>;
|
||||
}
|
||||
|
||||
export default SvgComponent;"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"ref":true} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgComponent(props, svgRef) {
|
||||
return (
|
||||
<svg
|
||||
width={88}
|
||||
height={88}
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
ref={svgRef}
|
||||
{...props}
|
||||
>
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
const ForwardRef = React.forwardRef(SvgComponent)
|
||||
export default ForwardRef
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"replaceAttrValues":{"none":"{black}"}} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgComponent(props) {
|
||||
return (
|
||||
<svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill={black}
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"replaceAttrValues":{"none":"black"}} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgComponent(props) {
|
||||
return (
|
||||
<svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"black\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"svgProps":{"a":"b","b":"{props.b}"}} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgComponent(props) {
|
||||
return (
|
||||
<svg
|
||||
width={88}
|
||||
height={88}
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
a=\\"b\\"
|
||||
b={props.b}
|
||||
{...props}
|
||||
>
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"svgo":false} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgComponent(props) {
|
||||
return (
|
||||
<svg
|
||||
width=\\"88px\\"
|
||||
height=\\"88px\\"
|
||||
viewBox=\\"0 0 88 88\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
xmlnsXlink=\\"http://www.w3.org/1999/xlink\\"
|
||||
{...props}
|
||||
>
|
||||
<title>{'Dismiss'}</title>
|
||||
<desc>{'Created with Sketch.'}</desc>
|
||||
<defs />
|
||||
<g
|
||||
id=\\"Blocks\\"
|
||||
stroke=\\"none\\"
|
||||
strokeWidth={1}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<g id=\\"Dismiss\\" stroke=\\"#063855\\" strokeWidth={2}>
|
||||
<path d=\\"M51,37 L37,51\\" id=\\"Shape\\" />
|
||||
<path d=\\"M51,51 L37,37\\" id=\\"Shape\\" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"titleProp":true} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgComponent({ title, titleId, ...props }) {
|
||||
return (
|
||||
<svg
|
||||
width={88}
|
||||
height={88}
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
aria-labelledby={titleId}
|
||||
{...props}
|
||||
>
|
||||
{title ? <title id={titleId}>{title}</title> : null}
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {} 1`] = `
|
||||
"const noop = () => null
|
||||
|
||||
export default noop
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config titleProp: without title added 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgComponent({ title, titleId, ...props }) {
|
||||
return (
|
||||
<svg
|
||||
width={0}
|
||||
height={0}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
}}
|
||||
aria-labelledby={titleId}
|
||||
{...props}
|
||||
>
|
||||
{title ? <title id={titleId}>{title}</title> : null}
|
||||
<path d=\\"M0 0h24v24H0z\\" fill=\\"none\\" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert should convert 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgComponent(props) {
|
||||
return (
|
||||
<svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert should convert style attribute 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgComponent(props) {
|
||||
return (
|
||||
<svg
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
xmlnsXlink=\\"http://www.w3.org/1999/xlink\\"
|
||||
width={48}
|
||||
height={48}
|
||||
{...props}
|
||||
>
|
||||
<g transform=\\"translate(0 -1004.362)\\">
|
||||
<g id=\\"prefix__a\\">
|
||||
<rect
|
||||
style={{
|
||||
color: '#000',
|
||||
fill: '#a3a3a3',
|
||||
fillOpacity: 1,
|
||||
fillRule: 'nonzero',
|
||||
stroke: 'none',
|
||||
strokeWidth: 8,
|
||||
marker: 'none',
|
||||
visibility: 'visible',
|
||||
display: 'inline',
|
||||
overflow: 'visible',
|
||||
enableBackground: 'accumulate',
|
||||
}}
|
||||
width={4}
|
||||
height={4}
|
||||
x={4}
|
||||
y={1010.362}
|
||||
rx={0.2}
|
||||
ry={0.2}
|
||||
/>
|
||||
<rect
|
||||
ry={0.2}
|
||||
rx={0.2}
|
||||
y={1010.362}
|
||||
x={12}
|
||||
height={4}
|
||||
width={32}
|
||||
style={{
|
||||
color: '#000',
|
||||
fill: '#a3a3a3',
|
||||
fillOpacity: 1,
|
||||
fillRule: 'nonzero',
|
||||
stroke: 'none',
|
||||
strokeWidth: 8,
|
||||
marker: 'none',
|
||||
visibility: 'visible',
|
||||
display: 'inline',
|
||||
overflow: 'visible',
|
||||
enableBackground: 'accumulate',
|
||||
}}
|
||||
/>
|
||||
</g>
|
||||
<use xlinkHref=\\"#prefix__a\\" />
|
||||
<use xlinkHref=\\"#prefix__a\\" transform=\\"translate(0 8)\\" />
|
||||
<use xlinkHref=\\"#prefix__a\\" transform=\\"translate(0 16)\\" />
|
||||
<use xlinkHref=\\"#prefix__a\\" transform=\\"translate(0 24)\\" />
|
||||
<use xlinkHref=\\"#prefix__a\\" transform=\\"translate(0 32)\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert should handle special SVG attributes 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgComponent(props) {
|
||||
return (
|
||||
<svg xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<path externalResourcesRequired=\\"false\\" d=\\"M10 10h100v100H10z\\" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert should not remove all style tags 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgComponent(props) {
|
||||
return (
|
||||
<svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<style>{'path{fill:red}'}</style>
|
||||
<g
|
||||
id=\\"prefix__Blocks\\"
|
||||
stroke=\\"none\\"
|
||||
strokeWidth={1}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<g id=\\"prefix__Dismiss\\" stroke=\\"#063855\\" strokeWidth={2}>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" id=\\"prefix__Shape\\" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert should remove null characters 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgComponent(props) {
|
||||
return (
|
||||
<svg
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
width={25}
|
||||
height={25}
|
||||
style={{
|
||||
enableBackground: 'new 0 0 25 25',
|
||||
}}
|
||||
xmlSpace=\\"preserve\\"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d=\\"M19.4 24.5H5.6c-2.8 0-5.1-2.3-5.1-5.1V5.6C.5 2.8 2.8.5 5.6.5h13.8c2.8 0 5.1 2.3 5.1 5.1v13.8c0 2.8-2.3 5.1-5.1 5.1z\\"
|
||||
style={{
|
||||
fill: '#fff',
|
||||
stroke: '#434a54',
|
||||
strokeMiterlimit: 10,
|
||||
}}
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert should remove style tags 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
function SvgComponent(props) {
|
||||
return (
|
||||
<svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<style />
|
||||
<g
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
style={{
|
||||
fill: 'red',
|
||||
}}
|
||||
>
|
||||
<g id=\\"prefix__Dismiss\\" stroke=\\"#063855\\" strokeWidth={2}>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" id=\\"prefix__Shape\\" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
641
packages/core/src/__snapshots__/convert.test.ts.snap
Normal file
641
packages/core/src/__snapshots__/convert.test.ts.snap
Normal file
@ -0,0 +1,641 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`convert config should support options {"dimensions":false} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgComponent = (props) => (
|
||||
<svg viewBox=\\"0 0 88 88\\" xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"expandProps":"start"} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgComponent = (props) => (
|
||||
<svg {...props} width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\">
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"expandProps":false} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgComponent = () => (
|
||||
<svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\">
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"exportType":"named"} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgComponent = (props) => (
|
||||
<svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export { SvgComponent as ReactComponent }
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"icon":true} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgComponent = (props) => (
|
||||
<svg
|
||||
width=\\"1em\\"
|
||||
height=\\"1em\\"
|
||||
viewBox=\\"0 0 88 88\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
{...props}
|
||||
>
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"memo":true} 1`] = `
|
||||
"import * as React from 'react'
|
||||
import { memo } from 'react'
|
||||
|
||||
const SvgComponent = (props) => (
|
||||
<svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
const Memo = memo(SvgComponent)
|
||||
export default Memo
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"namedExport":"Component","state":{"caller":{"previousExport":"export default \\"logo.svg\\";"}}} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgComponent = (props) => (
|
||||
<svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"native":true,"expandProps":false} 1`] = `
|
||||
"import * as React from 'react'
|
||||
import Svg, { G, Path } from 'react-native-svg'
|
||||
|
||||
const SvgComponent = () => (
|
||||
<Svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\">
|
||||
<G
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<Path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</G>
|
||||
</Svg>
|
||||
)
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"native":true,"icon":true} 1`] = `
|
||||
"import * as React from 'react'
|
||||
import Svg, { G, Path } from 'react-native-svg'
|
||||
|
||||
const SvgComponent = (props) => (
|
||||
<Svg
|
||||
width=\\"1em\\"
|
||||
height=\\"1em\\"
|
||||
viewBox=\\"0 0 88 88\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
{...props}
|
||||
>
|
||||
<G
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<Path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</G>
|
||||
</Svg>
|
||||
)
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"native":true,"ref":true} 1`] = `
|
||||
"import * as React from 'react'
|
||||
import Svg, { G, Path } from 'react-native-svg'
|
||||
import { forwardRef } from 'react'
|
||||
|
||||
const SvgComponent = (props, ref) => (
|
||||
<Svg
|
||||
width={88}
|
||||
height={88}
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
ref={svgRef}
|
||||
{...props}
|
||||
>
|
||||
<G
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<Path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</G>
|
||||
</Svg>
|
||||
)
|
||||
|
||||
const ForwardRef = forwardRef(SvgComponent)
|
||||
export default ForwardRef
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"native":true} 1`] = `
|
||||
"import * as React from 'react'
|
||||
import Svg, { G, Path } from 'react-native-svg'
|
||||
|
||||
const SvgComponent = (props) => (
|
||||
<Svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<G
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<Path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</G>
|
||||
</Svg>
|
||||
)
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"prettier":false} 1`] = `
|
||||
"import * as React from \\"react\\";
|
||||
|
||||
const SvgComponent = props => <svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}><g stroke=\\"#063855\\" strokeWidth={2} fill=\\"none\\" fillRule=\\"evenodd\\" strokeLinecap=\\"square\\"><path d=\\"M51 37 37 51M51 51 37 37\\" /></g></svg>;
|
||||
|
||||
export default SvgComponent;"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"ref":true} 1`] = `
|
||||
"import * as React from 'react'
|
||||
import { forwardRef } from 'react'
|
||||
|
||||
const SvgComponent = (props, ref) => (
|
||||
<svg
|
||||
width={88}
|
||||
height={88}
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
ref={svgRef}
|
||||
{...props}
|
||||
>
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
const ForwardRef = forwardRef(SvgComponent)
|
||||
export default ForwardRef
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"replaceAttrValues":{"none":"{black}"}} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgComponent = (props) => (
|
||||
<svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill={black}
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"replaceAttrValues":{"none":"black"}} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgComponent = (props) => (
|
||||
<svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"black\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"svgProps":{"a":"b","b":"{props.b}"}} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgComponent = (props) => (
|
||||
<svg
|
||||
width={88}
|
||||
height={88}
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
a=\\"b\\"
|
||||
b={props.b}
|
||||
{...props}
|
||||
>
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"svgo":false} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgComponent = (props) => (
|
||||
<svg
|
||||
width=\\"88px\\"
|
||||
height=\\"88px\\"
|
||||
viewBox=\\"0 0 88 88\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
xmlnsXlink=\\"http://www.w3.org/1999/xlink\\"
|
||||
{...props}
|
||||
>
|
||||
<title>{'Dismiss'}</title>
|
||||
<desc>{'Created with Sketch.'}</desc>
|
||||
<defs />
|
||||
<g
|
||||
id=\\"Blocks\\"
|
||||
stroke=\\"none\\"
|
||||
strokeWidth={1}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<g id=\\"Dismiss\\" stroke=\\"#063855\\" strokeWidth={2}>
|
||||
<path d=\\"M51,37 L37,51\\" id=\\"Shape\\" />
|
||||
<path d=\\"M51,51 L37,37\\" id=\\"Shape\\" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {"titleProp":true} 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgComponent = ({ title, titleId, ...props }) => (
|
||||
<svg
|
||||
width={88}
|
||||
height={88}
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
aria-labelledby={titleId}
|
||||
{...props}
|
||||
>
|
||||
{title ? <title id={titleId}>{title}</title> : null}
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config should support options {} 1`] = `
|
||||
"const noop = () => null
|
||||
|
||||
export default noop
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert config titleProp: without title added 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgComponent = ({ title, titleId, ...props }) => (
|
||||
<svg
|
||||
width={0}
|
||||
height={0}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
}}
|
||||
aria-labelledby={titleId}
|
||||
{...props}
|
||||
>
|
||||
{title ? <title id={titleId}>{title}</title> : null}
|
||||
<path d=\\"M0 0h24v24H0z\\" fill=\\"none\\" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert should convert 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgComponent = (props) => (
|
||||
<svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<g
|
||||
stroke=\\"#063855\\"
|
||||
strokeWidth={2}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<path d=\\"M51 37 37 51M51 51 37 37\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert should convert style attribute 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgComponent = (props) => (
|
||||
<svg
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
xmlnsXlink=\\"http://www.w3.org/1999/xlink\\"
|
||||
width={48}
|
||||
height={48}
|
||||
{...props}
|
||||
>
|
||||
<g transform=\\"translate(0 -1004.362)\\">
|
||||
<g id=\\"prefix__a\\">
|
||||
<rect
|
||||
style={{
|
||||
color: '#000',
|
||||
fill: '#a3a3a3',
|
||||
fillOpacity: 1,
|
||||
fillRule: 'nonzero',
|
||||
stroke: 'none',
|
||||
strokeWidth: 8,
|
||||
marker: 'none',
|
||||
visibility: 'visible',
|
||||
display: 'inline',
|
||||
overflow: 'visible',
|
||||
enableBackground: 'accumulate',
|
||||
}}
|
||||
width={4}
|
||||
height={4}
|
||||
x={4}
|
||||
y={1010.362}
|
||||
rx={0.2}
|
||||
ry={0.2}
|
||||
/>
|
||||
<rect
|
||||
ry={0.2}
|
||||
rx={0.2}
|
||||
y={1010.362}
|
||||
x={12}
|
||||
height={4}
|
||||
width={32}
|
||||
style={{
|
||||
color: '#000',
|
||||
fill: '#a3a3a3',
|
||||
fillOpacity: 1,
|
||||
fillRule: 'nonzero',
|
||||
stroke: 'none',
|
||||
strokeWidth: 8,
|
||||
marker: 'none',
|
||||
visibility: 'visible',
|
||||
display: 'inline',
|
||||
overflow: 'visible',
|
||||
enableBackground: 'accumulate',
|
||||
}}
|
||||
/>
|
||||
</g>
|
||||
<use xlinkHref=\\"#prefix__a\\" />
|
||||
<use xlinkHref=\\"#prefix__a\\" transform=\\"translate(0 8)\\" />
|
||||
<use xlinkHref=\\"#prefix__a\\" transform=\\"translate(0 16)\\" />
|
||||
<use xlinkHref=\\"#prefix__a\\" transform=\\"translate(0 24)\\" />
|
||||
<use xlinkHref=\\"#prefix__a\\" transform=\\"translate(0 32)\\" />
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert should handle special SVG attributes 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgComponent = (props) => (
|
||||
<svg xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<path externalResourcesRequired=\\"false\\" d=\\"M10 10h100v100H10z\\" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert should not remove all style tags 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgComponent = (props) => (
|
||||
<svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<style>{'path{fill:red}'}</style>
|
||||
<g
|
||||
id=\\"prefix__Blocks\\"
|
||||
stroke=\\"none\\"
|
||||
strokeWidth={1}
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
>
|
||||
<g id=\\"prefix__Dismiss\\" stroke=\\"#063855\\" strokeWidth={2}>
|
||||
<path d=\\"M51 37 37 51\\" id=\\"prefix__Shape\\" />
|
||||
<path d=\\"M51 51 37 37\\" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert should remove null characters 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgComponent = (props) => (
|
||||
<svg
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
width={25}
|
||||
height={25}
|
||||
style={{
|
||||
enableBackground: 'new 0 0 25 25',
|
||||
}}
|
||||
xmlSpace=\\"preserve\\"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d=\\"M19.4 24.5H5.6c-2.8 0-5.1-2.3-5.1-5.1V5.6C.5 2.8 2.8.5 5.6.5h13.8c2.8 0 5.1 2.3 5.1 5.1v13.8c0 2.8-2.3 5.1-5.1 5.1z\\"
|
||||
style={{
|
||||
fill: '#fff',
|
||||
stroke: '#434a54',
|
||||
strokeMiterlimit: 10,
|
||||
}}
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`convert should remove style tags 1`] = `
|
||||
"import * as React from 'react'
|
||||
|
||||
const SvgComponent = (props) => (
|
||||
<svg width={88} height={88} xmlns=\\"http://www.w3.org/2000/svg\\" {...props}>
|
||||
<style />
|
||||
<g
|
||||
fill=\\"none\\"
|
||||
fillRule=\\"evenodd\\"
|
||||
strokeLinecap=\\"square\\"
|
||||
style={{
|
||||
fill: 'red',
|
||||
}}
|
||||
>
|
||||
<g id=\\"prefix__Dismiss\\" stroke=\\"#063855\\" strokeWidth={2}>
|
||||
<path d=\\"M51 37 37 51\\" id=\\"prefix__Shape\\" />
|
||||
<path d=\\"M51 51 37 37\\" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default SvgComponent
|
||||
"
|
||||
`;
|
||||
@ -1,80 +0,0 @@
|
||||
import { cosmiconfig, cosmiconfigSync } from 'cosmiconfig'
|
||||
|
||||
export const DEFAULT_CONFIG = {
|
||||
dimensions: true,
|
||||
expandProps: 'end',
|
||||
icon: false,
|
||||
native: false,
|
||||
typescript: false,
|
||||
prettier: true,
|
||||
prettierConfig: null,
|
||||
memo: false,
|
||||
ref: false,
|
||||
replaceAttrValues: null,
|
||||
svgProps: null,
|
||||
svgo: true,
|
||||
svgoConfig: null,
|
||||
template: null,
|
||||
index: false,
|
||||
titleProp: false,
|
||||
runtimeConfig: true,
|
||||
plugins: null,
|
||||
namedExport: 'ReactComponent',
|
||||
exportType: 'default',
|
||||
}
|
||||
|
||||
const explorer = cosmiconfig('svgr', {
|
||||
sync: true,
|
||||
cache: true,
|
||||
rcExtensions: true,
|
||||
})
|
||||
|
||||
const explorerSync = cosmiconfigSync('svgr', {
|
||||
sync: true,
|
||||
cache: true,
|
||||
rcExtensions: true,
|
||||
})
|
||||
|
||||
export async function resolveConfig(searchFrom, configFile) {
|
||||
if (configFile == null) {
|
||||
const result = await explorer.search(searchFrom)
|
||||
return result ? result.config : null
|
||||
}
|
||||
const result = await explorer.load(configFile)
|
||||
return result ? result.config : null
|
||||
}
|
||||
|
||||
resolveConfig.sync = (searchFrom, configFile) => {
|
||||
if (configFile == null) {
|
||||
const result = explorerSync.search(searchFrom)
|
||||
return result ? result.config : null
|
||||
}
|
||||
const result = explorerSync.load(configFile)
|
||||
return result ? result.config : null
|
||||
}
|
||||
|
||||
export async function resolveConfigFile(filePath) {
|
||||
const result = await explorer.search(filePath)
|
||||
return result ? result.filepath : null
|
||||
}
|
||||
|
||||
resolveConfigFile.sync = (filePath) => {
|
||||
const result = explorerSync.search(filePath)
|
||||
return result ? result.filepath : null
|
||||
}
|
||||
|
||||
export async function loadConfig({ configFile, ...baseConfig }, state = {}) {
|
||||
const rcConfig =
|
||||
state.filePath && baseConfig.runtimeConfig !== false
|
||||
? await resolveConfig(state.filePath, configFile)
|
||||
: {}
|
||||
return { ...DEFAULT_CONFIG, ...rcConfig, ...baseConfig }
|
||||
}
|
||||
|
||||
loadConfig.sync = ({ configFile, ...baseConfig }, state = {}) => {
|
||||
const rcConfig =
|
||||
state.filePath && baseConfig.runtimeConfig !== false
|
||||
? resolveConfig.sync(state.filePath, configFile)
|
||||
: {}
|
||||
return { ...DEFAULT_CONFIG, ...rcConfig, ...baseConfig }
|
||||
}
|
||||
@ -1,7 +1,8 @@
|
||||
import path from 'path'
|
||||
import * as path from 'path'
|
||||
import { resolveConfig, resolveConfigFile, loadConfig } from './config'
|
||||
|
||||
const getMethod = (method, mode) => (mode === 'sync' ? method.sync : method)
|
||||
const getMethod = (method: any, mode: string) =>
|
||||
mode === 'sync' ? method.sync : method
|
||||
|
||||
describe('svgo', () => {
|
||||
describe.each([['sync'], ['async']])('%s', (mode) => {
|
||||
109
packages/core/src/config.ts
Normal file
109
packages/core/src/config.ts
Normal file
@ -0,0 +1,109 @@
|
||||
import { cosmiconfig, cosmiconfigSync } from 'cosmiconfig'
|
||||
import type { Options as PrettierOptions } from 'prettier'
|
||||
import type { OptimizeOptions as SvgoOptions } from 'svgo'
|
||||
import type { Options as TransformOptions } from '@svgr/babel-preset'
|
||||
import type { TransformOptions as BabelTransformOptions } from '@babel/core'
|
||||
import type { ConfigPlugin } from './plugins'
|
||||
import type { State } from './state'
|
||||
|
||||
export interface Config extends Partial<Omit<TransformOptions, 'state'>> {
|
||||
dimensions?: boolean
|
||||
runtimeConfig?: boolean
|
||||
native?: boolean
|
||||
typescript?: boolean
|
||||
prettier?: boolean
|
||||
prettierConfig?: PrettierOptions
|
||||
svgo?: boolean
|
||||
svgoConfig?: SvgoOptions
|
||||
configFile?: string
|
||||
|
||||
// CLI only
|
||||
index?: boolean
|
||||
plugins?: ConfigPlugin[]
|
||||
|
||||
// JSX
|
||||
jsx?: { babelConfig?: BabelTransformOptions }
|
||||
}
|
||||
|
||||
export const DEFAULT_CONFIG: Config = {
|
||||
dimensions: true,
|
||||
expandProps: 'end',
|
||||
icon: false,
|
||||
native: false,
|
||||
typescript: false,
|
||||
prettier: true,
|
||||
prettierConfig: undefined,
|
||||
memo: false,
|
||||
ref: false,
|
||||
replaceAttrValues: undefined,
|
||||
svgProps: undefined,
|
||||
svgo: true,
|
||||
svgoConfig: undefined,
|
||||
template: undefined,
|
||||
index: false,
|
||||
titleProp: false,
|
||||
runtimeConfig: true,
|
||||
namedExport: 'ReactComponent',
|
||||
exportType: 'default',
|
||||
}
|
||||
|
||||
const explorer = cosmiconfig('svgr')
|
||||
const explorerSync = cosmiconfigSync('svgr')
|
||||
|
||||
export const resolveConfig = async (
|
||||
searchFrom?: string,
|
||||
configFile?: string,
|
||||
): Promise<Config | null> => {
|
||||
if (configFile == null) {
|
||||
const result = await explorer.search(searchFrom)
|
||||
return result ? result.config : null
|
||||
}
|
||||
const result = await explorer.load(configFile)
|
||||
return result ? result.config : null
|
||||
}
|
||||
|
||||
resolveConfig.sync = (
|
||||
searchFrom?: string,
|
||||
configFile?: string,
|
||||
): Config | null => {
|
||||
if (configFile == null) {
|
||||
const result = explorerSync.search(searchFrom)
|
||||
return result ? result.config : null
|
||||
}
|
||||
const result = explorerSync.load(configFile)
|
||||
return result ? result.config : null
|
||||
}
|
||||
|
||||
export const resolveConfigFile = async (
|
||||
filePath: string,
|
||||
): Promise<string | null> => {
|
||||
const result = await explorer.search(filePath)
|
||||
return result ? result.filepath : null
|
||||
}
|
||||
|
||||
resolveConfigFile.sync = (filePath: string): string | null => {
|
||||
const result = explorerSync.search(filePath)
|
||||
return result ? result.filepath : null
|
||||
}
|
||||
|
||||
export const loadConfig = async (
|
||||
{ configFile, ...baseConfig }: Config,
|
||||
state: Pick<State, 'filePath'> = {},
|
||||
): Promise<Config> => {
|
||||
const rcConfig =
|
||||
state.filePath && baseConfig.runtimeConfig !== false
|
||||
? await resolveConfig(state.filePath, configFile)
|
||||
: {}
|
||||
return { ...DEFAULT_CONFIG, ...rcConfig, ...baseConfig }
|
||||
}
|
||||
|
||||
loadConfig.sync = (
|
||||
{ configFile, ...baseConfig }: Config,
|
||||
state: Pick<State, 'filePath'> = {},
|
||||
): Config => {
|
||||
const rcConfig =
|
||||
state.filePath && baseConfig.runtimeConfig !== false
|
||||
? resolveConfig.sync(state.filePath, configFile)
|
||||
: {}
|
||||
return { ...DEFAULT_CONFIG, ...rcConfig, ...baseConfig }
|
||||
}
|
||||
@ -1,6 +1,10 @@
|
||||
import convert from '.'
|
||||
import convert, { Config, State } from '.'
|
||||
|
||||
function convertWithAllPlugins(code, config, state) {
|
||||
function convertWithAllPlugins(
|
||||
code: string,
|
||||
config?: Config,
|
||||
state?: Partial<State>,
|
||||
) {
|
||||
return convert(
|
||||
code,
|
||||
{
|
||||
@ -15,7 +19,11 @@ function convertWithAllPlugins(code, config, state) {
|
||||
)
|
||||
}
|
||||
|
||||
function convertSyncWithAllPlugins(code, config, state) {
|
||||
function convertSyncWithAllPlugins(
|
||||
code: string,
|
||||
config?: Config,
|
||||
state?: Partial<State>,
|
||||
) {
|
||||
return convert.sync(
|
||||
code,
|
||||
{
|
||||
@ -287,13 +295,12 @@ describe('convert', () => {
|
||||
})
|
||||
|
||||
describe('config', () => {
|
||||
const configs = [
|
||||
const configs: (Config & { state?: Partial<State> })[] = [
|
||||
{ dimensions: false },
|
||||
{ expandProps: false },
|
||||
{ expandProps: 'start' },
|
||||
{ icon: true },
|
||||
{ native: true },
|
||||
{ native: { expo: true } },
|
||||
{ native: true, icon: true },
|
||||
{ native: true, expandProps: false },
|
||||
{ native: true, ref: true },
|
||||
@ -304,8 +311,8 @@ describe('convert', () => {
|
||||
{ svgo: false },
|
||||
{ prettier: false },
|
||||
{
|
||||
template: ({ template }) =>
|
||||
template.ast`const noop = () => null; export default noop;`,
|
||||
template: (_, { tpl }) =>
|
||||
tpl`const noop = () => null; export default noop;`,
|
||||
},
|
||||
{ titleProp: true },
|
||||
{ memo: true },
|
||||
@ -1,8 +1,10 @@
|
||||
import { expandState } from './state'
|
||||
import { loadConfig } from './config'
|
||||
import { resolvePlugin, getPlugins } from './plugins'
|
||||
import type { Config } from './config'
|
||||
import type { State } from './state'
|
||||
|
||||
function run(code, config, state) {
|
||||
const run = (code: string, config: Config, state: Partial<State>): string => {
|
||||
const expandedState = expandState(state)
|
||||
const plugins = getPlugins(config, state).map(resolvePlugin)
|
||||
let nextCode = String(code).replace('\0', '')
|
||||
@ -13,12 +15,20 @@ function run(code, config, state) {
|
||||
return nextCode
|
||||
}
|
||||
|
||||
async function convert(code, config = {}, state = {}) {
|
||||
const convert = async (
|
||||
code: string,
|
||||
config: Config = {},
|
||||
state: Partial<State> = {},
|
||||
): Promise<string> => {
|
||||
config = await loadConfig(config, state)
|
||||
return run(code, config, state)
|
||||
}
|
||||
|
||||
convert.sync = (code, config = {}, state = {}) => {
|
||||
convert.sync = (
|
||||
code: string,
|
||||
config: Config = {},
|
||||
state: Partial<State> = {},
|
||||
): string => {
|
||||
config = loadConfig.sync(config, state)
|
||||
return run(code, config, state)
|
||||
}
|
||||
103
packages/core/src/index.d.ts
vendored
103
packages/core/src/index.d.ts
vendored
@ -1,103 +0,0 @@
|
||||
export interface TemplateOptions extends SvgrOpts {}
|
||||
|
||||
export interface TemplateData {
|
||||
imports?: string[]
|
||||
interfaces?: string[]
|
||||
componentName?: string
|
||||
props?: string[]
|
||||
jsx?: string
|
||||
exports?: string[]
|
||||
}
|
||||
|
||||
export type TemplateFunc = (
|
||||
templateOptions: { template: unknown },
|
||||
opts: TemplateOptions,
|
||||
data: TemplateData,
|
||||
) => string
|
||||
|
||||
export interface SvgrOpts {
|
||||
/** Specify a custom config file. */
|
||||
configFile?: string
|
||||
/** Replace SVG width and height with 1em to make SVG inherit text size. */
|
||||
icon?: boolean
|
||||
/** Custom extension for generated files (default "js"). */
|
||||
ext?: string
|
||||
/** Modify all SVG nodes with uppercase and use react-native-svg template. */
|
||||
native?: boolean | { expo: boolean }
|
||||
/** Generate .tsx files with TypeScript bindings. */
|
||||
typescript?: boolean
|
||||
/** Keep width and height attributes from the root SVG tag. */
|
||||
dimensions?: boolean
|
||||
/** Forward all properties on the React component to the SVG tag. */
|
||||
expandProps?: 'start' | 'end' | false
|
||||
/** Use Prettier to format JavaScript code output. */
|
||||
prettier?: boolean
|
||||
/** Specify prettier config. */
|
||||
prettierConfig?: Record<string, unknown>
|
||||
/** Use SVGO to optimize SVG code before transforming into a React component. Default: true. */
|
||||
svgo?: boolean
|
||||
/** Specify SVGO config. https://gist.github.com/pladaria/69321af86ce165c2c1fc1c718b098dd0 */
|
||||
svgoConfig?: Record<string, unknown>
|
||||
/** Forward the ref to the root SVG tag if true. */
|
||||
ref?: boolean
|
||||
/** Wrap the exported component in React.memo if true. */
|
||||
memo?: boolean
|
||||
/**
|
||||
* Replace an attribute value by another. Intended for changing an Icon
|
||||
* color to currentColor to inherit from text color.
|
||||
*
|
||||
* Specify dynamic property using curly braces: { '#000': "{props.color}" }
|
||||
*/
|
||||
replaceAttrValues?: Record<string, string>
|
||||
/**
|
||||
* Add props to the SVG tag.
|
||||
*
|
||||
* Specify dynamic property using curly braces: { focusable: "{true}" }.
|
||||
* Particularly useful with a custom template.
|
||||
*/
|
||||
svgProps?: Record<string, string>
|
||||
/**
|
||||
* Add title tag via title property. If titleProp is set to true and no
|
||||
* title is provided (title={undefined}) at render time, this will fallback
|
||||
* to an existing title element in the svg if it exists.
|
||||
*/
|
||||
titleProp?: boolean
|
||||
/**
|
||||
* Specify a template file (CLI) or a template function (API) to use.
|
||||
* For an example of template, see the default one.
|
||||
* https://github.com/gregberge/svgr/blob/main/packages/babel-plugin-transform-svg-component/src/index.js
|
||||
*/
|
||||
template?: TemplateFunc
|
||||
/** Disable index file generation. */
|
||||
index?: boolean
|
||||
/** Output files into a directory. */
|
||||
outDir?: string
|
||||
/**
|
||||
* Specify a template function (API) to change default index.js output
|
||||
* (when --out-dir is used).
|
||||
*
|
||||
* https://github.com/gregberge/svgr/blob/main/packages/cli/src/dirCommand.js#L39
|
||||
*/
|
||||
indexTemplate?: (filePaths: string[]) => string
|
||||
/** When used with --out-dir, it ignores already existing files. */
|
||||
ignoreExisting?: boolean
|
||||
/**
|
||||
* Specify a custom filename case. Possible values: pascal for PascalCase,
|
||||
* kebab for kebab-case or camel for camelCase.
|
||||
*/
|
||||
filenameCase?: 'kebab' | 'camel' | 'pascal'
|
||||
/**
|
||||
* By default @svgr/core doesn't include svgo and prettier plugins,
|
||||
* if you want them, you have to install them and include them in config.
|
||||
*/
|
||||
plugins?: string[]
|
||||
}
|
||||
|
||||
type ConvertT = {
|
||||
(svgCode: string, opts?: SvgrOpts, state?: TemplateData): Promise<string>
|
||||
sync: (svgCode: string, opts?: SvgrOpts, state?: TemplateData) => string
|
||||
}
|
||||
|
||||
declare const convert: ConvertT
|
||||
|
||||
export default convert
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user