Skip to content

Commit

Permalink
fix(svgo): support any SVGO config format
Browse files Browse the repository at this point in the history
Fixes #400
  • Loading branch information
gregberge committed Mar 22, 2020
1 parent 853db4e commit 0e1291b
Show file tree
Hide file tree
Showing 4 changed files with 204 additions and 45 deletions.
48 changes: 48 additions & 0 deletions packages/plugin-svgo/src/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import mergeDeep from 'merge-deep'

export function getFilePath(state) {
return state.filePath || process.cwd()
}

export function getBaseSvgoConfig(config) {
const baseSvgoConfig = {
plugins: [{ prefixIds: true }],
}
if (config.icon || config.dimensions === false) {
baseSvgoConfig.plugins.push({ removeViewBox: false })
}
return baseSvgoConfig
}

export function getPlugins(config) {
if (!config || !config.plugins) {
return []
}
if (!Array.isArray(config.plugins)) {
throw Error('`svgoConfig.plugins` must be an array')
}
return config.plugins
}

function extractPlugins(config) {
if (!config) return []
if (!config.plugins) return []
if (!Array.isArray(config.plugins)) return [config.plugins]
return config.plugins
}

function mergePlugins(configs) {
const plugins = configs.reduce(
(merged, config) => mergeDeep(merged, ...extractPlugins(config)),
{},
)
return Object.keys(plugins).reduce((array, key) => {
array.push({ [key]: plugins[key] })
return array
}, [])
}

export function mergeSvgoConfig(...configs) {
const plugins = mergePlugins(configs)
return { ...mergeDeep(...configs), plugins }
}
133 changes: 133 additions & 0 deletions packages/plugin-svgo/src/config.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { getFilePath, getBaseSvgoConfig, mergeSvgoConfig } from './config'

describe('svgo config', () => {
describe('#getFilePath', () => {
describe('if `state.filePath` exists', () => {
it('returns `state.filePath', () => {
expect(getFilePath({ filePath: '/foo/bar' })).toBe('/foo/bar')
})
})
describe('if `state.filePath` does not exists', () => {
it('returns current working directory', () => {
expect(getFilePath({})).toBe(process.cwd())
})
})
})

describe('#getBaseSvgoConfig', () => {
describe('with no specific config', () => {
it('returns config with `prefixIds: true`', () => {
expect(getBaseSvgoConfig({})).toEqual({
plugins: [{ prefixIds: true }],
})
})
})

describe('with `config.icons` enabled', () => {
it('returns config with `removeViewBox: false`', () => {
expect(getBaseSvgoConfig({ icon: true })).toEqual({
plugins: [{ prefixIds: true }, { removeViewBox: false }],
})
})
})

describe('with `config.dimensions` disabled', () => {
it('returns config with `removeViewBox: false`', () => {
expect(getBaseSvgoConfig({ dimensions: false })).toEqual({
plugins: [{ prefixIds: true }, { removeViewBox: false }],
})
})
})
})

describe('#mergeSvgoConfig', () => {
it('merges any config format', () => {
expect(mergeSvgoConfig({ foo: 'bar' }, { foo: 'rab' })).toEqual({
foo: 'rab',
plugins: [],
})
expect(
mergeSvgoConfig({ plugins: { removeViewBox: false } }, null),
).toEqual({
plugins: [{ removeViewBox: false }],
})
expect(
mergeSvgoConfig({ plugins: { removeViewBox: false } }, {}),
).toEqual({
plugins: [{ removeViewBox: false }],
})
expect(mergeSvgoConfig({ plugins: { removeViewBox: false } })).toEqual({
plugins: [{ removeViewBox: false }],
})
expect(mergeSvgoConfig({ plugins: [{ removeViewBox: false }] })).toEqual({
plugins: [{ removeViewBox: false }],
})
expect(
mergeSvgoConfig({
plugins: [{ removeViewBox: false }, { removeViewBox: true }],
}),
).toEqual({
plugins: [{ removeViewBox: true }],
})
expect(
mergeSvgoConfig({
plugins: [
{
convertColors: {
currentColor: true,
},
},
{
prefixIds: {
prefix: 'foo',
},
},
],
}),
).toEqual({
plugins: [
{
convertColors: {
currentColor: true,
},
},
{
prefixIds: {
prefix: 'foo',
},
},
],
})
expect(
mergeSvgoConfig(
{
plugins: [
{
prefixIds: {
prefix: 'foo',
},
},
],
},
{
plugins: [
{
prefixIds: {
prefix: 'bar',
},
},
],
},
),
).toEqual({
plugins: [
{
prefixIds: {
prefix: 'bar',
},
},
],
})
})
})
})
47 changes: 3 additions & 44 deletions packages/plugin-svgo/src/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable no-underscore-dangle */
import SVGO from 'svgo'
import { cosmiconfigSync } from 'cosmiconfig'
import mergeDeep from 'merge-deep'
import { getFilePath, getBaseSvgoConfig, mergeSvgoConfig } from './config'

