diff --git a/index.js b/index.js index 8fdd1b9..6f70733 100755 --- a/index.js +++ b/index.js @@ -22,7 +22,8 @@ const unlabeledInputs = require("./src/rules/unlabeledInputs"); // Utils const configuration = require("./src/utils/configuration"); -const { printErrors, printSummary } = require("./src/utils/logger"); +const shouldRun = require("./src/utils/runner"); +const { printErrors, printSummary, exportToJson } = require("./src/utils/logger"); const allowedExtensions = [ ".latte", @@ -70,17 +71,10 @@ if (!input) { process.exit(1); } -/** - * Determines if a rule should run based on configuration. - * Defaults to enabled unless explicitly set to false. - * @param {string} rule - Rule name from config.rules keys. - * @returns {boolean} Whether the rule is enabled. - */ -const shouldRun = (rule) => config.rules[rule] !== false; - /** * Recursively finds files with allowed extensions in a directory. * Ignores directories listed in `excludedDirs`. + * * @param {string} dir - Directory path to search. * @returns {string[]} Array of matched file paths. */ @@ -97,44 +91,29 @@ function findFiles(dir) { }); } -/** - * Exports the full list of errors to a JSON file. - * @param {object[]} errors - List of error objects. - * @param {string} outputPath - Path to save the JSON file. - */ -function exportToJson(errors, outputPath) { - try { - fs.writeFileSync(outputPath, JSON.stringify(errors, null, 2), "utf-8"); - console.log(chalk.blue(`📦 Results exported to ${outputPath}`)); - } catch (err) { - console.error(chalk.red(`Failed to export JSON: ${err.message}`)); - } -} - /** * Runs all accessibility checks on a single HTML content string. * Used for analyzing remote HTML via URL input. + * * @param {string} content - Raw HTML string. * @param {string} label - Display name (usually file path or URL). */ async function analyzeContent(content, label) { const errors = [ - ...(shouldRun("alt-attributes") ? altAttributes(content, label) : []), - ...(shouldRun("aria-invalid") ? ariaLabels(content, label) : []), - ...(shouldRun("missing-aria") ? missingAria(content, label) : []), - ...(shouldRun("contrast") ? contrast(content, label) : []), - ...(shouldRun("aria-role-invalid") ? ariaRoles(content, label) : []), - ...(shouldRun("missing-landmark") ? landmarkRoles(content, label) : []), - ...(shouldRun("label-missing-for") ? labelsWithoutFor(content, label) : []), - ...(shouldRun("input-unlabeled") ? unlabeledInputs(content, label) : []), - ...(shouldRun("empty-link") ? emptyLinks(content, label) : []), - ...(shouldRun("iframe-title-missing") ? iframeTitles(content, label) : []), - ...(shouldRun("multiple-h1") ? multipleH1(content, label) : []), - ...(shouldRun("heading-order") ? headingOrder(content, label) : []), - ...(shouldRun("heading-empty") ? headingEmpty(content, label) : []), - ...(shouldRun("link-new-tab-warning") - ? linksOpenNewTab(content, label) - : []), + ...(shouldRun(config, "alt-attributes") ? altAttributes(content, label) : []), + ...(shouldRun(config, "aria-invalid") ? ariaLabels(content, label) : []), + ...(shouldRun(config, "missing-aria") ? missingAria(content, label) : []), + ...(shouldRun(config, "contrast") ? contrast(content, label) : []), + ...(shouldRun(config, "aria-role-invalid") ? ariaRoles(content, label) : []), + ...(shouldRun(config, "missing-landmark") ? landmarkRoles(content, label) : []), + ...(shouldRun(config, "label-missing-for") ? labelsWithoutFor(content, label) : []), + ...(shouldRun(config, "input-unlabeled") ? unlabeledInputs(content, label) : []), + ...(shouldRun(config, "empty-link") ? emptyLinks(content, label) : []), + ...(shouldRun(config, "iframe-title-missing") ? iframeTitles(content, label) : []), + ...(shouldRun(config, "multiple-h1") ? multipleH1(content, label) : []), + ...(shouldRun(config, "heading-order") ? headingOrder(content, label) : []), + ...(shouldRun(config, "heading-empty") ? headingEmpty(content, label) : []), + ...(shouldRun(config, "link-new-tab-warning") ? linksOpenNewTab(content, label) : []), ]; if (errors.length > 0) { @@ -165,28 +144,20 @@ async function analyzeContent(content, label) { const content = fs.readFileSync(file, "utf-8"); allErrors.push( - ...(shouldRun("alt-attributes") - ? altAttributes(content, file, config) - : []), - ...(shouldRun("aria-invalid") ? ariaLabels(content, file) : []), - ...(shouldRun("missing-aria") ? missingAria(content, file) : []), - ...(shouldRun("contrast") ? contrast(content, file) : []), - ...(shouldRun("aria-role-invalid") ? ariaRoles(content, file) : []), - ...(shouldRun("label-missing-for") - ? labelsWithoutFor(content, file) - : []), - ...(shouldRun("input-unlabeled") ? unlabeledInputs(content, file) : []), - ...(shouldRun("empty-link") ? emptyLinks(content, file) : []), - ...(shouldRun("iframe-title-missing") - ? iframeTitles(content, file) - : []), - ...(shouldRun("multiple-h1") ? multipleH1(content, file) : []), - ...(shouldRun("heading-order") ? headingOrder(content, file) : []), - ...(shouldRun("heading-empty") ? headingEmpty(content, file) : []), - ...(shouldRun("link-new-tab-warning") - ? linksOpenNewTab(content, file) - : []) - // ...(shouldRun("missing-landmark") ? landmarkRoles(content, file) : []), + ...(shouldRun(config, "alt-attributes") ? altAttributes(content, file, config) : []), + ...(shouldRun(config, "aria-invalid") ? ariaLabels(content, file) : []), + ...(shouldRun(config, "missing-aria") ? missingAria(content, file) : []), + ...(shouldRun(config, "contrast") ? contrast(content, file) : []), + ...(shouldRun(config, "aria-role-invalid") ? ariaRoles(content, file) : []), + ...(shouldRun(config, "label-missing-for") ? labelsWithoutFor(content, file) : []), + ...(shouldRun(config, "input-unlabeled") ? unlabeledInputs(content, file) : []), + ...(shouldRun(config, "empty-link") ? emptyLinks(content, file) : []), + ...(shouldRun(config, "iframe-title-missing") ? iframeTitles(content, file) : []), + ...(shouldRun(config, "multiple-h1") ? multipleH1(content, file) : []), + ...(shouldRun(config, "heading-order") ? headingOrder(content, file) : []), + ...(shouldRun(config, "heading-empty") ? headingEmpty(content, file) : []), + ...(shouldRun(config, "link-new-tab-warning") ? linksOpenNewTab(content, file) : []), + // ...(shouldRun(config, "missing-landmark") ? landmarkRoles(content, file) : []), ); } diff --git a/package.json b/package.json index 9c27480..c9be26e 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "@actions/core": "^1.11.1", "be-a11y": "github:be-lenka/be-a11y", "chalk": "^4.1.2", - "cheerio": "^1.0.0-rc.12", + "cheerio": "^1.1.0", "css": "^3.0.0", "node-fetch": "^2.7.0", "tinycolor2": "^1.6.0" diff --git a/src/utils/configuration.js b/src/utils/configuration.js index 8599be0..2dce694 100644 --- a/src/utils/configuration.js +++ b/src/utils/configuration.js @@ -14,8 +14,8 @@ module.exports = function configuration(configFile) { } catch (err) { console.warn(chalk.yellow("⚠️ No config file found or invalid JSON. Using default rules.")); config.rules = {}; - // config.allowedExtensions = {}; - // config.excludedDirs = {}; + config.allowedExtensions = {}; + config.excludedDirs = {}; } config.rules ??= {}; diff --git a/src/utils/logger.js b/src/utils/logger.js index 34607e6..008961d 100644 --- a/src/utils/logger.js +++ b/src/utils/logger.js @@ -2,6 +2,7 @@ const chalk = require("chalk"); /** * Groups an array of errors by their `type` property. + * * @param {object[]} errors - List of error objects. * @returns {object} Errors grouped by type. */ @@ -16,6 +17,7 @@ function groupErrors(errors) { /** * Prints detailed accessibility issues to the console. * Issues are grouped by type with color-coded headings. + * * @param {object[]} errors - List of error objects. */ function printErrors(errors) { @@ -61,6 +63,7 @@ function printErrors(errors) { /** * Prints a summary table of accessibility issue counts by type. + * * @param {object[]} errors - List of error objects. */ function printSummary(errors) { @@ -74,5 +77,19 @@ function printSummary(errors) { console.table(summary); } +/** + * Exports the full list of errors to a JSON file. + * + * @param {object[]} errors - List of error objects. + * @param {string} outputPath - Path to save the JSON file. + */ +function exportToJson(errors, outputPath) { + try { + fs.writeFileSync(outputPath, JSON.stringify(errors, null, 2), "utf-8"); + console.log(chalk.blue(`📦 Results exported to ${outputPath}`)); + } catch (err) { + console.error(chalk.red(`Failed to export JSON: ${err.message}`)); + } +} -module.exports = { printErrors, printSummary } +module.exports = { printErrors, printSummary, exportToJson } diff --git a/src/utils/runner.js b/src/utils/runner.js new file mode 100644 index 0000000..59c19cd --- /dev/null +++ b/src/utils/runner.js @@ -0,0 +1,11 @@ + +/** + * Determines if a rule should run based on configuration. + * Defaults to enabled unless explicitly set to false. + * + * @param {string} rule - Rule name from config.rules keys. + * @returns {boolean} Whether the rule is enabled. + */ + module.exports = function shouldRun(config, rule) { + return config.rules[rule] !== false; +};