UNPKG

postcss-styled-syntax

Version:

PostCSS syntax for template literals CSS-in-JS (e. g. styled-components).

96 lines (73 loc) 2.33 kB
let postcss = require('postcss'); let Parser = require('./parser'); const { parseJs } = require('./parseJs'); /** @typedef {import('./types.d.ts').NodeData} NodeData */ /** @type {import('postcss').Parser<import('postcss').Document>} */ module.exports = function parse(css, opts) { let inputCode = typeof css === 'string' ? css : css.toString(); let options = opts ?? {}; options.document = inputCode; let document = new postcss.Document({ source: { input: new postcss.Input(inputCode, options), start: { offset: 0, line: 1, column: 1 }, }, }); /** @type {NodeData[]} */ let foundNodes = parseJs(inputCode, opts); let components = foundNodes.filter((node) => isComponent(node, foundNodes)); let lastComponent = components[components.length - 1]; let previousComponentRangeEnd = 0; for (let node of foundNodes) { /** @type {postcss.Root} */ let parsedNode; let input = new postcss.Input(node.css, options); let interpolationsRanges = node.interpolationRanges.map((range) => { return { start: range.start - node.rangeStart, end: range.end - node.rangeStart - 1, }; }); let parser = new Parser(input, { interpolations: interpolationsRanges, isComponent: isComponent(node, foundNodes), raws: { originalContent: node.css, rangeStart: node.rangeStart, rangeEnd: node.rangeEnd, locationStart: node.locationStart, }, }); parser.parse(); // @ts-ignore -- Parser types are missing in PostCSS parsedNode = parser.root; if (isComponent(node, foundNodes)) { parsedNode.raws.codeBefore = inputCode.slice( previousComponentRangeEnd, node.rangeStart, ); previousComponentRangeEnd = node.rangeEnd; let isLastNode = node.rangeStart === lastComponent?.rangeStart; if (isLastNode) { parsedNode.raws.codeAfter = inputCode.slice(node.rangeEnd); } } document.append(parsedNode); } return document; }; /** * Check if it's a standalone component or interpolation within a component * * @param {NodeData} node * @param {NodeData[]} allNodes * @returns {boolean} */ function isComponent(node, allNodes) { let isSubNode = allNodes.some((item) => { return item.interpolationRanges.some((range) => { return range.start < node.rangeStart && node.rangeEnd < range.end; }); }); return !isSubNode; }