diff --git a/.svgo.yml b/.svgo.yml index 31862671..d467e3a7 100644 --- a/.svgo.yml +++ b/.svgo.yml @@ -45,3 +45,4 @@ plugins: - transformsWithOnePath - sortAttrs - removeDimensions + - removeAttrs diff --git a/README.md b/README.md index 9ddf74c5..d681a187 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ Today we have: * [ [>](https://github.com/svg/svgo/blob/master/plugins/convertShapeToPath.js) ] convert some basic shapes to path * [ [>](https://github.com/svg/svgo/blob/master/plugins/transformsWithOnePath.js) ] apply transforms, crop by real width, center vertical alignment and resize SVG with one Path inside * [ [>](https://github.com/svg/svgo/blob/master/plugins/removeDimensions.js) ] remove width/height attributes if viewBox is present +* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeAttrs.js) ] remove attributes by pattern Want to know how it works and how to write your own plugin? [Of course you want to](https://github.com/svg/svgo/blob/master/docs/how-it-works/en.md). diff --git a/README.ru.md b/README.ru.md index 75afee26..28d4a229 100644 --- a/README.ru.md +++ b/README.ru.md @@ -48,6 +48,7 @@ SVGO имеет расширяемую архитектуру, в которой * [ [>](https://github.com/svg/svgo/blob/master/plugins/convertShapeToPath.js) ] конвертирование простых форм в Path * [ [>](https://github.com/svg/svgo/blob/master/plugins/transformsWithOnePath.js) ] применение трансформаций, обрезка по реальной ширине, вертикальное выравнивание по центру и изменение размеров SVG с одним Path внутри * [ [>](https://github.com/svg/svgo/blob/master/plugins/removeDimensions.js) ] !!translation needed - remove width/height attributes if viewBox is present +* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeAttrs.js) ] !!translation needed - remove attributes by pattern Хотите узнать, как это работает и как написать свой плагин? [Конечно же, да!](https://github.com/svg/svgo/blob/master/docs/how-it-works/ru.md). diff --git a/plugins/removeAttrs.js b/plugins/removeAttrs.js new file mode 100644 index 00000000..eef4606d --- /dev/null +++ b/plugins/removeAttrs.js @@ -0,0 +1,112 @@ +'use strict'; + +var ELEM_SEP = ':'; + +exports.type = 'perItem'; + +exports.active = false; + +exports.params = { + attrs: [] +}; + +/** + * Remove attributes + * + * @param attrs: + * + * format: [ element* : attribute* ] + * + * element : regexp (wrapped into ^...$), single * or omitted > all elements + * attribute : regexp (wrapped into ^...$) + * + * examples: + * + * > remove fill attribute on path element + * --- + * attrs: 'path:fill' + * + * + * > remove all fill and stroke attribute + * --- + * attrs: + * - 'fill' + * - 'stroke' + * + * [is same as] + * + * attrs: '(fill|stroke)' + * + * [is same as] + * + * attrs: '*:(fill|stroke)' + * + * [is same as] + * + * attrs: '.*:(fill|stroke)' + * + * + * > remove all stroke related attributes + * ---- + * attrs: 'stroke.*' + * + * + * @param {Object} item current iteration item + * @param {Object} params plugin params + * @return {Boolean} if false, item will be filtered out + * + * @author Benny Schudel + */ +exports.fn = function(item, params) { + + // wrap into an array if params is not + if (!Array.isArray(params.attrs)) { + params.attrs = [params.attrs]; + } + + if (item.isElem()) { + + // prepare patterns + var patterns = params.attrs.map(function(pattern) { + + // apply to all elements if specifc element is omitted + if (pattern.indexOf(ELEM_SEP) === -1) { + pattern = ['.*', ELEM_SEP, pattern].join(''); + } + + // create regexps for element and attribute name + return pattern.split(ELEM_SEP) + .map(function(value) { + + // adjust single * to match anything + if (value === '*') { value = '.*'; } + + return new RegExp(['^', value, '$'].join(''), 'i'); + }); + + }); + + // loop patterns + patterns.forEach(function(pattern) { + + // matches element + if (pattern[0].test(item.elem)) { + + // loop attributes + item.eachAttr(function(attr) { + var name = attr.name; + + // matches attribute name + if (pattern[1].test(name)) { + item.removeAttr(name); + } + + }); + + } + + }); + + } + +}; diff --git a/test/plugins/_index.js b/test/plugins/_index.js index cf39ed78..6b3030f7 100644 --- a/test/plugins/_index.js +++ b/test/plugins/_index.js @@ -13,38 +13,39 @@ describe('plugins tests', function() { var match = file.match(regFilename), index, - name, - svgo, - plugins; + name; if (match) { - name = match[1]; + name = match[1]; index = match[2]; file = PATH.resolve(__dirname, file); - plugins = {}; - plugins[name] = true; - - svgo = new SVGO({ - full: true, - plugins: [ plugins ], - js2svg: { pretty: true } - }); - it(name + '.' + index, function(done) { FS.readFile(file, 'utf8', function(err, data) { - var splitted = data.split('@@@'), - orig = splitted[0], - should = splitted[1]; + var splitted = data.trim().split(/\s*@@@\s*/), + orig = splitted[0], + should = splitted[1], + params = splitted[2], + + plugins = {}, + svgo; + + plugins[name] = (params) ? JSON.parse(params) : true; + + svgo = new SVGO({ + full : true, + plugins : [ plugins ], + js2svg : { pretty: true } + }); svgo.optimize(orig, function(result) { - result = '\n\n' + result.data; - result.should.be.equal(should); +//FIXME: results.data has a '\n' at the end while it should not + ( result.data.trim() ).should.be.equal(should); done(); }); diff --git a/test/plugins/removeAttrs.01.svg b/test/plugins/removeAttrs.01.svg new file mode 100644 index 00000000..241c29d8 --- /dev/null +++ b/test/plugins/removeAttrs.01.svg @@ -0,0 +1,19 @@ + + + + + + + +@@@ + + + + + + + + +@@@ + +{"attrs":["circle:stroke.*","path:fill"]} diff --git a/test/plugins/removeAttrs.02.svg b/test/plugins/removeAttrs.02.svg new file mode 100644 index 00000000..98b857c1 --- /dev/null +++ b/test/plugins/removeAttrs.02.svg @@ -0,0 +1,19 @@ + + + + + + + +@@@ + + + + + + + + +@@@ + +{"attrs":"(fill|stroke)"}