const explorer = cosmiconfigSync('svgo', {
searchPlaces: [
Expand Down Expand Up @@ -83,54 +83,13 @@ function optimizeSync(svgstr, info) {
return result
}

function getBaseSvgoConfig(config) {
const baseSvgoConfig = {
plugins: [{ prefixIds: true }],
}
if (config.icon || config.dimensions === false)
baseSvgoConfig.plugins.push({ removeViewBox: false })
return baseSvgoConfig
}

function getFilePath(state) {
return state.filePath || process.cwd()
}

function getPlugins(config) {
if (!config || !config.plugins) {
return []
}
if (!Array.isArray(config.plugins)) {
throw Error("`svgoConfig.plugins` must be an array")
}
return config.plugins
}

function extendPlugins(...configs) {
const init = [];
let i = configs.length;

while (i-- > 0) {
const plugins = configs[i];
for (let j = 0; j < plugins.length; j++) {
const plugin = plugins[j];
if (!init.some(item => Object.keys(item)[0] === Object.keys(plugin)[0])) {
init.push(plugin);
}
}
}
return init;
}

function createSvgo(config, rcConfig) {
const baseSvgoConfig = getBaseSvgoConfig(config);
const plugins = extendPlugins(getPlugins(baseSvgoConfig), getPlugins(rcConfig), getPlugins(config.svgoConfig));
const mergedConfig = mergeDeep(
const baseSvgoConfig = getBaseSvgoConfig(config)
const mergedConfig = mergeSvgoConfig(
baseSvgoConfig,
rcConfig,
config.svgoConfig,
)
mergedConfig.plugins = plugins
return new SVGO(mergedConfig)
}

Expand Down
21 changes: 20 additions & 1 deletion packages/plugin-svgo/src/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,20 @@ describe('svgo', () => {
expect(result).toMatchSnapshot()
})

it.only('should support config.svgoConfig', () => {
const result = svgo(
baseSvg,
{
svgo: true,
runtimeConfig: true,
svgoConfig: { plugins: [{ removeDesc: false }] },
},
{},
)

expect(result).toMatchSnapshot()
})

it('should throw error for invalid config.svgoConfig', () => {
const svgoOptions = [
baseSvg,
Expand Down Expand Up @@ -129,7 +143,12 @@ describe('svgo', () => {
svgo: true,
icon: true,
runtimeConfig: true,
svgoConfig: { full: true, plugins: [{ prefixIds: {prefixIds: true, prefixClassNames: false} }] },
svgoConfig: {
full: true,
plugins: [
{ prefixIds: { prefixIds: true, prefixClassNames: false } },
],
},
},
{ filePath: path.join(__dirname, '../__fixtures__/svgo') },
)
Expand Down

0 comments on commit 0e1291b

Please sign in to comment.