160 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			160 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | |
| 
 | |
| exports.name = 'removeAttrs';
 | |
| exports.type = 'visitor';
 | |
| exports.active = false;
 | |
| exports.description = 'removes specified attributes';
 | |
| 
 | |
| const DEFAULT_SEPARATOR = ':';
 | |
| const ENOATTRS = `Warning: The plugin "removeAttrs" requires the "attrs" parameter.
 | |
| It should have a pattern to remove, otherwise the plugin is a noop.
 | |
| Config example:
 | |
| 
 | |
| plugins: [
 | |
|   {
 | |
|     name: "removeAttrs",
 | |
|     params: {
 | |
|       attrs: "(fill|stroke)"
 | |
|     }
 | |
|   }
 | |
| ]
 | |
| `;
 | |
| 
 | |
| /**
 | |
|  * Remove attributes
 | |
|  *
 | |
|  * @example elemSeparator
 | |
|  *   format: string
 | |
|  *
 | |
|  * @example preserveCurrentColor
 | |
|  *   format: boolean
 | |
|  *
 | |
|  * @example attrs:
 | |
|  *
 | |
|  *   format: [ element* : attribute* : value* ]
 | |
|  *
 | |
|  *   element   : regexp (wrapped into ^...$), single * or omitted > all elements (must be present when value is used)
 | |
|  *   attribute : regexp (wrapped into ^...$)
 | |
|  *   value     : regexp (wrapped into ^...$), single * or omitted > all values
 | |
|  *
 | |
|  *   examples:
 | |
|  *
 | |
|  *     > basic: remove fill attribute
 | |
|  *     ---
 | |
|  *     removeAttrs:
 | |
|  *       attrs: 'fill'
 | |
|  *
 | |
|  *     > remove fill attribute on path element
 | |
|  *     ---
 | |
|  *       attrs: 'path:fill'
 | |
|  *
 | |
|  *     > remove fill attribute on path element where value is none
 | |
|  *     ---
 | |
|  *       attrs: 'path:fill:none'
 | |
|  *
 | |
|  *
 | |
|  *     > 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)'
 | |
|  *
 | |
|  *     [is same as]
 | |
|  *
 | |
|  *       attrs: '.*:(fill|stroke):.*'
 | |
|  *
 | |
|  *
 | |
|  *     > remove all stroke related attributes
 | |
|  *     ----
 | |
|  *     attrs: 'stroke.*'
 | |
|  *
 | |
|  *
 | |
|  * @author Benny Schudel
 | |
|  *
 | |
|  * @type {import('../lib/types').Plugin<{
 | |
|  *   elemSeparator?: string,
 | |
|  *   preserveCurrentColor?: boolean,
 | |
|  *   attrs: string | Array<string>
 | |
|  * }>}
 | |
|  */
 | |
| exports.fn = (root, params) => {
 | |
|   if (typeof params.attrs == 'undefined') {
 | |
|     console.warn(ENOATTRS);
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   const elemSeparator =
 | |
|     typeof params.elemSeparator == 'string'
 | |
|       ? params.elemSeparator
 | |
|       : DEFAULT_SEPARATOR;
 | |
|   const preserveCurrentColor =
 | |
|     typeof params.preserveCurrentColor == 'boolean'
 | |
|       ? params.preserveCurrentColor
 | |
|       : false;
 | |
|   const attrs = Array.isArray(params.attrs) ? params.attrs : [params.attrs];
 | |
| 
 | |
|   return {
 | |
|     element: {
 | |
|       enter: (node) => {
 | |
|         for (let pattern of attrs) {
 | |
|           // if no element separators (:), assume it's attribute name, and apply to all elements *regardless of value*
 | |
|           if (pattern.includes(elemSeparator) === false) {
 | |
|             pattern = ['.*', elemSeparator, pattern, elemSeparator, '.*'].join(
 | |
|               ''
 | |
|             );
 | |
|             // if only 1 separator, assume it's element and attribute name, and apply regardless of attribute value
 | |
|           } else if (pattern.split(elemSeparator).length < 3) {
 | |
|             pattern = [pattern, elemSeparator, '.*'].join('');
 | |
|           }
 | |
| 
 | |
|           // create regexps for element, attribute name, and attribute value
 | |
|           const list = pattern.split(elemSeparator).map((value) => {
 | |
|             // adjust single * to match anything
 | |
|             if (value === '*') {
 | |
|               value = '.*';
 | |
|             }
 | |
|             return new RegExp(['^', value, '$'].join(''), 'i');
 | |
|           });
 | |
| 
 | |
|           // matches element
 | |
|           if (list[0].test(node.name)) {
 | |
|             // loop attributes
 | |
|             for (const [name, value] of Object.entries(node.attributes)) {
 | |
|               const isFillCurrentColor =
 | |
|                 preserveCurrentColor &&
 | |
|                 name == 'fill' &&
 | |
|                 value == 'currentColor';
 | |
|               const isStrokeCurrentColor =
 | |
|                 preserveCurrentColor &&
 | |
|                 name == 'stroke' &&
 | |
|                 value == 'currentColor';
 | |
|               if (
 | |
|                 !isFillCurrentColor &&
 | |
|                 !isStrokeCurrentColor &&
 | |
|                 // matches attribute name
 | |
|                 list[1].test(name) &&
 | |
|                 // matches attribute value
 | |
|                 list[2].test(value)
 | |
|               ) {
 | |
|                 delete node.attributes[name];
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       },
 | |
|     },
 | |
|   };
 | |
| };
 |