UNPKG

@shopify/polaris-icons-audit

Version:

[![npm version](https://img.shields.io/npm/v/@shopify/polaris-icons-audit.svg?style=flat)](https://www.npmjs.com/package/@shopify/polaris-icons-audit)

90 lines (72 loc) 2.72 kB
const unified = require('unified'); const parse = require('rehype-parse'); const {select, selectAll} = require('hast-util-select'); function audit({filenames, contentPerFilename}) { const resultsPerFilename = filenames.reduce((memo, filename) => { const iconSource = contentPerFilename[filename]; const data = { iconSource, iconAst: unified() .use(parse, {fragment: true, space: 'svg'}) .parse(iconSource), }; const problematicResults = [ testHasNamespace(data), testHasExpectedViewbox(data), testHasExpectedFillColors(data), ].filter((result) => Boolean(result)); return Object.assign( memo, problematicResults.length ? {[filename]: problematicResults} : {}, ); }, {}); const resultsPerFilenameCount = Object.keys(resultsPerFilename).length; return { summary: `Found ${resultsPerFilenameCount} icon svgs with unexpected content`, status: resultsPerFilenameCount > 0 ? 'warn' : 'pass', info: Object.entries(resultsPerFilename) .map(([filename, results]) => { const count = results.length; const filesStr = results.map((result) => ` ${result}`).join('\n'); return ` ${filename} has ${count} issues:\n${filesStr}`; }) .join('\n'), }; } function testHasNamespace({iconAst}) { const xmlns = select(':root', iconAst).properties.xmlns; const isProblem = xmlns !== 'http://www.w3.org/2000/svg'; return isProblem ? `Has xmlns of "${xmlns}" on the <svg> element but expected "http://www.w3.org/2000/svg"` : ''; } function testHasExpectedViewbox({iconAst}) { const expectedViewboxes = ['0 0 20 20']; const viewBox = select(':root', iconAst).properties.viewBox; const isProblem = !expectedViewboxes.includes(viewBox); return isProblem ? `Has a viewbox of "${viewBox}" but expected "0 0 20 20"` : ''; } function testHasExpectedFillColors({iconAst, iconSource}) { const expectedFillColors = ['#5C5F62']; const nodesWithInvalidFill = selectAll('[fill]', iconAst).filter((node) => { return !expectedFillColors.includes(node.properties.fill); }); const nodeStrs = nodeSources(nodesWithInvalidFill, iconSource); const problems = nodeStrs.map((nodeStr) => ` ${nodeStr}`).join('\n'); return problems ? `Has elements that use a fill that is not "#5C5F62":\n${problems}` : ''; } function nodeSources(nodes, iconSource) { return nodes.map((node) => iconSource.substr( node.position.start.offset, node.position.end.offset - node.position.start.offset, ), ); } audit.auditName = 'icon-content'; audit.filter = (filename) => /(^|\/)icons\/.+\.svg$/.exec(filename); module.exports = audit;