Skip to content
This repository was archived by the owner on Feb 18, 2022. It is now read-only.

Switching to postcss-value-parser #260

Merged
merged 5 commits into from
Dec 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"node": ">=12"
},
"dependencies": {
"postcss-values-parser": "^6"
"postcss-value-parser": "^4.2.0"
},
"peerDependencies": {
"postcss": "^8.3"
Expand Down
8 changes: 4 additions & 4 deletions src/lib/get-custom-properties-from-imports.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import fs from 'fs';
import path from 'path';
import { parse as postcssParse } from 'postcss';
import { parse } from 'postcss-values-parser';
import { parse } from 'postcss';
import valuesParser from 'postcss-value-parser';
import getCustomPropertiesFromRoot from './get-custom-properties-from-root';

/* Get Custom Properties from CSS File
/* ========================================================================== */

async function getCustomPropertiesFromCSSFile(from) {
const css = await readFile(from);
const root = postcssParse(css, { from });
const root = parse(css, { from });

return getCustomPropertiesFromRoot(root, { preserve: true });
}
Expand All @@ -25,7 +25,7 @@ function getCustomPropertiesFromObject(object) {
);

for (const key in customProperties) {
customProperties[key] = parse(String(customProperties[key])).nodes;
customProperties[key] = valuesParser(String(customProperties[key]));
}

return customProperties;
Expand Down
4 changes: 2 additions & 2 deletions src/lib/get-custom-properties-from-root.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { parse } from 'postcss-values-parser';
import valuesParser from 'postcss-value-parser';
import { isBlockIgnored } from './is-ignored';

// return custom selectors from the css root, conditionally removing them
Expand All @@ -22,7 +22,7 @@ export default function getCustomPropertiesFromRoot(root, opts) {
const { prop } = decl;

// write the parsed value to the custom property
customPropertiesObject[prop] = parse(decl.value).nodes;
customPropertiesObject[prop] = valuesParser(decl.value);

// conditionally remove the custom property declaration
if (!opts.preserve) {
Expand Down
10 changes: 5 additions & 5 deletions src/lib/transform-properties.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import { parse } from 'postcss-values-parser';
import valuesParser from 'postcss-value-parser';
import transformValueAST from './transform-value-ast';
import { isRuleIgnored } from './is-ignored';

// transform custom pseudo selectors with custom selectors
export default (decl, customProperties, opts) => {
if (isTransformableDecl(decl) && !isRuleIgnored(decl)) {
const originalValue = decl.value;
const valueAST = parse(originalValue);
let value = String(transformValueAST(valueAST, customProperties));
const valueAST = valuesParser(originalValue);
let value = transformValueAST(valueAST, customProperties);

// protect against circular references
const valueSet = new Set();

while (customPropertiesRegExp.test(value) && !valueSet.has(value)) {
valueSet.add(value);
const parsedValueAST = parse(valueAST);
value = String(transformValueAST(parsedValueAST, customProperties));
const parsedValueAST = valuesParser(value);
value = transformValueAST(parsedValueAST, customProperties);
}

// conditionally transform values that have changed
Expand Down
73 changes: 16 additions & 57 deletions src/lib/transform-value-ast.js
Original file line number Diff line number Diff line change
@@ -1,47 +1,37 @@
export default function transformValueAST(root, customProperties) {
if (root.nodes && root.nodes.length) {
root.nodes.slice().forEach(child => {
root.nodes.slice().forEach((child) => {
if (isVarFunction(child)) {
// eslint-disable-next-line no-unused-vars
const [propertyNode, comma, ...fallbacks] = child.nodes;
const [propertyNode, ...fallbacks] = child.nodes.filter((node) => node.type !== 'div');
const { value: name } = propertyNode;
const index = root.nodes.indexOf(child);

if (name in Object(customProperties)) {
// conditionally replace a known custom property
const nodes = asClonedArrayWithBeforeSpacing(customProperties[name], child.raws.before);

/**
* https://github.com/postcss/postcss-custom-properties/issues/221
* https://github.com/postcss/postcss-custom-properties/issues/218
*
* replaceWith loses node.raws values, so we need to save it and restore
*/
const raws = nodes.map(node => ({...node.raws}));

child.replaceWith(...nodes);

nodes.forEach((node, index) => {
node.raws = raws[index];
});
// Direct match of a custom property to a parsed value
const nodes = customProperties[name].nodes;

// Re-transform nested properties without given one to avoid circular from keeping this forever
retransformValueAST({ nodes }, customProperties, name);
} else if (fallbacks.length) {
// conditionally replace a custom property with a fallback
const index = root.nodes.indexOf(child);

if (index !== -1) {
root.nodes.splice(index, 1, ...asClonedArrayWithBeforeSpacing(fallbacks, child.raws.before));
if (index > -1) {
root.nodes.splice(index, 1, ...nodes);
}
} else if (fallbacks.length) {
// No match, but fallback available
if (index > -1) {
root.nodes.splice(index, 1, ...fallbacks);
}

transformValueAST(root, customProperties);
}
} else {
// Transform child nodes of current child
transformValueAST(child, customProperties);
}
});
}

return root;
return root.toString();
}

// retransform the current ast without a custom property (to prevent recursion)
Expand All @@ -57,35 +47,4 @@ function retransformValueAST(root, customProperties, withoutProperty) {
const varRegExp = /^var$/i;

// whether the node is a var() function
const isVarFunction = node => node.type === 'func' && varRegExp.test(node.name) && Object(node.nodes).length > 0;

// return an array with its nodes cloned, preserving the raw
const asClonedArrayWithBeforeSpacing = (array, beforeSpacing) => {
const clonedArray = asClonedArray(array, null);

if (clonedArray[0]) {
clonedArray[0].raws.before = beforeSpacing;
}

return clonedArray;
};

// return an array with its nodes cloned
const asClonedArray = (array, parent) => array.map(node => asClonedNode(node, parent));

// return a cloned node
const asClonedNode = (node, parent) => {
const cloneNode = new node.constructor(node);

for (const key in node) {
if (key === 'parent') {
cloneNode.parent = parent;
} else if (Object(node[key]).constructor === Array) {
cloneNode[key] = asClonedArray(node.nodes, cloneNode);
} else if (Object(node[key]).constructor === Object) {
cloneNode[key] = Object.assign({}, node[key]);
}
}

return cloneNode;
};
const isVarFunction = node => node.type === 'function' && varRegExp.test(node.value) && Object(node.nodes).length > 0;
4 changes: 1 addition & 3 deletions src/lib/write-custom-properties-to-exports.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,7 @@ export default function writeCustomPropertiesToExports(customProperties, destina
const defaultCustomPropertiesToJSON = customProperties => {
return Object.keys(customProperties).reduce((customPropertiesJSON, key) => {
const valueNodes = customProperties[key];
customPropertiesJSON[key] = valueNodes.map((propertyObject) => {
return propertyObject.toString();
}).join(' ');
customPropertiesJSON[key] = valueNodes.toString();

return customPropertiesJSON;
}, {});
Expand Down
2 changes: 1 addition & 1 deletion test/export-properties.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@
--margin: 0 10px 20px 30px;
--shadow-color: rgb(255,0,0);
--shadow: 0 6px 14px 0 color(var(--shadow-color) a(.15));
--font-family: "Open Sans" , sans-serif;
--font-family: "Open Sans", sans-serif;
--theme-color: #053;
}
2 changes: 1 addition & 1 deletion test/export-properties.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ module.exports = {
'--margin': '0 10px 20px 30px',
'--shadow-color': 'rgb(255,0,0)',
'--shadow': '0 6px 14px 0 color(var(--shadow-color) a(.15))',
'--font-family': '"Open Sans" , sans-serif',
'--font-family': '"Open Sans", sans-serif',
'--theme-color': '#053'
}
};
2 changes: 1 addition & 1 deletion test/export-properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"--margin": "0 10px 20px 30px",
"--shadow-color": "rgb(255,0,0)",
"--shadow": "0 6px 14px 0 color(var(--shadow-color) a(.15))",
"--font-family": "\"Open Sans\" , sans-serif",
"--font-family": "\"Open Sans\", sans-serif",
"--theme-color": "#053"
}
}
2 changes: 1 addition & 1 deletion test/export-properties.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ export const customProperties = {
'--margin': '0 10px 20px 30px',
'--shadow-color': 'rgb(255,0,0)',
'--shadow': '0 6px 14px 0 color(var(--shadow-color) a(.15))',
'--font-family': '"Open Sans" , sans-serif',
'--font-family': '"Open Sans", sans-serif',
'--theme-color': '#053'
};
2 changes: 1 addition & 1 deletion test/export-properties.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ $circular-2: var(--circular);
$margin: 0 10px 20px 30px;
$shadow-color: rgb(255,0,0);
$shadow: 0 6px 14px 0 color(var(--shadow-color) a(.15));
$font-family: "Open Sans" , sans-serif;
$font-family: "Open Sans", sans-serif;
$theme-color: #053;