New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@cssfn/cssfn

Package Overview
Dependencies
Maintainers
1
Versions
58
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@cssfn/cssfn - npm Package Compare versions

Comparing version 2.0.32 to 2.0.33

87

dist/cssfn-decoders.js

@@ -1,53 +0,64 @@

const decodeRuleData = (ruleData) => {
const [selector, styles] = ruleData;
return [
selector,
decodeStyles(styles)
];
};
const decodeNestedRule = (ruleData) => {
return [
Symbol(),
decodeRuleData(ruleData)
];
};
export const decodeStyle = (style) => {
if (!style || (style === true))
return undefined; // falsy style => ignore
const ruleDatas = style['']; // an empty string key is a special property for storing (nested) rules
const decodedStyle = style; // no need to clone to improve performance
if (ruleDatas && ruleDatas.length) {
// delete style['']; // expensive op! causing chrome's to re-create hidden class
style[''] = undefined; // assigning to undefined instead of deleting, to improve performance
const nestedRules = (ruleDatas
.map(decodeNestedRule));
Object.assign(decodedStyle, Object.fromEntries(nestedRules));
return undefined; // ignore : falsy style
const nestedRules = style['']; // an empty string key is a special property for storing (nested) rules
if (nestedRules /* ignore null|undefined marker */ && nestedRules.length) {
delete style['']; // expensive op! causing chrome's to re-create hidden class
for (let index = 0, max = nestedRules.length, encodedRuleData; index < max; index++) {
encodedRuleData = nestedRules[index];
const decodedStyles = decodeStyles(// mutate : EncodedCssStyleCollection => CssStyleCollection
encodedRuleData[1] // type : EncodedCssStyleCollection
);
if (!decodedStyles || (decodedStyles === true)) {
nestedRules[index] = undefined; // mutate : falsy style => undefined (delete)
}
else {
encodedRuleData[1] = [
encodedRuleData[0],
decodedStyles // type : CssStyleCollection
];
encodedRuleData[0] = Symbol(); // mutate : undefined|CssRawSelector|CssFinalSelector => new symbol
} // if
} // for
// cleanup blank entries:
for (let index = nestedRules.length - 1; index >= 0; index--) {
if (!nestedRules[index])
nestedRules.splice(index, 1);
} // for
// expensive op! causing chrome's to re-create hidden class:
Object.assign(style, Object.fromEntries(nestedRules));
} // if
return decodedStyle;
return style;
};
function unwrapStyles(styles, result) {
for (const style of styles) {
if (!style || (style === true))
continue; // falsy style(s) => ignore
const unwrapStyles = (styles) => {
for (let index = 0, max = styles.length, style; index < max; index++) {
style = styles[index];
// handle falsy item:
if (!style || (style === true)) {
styles[index] = undefined; // mutate : falsy style => undefined (delete)
continue; // handled => continue to next loop
} // if
// handle single item:
if (!Array.isArray(style)) {
const decodedStyle = decodeStyle(style);
if (!decodedStyle || (decodedStyle === true))
continue; // falsy style(s) => ignore
result.push(decodedStyle);
continue;
const decodedStyle = decodeStyle(style); // mutate : EncodedCssStyle => CssStyle
if (!decodedStyle || (decodedStyle === true)) {
styles[index] = undefined; // mutate : falsy style => undefined (delete)
}
else {
styles[index] = decodedStyle; // mutate : EncodedCssStyle => CssStyle
} // if
continue; // handled => continue to next loop
} // if
// handle multi item(s):
unwrapStyles(style, result);
unwrapStyles(style); // mutate : EncodedCssStyle(s) => CssStyle(s)
} // for
}
};
export const decodeStyles = (styles) => {
// statically handle single item:
if (!Array.isArray(styles)) {
return decodeStyle(styles);
return decodeStyle(styles); // mutate : EncodedCssStyle => CssStyle
} // if
// dynamically handle multi item(s):
const result = [];
unwrapStyles(styles, result);
return result;
unwrapStyles(styles); // mutate : EncodedCssStyle(s) => CssStyle(s)
return styles;
};
import type { OptionalOrBoolean, ProductOrFactory } from '@cssfn/types';
import type { CssStyle, CssStyleCollection } from '@cssfn/css-types';
import type { EncodedCssRuleData, EncodedCssStyle, EncodedCssStyleCollection } from './cssfn-encoded-types.js';
export declare function encodeNestedRule(this: CssStyle, symbolProp: symbol): EncodedCssRuleData;
import type { EncodedCssStyle, EncodedCssStyleCollection } from './cssfn-encoded-types.js';
export declare const encodeStyle: (style: ProductOrFactory<OptionalOrBoolean<CssStyle>>) => OptionalOrBoolean<EncodedCssStyle>;
export declare const encodeStyles: (styles: CssStyleCollection) => EncodedCssStyleCollection;
const isTransferablePrimitive = (propValue) => {
if (propValue === undefined)
return true; // undefined => *transferable*
if (propValue === null)
return true; // null => *transferable*
return true; // null object => *transferable* // the only object that transferable
switch (typeof (propValue)) {
case 'string': // string => *transferable*
case 'number': // number => *transferable*
return true;
case 'object': // any object => *NON-transferable*
case 'symbol': // primitive symbol => *NON-transferable* // the only primitive that NON-transferable
return false;
default:
return true; // any primitive => *transferable*
} // switch
return false; // unknown => assumes as *NON-transferable*
};
const isTransferableDeepArray = (propValue) => {
for (const propSubValue of propValue) {
if (Array.isArray(propSubValue)) {
if (!isTransferableDeepArray(propSubValue))
return false;
}
else {
if (!isTransferablePrimitive(propSubValue))
return false;
} // if
} // for
return true; // all subValues are passed -or- empty array
};
const isTransferableProp = (propValue) => {
if (isTransferablePrimitive(propValue))
return true;
if (Array.isArray(propValue))
return isTransferableDeepArray(propValue);
return false; // CssCustomKeyframesRef => *NON-transferable* => false
};
const encodePropSimpleValue = (propValue) => {
if (isTransferablePrimitive(propValue))
return propValue;
return propValue.toString(); // CssCustomKeyframesRef => *NON-transferable* => make *transferable* => .toString()
};
const encodePropSubValue = (propSubValue) => {
if (!Array.isArray(propSubValue))
return encodePropSimpleValue(propSubValue);
if (propSubValue.every(isTransferablePrimitive))
return propSubValue; // all items in the array are *transferable* -or- empty array => no need to mutate
// some item(s) in the array is/are *NON-transferable* => NEED to mutate the array with *encoded* value(s):
return (propSubValue
.map(encodePropSimpleValue) // expensive op!
);
};
const encodeRuleData = (ruleData) => {
// SLOW:
// const [selector, styles] = ruleData;
// return [
// selector,
// encodeStyles(styles) // expensive op!
// ];
// FASTER:
return [
ruleData[0],
encodeStyles(ruleData[1]) // expensive op!
];
};
export function encodeNestedRule(symbolProp) {
return encodeRuleData(this[symbolProp]); // expensive op!
}
export const encodeStyle = (style) => {
if (!style || (style === true))
return undefined; // falsy style => ignore
return undefined; // ignore : falsy style
const styleValue = (typeof (style) === 'function') ? style() : style;
if (!styleValue || (styleValue === true))
return undefined; // falsy style => ignore
// SLOW:
// const encodedStyle = Object.fromEntries(
// Object.entries(styleValue) // take all string keys (excluding symbol keys)
// .map(encodeProp) // expensive op!
// ) as EncodedCssProps as EncodedCssStyle;
// FASTER:
const encodedStyle = styleValue; // hack: re-use the style object as encoded object; the symbol keys will be ignored when transfering
return undefined; // ignore : falsy style
// an empty string key is a special property for storing (nested) rules
// if exists => assumes as already encoded:
if (encodedStyle[''] !== undefined)
return encodedStyle;
for (const propName in encodedStyle) { // iterates string keys, ignoring symbol keys
const propValue = encodedStyle[propName];
if (isTransferableProp(propValue))
continue; // ignore *transferable* prop, no need to mutate
// *NON-transferable* => NEED to mutate the array with *encoded* value(s):
encodedStyle[propName] = (Array.isArray(propValue)
?
// some item(s) in the array is/are *NON-transferable* => NEED to mutate the array with *encoded* value(s):
propValue.map(encodePropSubValue) // expensive op!
:
propValue.toString() // CssCustomKeyframesRef => *NON-transferable* => make *transferable* => .toString()
);
if (styleValue[''] !== undefined)
return styleValue;
for (const propName in styleValue) { // iterates string keys, ignoring symbol keys
const propValue = styleValue[propName];
if (!Array.isArray(propValue)) {
if (isTransferablePrimitive(propValue))
continue; // ignore : *transferable* propValue
styleValue[propName] = propValue.toString(); // mutate : CssCustomKeyframesRef => .toString()
}
else {
for (let subIndex = 0, subMax = propValue.length, propSubValue; subIndex < subMax; subIndex++) {
propSubValue = propValue[subIndex];
if (!Array.isArray(propSubValue)) {
if (isTransferablePrimitive(propSubValue))
continue; // ignore : *transferable* propSubValue
propValue[subIndex] = propSubValue.toString(); // mutate : CssCustomKeyframesRef => .toString()
}
else {
for (let subSubIndex = 0, subSubMax = propSubValue.length, propSubSubValue; subSubIndex < subSubMax; subSubIndex++) {
propSubSubValue = propSubValue[subSubIndex];
if (isTransferablePrimitive(propSubSubValue))
continue; // ignore : *transferable* propSubSubValue
propSubValue[subSubIndex] = propSubSubValue.toString(); // mutate : CssCustomKeyframesRef => .toString()
} // for
} // if
} // for
} // if
} // for
const symbolProps = Object.getOwnPropertySymbols(styleValue); // take all symbol keys
if (symbolProps.length) {
const nestedRules = (symbolProps
.map(encodeNestedRule.bind(styleValue)) // expensive op!
);
const nestedRules = Object.getOwnPropertySymbols(styleValue); // take all symbol keys
if (nestedRules.length) {
for (let index = 0, max = nestedRules.length, ruleData; index < max; index++) {
ruleData = styleValue[nestedRules[index]];
const encodedStyles = encodeStyles(// mutate : CssStyleCollection => EncodedCssStyleCollection
ruleData[1] // type : CssStyleCollection
);
if (!encodedStyles || (encodedStyles === true)) {
nestedRules[index] = undefined; // mutate : falsy style => undefined (delete)
}
else {
ruleData[1] = encodedStyles; // mutate : CssStyleCollection => EncodedCssStyleCollection
// ruleData[0] = ruleData[0]; // unchanged : undefined|CssRawSelector|CssFinalSelector
nestedRules[index] = ruleData; // mutate : symbol => EncodedCssRuleData
} // if
} // for
// mark as already converted & store the nestedRules:
// expensive op! causing chrome's to re-create hidden class:
encodedStyle[''] = nestedRules; // an empty string key is a special property for storing (nested) rules
styleValue[''] = nestedRules; // an empty string key is a special property for storing (nested) rules
}
else {
// mark as already converted:
// expensive op! causing chrome's to re-create hidden class:
styleValue[''] = null; // an empty string key is a special property for storing (nested) rules
} // if
return encodedStyle;
return styleValue;
};
function unwrapStyles(styles, result) {
for (const style of styles) {
if (!style || (style === true))
continue; // falsy style(s) => ignore
const unwrapStyles = (styles) => {
for (let index = 0, max = styles.length, style; index < max; index++) {
style = styles[index];
// handle falsy item:
if (!style || (style === true)) {
styles[index] = undefined; // mutate : falsy style => undefined (delete)
continue; // handled => continue to next loop
} // if
// handle single item:
if (!Array.isArray(style)) {
const encodedStyle = encodeStyle(style); // expensive op!
if (!encodedStyle || (encodedStyle === true))
continue; // falsy style(s) => ignore
result.push(encodedStyle);
continue;
const encodedStyle = encodeStyle(style); // mutate : CssStyle => EncodedCssStyle
if (!encodedStyle || (encodedStyle === true)) {
styles[index] = undefined; // mutate : falsy style => undefined (delete)
}
else {
styles[index] = encodedStyle; // mutate : CssStyle => EncodedCssStyle
} // if
continue; // handled => continue to next loop
} // if
// handle multi item(s):
unwrapStyles(style, result); // expensive op!
unwrapStyles(style); // mutate : CssStyle(s) => EncodedCssStyle(s)
} // for
}
};
export const encodeStyles = (styles) => {
// statically handle single item:
if (!Array.isArray(styles)) {
return encodeStyle(styles); // expensive op!
return encodeStyle(styles); // mutate : CssStyle => EncodedCssStyle
} // if
// dynamically handle multi item(s):
const result = [];
unwrapStyles(styles, result); // expensive op!
return result;
unwrapStyles(styles); // mutate : CssStyle(s) => EncodedCssStyle(s)
return styles;
};
import type { CssCustomValue } from '@cssfn/css-types';
export declare const renderValue: (value: CssCustomValue) => string;
export declare const renderValue: (propValue: CssCustomValue) => string;
// processors:
const renderSimpleValue = (value) => {
if (typeof (value) === 'number')
return `${value}`; // CssSimpleNumericValue => number => string
if (typeof (value) === 'string')
return value; // CssSimpleLiteralValue|CssCustomRef => string
return value.toString(); // CssCustomKeyframesRef => .toString()
const renderSimpleValue = (propValue) => {
switch (typeof (propValue)) {
case 'string': return propValue; // CssSimpleLiteralValue|CssCustomRef => string
case 'number': return '' + propValue; // CssSimpleNumericValue => number => string
default: return propValue.toString(); // CssCustomKeyframesRef => .toString()
} // switch
};
const reducedRenderSubValues = { hasImportant: false, rendered: [] };
const reduceRenderSubValues = (accum, subValue, index, array) => {
if (!Array.isArray(subValue)) {
if (typeof (subValue) === 'number') {
accum.rendered.push(`${subValue}` // CssSimpleNumericValue => number => string
);
}
else if ((index === (array.length - 1)) && (subValue === '!important')) {
accum.hasImportant = true;
}
else if (typeof (subValue) === 'string') {
accum.rendered.push(subValue // CssSimpleLiteralValue|CssCustomRef => string
);
}
else {
accum.rendered.push(subValue.toString() // CssCustomKeyframesRef => .toString()
);
} // if
export const renderValue = (propValue) => {
if (!Array.isArray(propValue)) {
return renderSimpleValue(propValue);
}
else {
accum.rendered.push(subValue
.map(renderSimpleValue)
.join(' ') // [[double array]] => join separated with [space]
);
let hasImportant = false;
let result = ''; // for a small array : a string concatenation is faster than array.join('')
for (let subIndex = 0, subMax = propValue.length, propSubValue; subIndex < subMax; subIndex++) {
propSubValue = propValue[subIndex];
if (!Array.isArray(propSubValue)) {
if ((subIndex >= 1) && (subIndex === (subMax - 1)) && (propSubValue === '!important')) {
hasImportant = true;
}
else {
if (subIndex >= 1)
result += ', '; // comma separated values
result += renderSimpleValue(propSubValue);
} // if
}
else {
for (let subSubIndex = 0, subSubMax = propSubValue.length, propSubSubValue; subSubIndex < subSubMax; subSubIndex++) {
propSubSubValue = propSubValue[subSubIndex];
if ((subSubIndex >= 1) && (subSubIndex === (subSubMax - 1)) && (propSubSubValue === '!important')) {
hasImportant = true;
}
else {
if ((subIndex >= 1) && (subSubIndex === 0))
result += ', '; // comma separated values
if (subSubIndex >= 1)
result += ' '; // space separated values
result += renderSimpleValue(propSubSubValue);
} // if
} // for
} // if
} // for
if (hasImportant)
result += ' !important';
return result;
} // if
return accum;
};
export const renderValue = (value) => {
if (!Array.isArray(value))
return renderSimpleValue(value); // CssComplexBaseValueOf<CssSimpleValue>
try {
value.reduce(reduceRenderSubValues, reducedRenderSubValues);
return (reducedRenderSubValues.rendered
.join(', ') // comma_separated_values
+
(reducedRenderSubValues.hasImportant ? ' !important' : ''));
}
finally {
// reset the accumulator to be used later:
reducedRenderSubValues.hasImportant = false;
reducedRenderSubValues.rendered.splice(0);
} // try
};
{
"name": "@cssfn/cssfn",
"version": "2.0.32",
"version": "2.0.33",
"description": "Writes, imports, and exports css stylesheets as javascript modules.",

@@ -33,3 +33,3 @@ "keywords": [

"@cssfn/css-prop-auto-prefix": "^2.0.2",
"@cssfn/css-selectors": "^2.0.9",
"@cssfn/css-selectors": "^2.0.10",
"@cssfn/css-types": "^2.0.7",

@@ -51,3 +51,3 @@ "@cssfn/types": "^2.0.1",

},
"gitHead": "cb9755c614f545159f304f7db3753478955de44d"
"gitHead": "7848ea5c0049e71d98ad03325a18f2569e5e1056"
}

@@ -23,38 +23,50 @@ // cssfn:

const decodeRuleData = (ruleData: EncodedCssRuleData): CssRuleData => {
const [selector, styles] = ruleData;
return [
selector,
decodeStyles(styles)
];
}
const decodeNestedRule = (ruleData: EncodedCssRuleData): readonly [symbol, CssRuleData] => {
return [
Symbol(),
decodeRuleData(ruleData)
];
}
export const decodeStyle = (style: OptionalOrBoolean<EncodedCssStyle>): OptionalOrBoolean<CssStyle> => {
if (!style || (style === true)) return undefined; // falsy style => ignore
if (!style || (style === true)) return undefined; // ignore : falsy style
const ruleDatas = style['']; // an empty string key is a special property for storing (nested) rules
const decodedStyle = style as CssStyle; // no need to clone to improve performance
if (ruleDatas && ruleDatas.length) {
// delete style['']; // expensive op! causing chrome's to re-create hidden class
style[''] = undefined; // assigning to undefined instead of deleting, to improve performance
type CssRuleEntry = readonly [symbol, CssRuleData];
const nestedRules : (EncodedCssRuleData|CssRuleEntry|undefined)[]|null|undefined = style['']; // an empty string key is a special property for storing (nested) rules
if (nestedRules /* ignore null|undefined marker */ && nestedRules.length) {
delete style['']; // expensive op! causing chrome's to re-create hidden class
const nestedRules = (
ruleDatas
.map(decodeNestedRule)
);
type MutableEncodedCssRuleData = [...EncodedCssRuleData]|[...CssRuleEntry];
for (let index = 0, max = nestedRules.length, encodedRuleData: MutableEncodedCssRuleData; index < max; index++) {
encodedRuleData = nestedRules[index] as MutableEncodedCssRuleData;
const decodedStyles = decodeStyles( // mutate : EncodedCssStyleCollection => CssStyleCollection
(encodedRuleData as EncodedCssRuleData)[1] // type : EncodedCssStyleCollection
);
if (!decodedStyles || (decodedStyles === true)) {
nestedRules[index] = undefined; // mutate : falsy style => undefined (delete)
}
else {
encodedRuleData[1] = [ // mutate : EncodedCssStyleCollection => CssRuleData
(encodedRuleData as EncodedCssRuleData)[0], // type : undefined|CssRawSelector|CssFinalSelector
decodedStyles // type : CssStyleCollection
] as CssRuleData;
encodedRuleData[0] = Symbol(); // mutate : undefined|CssRawSelector|CssFinalSelector => new symbol
} // if
} // for
// cleanup blank entries:
for (let index = nestedRules.length - 1; index >= 0; index--) {
if (!nestedRules[index]) nestedRules.splice(index, 1);
} // for
// expensive op! causing chrome's to re-create hidden class:
Object.assign(
decodedStyle,
Object.fromEntries(nestedRules)
style,
Object.fromEntries(
nestedRules as CssRuleEntry[]
)
);

@@ -65,16 +77,34 @@ } // if

return decodedStyle;
return style as CssStyle;
}
function unwrapStyles(styles: Extract<EncodedCssStyleCollection, any[]>, result: CssStyle[]): void {
for (const style of styles) {
if (!style || (style === true)) continue; // falsy style(s) => ignore
const unwrapStyles = (styles: Extract<EncodedCssStyleCollection, any[]>): void => {
for (let index = 0, max = styles.length, style : typeof styles[number]; index < max; index++) {
style = styles[index];
// handle falsy item:
if (!style || (style === true)) {
styles[index] = undefined; // mutate : falsy style => undefined (delete)
continue; // handled => continue to next loop
} // if
// handle single item:
if (!Array.isArray(style)) {
const decodedStyle = decodeStyle(style);
if (!decodedStyle || (decodedStyle === true)) continue; // falsy style(s) => ignore
result.push(decodedStyle);
continue;
const decodedStyle = decodeStyle(style); // mutate : EncodedCssStyle => CssStyle
if (!decodedStyle || (decodedStyle === true)) {
styles[index] = undefined; // mutate : falsy style => undefined (delete)
}
else {
styles[index] = decodedStyle as CssStyle as any; // mutate : EncodedCssStyle => CssStyle
} // if
continue; // handled => continue to next loop
} // if

@@ -85,3 +115,3 @@

// handle multi item(s):
unwrapStyles(style, result);
unwrapStyles(style); // mutate : EncodedCssStyle(s) => CssStyle(s)
} // for

@@ -92,3 +122,3 @@ }

if (!Array.isArray(styles)) {
return decodeStyle(styles);
return decodeStyle(styles); // mutate : EncodedCssStyle => CssStyle
} // if

@@ -99,5 +129,4 @@

// dynamically handle multi item(s):
const result: CssStyle[] = [];
unwrapStyles(styles, result);
return result;
unwrapStyles(styles); // mutate : EncodedCssStyle(s) => CssStyle(s)
return styles as CssStyle[];
}

@@ -5,13 +5,5 @@ // cssfn:

DeepArray,
ProductOrFactory,
} from '@cssfn/types'
import type {
// css values:
CssSimpleValue,
CssComplexBaseValueOf,
// css custom properties:

@@ -33,14 +25,3 @@ CssCustomValue,

import type {
// css values:
EncodedCssSimpleValue,
// css custom properties:
EncodedCssCustomValue,
// cssfn properties:
// EncodedCssProps,
EncodedCssRuleData,

@@ -55,3 +36,2 @@ EncodedCssStyle,

type TransferablePrimitive = undefined|null|string|number
type TransferableDeepArray = DeepArray<TransferablePrimitive>

@@ -61,115 +41,65 @@

const isTransferablePrimitive = <TPropValue extends CssCustomValue|undefined|null>(propValue : TPropValue): propValue is (TPropValue & TransferablePrimitive) => {
if (propValue === undefined) return true; // undefined => *transferable*
if (propValue === null ) return true; // null => *transferable*
if (propValue === null) return true; // null object => *transferable* // the only object that transferable
switch (typeof(propValue)) {
case 'string': // string => *transferable*
case 'number': // number => *transferable*
return true;
case 'object': // any object => *NON-transferable*
case 'symbol': // primitive symbol => *NON-transferable* // the only primitive that NON-transferable
return false;
default:
return true; // any primitive => *transferable*
} // switch
return false; // unknown => assumes as *NON-transferable*
}
const isTransferableDeepArray = <TPropValue extends Extract<CssCustomValue, any[]>>(propValue : TPropValue): propValue is (TPropValue & TransferableDeepArray) => {
for (const propSubValue of propValue) {
if (Array.isArray(propSubValue)) {
if (!isTransferableDeepArray(propSubValue)) return false;
}
else {
if (!isTransferablePrimitive(propSubValue)) return false;
} // if
} // for
return true; // all subValues are passed -or- empty array
}
const isTransferableProp = <TPropValue extends CssCustomValue|undefined|null>(propValue : TPropValue): propValue is ((TPropValue & TransferablePrimitive) | (TPropValue & TransferableDeepArray)) => {
if (isTransferablePrimitive(propValue)) return true;
if (Array.isArray(propValue)) return isTransferableDeepArray(propValue);
return false; // CssCustomKeyframesRef => *NON-transferable* => false
}
const encodePropSimpleValue = (propValue: CssComplexBaseValueOf<CssSimpleValue>): CssComplexBaseValueOf<EncodedCssSimpleValue> => {
if (isTransferablePrimitive(propValue)) return propValue;
return propValue.toString(); // CssCustomKeyframesRef => *NON-transferable* => make *transferable* => .toString()
}
const encodePropSubValue = (propSubValue: Extract<CssCustomValue, any[]>[number]): Extract<EncodedCssCustomValue, any[]>[number] => {
if (!Array.isArray(propSubValue)) return encodePropSimpleValue(propSubValue);
if (propSubValue.every(isTransferablePrimitive)) return propSubValue; // all items in the array are *transferable* -or- empty array => no need to mutate
// some item(s) in the array is/are *NON-transferable* => NEED to mutate the array with *encoded* value(s):
return (
propSubValue
.map(encodePropSimpleValue) // expensive op!
);
}
const encodeRuleData = (ruleData: CssRuleData): EncodedCssRuleData => {
// SLOW:
// const [selector, styles] = ruleData;
// return [
// selector,
// encodeStyles(styles) // expensive op!
// ];
// FASTER:
return [
ruleData[0],
encodeStyles(ruleData[1]) // expensive op!
];
}
export function encodeNestedRule(this: CssStyle, symbolProp: symbol): EncodedCssRuleData {
return encodeRuleData(this[symbolProp]); // expensive op!
}
export const encodeStyle = (style: ProductOrFactory<OptionalOrBoolean<CssStyle>>): OptionalOrBoolean<EncodedCssStyle> => {
if (!style || (style === true)) return undefined; // falsy style => ignore
if (!style || (style === true)) return undefined; // ignore : falsy style
const styleValue = (typeof(style) === 'function') ? style() : style;
if (!styleValue || (styleValue === true)) return undefined; // falsy style => ignore
if (!styleValue || (styleValue === true)) return undefined; // ignore : falsy style
// SLOW:
// const encodedStyle = Object.fromEntries(
// Object.entries(styleValue) // take all string keys (excluding symbol keys)
// .map(encodeProp) // expensive op!
// ) as EncodedCssProps as EncodedCssStyle;
// FASTER:
const encodedStyle = styleValue; // hack: re-use the style object as encoded object; the symbol keys will be ignored when transfering
// an empty string key is a special property for storing (nested) rules
// if exists => assumes as already encoded:
if (encodedStyle['' as any] !== undefined) return encodedStyle as EncodedCssStyle;
if (styleValue['' as any] !== undefined) return styleValue as EncodedCssStyle;
for (const propName in encodedStyle) { // iterates string keys, ignoring symbol keys
const propValue : CssCustomValue|undefined|null = encodedStyle[propName as keyof CssProps];
for (const propName in styleValue) { // iterates string keys, ignoring symbol keys
const propValue : CssCustomValue|undefined|null = styleValue[propName as keyof CssProps];
if (isTransferableProp(propValue)) continue; // ignore *transferable* prop, no need to mutate
// *NON-transferable* => NEED to mutate the array with *encoded* value(s):
encodedStyle[propName as any] = (
Array.isArray(propValue)
?
// some item(s) in the array is/are *NON-transferable* => NEED to mutate the array with *encoded* value(s):
(propValue.map(encodePropSubValue) as any) // expensive op!
:
(propValue.toString() as any) // CssCustomKeyframesRef => *NON-transferable* => make *transferable* => .toString()
);
if (!Array.isArray(propValue)) {
if (isTransferablePrimitive(propValue)) continue; // ignore : *transferable* propValue
styleValue[propName as any] = propValue.toString() as any; // mutate : CssCustomKeyframesRef => .toString()
}
else {
for (let subIndex = 0, subMax = propValue.length, propSubValue : typeof propValue[number]; subIndex < subMax; subIndex++) {
propSubValue = propValue[subIndex];
if (!Array.isArray(propSubValue)) {
if (isTransferablePrimitive(propSubValue)) continue; // ignore : *transferable* propSubValue
propValue[subIndex] = propSubValue.toString(); // mutate : CssCustomKeyframesRef => .toString()
}
else {
for (let subSubIndex = 0, subSubMax = propSubValue.length, propSubSubValue : typeof propSubValue[number]; subSubIndex < subSubMax; subSubIndex++) {
propSubSubValue = propSubValue[subSubIndex];
if (isTransferablePrimitive(propSubSubValue)) continue; // ignore : *transferable* propSubSubValue
propSubValue[subSubIndex] = propSubSubValue.toString(); // mutate : CssCustomKeyframesRef => .toString()
} // for
} // if
} // for
} // if
} // for

@@ -179,13 +109,36 @@

const symbolProps = Object.getOwnPropertySymbols(styleValue); // take all symbol keys
if (symbolProps.length) {
const nestedRules = (
symbolProps
.map(encodeNestedRule.bind(styleValue)) // expensive op!
);
const nestedRules : (symbol|EncodedCssRuleData|undefined)[] = Object.getOwnPropertySymbols(styleValue); // take all symbol keys
if (nestedRules.length) {
type MutableCssRuleData = [...CssRuleData]|[...EncodedCssRuleData];
for (let index = 0, max = nestedRules.length, ruleData: MutableCssRuleData; index < max; index++) {
ruleData = styleValue[nestedRules[index] as symbol] as MutableCssRuleData;
const encodedStyles = encodeStyles( // mutate : CssStyleCollection => EncodedCssStyleCollection
(ruleData as CssRuleData)[1] // type : CssStyleCollection
);
if (!encodedStyles || (encodedStyles === true)) {
nestedRules[index] = undefined; // mutate : falsy style => undefined (delete)
}
else {
ruleData[1] = encodedStyles; // mutate : CssStyleCollection => EncodedCssStyleCollection
// ruleData[0] = ruleData[0]; // unchanged : undefined|CssRawSelector|CssFinalSelector
nestedRules[index] = ruleData as EncodedCssRuleData; // mutate : symbol => EncodedCssRuleData
} // if
} // for
// mark as already converted & store the nestedRules:
// expensive op! causing chrome's to re-create hidden class:
encodedStyle['' as any] = nestedRules as any; // an empty string key is a special property for storing (nested) rules
styleValue['' as any] = nestedRules as any; // an empty string key is a special property for storing (nested) rules
}
else {
// mark as already converted:
// expensive op! causing chrome's to re-create hidden class:
styleValue['' as any] = null as any; // an empty string key is a special property for storing (nested) rules
} // if

@@ -195,16 +148,34 @@

return encodedStyle as EncodedCssStyle;
return styleValue as EncodedCssStyle;
}
function unwrapStyles(styles: Extract<CssStyleCollection, any[]>, result: EncodedCssStyle[]): void {
for (const style of styles) {
if (!style || (style === true)) continue; // falsy style(s) => ignore
const unwrapStyles = (styles: Extract<CssStyleCollection, any[]>): void => {
for (let index = 0, max = styles.length, style : typeof styles[number]; index < max; index++) {
style = styles[index];
// handle falsy item:
if (!style || (style === true)) {
styles[index] = undefined; // mutate : falsy style => undefined (delete)
continue; // handled => continue to next loop
} // if
// handle single item:
if (!Array.isArray(style)) {
const encodedStyle = encodeStyle(style); // expensive op!
if (!encodedStyle || (encodedStyle === true)) continue; // falsy style(s) => ignore
result.push(encodedStyle);
continue;
const encodedStyle = encodeStyle(style); // mutate : CssStyle => EncodedCssStyle
if (!encodedStyle || (encodedStyle === true)) {
styles[index] = undefined; // mutate : falsy style => undefined (delete)
}
else {
styles[index] = encodedStyle as EncodedCssStyle as any; // mutate : CssStyle => EncodedCssStyle
} // if
continue; // handled => continue to next loop
} // if

@@ -215,3 +186,3 @@

// handle multi item(s):
unwrapStyles(style, result); // expensive op!
unwrapStyles(style); // mutate : CssStyle(s) => EncodedCssStyle(s)
} // for

@@ -222,3 +193,3 @@ }

if (!Array.isArray(styles)) {
return encodeStyle(styles); // expensive op!
return encodeStyle(styles); // mutate : CssStyle => EncodedCssStyle
} // if

@@ -229,5 +200,4 @@

// dynamically handle multi item(s):
const result: EncodedCssStyle[] = [];
unwrapStyles(styles, result); // expensive op!
return result;
unwrapStyles(styles); // mutate : CssStyle(s) => EncodedCssStyle(s)
return styles as EncodedCssStyle[];
}

@@ -16,66 +16,56 @@ // cssfn:

// processors:
const renderSimpleValue = (value: CssComplexBaseValueOf<CssSimpleValue>): string => {
if (typeof(value) === 'number') return `${value}`; // CssSimpleNumericValue => number => string
if (typeof(value) === 'string') return value; // CssSimpleLiteralValue|CssCustomRef => string
return value.toString(); // CssCustomKeyframesRef => .toString()
const renderSimpleValue = (propValue: CssComplexBaseValueOf<CssSimpleValue>): string => {
switch (typeof(propValue)) {
case 'string' : return propValue; // CssSimpleLiteralValue|CssCustomRef => string
case 'number' : return '' + propValue; // CssSimpleNumericValue => number => string
default : return propValue.toString(); // CssCustomKeyframesRef => .toString()
} // switch
};
type ReducedRenderSubValues = { hasImportant: boolean, rendered: string[] }
const reducedRenderSubValues : ReducedRenderSubValues = { hasImportant: false, rendered: [] }
const reduceRenderSubValues = (accum: ReducedRenderSubValues, subValue: Extract<CssCustomValue, Array<any>>[number], index: number, array: Extract<CssCustomValue, Array<any>>[number][]): ReducedRenderSubValues => {
if (!Array.isArray(subValue)) {
if (typeof(subValue) === 'number') {
accum.rendered.push(
`${subValue}` // CssSimpleNumericValue => number => string
);
}
else if ((index === (array.length - 1)) && (subValue === '!important')) {
accum.hasImportant = true;
}
else if (typeof(subValue) === 'string') {
accum.rendered.push(
subValue // CssSimpleLiteralValue|CssCustomRef => string
);
}
else {
accum.rendered.push(
subValue.toString() // CssCustomKeyframesRef => .toString()
);
} // if
export const renderValue = (propValue: CssCustomValue): string => {
if (!Array.isArray(propValue)) {
return renderSimpleValue(propValue);
}
else {
accum.rendered.push(
subValue
.map(renderSimpleValue)
.join(' ') // [[double array]] => join separated with [space]
);
} // if
return accum;
};
export const renderValue = (value: CssCustomValue): string => {
if (!Array.isArray(value)) return renderSimpleValue(value); // CssComplexBaseValueOf<CssSimpleValue>
try {
(value as Extract<CssCustomValue, Array<any>>[number][]).reduce(reduceRenderSubValues, reducedRenderSubValues);
let hasImportant = false;
let result = ''; // for a small array : a string concatenation is faster than array.join('')
return (
reducedRenderSubValues.rendered
.join(', ') // comma_separated_values
for (let subIndex = 0, subMax = propValue.length, propSubValue : typeof propValue[number]; subIndex < subMax; subIndex++) {
propSubValue = propValue[subIndex];
+
(reducedRenderSubValues.hasImportant ? ' !important' : '')
);
}
finally {
// reset the accumulator to be used later:
reducedRenderSubValues.hasImportant = false;
reducedRenderSubValues.rendered.splice(0);
} // try
if (!Array.isArray(propSubValue)) {
if ((subIndex >= 1) && (subIndex === (subMax - 1)) && (propSubValue === '!important')) {
hasImportant = true;
}
else {
if (subIndex >= 1) result += ', '; // comma separated values
result += renderSimpleValue(propSubValue);
} // if
}
else {
for (let subSubIndex = 0, subSubMax = propSubValue.length, propSubSubValue : typeof propSubValue[number]; subSubIndex < subSubMax; subSubIndex++) {
propSubSubValue = propSubValue[subSubIndex];
if ((subSubIndex >= 1) && (subSubIndex === (subSubMax - 1)) && (propSubSubValue === '!important')) {
hasImportant = true;
}
else {
if ((subIndex >= 1) && (subSubIndex === 0)) result += ', '; // comma separated values
if (subSubIndex >= 1) result += ' '; // space separated values
result += renderSimpleValue(propSubSubValue);
} // if
} // for
} // if
} // for
if (hasImportant) result += ' !important';
return result;
} // if
};
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc