import { collectStylesheet, computeStyle } from './style.js'; import { visit } from './xast.js'; import { parseSvg } from './parser.js'; /** * @param {import('./types.js').XastParent} node * @param {string} id * @returns {import('./types.js').XastElement} */ const getElementById = (node, id) => { /** @type {?import('./types.js').XastElement} */ let matched = null; visit(node, { element: { enter: (node) => { if (node.attributes.id === id) { matched = node; } }, }, }); if (matched == null) { throw Error('Assert node'); } return matched; }; it('collects styles', () => { const root = parseSvg(` `); const stylesheet = collectStylesheet(root); expect(computeStyle(stylesheet, getElementById(root, 'class'))).toStrictEqual( { fill: { type: 'static', inherited: false, value: 'red' }, }, ); expect( computeStyle(stylesheet, getElementById(root, 'two-classes')), ).toStrictEqual({ fill: { type: 'static', inherited: false, value: 'green' }, stroke: { type: 'static', inherited: false, value: 'black' }, }); expect( computeStyle(stylesheet, getElementById(root, 'attribute')), ).toStrictEqual({ fill: { type: 'static', inherited: false, value: 'purple' }, }); expect( computeStyle(stylesheet, getElementById(root, 'inline-style')), ).toStrictEqual({ fill: { type: 'static', inherited: false, value: 'grey' }, }); expect( computeStyle(stylesheet, getElementById(root, 'inheritance')), ).toStrictEqual({ fill: { type: 'static', inherited: true, value: 'yellow' }, }); expect( computeStyle(stylesheet, getElementById(root, 'nested-inheritance')), ).toStrictEqual({ fill: { type: 'static', inherited: true, value: 'blue' }, }); }); it('prioritizes different kinds of styles', () => { const root = parseSvg(` `); const stylesheet = collectStylesheet(root); expect( computeStyle(stylesheet, getElementById(root, 'complex-selector')), ).toStrictEqual({ fill: { type: 'static', inherited: false, value: 'red' }, }); expect( computeStyle(stylesheet, getElementById(root, 'override-selector')), ).toStrictEqual({ fill: { type: 'static', inherited: false, value: 'blue' }, }); expect( computeStyle( stylesheet, getElementById(root, 'attribute-over-inheritance'), ), ).toStrictEqual({ fill: { type: 'static', inherited: false, value: 'orange' }, }); expect( computeStyle(stylesheet, getElementById(root, 'style-rule-over-attribute')), ).toStrictEqual({ fill: { type: 'static', inherited: false, value: 'blue' }, }); expect( computeStyle( stylesheet, getElementById(root, 'inline-style-over-style-rule'), ), ).toStrictEqual({ fill: { type: 'static', inherited: false, value: 'purple' }, }); }); it('prioritizes important styles', () => { const root = parseSvg(` `); const stylesheet = collectStylesheet(root); expect( computeStyle(stylesheet, getElementById(root, 'complex-selector')), ).toStrictEqual({ fill: { type: 'static', inherited: false, value: 'green' }, }); expect( computeStyle( stylesheet, getElementById(root, 'style-rule-over-inline-style'), ), ).toStrictEqual({ fill: { type: 'static', inherited: false, value: 'green' }, }); expect( computeStyle( stylesheet, getElementById(root, 'inline-style-over-style-rule'), ), ).toStrictEqual({ fill: { type: 'static', inherited: false, value: 'purple' }, }); }); it('treats at-rules and pseudo-classes as dynamic styles', () => { const root = parseSvg(` `); const stylesheet = collectStylesheet(root); expect( computeStyle(stylesheet, getElementById(root, 'media-query')), ).toStrictEqual({ fill: { type: 'dynamic', inherited: false }, }); expect(computeStyle(stylesheet, getElementById(root, 'hover'))).toStrictEqual( { fill: { type: 'dynamic', inherited: false }, }, ); expect( computeStyle(stylesheet, getElementById(root, 'inherited')), ).toStrictEqual({ fill: { type: 'dynamic', inherited: true }, }); expect( computeStyle(stylesheet, getElementById(root, 'inherited-overridden')), ).toStrictEqual({ fill: { type: 'static', inherited: false, value: 'blue' }, }); expect( computeStyle(stylesheet, getElementById(root, 'static')), ).toStrictEqual({ fill: { type: 'static', inherited: false, value: 'black' }, }); }); it('considers `); const stylesheet = collectStylesheet(root); expect( computeStyle(stylesheet, getElementById(root, 'media-query')), ).toStrictEqual({ fill: { type: 'dynamic', inherited: false }, }); expect( computeStyle(stylesheet, getElementById(root, 'kinda-static')), ).toStrictEqual({ fill: { type: 'dynamic', inherited: false }, }); expect( computeStyle(stylesheet, getElementById(root, 'static')), ).toStrictEqual({ fill: { type: 'static', inherited: false, value: 'blue' }, }); }); it('ignores `); const stylesheet = collectStylesheet(root); expect( computeStyle(stylesheet, getElementById(root, 'valid-type')), ).toStrictEqual({ fill: { type: 'static', inherited: false, value: 'red' }, }); expect( computeStyle(stylesheet, getElementById(root, 'empty-type')), ).toStrictEqual({ fill: { type: 'static', inherited: false, value: 'green' }, }); expect( computeStyle(stylesheet, getElementById(root, 'invalid-type')), ).toStrictEqual({}); }); it('ignores keyframes atrule', () => { const root = parseSvg(` `); const stylesheet = collectStylesheet(root); expect( computeStyle(stylesheet, getElementById(root, 'element')), ).toStrictEqual({ animation: { type: 'static', inherited: false, value: 'loading 4s linear infinite', }, }); }); it('ignores @-webkit-keyframes atrule', () => { const root = parseSvg(` `); const stylesheet = collectStylesheet(root); expect( computeStyle(stylesheet, getElementById(root, 'element')), ).toStrictEqual({ animation: { type: 'static', inherited: false, value: 'loading 4s linear infinite', }, }); }); it('ignores @-moz-keyframes atrule', () => { const root = parseSvg(` `); const stylesheet = collectStylesheet(root); expect( computeStyle(stylesheet, getElementById(root, 'element')), ).toStrictEqual({ animation: { type: 'static', inherited: false, value: 'loading 4s linear infinite', }, }); }); it('ignores @-o-keyframes atrule', () => { const root = parseSvg(` `); const stylesheet = collectStylesheet(root); expect( computeStyle(stylesheet, getElementById(root, 'element')), ).toStrictEqual({ animation: { type: 'static', inherited: false, value: 'loading 4s linear infinite', }, }); });