Skip to content

Migrate source code to TypeScript #72

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
}
29,151 changes: 21,449 additions & 7,702 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"path-type": "^4.0.0",
"picocolors": "^1.0.0",
"puppeteer": "~9.1.1",
"readdirp": "^3.6.0"
"readdirp": "^3.6.0",
"tslib": "^2.3.1"
},
"scripts": {
"build": "tsc",
Expand All @@ -38,14 +39,17 @@
"node": ">=12"
},
"devDependencies": {
"@netlify/build": "^26.0.2",
"@netlify/eslint-config-node": "^4.0.4",
"@types/jest": "^27.4.0",
"eslint": "^8.5.0",
"eslint-config-prettier": "^8.3.0",
"husky": "^7.0.4",
"jest": "^27.4.5",
"lint-staged": "^11.2.6",
"prettier": "^2.5.1",
"rimraf": "^3.0.2",
"ts-jest": "^27.1.2",
"typescript": "^4.5.4"
},
"repository": "https://github.com/netlify-labs/netlify-plugin-a11y",
Expand Down
45 changes: 0 additions & 45 deletions src/config.js

This file was deleted.

52 changes: 52 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import puppeteer from 'puppeteer'
import type { NetlifyPluginOptions } from '@netlify/build'

export type WCAGLevel = 'WCAG2A' | 'WCAG2AA' | 'WCAG2AAA'

type InputT = {
checkPaths?: string[],
ignoreDirectories?: string[],
ignoreElements?: string,
failWithIssues?: boolean,
wcagLevel?: WCAGLevel
}

const DEFAULT_CHECK_PATHS = ['/']
const DEFAULT_FAIL_WITH_ISSUES = true
const DEFAULT_IGNORE_DIRECTORIES: string[] = []

const PA11Y_DEFAULT_WCAG_LEVEL = 'WCAG2AA'
const PA11Y_RUNNERS = ['axe']
const PA11Y_USER_AGENT = 'netlify-plugin-a11y'

export const getConfiguration = async ({
constants: { PUBLISH_DIR },
inputs,
}: Pick<NetlifyPluginOptions, 'constants' | 'inputs'>) => {
const { checkPaths, ignoreDirectories, ignoreElements, failWithIssues, wcagLevel } =
inputs as InputT
return {
checkPaths: checkPaths || DEFAULT_CHECK_PATHS,
failWithIssues: failWithIssues ?? DEFAULT_FAIL_WITH_ISSUES,
ignoreDirectories: ignoreDirectories || DEFAULT_IGNORE_DIRECTORIES,
pa11yOpts: await getPa11yOpts({
hideElements: ignoreElements,
standard: wcagLevel || PA11Y_DEFAULT_WCAG_LEVEL,
}),
publishDir: (PUBLISH_DIR || process.env.PUBLISH_DIR) as string,
}
}

export type Config = ReturnType<typeof getConfiguration>

export const getPa11yOpts = async ({ hideElements, standard }: { hideElements?: string; standard: WCAGLevel }) => {
return {
browser: await puppeteer.launch({ ignoreHTTPSErrors: true }),
hideElements,
runners: PA11Y_RUNNERS,
userAgent: PA11Y_USER_AGENT,
standard,
}
}

export type Pa11yOpts = Awaited<ReturnType<typeof getPa11yOpts>>
12 changes: 7 additions & 5 deletions src/index.js → src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// @ts-check
import { getConfiguration } from './config'
import { generateFilePaths, runPa11y } from './pluginCore'
import pico from 'picocolors'

const { getConfiguration } = require('./config')
const { generateFilePaths, runPa11y } = require('./pluginCore')
const pico = require('picocolors')
import type { OnPostBuild } from '@netlify/build'

