From b0ef223c9d9b8d90fedd1ecce419b5e179e80683 Mon Sep 17 00:00:00 2001 From: "M. George Hansen" Date: Mon, 1 Jun 2020 23:29:59 -0700 Subject: [PATCH] chore: resolve linting errors & warnings --- .eslintrc | 10 +- src/build.ts | 1 + src/cli/index.ts | 6 +- src/component.ts | 4 +- src/config.ts | 1 + src/create-element.ts | 22 +++- src/index.ts | 11 +- src/jsx.ts | 244 ++++++++++++++++++++++-------------------- src/utils.ts | 2 +- test/lib/expect.ts | 8 +- test/lib/utils.ts | 12 ++- 11 files changed, 177 insertions(+), 144 deletions(-) diff --git a/.eslintrc b/.eslintrc index fbceddb..c6e03ed 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,11 +1,19 @@ { "root": true, "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaFeatures": { + "jsx": true + } + }, "plugins": ["@typescript-eslint", "prettier"], "extends": [ "eslint:recommended", "plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/recommended", "plugin:prettier/recommended" - ] + ], + "rules": { + "@typescript-eslint/no-namespace": "off" + } } diff --git a/src/build.ts b/src/build.ts index 3e272ab..aa676f6 100644 --- a/src/build.ts +++ b/src/build.ts @@ -23,6 +23,7 @@ const renderPagesToHtml = async ({ // Ensure that we don't cache page modules when running in dev server. purgeModuleAndDepsFromCache(srcPath); + // eslint-disable-next-line @typescript-eslint/no-var-requires const pageSrc = require(srcPath); if (!("page" in pageSrc)) { throw new Error( diff --git a/src/cli/index.ts b/src/cli/index.ts index c138e28..f7a6151 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -36,11 +36,12 @@ const parseArgs = ( const opt = args.shift(); switch (opt) { case "-h": - case "--help": + case "--help": { options.showHelp = true; break; + } case "-r": - case "--require": + case "--require": { const moduleName = args.shift(); if (moduleName == null) { throw new UsageError( @@ -50,6 +51,7 @@ const parseArgs = ( } options.require.push(moduleName); break; + } default: throw new UsageError(`unknown option ${opt}`, globalHelpText); } diff --git a/src/component.ts b/src/component.ts index f274d3b..7e579b8 100644 --- a/src/component.ts +++ b/src/component.ts @@ -30,7 +30,9 @@ export type Element = HTMLElement | string | boolean | undefined | null; /** * Custom HTMLElement factory that can be parameterized by props. */ -export interface Component

{ +export interface Component< + P extends Record = Record +> { ( props: P & { children?: Element[]; diff --git a/src/config.ts b/src/config.ts index a210b96..6baa45c 100644 --- a/src/config.ts +++ b/src/config.ts @@ -47,6 +47,7 @@ export interface Config { watch: string[]; } +// eslint-disable-next-line @typescript-eslint/no-empty-function const noop = () => {}; /** diff --git a/src/create-element.ts b/src/create-element.ts index 76cb95e..1163a9a 100644 --- a/src/create-element.ts +++ b/src/create-element.ts @@ -16,7 +16,7 @@ import { HTMLAttributes } from "./jsx"; * * @return Fully-realized HTMLElement, ready for rendering. */ -export function createElement

( +export function createElement

>( comp: Component

, props: P, ...children: Element[] @@ -37,8 +37,8 @@ export function createElement( ...children: Element[] ): HTMLElement; export function createElement( - type: string | Component, - props: (HTMLAttributes & Record) | null, + type: string | Component>, + props: HTMLAttributes | Record | null, ...children: Element[] ): HTMLElement { // Flatten the children array so we can accept arrays as children. @@ -50,5 +50,19 @@ export function createElement( if (type !== type.toLowerCase()) { console.warn(`constructed HTML5 tag with non-lowercase name ${type}`); } - return { tag: type, attributes: props || {}, children: normalizedChildren }; + const attrs: Record = {}; + for (const [key, value] of Object.entries(props || {})) { + if ( + typeof value !== "string" && + typeof value !== "number" && + typeof value !== "boolean" + ) { + console.warn( + `non-primitive attribute ${key} = ${JSON.stringify(value)}` + ); + continue; + } + attrs[key] = value; + } + return { tag: type, attributes: attrs, children: normalizedChildren }; } diff --git a/src/index.ts b/src/index.ts index c82e7dd..2e5606b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,13 +6,4 @@ export { HTMLElement, Component } from "./component"; export { UserConfig as Config } from "./config"; export { createElement } from "./create-element"; - -import { HTMLElement } from "./component"; -import { IntrinsicElements as JsxIntrinsics } from "./jsx"; - -declare global { - namespace JSX { - type Element = HTMLElement; - type IntrinsicElements = JsxIntrinsics; - } -} +export * from "./jsx"; diff --git a/src/jsx.ts b/src/jsx.ts index 4848c47..55d69a9 100644 --- a/src/jsx.ts +++ b/src/jsx.ts @@ -3,10 +3,13 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { HTMLElement } from "./component"; + export interface RdfaAttributes { about?: string; datatype?: string; - inlist?: any; + inlist?: boolean; prefix?: string; property?: string; resource?: string; @@ -60,7 +63,7 @@ export interface HTMLAttributes extends RdfaAttributes, MicrodataAttributes { dir?: "auto" | "rtl" | "ltr"; disabled?: boolean; disableRemotePlayback?: boolean; - download?: any; + download?: boolean | string; draggable?: boolean; encType?: string; form?: string; @@ -154,120 +157,125 @@ export interface HTMLAttributes extends RdfaAttributes, MicrodataAttributes { wrap?: string; } -export interface IntrinsicElements { - a: HTMLAttributes; - abbr: HTMLAttributes; - address: HTMLAttributes; - area: HTMLAttributes; - article: HTMLAttributes; - aside: HTMLAttributes; - audio: HTMLAttributes; - b: HTMLAttributes; - base: HTMLAttributes; - bdi: HTMLAttributes; - bdo: HTMLAttributes; - big: HTMLAttributes; - blockquote: HTMLAttributes; - body: HTMLAttributes; - br: HTMLAttributes; - button: HTMLAttributes; - canvas: HTMLAttributes; - caption: HTMLAttributes; - cite: HTMLAttributes; - code: HTMLAttributes; - col: HTMLAttributes; - colgroup: HTMLAttributes; - data: HTMLAttributes; - datalist: HTMLAttributes; - dd: HTMLAttributes; - del: HTMLAttributes; - details: HTMLAttributes; - dfn: HTMLAttributes; - dialog: HTMLAttributes; - div: HTMLAttributes; - dl: HTMLAttributes; - dt: HTMLAttributes; - em: HTMLAttributes; - embed: HTMLAttributes; - fieldset: HTMLAttributes; - figcaption: HTMLAttributes; - figure: HTMLAttributes; - footer: HTMLAttributes; - form: HTMLAttributes; - h1: HTMLAttributes; - h2: HTMLAttributes; - h3: HTMLAttributes; - h4: HTMLAttributes; - h5: HTMLAttributes; - h6: HTMLAttributes; - head: HTMLAttributes; - header: HTMLAttributes; - hgroup: HTMLAttributes; - hr: HTMLAttributes; - html: HTMLAttributes; - i: HTMLAttributes; - iframe: HTMLAttributes; - img: HTMLAttributes; - input: HTMLAttributes; - ins: HTMLAttributes; - kbd: HTMLAttributes; - keygen: HTMLAttributes; - label: HTMLAttributes; - legend: HTMLAttributes; - li: HTMLAttributes; - link: HTMLAttributes; - main: HTMLAttributes; - map: HTMLAttributes; - mark: HTMLAttributes; - marquee: HTMLAttributes; - menu: HTMLAttributes; - menuitem: HTMLAttributes; - meta: HTMLAttributes; - meter: HTMLAttributes; - nav: HTMLAttributes; - noscript: HTMLAttributes; - object: HTMLAttributes; - ol: HTMLAttributes; - optgroup: HTMLAttributes; - option: HTMLAttributes; - output: HTMLAttributes; - p: HTMLAttributes; - param: HTMLAttributes; - picture: HTMLAttributes; - pre: HTMLAttributes; - progress: HTMLAttributes; - q: HTMLAttributes; - rp: HTMLAttributes; - rt: HTMLAttributes; - ruby: HTMLAttributes; - s: HTMLAttributes; - samp: HTMLAttributes; - script: HTMLAttributes; - section: HTMLAttributes; - select: HTMLAttributes; - slot: HTMLAttributes; - small: HTMLAttributes; - source: HTMLAttributes; - span: HTMLAttributes; - strong: HTMLAttributes; - style: HTMLAttributes; - sub: HTMLAttributes; - summary: HTMLAttributes; - sup: HTMLAttributes; - table: HTMLAttributes; - tbody: HTMLAttributes; - td: HTMLAttributes; - textarea: HTMLAttributes; - tfoot: HTMLAttributes; - th: HTMLAttributes; - thead: HTMLAttributes; - time: HTMLAttributes; - title: HTMLAttributes; - tr: HTMLAttributes; - track: HTMLAttributes; - u: HTMLAttributes; - ul: HTMLAttributes; - var: HTMLAttributes; - video: HTMLAttributes; - wbr: HTMLAttributes; +declare global { + namespace JSX { + type Element = HTMLElement; + type IntrinsicElements = { + a: HTMLAttributes; + abbr: HTMLAttributes; + address: HTMLAttributes; + area: HTMLAttributes; + article: HTMLAttributes; + aside: HTMLAttributes; + audio: HTMLAttributes; + b: HTMLAttributes; + base: HTMLAttributes; + bdi: HTMLAttributes; + bdo: HTMLAttributes; + big: HTMLAttributes; + blockquote: HTMLAttributes; + body: HTMLAttributes; + br: HTMLAttributes; + button: HTMLAttributes; + canvas: HTMLAttributes; + caption: HTMLAttributes; + cite: HTMLAttributes; + code: HTMLAttributes; + col: HTMLAttributes; + colgroup: HTMLAttributes; + data: HTMLAttributes; + datalist: HTMLAttributes; + dd: HTMLAttributes; + del: HTMLAttributes; + details: HTMLAttributes; + dfn: HTMLAttributes; + dialog: HTMLAttributes; + div: HTMLAttributes; + dl: HTMLAttributes; + dt: HTMLAttributes; + em: HTMLAttributes; + embed: HTMLAttributes; + fieldset: HTMLAttributes; + figcaption: HTMLAttributes; + figure: HTMLAttributes; + footer: HTMLAttributes; + form: HTMLAttributes; + h1: HTMLAttributes; + h2: HTMLAttributes; + h3: HTMLAttributes; + h4: HTMLAttributes; + h5: HTMLAttributes; + h6: HTMLAttributes; + head: HTMLAttributes; + header: HTMLAttributes; + hgroup: HTMLAttributes; + hr: HTMLAttributes; + html: HTMLAttributes; + i: HTMLAttributes; + iframe: HTMLAttributes; + img: HTMLAttributes; + input: HTMLAttributes; + ins: HTMLAttributes; + kbd: HTMLAttributes; + keygen: HTMLAttributes; + label: HTMLAttributes; + legend: HTMLAttributes; + li: HTMLAttributes; + link: HTMLAttributes; + main: HTMLAttributes; + map: HTMLAttributes; + mark: HTMLAttributes; + marquee: HTMLAttributes; + menu: HTMLAttributes; + menuitem: HTMLAttributes; + meta: HTMLAttributes; + meter: HTMLAttributes; + nav: HTMLAttributes; + noscript: HTMLAttributes; + object: HTMLAttributes; + ol: HTMLAttributes; + optgroup: HTMLAttributes; + option: HTMLAttributes; + output: HTMLAttributes; + p: HTMLAttributes; + param: HTMLAttributes; + picture: HTMLAttributes; + pre: HTMLAttributes; + progress: HTMLAttributes; + q: HTMLAttributes; + rp: HTMLAttributes; + rt: HTMLAttributes; + ruby: HTMLAttributes; + s: HTMLAttributes; + samp: HTMLAttributes; + script: HTMLAttributes; + section: HTMLAttributes; + select: HTMLAttributes; + slot: HTMLAttributes; + small: HTMLAttributes; + source: HTMLAttributes; + span: HTMLAttributes; + strong: HTMLAttributes; + style: HTMLAttributes; + sub: HTMLAttributes; + summary: HTMLAttributes; + sup: HTMLAttributes; + table: HTMLAttributes; + tbody: HTMLAttributes; + td: HTMLAttributes; + textarea: HTMLAttributes; + tfoot: HTMLAttributes; + th: HTMLAttributes; + thead: HTMLAttributes; + time: HTMLAttributes; + title: HTMLAttributes; + tr: HTMLAttributes; + track: HTMLAttributes; + u: HTMLAttributes; + ul: HTMLAttributes; + var: HTMLAttributes; + video: HTMLAttributes; + wbr: HTMLAttributes; + }; + } } diff --git a/src/utils.ts b/src/utils.ts index 78bd64f..c8ff29b 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -35,7 +35,7 @@ export const walkDir = async function* ( * @param modName Name of the module to purge from the require cache. */ export const purgeModuleAndDepsFromCache = (modName: string): void => { - var modPath = require.resolve(modName); + const modPath = require.resolve(modName); if (modPath == null) { return; } diff --git a/test/lib/expect.ts b/test/lib/expect.ts index 7fe091f..3744310 100644 --- a/test/lib/expect.ts +++ b/test/lib/expect.ts @@ -6,7 +6,7 @@ import { areEqual, displayValue, matches } from "./utils"; class ExpectError extends Error { - public constructor(reason: string, expected: any, actual: any) { + public constructor(reason: string, expected: unknown, actual: unknown) { super( `${reason}\n` + `\texpected: ${displayValue(expected)}\n` + @@ -45,7 +45,7 @@ export class Expect { * * @throws ExpectError If the actual value does not equal the expected value. */ - public toEqual(expected: T) { + public toEqual(expected: T): void { if (!areEqual(this.value, expected)) { throw new ExpectError( `value does not equal expected`, @@ -201,12 +201,12 @@ export function expect(fn: () => T): FunctionExpect; * * @param value Value to place expectations upon. */ -export function expect(value: any): Expect { +export function expect(value: unknown): Expect { if (typeof value === "string") { return new StringExpect(value); } if (typeof value === "function") { - return new FunctionExpect(value); + return new FunctionExpect(value as () => unknown); } return new Expect(value); } diff --git a/test/lib/utils.ts b/test/lib/utils.ts index 5827c8c..cdccd73 100644 --- a/test/lib/utils.ts +++ b/test/lib/utils.ts @@ -31,7 +31,10 @@ const areArraysEqual = (a: T[], b: T[]): boolean => { return true; }; -const areObjectsEqual = (a: T, b: T): boolean => { +const areObjectsEqual = >( + a: T, + b: T +): boolean => { const aKeys = Object.keys(a) as Array; const bKeys = Object.keys(b) as Array; if (aKeys.length !== bKeys.length) { @@ -62,7 +65,10 @@ export const areEqual = (a: T, b: T): boolean => { return a.source === b.source; } if (typeof a === "object" && typeof b === "object") { - return areObjectsEqual(a as any, b); + return areObjectsEqual( + a as Record, + b as Record + ); } return a === b; }; @@ -95,7 +101,7 @@ export const matches = (value: string, pattern: string | RegExp): boolean => { * * @return Rendered value to display. */ -export const displayValue = (value: any): string => { +export const displayValue = (value: unknown): string => { if (value === undefined) { return "undefined"; }