import postcssValueParser from "postcss-value-parser" ; import { deprecatedTokenReplacements } from "../../../deprecatedTokens" ; import { cantFindReplacementTokenForDeprecatedMessage , noMatchingRgbParamsVariableMessage , } from "../../messages" ; import { KaizenToken } from "../../types" ; import { transformDecl } from "../../util/functionTransformer" ; import { kaizenTokensByName } from "../../util/kaizenTokens" ; import { parseVariable , replaceTokenInVariable , stringifyVariable , } from "../../util/variableUtils" ; const parsePercentageOrDecimal = ( percentageOrDecimal ) : number | "NaN" => { if ( percentageOrDecimal . indexOf ( "%" ) !== - 1 ) { return parsePercentage ( percentageOrDecimal ) ; } else { const parsed = parseFloat ( percentageOrDecimal ) ; if ( isNaN ( parsed ) ) { return "NaN" ; } else { return parsed ; } } } ; /**
 * Given a string like "50%", "40%", "30", "15" etc (you don't have to pass in the percentage sign), return a decimal like 0.5, 0.4, 0.3 etc
 */ const parsePercentage = ( value ) : number | "NaN" => { const parsed = parseFloat ( value . replace ( /\%/ , "" ) ) ; if ( isNaN ( parsed ) ) { return "NaN" ; } return parsed / 100 ; } ; const getReplacementRgbTriple = ( kaizenTokenName ) : { replacement : KaizenToken ; } | "CantFindReplacementForDeprecatedToken" | "NoRGBTripleReplacement" | "NoReplacementNeeded" | "NotAKaizenToken" => { let kaizenTokenSubject ; const currentKaizenToken = kaizenTokensByName [ kaizenTokenName ] ; const replacement = kaizenTokensByName [ deprecatedTokenReplacements . get ( kaizenTokenName ) || "" ] ; const isDeprecated = deprecatedTokenReplacements . has ( kaizenTokenName ) ; if ( replacement ) { kaizenTokenSubject = replacement ; } else if ( ! isDeprecated && currentKaizenToken ) { kaizenTokenSubject = currentKaizenToken ; } else if ( ! replacement && isDeprecated ) { return "CantFindReplacementForDeprecatedToken" ; } else if ( ! isDeprecated && ! currentKaizenToken ) { return "NotAKaizenToken" ; } else { return "NoReplacementNeeded" ; } if ( kaizenTokenSubject . cssVariable && kaizenTokenSubject . cssVariable . fallback && ! isRgbTriple ( kaizenTokenSubject . cssVariable . fallback ) ) { const fixedVariable = kaizenTokensByName [ kaizenTokenSubject . name + "-rgb" ] ; if ( ! fixedVariable ) { return "NoRGBTripleReplacement" ; } return { replacement : fixedVariable } ; } return "NoReplacementNeeded" ; } ; const isRgbTriple = ( value ) => /^\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*$/ . test ( value ) ; /**
 * Given a CSS declaration value, find any alpha modifying functions like add-alpha, transparentize, or rgba, then normalise them to either rgba or rgb,
 * and ensure that a RGB triple Kaizen token is being used, e.g. `$color-purple-100-rgb` rather than `$color-purple-100`.
 * It also knows how to migrate from a deprecated variable within a function, e.g. `$kz-color-wisteria-100` -> `$color-purple-100-rgb`
 */ export const fixAlphaModificationFunctions = ( /** The value part of a declaration: e.g. the string "5px 10px" within "padding: 5px 10px" */ value ) => { const errors = [ ] ; const fixAlphaModificationFunction = ( functionName , ... params ) => { const [ firstParameter , secondParameter ] = params ; const originalValueWithoutModification = `${ functionName }(${ params . join ( ", " ) })` ; const parsedFirstParameter = postcssValueParser ( firstParameter ) . nodes [ 0 ] ; if ( parsedFirstParameter . type !== "word" ) return originalValueWithoutModification ; const variable = parseVariable ( parsedFirstParameter ) ; if ( ! variable ) { return originalValueWithoutModification ; } const isVariableCurrentKaizenToken = ! ! variable ?. kaizenToken ; const isVariableDeprecatedKaizenToken = deprecatedTokenReplacements . has ( variable . name ) ; const isKaizenToken = isVariableCurrentKaizenToken || isVariableDeprecatedKaizenToken ; if ( ! isKaizenToken ) return originalValueWithoutModification ; const replacementResult = getReplacementRgbTriple ( variable . name ) ; let replacement ; switch ( replacementResult ) { case "NoReplacementNeeded" : case "NotAKaizenToken" : return originalValueWithoutModification ; case "CantFindReplacementForDeprecatedToken" : errors . push ( cantFindReplacementTokenForDeprecatedMessage ( variable . name ) ) ; return originalValueWithoutModification ; case "NoRGBTripleReplacement" : errors . push ( noMatchingRgbParamsVariableMessage ( variable . name ) ) ; return originalValueWithoutModification ; default : replacement = replacementResult . replacement ; } const stringifiedReplacement = stringifyVariable ( replaceTokenInVariable ( variable , replacement ) ) ; switch ( functionName ) { case "rgb" : return `rgb(${ stringifiedReplacement })` ; case "rgba" : return `rgba(${ stringifiedReplacement }, ${ secondParameter })` ; case "transparentize" : const normedTransparentizeAmount = parsePercentageOrDecimal ( secondParameter ) ; if ( normedTransparentizeAmount === "NaN" ) return originalValueWithoutModification ; return `rgba(${ stringifiedReplacement }, ${ 1 - normedTransparentizeAmount })` ; case "add-alpha" : const normedAddAlphaPercentage = parsePercentage ( secondParameter ) ; if ( normedAddAlphaPercentage === "NaN" ) return originalValueWithoutModification ; return `rgba(${ stringifiedReplacement }, ${ normedAddAlphaPercentage })` ; } return originalValueWithoutModification ; } ; const newValue = transformDecl ( value , { rgba : fixAlphaModificationFunction , rgb : fixAlphaModificationFunction , "add-alpha" : fixAlphaModificationFunction , transparentize : fixAlphaModificationFunction , } ) ; return { newValue , errors } ; } ;