diff --git a/package.json b/package.json index 0cb50dc167e6e..b615a2ace3363 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,12 @@ "@testing-library/jest-dom": "^5.11.0", "axios": "^0.19.2", "axios-mock-adapter": "^1.18.1", + "color-contrast-checker": "^2.1.0", "css-to-object": "^1.1.0", + "hjson": "^3.2.2", "husky": "^4.2.5", "jest": "^26.1.0", + "lodash.snakecase": "^4.1.1", "parse-diff": "^0.7.0" }, "dependencies": { diff --git a/scripts/preview-theme.js b/scripts/preview-theme.js index 31622c6a7d400..f9be3f99989b8 100644 --- a/scripts/preview-theme.js +++ b/scripts/preview-theme.js @@ -1,6 +1,10 @@ const core = require("@actions/core"); const github = require("@actions/github"); const parse = require("parse-diff"); +const Hjson = require("hjson"); +const snakeCase = require("lodash.snakecase"); +const ColorContrastChecker = require("color-contrast-checker"); + require("dotenv").config(); function getPrNumber() { @@ -21,6 +25,8 @@ const themeContribGuidelines = ` async function run() { try { + const ccc = new ColorContrastChecker(); + const warnings = []; const token = core.getInput("token"); const octokit = github.getOctokit(token || process.env.PERSONAL_TOKEN); const pullRequestId = getPrNumber(); @@ -30,7 +36,7 @@ async function run() { return; } - let res = await octokit.pulls.get({ + const res = await octokit.pulls.get({ owner: "anuraghazra", repo: "github-readme-stats", pull_number: pullRequestId, @@ -39,15 +45,20 @@ async function run() { }, }); - let diff = parse(res.data); - let colorStrings = diff + const diff = parse(res.data); + const content = diff .find((file) => file.to === "themes/index.js") .chunks[0].changes.filter((c) => c.type === "add") .map((c) => c.content.replace("+", "")) .join(""); - let matches = colorStrings.match(/(title_color:.*bg_color.*\")/); - let colors = matches && matches[0].split(","); + const themeObject = Hjson.parse(content); + const themeName = Object.keys(themeObject)[0]; + const colors = themeObject[themeName]; + + if (themeName !== snakeCase(themeName)) { + warnings.push("Theme name isn't in snake_case"); + } if (!colors) { await octokit.issues.createComment({ @@ -64,22 +75,39 @@ async function run() { }); return; } - colors = colors.map((color) => - color.replace(/.*\:\s/, "").replace(/\"/g, ""), - ); - - const titleColor = colors[0]; - const iconColor = colors[1]; - const textColor = colors[2]; - const bgColor = colors[3]; + + const titleColor = colors.title_color; + const iconColor = colors.icon_color; + const textColor = colors.text_color; + const bgColor = colors.bg_color; const url = `https://github-readme-stats.vercel.app/api?username=anuraghazra&title_color=${titleColor}&icon_color=${iconColor}&text_color=${textColor}&bg_color=${bgColor}&show_icons=true`; + const colorPairs = { + title_color: [titleColor, bgColor], + icon_color: [iconColor, bgColor], + text_color: [textColor, bgColor], + }; + + // check color contrast + Object.keys(colorPairs).forEach((key) => { + const color1 = colorPairs[key][0]; + const color2 = colorPairs[key][1]; + if (!ccc.isLevelAA(`#${color1}`, `#${color2}`)) { + const permalink = `https://webaim.org/resources/contrastchecker/?fcolor=${color1}&bcolor=${color2}`; + warnings.push( + `\`${key}\` does not passes [AA contrast ratio](${permalink})`, + ); + } + }); + await octokit.issues.createComment({ owner: "anuraghazra", repo: "github-readme-stats", body: ` \r**Automated Theme preview** + \r${warnings.map((warning) => `- :warning: ${warning}\n`).join("")} + \ntitle_color: #${titleColor} | icon_color: #${iconColor} | text_color: #${textColor} | bg_color: #${bgColor} \r[Preview Link](${url})