Skip to content

Commit 05c8675

Browse files
chore: proper lint
2 parents 5e74d81 + 541f580 commit 05c8675

File tree

7 files changed

+63
-46
lines changed

7 files changed

+63
-46
lines changed

.eslintignore

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,7 @@ _site/
1212
_site-dev
1313
docs/_merged_assets/
1414
docs/_merged_data/
15-
docs/_merged_includes/
15+
docs/_merged_includes/
16+
**/tests/*
17+
*.js
18+
*.d.ts

.eslintrc.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@ module.exports = {
22
root: true,
33
parser: '@typescript-eslint/parser',
44
plugins: ['simple-import-sort', '@typescript-eslint'],
5-
extends: [ require.resolve('@open-wc/eslint-config'), require.resolve('eslint-config-prettier')],
5+
extends: [
6+
'eslint:recommended',
7+
'plugin:@typescript-eslint/eslint-recommended',
8+
'plugin:@typescript-eslint/recommended'
9+
],
610
rules: {
711
'lit/no-useless-template-literals': 'off',
812
'consistent-return': 'off',
9-
'max-classes-per-file': 'off'
13+
'max-classes-per-file': 'off',
14+
'no-prototype-builtins': 'off'
1015
}
1116
};

packages/form-control/src/FormControlMixin.ts

+22-20
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { IElementInternals } from 'element-internals-polyfill';
22
import { Constructor, FormControlInterface, FormValue, IControlHost, Validator } from './types';
33

4-
export function FormControlMixin<T extends Constructor<HTMLElement & IControlHost>>(SuperClass: T) {
4+
export function FormControlMixin<
5+
TBase extends Constructor<HTMLElement & IControlHost> & { observedAttributes: string[] }
6+
>(SuperClass: TBase) {
57
class FormControl extends SuperClass {
68
/** Wires up control instances to be form associated */
79
static get formAssociated() {
@@ -30,12 +32,11 @@ export function FormControlMixin<T extends Constructor<HTMLElement & IControlHos
3032
static get observedAttributes(): string[] {
3133
const validatorAttributes = this.validators.map((validator) => validator.attribute);
3234

33-
/** @ts-ignore This exits */
3435
const observedAttributes = super.observedAttributes || [];
3536

3637
/** Make sure there are no duplicates inside the attributes list */
3738
const attributeSet = new Set([...observedAttributes, ...validatorAttributes]);
38-
return [...attributeSet];
39+
return [...attributeSet] as string[];
3940
}
4041

4142
/**
@@ -130,6 +131,7 @@ export function FormControlMixin<T extends Constructor<HTMLElement & IControlHos
130131
return this.internals.validity;
131132
}
132133

134+
/* eslint-disable @typescript-eslint/no-explicit-any */
133135
constructor(...args: any[]) {
134136
super(...args);
135137
this.addEventListener('focus', this.#onFocus);
@@ -159,7 +161,9 @@ export function FormControlMixin<T extends Constructor<HTMLElement & IControlHos
159161
/** Initialize the form control and perform initial validation */
160162
this.#initFormControl();
161163
this.#validate(this.value);
162-
this.validationMessageCallback('');
164+
if (this.validationMessageCallback) {
165+
this.validationMessageCallback('');
166+
}
163167
}
164168

165169
disconnectedCallback() {
@@ -181,12 +185,6 @@ export function FormControlMixin<T extends Constructor<HTMLElement & IControlHos
181185
/** Closed over variable to track value changes */
182186
let value: FormValue = this.value || '';
183187

184-
/** Value getter reference within the closure */
185-
let set: ((v: FormValue) => void) | undefined;
186-
187-
/** Value setter reference within the closure */
188-
let get: ((v: FormValue) => void) | undefined;
189-
190188
/** Look to see if '`checked'` is on the control's prototype */
191189
const hasChecked = this.#isCheckedElement;
192190

@@ -210,15 +208,15 @@ export function FormControlMixin<T extends Constructor<HTMLElement & IControlHos
210208
}
211209

212210
/** Make sure to defer to the parent */
213-
set = descriptor && descriptor.set;
214-
get = descriptor && descriptor.get;
211+
const set = descriptor && descriptor.set;
212+
const get = descriptor && descriptor.get;
215213

216214
/** Define the FormControl's value property */
217215
Object.defineProperty(this, 'value', {
218216
get() {
219217
/** If a getter already exists, make sure to call it */
220218
if (get) {
221-
return get.call(this, null);
219+
return get.call(this);
222220
}
223221
return value;
224222
},
@@ -312,7 +310,7 @@ export function FormControlMixin<T extends Constructor<HTMLElement & IControlHos
312310
* in cases where `checked` is present upon initialization, this will be
313311
* effectively `this.checked && this.value`.
314312
*/
315-
valueChangedCallback(value: FormValue): void {}
313+
declare valueChangedCallback: (value: FormValue) => void;
316314

317315
/**
318316
* Resets a form control to its initial state
@@ -375,7 +373,9 @@ export function FormControlMixin<T extends Constructor<HTMLElement & IControlHos
375373
this.#forceError = true;
376374
}
377375
const showError = this.#shouldShowError();
378-
this.validationMessageCallback(showError ? this.validationMessage : '');
376+
if (this.validationMessageCallback) {
377+
this.validationMessageCallback(showError ? this.validationMessage : '');
378+
}
379379
};
380380

381381
/**
@@ -400,7 +400,9 @@ export function FormControlMixin<T extends Constructor<HTMLElement & IControlHos
400400
}
401401
this.#validate(value);
402402
const showError = this.#shouldShowError();
403-
this.validationMessageCallback(showError ? this.validationMessage : '');
403+
if (this.validationMessageCallback) {
404+
this.validationMessageCallback(showError ? this.validationMessage : '');
405+
}
404406
}
405407

406408
/**
@@ -443,7 +445,7 @@ export function FormControlMixin<T extends Constructor<HTMLElement & IControlHos
443445
* if a control has a ValidityCallback, it can override the error
444446
* message for a given validity key.
445447
*/
446-
if (this.validityCallback(key)) {
448+
if (this.validityCallback && this.validityCallback(key)) {
447449
messageResult = this.validityCallback(key) as string;
448450
} else if (message instanceof Function) {
449451
messageResult = message(this, value);
@@ -508,14 +510,14 @@ export function FormControlMixin<T extends Constructor<HTMLElement & IControlHos
508510
* The returned value will be used as the validationMessage for the given key.
509511
* @param validationKey {string} - The key that has returned invalid
510512
*/
511-
validityCallback(validationKey: string): string | void {}
513+
declare validityCallback: (validationKey: string) => string | void;
512514

513515
/**
514516
* Called when the control's validationMessage should be changed
515517
* @param message { string } - The new validation message
516518
*/
517-
validationMessageCallback(message: string): void {}
519+
declare validationMessageCallback: (message: string) => void;
518520
}
519521

520-
return FormControl as Constructor<FormControlInterface> & T;
522+
return FormControl as Constructor<FormControlInterface> & TBase;
521523
}

packages/form-control/src/types.ts

+8-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { IElementInternals } from 'element-internals-polyfill';
22

33
/** Generic constructor type */
4-
export type Constructor<T = {}> = new (...args: any[]) => T;
4+
/* eslint-disable @typescript-eslint/no-explicit-any */
5+
export type Constructor<T = Record<string, unknown>> = new (...args: any[]) => T;
56

67
/** Union type for form values */
78
export type FormValue = File|FormData|string|null;
@@ -10,7 +11,7 @@ export type FormValue = File|FormData|string|null;
1011
export interface FormControlInterface {
1112
checked?: boolean;
1213
validationTarget?: HTMLElement | null;
13-
value: any;
14+
value: FormValue;
1415
readonly form: HTMLFormElement;
1516
readonly internals: IElementInternals;
1617
readonly showError: boolean;
@@ -20,7 +21,7 @@ export interface FormControlInterface {
2021
checkValidity(): boolean;
2122
formResetCallback(): void;
2223
resetFormControl(): void;
23-
valueChangedCallback(value: any): void;
24+
valueChangedCallback(value: FormValue): void;
2425
validityCallback(validationKey: string): string | void;
2526
validationMessageCallback(message: string): void;
2627
}
@@ -64,22 +65,22 @@ export interface Validator {
6465
* ValidityState key as an argument and must return a validationMessage
6566
* for the given instance.
6667
*/
67-
message: string | ((instance: any, value: any) => string);
68+
message: string | ((instance: any, value: FormValue) => string);
6869

6970
/**
7071
* Callback for a given validator. Takes the FormControl instance
7172
* and the form control value as arguments and returns a
7273
* boolean to evaluate for that Validator.
7374
* @param instance {FormControlInterface} - The FormControl instance
74-
* @param value {any} - The form control value
75+
* @param value {FormValue} - The form control value
7576
* @returns {boolean} - The validity of a given Validator
7677
*/
77-
callback(instance: HTMLElement, value: any): boolean;
78+
callback(instance: HTMLElement, value: FormValue): boolean;
7879
}
7980

8081
/** Generic type to allow usage of HTMLElement lifecycle methods */
8182
export interface IControlHost {
82-
attributeChangedCallback?(name: string, oldValue: any, newValue: any): void;
83+
attributeChangedCallback?(name: string, oldValue: string, newValue: string): void;
8384
connectedCallback?(): void;
8485
disconnectedCallback?(): void;
8586
checked?: boolean;

packages/form-control/src/validators.ts

+15-8
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { Validator } from './index';
2-
import { FormControlInterface } from './types';
2+
import { FormControlInterface, FormValue } from './types';
33

44
export const requiredValidator: Validator = {
55
attribute: 'required',
66
key: 'valueMissing',
77
message: 'Please fill out this field',
8-
callback(instance: HTMLElement & { required: boolean }, value: any): boolean {
8+
callback(instance: HTMLElement & { required: boolean }, value: FormValue): boolean {
99
let valid = true;
1010

1111
if ((instance.hasAttribute('required') || instance.required) && !value) {
@@ -30,9 +30,10 @@ export const minLengthValidator: Validator = {
3030
attribute: 'minlength',
3131
key: 'rangeUnderflow',
3232
message(instance: FormControlInterface & { minLength: number }): string {
33-
return `Please use at least ${instance.minLength} characters (you are currently using ${instance.value.length} characters).`;
33+
const value = instance.value as string || '';
34+
return `Please use at least ${instance.minLength} characters (you are currently using ${value.length} characters).`;
3435
},
35-
callback(instance: HTMLElement & { minLength: number }, value): boolean {
36+
callback(instance: HTMLElement & { minLength: number }, value: string): boolean {
3637
/** If no value is provided, this validator should return true */
3738
if (!value) {
3839
return true;
@@ -49,10 +50,16 @@ export const minLengthValidator: Validator = {
4950
export const maxLengthValidator: Validator = {
5051
attribute: 'maxlength',
5152
key: 'rangeOverflow',
52-
message(instance: FormControlInterface & { maxLength: number }): string {
53-
return `Please use no more than ${instance.maxLength} characters (you are currently using ${instance.value.length} characters).`;
53+
message(
54+
instance: FormControlInterface & { maxLength: number }
55+
): string {
56+
const value = instance.value as string || '';
57+
return `Please use no more than ${instance.maxLength} characters (you are currently using ${value.length} characters).`;
5458
},
55-
callback(instance: HTMLElement & { maxLength: number }, value: any): boolean {
59+
callback(
60+
instance: HTMLElement & { maxLength: number },
61+
value: string
62+
): boolean {
5663
/** If maxLength isn't set, this is valid */
5764
if (!instance.maxLength) {
5865
return true;
@@ -70,7 +77,7 @@ export const patternValidator: Validator = {
7077
attribute: 'pattern',
7178
key: 'patternMismatch',
7279
message: 'Please match the requested format',
73-
callback(instance: HTMLElement & { pattern: string }, value): boolean {
80+
callback(instance: HTMLElement & { pattern: string }, value: string): boolean {
7481
/** If no value is provided, this validator should return true */
7582
if (!value || !instance.pattern) {
7683
return true;

packages/form-helpers/src/index.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@ export const formValues = (form: HTMLFormElement): Record<string, FormValue> =>
5858
* in declaratively in HTML.
5959
*
6060
* @param form {HTMLFormElement} - The form to grab values from
61-
* @returns {Object<any, any>} - An object representation of the form
61+
* @returns {Object<string, FormValue>} - An object representation of the form
6262
*/
6363
export const parseFormAsObject = (form: HTMLFormElement): Record<string, FormValue> => {
6464
const data = formValues(form);
65-
const output: Record<any, any> = {};
65+
const output: Record<string, FormValue> = {};
6666

6767
Object.entries(data).forEach(([key, value]) => {
6868
/** If the key has a '.', parse it as an object */
@@ -73,8 +73,8 @@ export const parseFormAsObject = (form: HTMLFormElement): Record<string, FormVal
7373

7474
while (path.length) {
7575
const key = path.shift();
76-
pointer[key as string] = pointer[key as string] || {};
77-
pointer = pointer[key as string];
76+
pointer[key as string] = pointer[key as string] || ({} as FormValue);
77+
pointer = pointer[key as string] as unknown as Record<string, FormValue>;
7878
}
7979

8080
pointer[destination as string] = value;

packages/form-helpers/tests/submit.test.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const submitCallbackPrevented = (event: Event) => {
77
event.preventDefault();
88
submitted = true;
99
};
10-
const submitCallback = (event: Event) => {
10+
const submitCallback = () => {
1111
submitted = true;
1212
};
1313

@@ -19,7 +19,7 @@ describe('The submit form helper', () => {
1919
form = await fixture<HTMLFormElement>(html`<form @submit="${submitCallback}">
2020
<input>
2121
</form>`);
22-
formSubmitStub = sinon.stub(form, 'submit').callsFake(() => {});
22+
formSubmitStub = sinon.stub(form, 'submit').callsFake(() => { return false; });
2323
submitted = false;
2424
});
2525

@@ -32,7 +32,6 @@ describe('The submit form helper', () => {
3232
submit(form);
3333
await aTimeout(0);
3434
expect(submitted).to.be.true;
35-
// form.submit() is called
3635
expect(formSubmitStub.callCount).to.equal(1);
3736
});
3837

@@ -56,7 +55,7 @@ describe('The submit form helper', () => {
5655
<input>
5756
</form>`);
5857

59-
formSubmitStub = sinon.stub(form, 'submit').callsFake(() => {});
58+
formSubmitStub = sinon.stub(form, 'submit').callsFake(() => { return false; });
6059

6160
submit(form);
6261

0 commit comments

Comments
 (0)