module.exports = {
async onPostBuild({ constants, inputs, utils: { build } }) {
async onPostBuild({ constants, inputs, utils: { build }, }) {
try {
const { publishDir, checkPaths, ignoreDirectories, failWithIssues, pa11yOpts } = await getConfiguration({
constants,
Expand Down Expand Up @@ -40,4 +40,6 @@ module.exports = {
build.failBuild(err.message)
}
},
} as {
onPostBuild: OnPostBuild
}
42 changes: 29 additions & 13 deletions src/pluginCore.js → src/pluginCore.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,35 @@
// @ts-check
import pa11y from 'pa11y'
import { extname, join } from 'path'
import { isDirectory, isFile } from 'path-type'
import { results as cliReporter } from './reporter'
import readdirp from 'readdirp'
import { StaticServer, SERVER_ADDRESS } from './server'

const pa11y = require('pa11y')
const { extname, join } = require('path')
const { isDirectory, isFile } = require('path-type')
const { results: cliReporter } = require('./reporter')
const readdirp = require('readdirp')
const { StaticServer, SERVER_ADDRESS } = require('./server')
import type { NetlifyPluginUtils } from '@netlify/build'
import type { Pa11yOpts } from './config'

const EMPTY_ARRAY = []
const ASTERISK = '*'
const ASTERISK = '*';
const HTML_EXT = '.html'
const GLOB_HTML = '*.html'

exports.runPa11y = async function ({ build, htmlFilePaths, pa11yOpts, publishDir }) {
export const runPa11y = async function ({
build,
htmlFilePaths,
pa11yOpts,
publishDir,
}: {
build: NetlifyPluginUtils['build']
htmlFilePaths: string[]
pa11yOpts: Pa11yOpts
publishDir: string
}) {
let issueCount = 0

const staticServer = new StaticServer(publishDir).listen()

const results = await Promise.all(
htmlFilePaths.map(async (/** @type {string} */ filePath) => {
htmlFilePaths.map(async (filePath) => {
try {
const res = await pa11y(join(SERVER_ADDRESS, filePath), pa11yOpts)
if (res.issues.length) {
Expand All @@ -41,10 +52,14 @@ exports.runPa11y = async function ({ build, htmlFilePaths, pa11yOpts, publishDir
}
}

exports.generateFilePaths = async function ({
export const generateFilePaths = async function ({
fileAndDirPaths, // array, mix of html and directories
ignoreDirectories,
publishDir,
}: {
fileAndDirPaths: string[]
ignoreDirectories: string[]
publishDir: string
}) {
const directoryFilter =
ignoreDirectories.length === 0
Expand All @@ -56,10 +71,11 @@ exports.generateFilePaths = async function ({
const htmlFilePaths = await Promise.all(
fileAndDirPaths.map((fileAndDirPath) => findHtmlFiles(`${publishDir}${fileAndDirPath}`, directoryFilter)),
)
return [].concat(...htmlFilePaths)

return [].concat(...htmlFilePaths) as string[]
}

const findHtmlFiles = async function (fileAndDirPath, directoryFilter) {
const findHtmlFiles = async function (fileAndDirPath: string, directoryFilter: '*' | string[]): Promise<string[]> {
if (await isDirectory(fileAndDirPath)) {
const filePaths = []
const stream = readdirp(fileAndDirPath, {
Expand Down
31 changes: 16 additions & 15 deletions src/reporter.js → src/reporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@
*
* @see https://github.com/pa11y/pa11y/blob/6.1.1/lib/reporters/cli.js
*/
// @ts-check

'use strict'

const { bold, cyan, green, gray, red, underline, yellow } = require('picocolors')
import { bold, cyan, green, gray, red, underline, yellow } from 'picocolors'

// Pa11y version support
const PA11Y_SUPPORTS = '^6.0.0 || ^6.0.0-alpha || ^6.0.0-beta'
Expand Down Expand Up @@ -43,7 +42,7 @@ function renderIssue(issue) {
}

// Output formatted results
function renderResults(results) {
function renderResults(results): string {
if (results.issues.length) {
const publicFilePath = results.pageUrl.replace(LOCAL_FILE_PATH_EXP, '')
const totals = {
Expand Down Expand Up @@ -91,21 +90,21 @@ function renderBegin() {
}

// Output debug messages
function renderDebug(message) {
function renderDebug(message: string) {
message = `Debug: ${message}`
return cleanWhitespace(`
${start} ${gray(message)}
`)
}

// Output information messages
function renderInfo(message) {
function renderInfo(message: string) {
return cleanWhitespace(`
${start} ${message}
`)
}

function renderError(message) {
function renderError(message: string) {
if (!/^error:/i.test(message)) {
message = `Error: ${message}`
}
Expand All @@ -116,19 +115,21 @@ function renderError(message) {

// Clean whitespace from output. This function is used to keep
// the reporter code a little cleaner
function cleanWhitespace(string) {
function cleanWhitespace(string): string {
return string.replace(/\t+|^\t*\n|\n\t*$/g, '')
}

function pluralize(noun, count) {
function pluralize(noun: string, count: number): string {
return count === 1 ? noun : noun + 's'
}

module.exports = {
begin: renderBegin,
debug: renderDebug,
info: renderInfo,
error: renderError,
results: renderResults,
supports: PA11Y_SUPPORTS,


export {
renderBegin as begin,
renderDebug as debug,
renderInfo as info,
renderError as error,
renderResults as results,
PA11Y_SUPPORTS as supports,
}
17 changes: 7 additions & 10 deletions src/server.js → src/server.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// @ts-check
const http = require('http')
const fs = require('fs')
const path = require('path')
const MIME_TYPES = require('./mimeTypes.json')
import http, { Server } from 'http'
import fs from 'fs'
import path from 'path'
import MIME_TYPES from './mimeTypes.json'

const HTML_EXT = '.html'

Expand All @@ -18,10 +17,8 @@ const SERVER_OPTS = {
const basePath = process.cwd()

class StaticServer {
/**
* @param {string} publishDir
*/
constructor(publishDir) {
instance: Server
constructor(publishDir: string) {
this.instance = http.createServer(function (req, res) {
const ext = path.extname(req.url)
const filepath = ext === HTML_EXT ? path.join(basePath, req.url) : path.join(basePath, publishDir, req.url)
Expand Down Expand Up @@ -50,7 +47,7 @@ class StaticServer {
}
}

module.exports = {
export {
StaticServer,
SERVER_ADDRESS,
}
6 changes: 3 additions & 3 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
"target": "ES2019",
"module": "commonjs",
"lib": ["ES2019"],
"allowJs": true,
"outDir": "./lib",
"types": ["jest"],
"esModuleInterop": true,
"removeComments": true,
"importHelpers": true,
"resolveJsonModule": true,
"skipLibCheck": true /* Skip type checking of declaration files. */,
"forceConsistentCasingInFileNames": true
"forceConsistentCasingInFileNames": true,
},
"include": ["src/**/*.ts", "src/**/*.js"]
"include": ["src/**/*.ts"]
}