-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(tokens): provide autofix for global non-color tokens
- Loading branch information
1 parent
f950da7
commit 973e700
Showing
11 changed files
with
706 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export * from './configs'; | ||
export * from './ruleCuration'; | ||
export * from './ruleCustomization' | ||
export * from "./configs"; | ||
export * from "./ruleCuration"; | ||
export * from "./ruleCustomization"; | ||
export * from "./tokenLists"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
178 changes: 150 additions & 28 deletions
178
packages/eslint-plugin-pf-codemods/src/rules/v6/tokensWarn/tokens-warn.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,82 +1,204 @@ | ||
import { Rule } from "eslint"; | ||
import { | ||
IdentifierWithParent, | ||
getDefaultDeclarationString, | ||
getDefaultImportsFromPackage, | ||
getFromPackage, | ||
} from "../../helpers"; | ||
import { ImportDeclaration, ImportSpecifier, Literal } from "estree-jsx"; | ||
import { oldTokens } from "./tokenLists/oldTokens"; | ||
import { oldCssVarNamesV5 } from "./tokenLists/oldCssVarNamesV5"; | ||
import { | ||
Identifier, | ||
ImportDeclaration, | ||
ImportSpecifier, | ||
Literal, | ||
} from "estree-jsx"; | ||
import { | ||
oldTokens, | ||
oldCssVarNamesV5, | ||
globalNonColorTokensMap, | ||
oldGlobalNonColorTokens, | ||
oldGlobalNonColorCssVarNames, | ||
globalNonColorCssVarNamesMap, | ||
} from "../../../tokenLists"; | ||
|
||
module.exports = { | ||
meta: {}, | ||
meta: { fixable: "code" }, | ||
create: function (context: Rule.RuleContext) { | ||
const tokensPackage = "@patternfly/react-tokens"; | ||
|
||
const { imports: tokenSpecifiers } = getFromPackage(context, tokensPackage); | ||
|
||
const defaultTokensWithDeclaration = getDefaultImportsFromPackage( | ||
const defaultTokenImports = getDefaultImportsFromPackage( | ||
context, | ||
tokensPackage | ||
) | ||
.map((specifier) => ({ | ||
specifier, | ||
path: getDefaultDeclarationString(specifier), | ||
declaration: specifier.parent, | ||
})) | ||
.filter(({ path }) => path !== undefined) | ||
.map(({ path, declaration }) => ({ | ||
.map(({ specifier, path, declaration }) => ({ | ||
specifier, | ||
token: (path as string).split("/").pop() as string, | ||
declaration, | ||
})); | ||
|
||
const getMessage = (tokenName: string) => | ||
const getWarnMessage = (tokenName: string) => | ||
`${tokenName} is an old CSS token. About half of our tokens have been replaced with newer ones. To find a suitable replacement token, check our new documentation https://staging-v6.patternfly.org/tokens/all-patternfly-tokens.`; | ||
|
||
const getFixMessage = (oldToken: string, newToken: string) => | ||
`${oldToken} is an old CSS token and has been replaced with ${newToken}. If you want to use a different token, check our new documentation https://staging-v6.patternfly.org/tokens/all-patternfly-tokens.`; | ||
|
||
const shouldReplaceToken = (token: string) => | ||
oldGlobalNonColorTokens.includes(token) && | ||
globalNonColorTokensMap[token as keyof typeof globalNonColorTokensMap] !== | ||
"SKIP"; | ||
|
||
const replaceToken = ( | ||
node: ImportDeclaration | ImportSpecifier | Identifier, | ||
oldToken: string | ||
) => { | ||
const newToken = | ||
globalNonColorTokensMap[ | ||
oldToken as keyof typeof globalNonColorTokensMap | ||
]; | ||
|
||
context.report({ | ||
node, | ||
message: getFixMessage(oldToken, newToken), | ||
fix(fixer) { | ||
if (node.type === "ImportDeclaration") { | ||
const newDeclaration = node.source.value | ||
?.toString() | ||
.replace(oldToken, newToken) as string; | ||
|
||
return [ | ||
fixer.replaceText(node.specifiers[0], newToken), | ||
fixer.replaceText(node.source, `"${newDeclaration}"`), | ||
]; | ||
} | ||
|
||
if (node.type === "ImportSpecifier") { | ||
return fixer.replaceText(node.imported, newToken); | ||
} | ||
|
||
return fixer.replaceText(node, newToken); | ||
}, | ||
}); | ||
}; | ||
|
||
const replaceTokenOrWarn = ( | ||
node: ImportSpecifier | ImportDeclaration, | ||
token: string | ||
) => { | ||
if (shouldReplaceToken(token)) { | ||
replaceToken(node, token); | ||
} else if (oldTokens.includes(token)) { | ||
context.report({ | ||
node, | ||
message: getWarnMessage(token), | ||
}); | ||
} | ||
}; | ||
|
||
return { | ||
ImportSpecifier(node: ImportSpecifier) { | ||
if (tokenSpecifiers.includes(node)) { | ||
const tokenName = node.imported.name; | ||
if (oldTokens.includes(tokenName)) { | ||
context.report({ | ||
node, | ||
message: getMessage(tokenName), | ||
}); | ||
} | ||
const token = node.imported.name; | ||
replaceTokenOrWarn(node, token); | ||
} | ||
}, | ||
ImportDeclaration(node: ImportDeclaration) { | ||
const tokenWithDeclaration = defaultTokensWithDeclaration.find( | ||
const tokenWithDeclaration = defaultTokenImports.find( | ||
({ declaration }) => node.source.value === declaration?.source.value | ||
); | ||
|
||
if (!tokenWithDeclaration) { | ||
return; | ||
} | ||
|
||
replaceTokenOrWarn(node, tokenWithDeclaration.token); | ||
}, | ||
Identifier(node: Identifier) { | ||
const parentType = (node as IdentifierWithParent).parent?.type; | ||
// handle ImportSpecifier and ImportDeclaration separately | ||
if ( | ||
tokenWithDeclaration && | ||
oldTokens.includes(tokenWithDeclaration.token) | ||
parentType === "ImportSpecifier" || | ||
parentType === "ImportDefaultSpecifier" | ||
) { | ||
context.report({ | ||
node, | ||
message: getMessage(tokenWithDeclaration.token), | ||
}); | ||
return; | ||
} | ||
|
||
const tokenInfo = defaultTokenImports.find( | ||
({ specifier }) => node.name === specifier.local.name | ||
); | ||
|
||
if (tokenInfo && shouldReplaceToken(tokenInfo.token)) { | ||
replaceToken(node, tokenInfo.token); | ||
} | ||
|
||
const unaliasedTokenSpecifier = tokenSpecifiers.find( | ||
(specifier) => | ||
specifier.local.name === specifier.imported.name && | ||
node.name === specifier.local.name | ||
); | ||
|
||
if (unaliasedTokenSpecifier && shouldReplaceToken(node.name)) { | ||
replaceToken(node, node.name); | ||
} | ||
}, | ||
Literal(node: Literal) { | ||
if ( | ||
typeof node.value === "string" && | ||
[...oldCssVarNames, ...oldCssVars].includes(node.value) | ||
) { | ||
if (typeof node.value !== "string") { | ||
return; | ||
} | ||
|
||
let varName = node.value; | ||
const varRegex = /var\(([^)]+)\)/; | ||
const match = node.value.match(varRegex); | ||
|
||
if (match) { | ||
varName = match[1]; | ||
} | ||
|
||
const shouldReplaceVar = | ||
oldGlobalNonColorCssVarNames.includes(varName) && | ||
globalNonColorCssVarNamesMap[ | ||
varName as keyof typeof globalNonColorCssVarNamesMap | ||
] !== "SKIP"; | ||
|
||
if (shouldReplaceVar) { | ||
const newVarName = | ||
globalNonColorCssVarNamesMap[ | ||
varName as keyof typeof globalNonColorCssVarNamesMap | ||
]; | ||
|
||
if (newVarName !== "SKIP") { | ||
context.report({ | ||
node, | ||
message: getFixMessage(varName, newVarName), | ||
fix(fixer) { | ||
return fixer.replaceText( | ||
node, | ||
node.value?.toString().startsWith("var") | ||
? `"var(${newVarName})"` | ||
: `"${newVarName}"` | ||
); | ||
}, | ||
}); | ||
} | ||
} else if (oldCssVarNames.includes(varName)) { | ||
context.report({ | ||
node, | ||
message: getMessage(node.value), | ||
message: getWarnMessage(node.value), | ||
}); | ||
} | ||
}, | ||
}; | ||
}, | ||
}; | ||
|
||
// consumers may run class-name-updater before codemods, so we have to check also old tokens with v6 prefix | ||
// consumers may have run the old class-name-updater before codemods, so we should check also old tokens with v6 prefix | ||
const oldCssVarNamesV6 = oldCssVarNamesV5.map((cssVarName) => | ||
cssVarName.replace("v5", "v6") | ||
); | ||
const oldCssVarNames = [...oldCssVarNamesV5, ...oldCssVarNamesV6]; | ||
const oldCssVars = oldCssVarNames.map((cssVarName) => `var(${cssVarName})`); |
31 changes: 23 additions & 8 deletions
31
packages/eslint-plugin-pf-codemods/src/rules/v6/tokensWarn/tokensWarnInput.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,29 @@ | ||
// replacements (fixable with --fix) | ||
import global_BorderWidth_lg from "@patternfly/react-tokens/dist/esm/global_BorderWidth_lg"; | ||
import { global_FontWeight_normal } from "@patternfly/react-tokens"; | ||
|
||
global_BorderWidth_lg; | ||
global_FontWeight_normal; | ||
|
||
document.documentElement.style.setProperty("--pf-v5-global--ZIndex--lg", "3"); | ||
<div | ||
style={{ | ||
borderWidth: "var(--pf-v5-global--BorderWidth--lg)", | ||
boxShadow: "var(--pf-v5-global--BoxShadow--sm)", | ||
marginTop: "var(--pf-v5-global--spacer--3xl)", | ||
}} | ||
></div>; | ||
|
||
// warnings (not fixable) | ||
import global_warning_color_100 from "@patternfly/react-tokens/dist/esm/global_warning_color_100"; | ||
import { c_alert__FontSize } from "@patternfly/react-tokens"; | ||
|
||
global_warning_color_100; | ||
c_alert__FontSize; | ||
|
||
<> | ||
<div | ||
style={{ | ||
"--pf-v5-global--success-color--200": "#abc", | ||
}} | ||
></div> | ||
<div style={{ borderWidth: "var(--pf-v5-global--BorderWidth--lg)" }}></div> | ||
</>; | ||
<div | ||
style={{ | ||
color: "var(--pf-v5-global--success-color--200)", | ||
width: "var(--pf-v5-global--arrow--width)", | ||
}} | ||
></div>; |
31 changes: 23 additions & 8 deletions
31
packages/eslint-plugin-pf-codemods/src/rules/v6/tokensWarn/tokensWarnOutput.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,29 @@ | ||
// replacements (fixable with --fix) | ||
import global_border_width_extra_strong from "@patternfly/react-tokens/dist/esm/global_border_width_extra_strong"; | ||
import { global_font_weight_body_default } from "@patternfly/react-tokens"; | ||
|
||
global_border_width_extra_strong; | ||
global_font_weight_body_default; | ||
|
||
document.documentElement.style.setProperty("--pf-t--global--z-index--lg", "3"); | ||
<div | ||
style={{ | ||
borderWidth: "var(--pf-t--global--border--width--extra-strong)", | ||
boxShadow: "var(--pf-t--global--box-shadow--sm)", | ||
marginTop: "var(--pf-t--global--spacer--3xl)", | ||
}} | ||
></div>; | ||
|
||
// warnings (not fixable) | ||
import global_warning_color_100 from "@patternfly/react-tokens/dist/esm/global_warning_color_100"; | ||
import { c_alert__FontSize } from "@patternfly/react-tokens"; | ||
|
||
global_warning_color_100; | ||
c_alert__FontSize; | ||
|
||
<> | ||
<div | ||
style={{ | ||
"--pf-v5-global--success-color--200": "#abc", | ||
}} | ||
></div> | ||
<div style={{ borderWidth: "var(--pf-v5-global--BorderWidth--lg)" }}></div> | ||
</>; | ||
<div | ||
style={{ | ||
color: "var(--pf-v5-global--success-color--200)", | ||
width: "var(--pf-v5-global--arrow--width)", | ||
}} | ||
></div>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export * from "./oldCssVarNamesV5"; | ||
export * from "./oldGlobalCssVarNames"; | ||
export * from "./oldGlobalTokens"; | ||
export * from "./oldTokens"; |
2 changes: 1 addition & 1 deletion
2
...tokensWarn/tokenLists/oldCssVarNamesV5.ts → ...demods/src/tokenLists/oldCssVarNamesV5.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.