diff --git a/cli.js b/cli.js index 33928af..11255ac 100755 --- a/cli.js +++ b/cli.js @@ -24,6 +24,7 @@ const cli = meow( --only-style Only output the styles, forces --preserve-variables on --only-variables Only output the variables for the specified themes --root-selector Specify the root selector when outputting styles, default '.markdown-body' + --no-use-fixture Exclude generated classes that come from GitHub Markdown API rendered fixture.md Examples $ github-markdown-css --list @@ -74,6 +75,10 @@ const cli = meow( rootSelector: { type: 'string', }, + useFixture: { + type: 'boolean', + default: true, + }, }, }, ); @@ -85,6 +90,7 @@ const { onlyStyle, onlyVariables, rootSelector, + useFixture, } = cli.flags; let {light, dark} = cli.flags; @@ -140,5 +146,6 @@ console.log( onlyStyles: onlyStyle, onlyVariables, rootSelector, + useFixture, }), ); diff --git a/index.js b/index.js index ddae818..f863408 100644 --- a/index.js +++ b/index.js @@ -1,8 +1,10 @@ import postcss from 'postcss'; -import {cachedFetch, reverseUnique, unique, zip} from './utilities.js'; +import {cachedFetch, getUniqueClasses, renderMarkdown, reverseUnique, unique, zip} from './utilities.js'; import {ALLOW_CLASS, ALLOW_TAGS, manuallyAddedStyle} from './constants.js'; -function extractStyles(rules, cssText) { +function extractStyles(rules, cssText, {extraAllowableClasses = []} = {}) { + const allowableClassList = new Set([...ALLOW_CLASS, ...extraAllowableClasses]); + function select(selector) { if (selector.startsWith('.markdown-body')) { return true; @@ -23,7 +25,7 @@ function extractStyles(rules, cssText) { } const klass = selector.match(/\.[-\w]+/); - if (klass && !ALLOW_CLASS.has(klass[0])) { + if (klass && !allowableClassList.has(klass[0])) { return false; } @@ -32,7 +34,7 @@ function extractStyles(rules, cssText) { const klass = selector.match(/^\.[-\w]+/); if (klass) { - return ALLOW_CLASS.has(klass[0]); + return allowableClassList.has(klass[0]); } return false; @@ -79,7 +81,7 @@ function extractStyles(rules, cssText) { return; } - if (rule.some(decl => decl.value.includes('prettylights'))) { + if (rule.some(node => node.type === 'decl' && node.value.includes('prettylights'))) { if (!rule.selector.includes('.QueryBuilder')) { rules.push(rule); } @@ -135,6 +137,10 @@ function classifyRules(rules) { return undefined; } + function isEmpty(rule) { + return !rule.first; + } + function mergeRules(rules) { const result = []; const selectorIndexMap = {}; @@ -163,7 +169,7 @@ function classifyRules(rules) { }); } - return result; + return result.filter(rule => !isEmpty(rule)); } const result = {rules: [], light: [], dark: []}; @@ -233,6 +239,7 @@ export default async function getCSS({ onlyVariables = false, onlyStyles = false, rootSelector = '.markdown-body', + useFixture = true, } = {}) { if (onlyVariables && onlyStyles) { // Would result in an empty output @@ -250,7 +257,12 @@ export default async function getCSS({ const body = await cachedFetch('https://github.com'); // Get a list of all css links on the page const links = unique(body.match(/(?<=href=").+?\.css/g)); - const contents = await Promise.all(links.map(url => cachedFetch(url))); + const renderMarkdownPromise = useFixture ? renderMarkdown() : Promise.resolve(); + const [fixtureHtml, ...contents] = await Promise.all([ + renderMarkdownPromise, + ...links.map(url => cachedFetch(url)), + ]); + const fixtureClasses = getUniqueClasses(fixtureHtml); let rules = []; const colors = []; @@ -277,7 +289,7 @@ export default async function getCSS({ extractVariables(colors, 'shared', cssText); } - extractStyles(rules, cssText); + extractStyles(rules, cssText, {extraAllowableClasses: fixtureClasses}); } } diff --git a/utilities.js b/utilities.js index 89782af..c333a25 100644 --- a/utilities.js +++ b/utilities.js @@ -75,7 +75,11 @@ export async function renderMarkdown() { const response = await fetch('https://api.github.com/markdown', { method: 'POST', - body: JSON.stringify({text}), + body: JSON.stringify({ + text, + mode: 'gfm', + context: 'sindresorhus/generate-github-markdown-css', + }), headers: { Accept: 'application/vnd.github.v3+json', 'User-Agent': 'Node.js', @@ -91,3 +95,9 @@ export async function renderMarkdown() { throw new Error(`Failed to render markdown: ${body}`); } + +export function getUniqueClasses(html = '') { + const classNames = [...html.matchAll(/class\s*=\s*["']([^"']+)["']/g)] + .flatMap(match => match[1].split(/\s+/).map(c => `.${c}`)); + return new Set(classNames); +}