'use strict'; const core = require('@capsizecss/core'); function useDeclare(declaration, Declaration) { function declareOne([prop, value]) { declaration.after( new Declaration({ prop: prop.replace(/[A-Z]/g, (r) => `-${r.toLowerCase()}`), value }) ); } function declare(props) { Object.entries(props).forEach(declareOne); } return declare; } function useParentDeclare(parent, Declaration, Rule) { function declareOnParent([selector, props]) { parent.after( new Rule({ selector: parent.selector + selector, source: parent.source, nodes: Object.entries(props).map( ([prop, value]) => new Declaration({ prop: prop.replace(/[A-Z]/g, (r) => `-${r.toLowerCase()}`), value: String(value) }) ) }) ); } function declareAllOnParent(props) { Object.entries(props).forEach(declareOnParent); } return declareAllOnParent; } const plugin = (ctx) => { const { metrics = {} } = ctx || {}; const fontFamilies = Object.keys(metrics); const matcher = new RegExp( `^(?\\d+)px (?(${fontFamilies.join("|")})) (?\\d+)px$` ); function addCapsizedRules(fontConfig, source, helpers) { const { size, fontFamily, gap } = fontConfig; const { Declaration, Rule } = helpers; const declare = useDeclare(source, Declaration); const declareOnParent = useParentDeclare( source.parent, Declaration, Rule ); const values = core.createStyleObject({ fontMetrics: metrics[fontFamily], fontSize: Number(size), lineGap: Number(gap) }); declare({ lineHeight: values.lineHeight }); declareOnParent({ "::before": values["::before"], "::after": values["::after"] }); source.remove(); } return { postcssPlugin: "postcss-capsize", Declaration: { "font-metrics": (declaration, helpers) => { const { size, family: fontFamily, gap } = declaration.value.match(matcher)?.groups || {}; if (!size || !fontFamily || !gap) { throw new Error( "Correct syntax is `font-metrics: [font-size]px [font-family] [line-gap]px;" ); } const declare = useDeclare(declaration, helpers.Declaration); declare({ fontFamily, fontSize: `${size}px` }); addCapsizedRules({ size, fontFamily, gap }, declaration, helpers); }, "line-gap": (declaration, helpers) => { let fontFamily; let size; const gap = (declaration.value.match(/^(\d+)px$/) || [])[1]; declaration.parent?.walkDecls("font-family", (d) => { fontFamily = d.value.split(",").map((val) => val.trim().replace(/['"]/g, "")).find((val) => fontFamilies.includes(val)); }); declaration.parent?.walkDecls("font-size", (d) => { size = (d.value.match(/^(\d+)px$/) || [])[1]; }); addCapsizedRules({ size, fontFamily, gap }, declaration, helpers); } } }; }; plugin.postcss = true; module.exports = plugin;