From 88c01db932067280b4f9d02569e0871dfd46d94b Mon Sep 17 00:00:00 2001 From: valadaptive Date: Tue, 18 Jun 2024 04:02:11 -0400 Subject: [PATCH] Enable lints requiring typechecking --- .eslintrc.cjs | 3 ++- src/audio/audio-engine.ts | 4 ++-- src/audio/decode-adpcm.ts | 2 +- src/block.ts | 2 +- src/blocks.ts | 2 +- src/html/html.ts | 6 +++++- src/html/internal-element.ts | 3 ++- src/html/stage.ts | 2 +- src/interpreter/thread.ts | 4 ++-- src/loader.ts | 2 +- src/monitor.ts | 4 ++-- src/parser.ts | 12 ++++++------ src/project.ts | 6 ++++-- src/renderer/shader.ts | 4 ++-- src/renderer/silhouette.ts | 4 ++-- src/renderer/svg-skin.ts | 2 +- src/schema.ts | 5 +++-- 17 files changed, 38 insertions(+), 29 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index c0a6863..f072f47 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -5,7 +5,8 @@ module.exports = { ], extends: [ 'eslint:recommended', - 'plugin:@typescript-eslint/recommended' + 'plugin:@typescript-eslint/recommended', + 'plugin:@typescript-eslint/recommended-requiring-type-checking' ], env: { es6: true, diff --git a/src/audio/audio-engine.ts b/src/audio/audio-engine.ts index beed7cd..180af3e 100644 --- a/src/audio/audio-engine.ts +++ b/src/audio/audio-engine.ts @@ -44,11 +44,11 @@ export default class AudioEngine { // In case the audio context was suspended due to a lack of user interaction if (this.ctx.state === 'suspended') { - this.ctx.resume(); + void this.ctx.resume(); } if (this.microphoneRequestState.state === 'NotRequested') { - this.requestMicrophone(); + void this.requestMicrophone(); } if (this.microphoneRequestState.state !== 'Granted') { diff --git a/src/audio/decode-adpcm.ts b/src/audio/decode-adpcm.ts index 95b117c..c6f1b4a 100644 --- a/src/audio/decode-adpcm.ts +++ b/src/audio/decode-adpcm.ts @@ -17,7 +17,7 @@ let __deltaTable: number[] | null = null; const getDeltaTable = () => { if (__deltaTable) return __deltaTable; - const deltaTable = new Array(STEP_TABLE.length * INDEX_TABLE.length); + const deltaTable = new Array(STEP_TABLE.length * INDEX_TABLE.length); for (let stepIndex = 0; stepIndex < STEP_TABLE.length; stepIndex++) { const step = STEP_TABLE[stepIndex]; diff --git a/src/block.ts b/src/block.ts index 0cbdf4b..c0b61a3 100644 --- a/src/block.ts +++ b/src/block.ts @@ -133,7 +133,7 @@ export class BlockInput { diff --git a/src/blocks.ts b/src/blocks.ts index d656104..d2889ef 100644 --- a/src/blocks.ts +++ b/src/blocks.ts @@ -805,7 +805,7 @@ export const sound_play = new ProtoBlock({ const soundName = toString(ctx.evaluateFast(SOUND_MENU)); const sound = ctx.target.sprite.getSoundByName(soundName); if (!sound) return; - ctx.target.audio.play(sound); + void ctx.target.audio.play(sound); }, colorCategory: 'sound', }); diff --git a/src/html/html.ts b/src/html/html.ts index 118f8b0..0473cb2 100644 --- a/src/html/html.ts +++ b/src/html/html.ts @@ -56,15 +56,19 @@ export default function h( for (const prop in props) { if (!Object.prototype.hasOwnProperty.call(props, prop)) continue; - // eslint-disable-next-line @typescript-eslint/no-explicit-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment const value = props[prop as keyof typeof props] as any; if (prop.startsWith('$')) { if (typeof value === 'function') { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument element.addEventListener(prop.slice(2), value); } else { + // eslint-disable-next-line @stylistic/max-len + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access element.addEventListener(prop.slice(2), value.listener, value.options); } } else { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment element[prop as keyof HTMLElementTagNameMap[Tag]] = value; } } diff --git a/src/html/internal-element.ts b/src/html/internal-element.ts index d2292a7..310e29b 100644 --- a/src/html/internal-element.ts +++ b/src/html/internal-element.ts @@ -22,7 +22,8 @@ export const defineInternalElement = (constructorFn: n customElements.define(tagName, constructorFn); return { tagName, - // eslint-disable-next-line @typescript-eslint/no-explicit-any + // eslint-disable-next-line @stylistic/max-len + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-argument h: ((...args: any[]) => h(tagName, ...args)) as any, create: () => document.createElement(tagName) as Elem, }; diff --git a/src/html/stage.ts b/src/html/stage.ts index e0007d4..78fa36c 100644 --- a/src/html/stage.ts +++ b/src/html/stage.ts @@ -60,7 +60,7 @@ export class InternalStageElement extends HTMLElement { } createMonitorView(): MonitorElement { - const elem = internalMonitor.h({className: 'monitor'}) as MonitorElement; + const elem = internalMonitor.h({className: 'monitor'}); elem.style.position = 'absolute'; this.monitorContainer.append(elem); return elem; diff --git a/src/interpreter/thread.ts b/src/interpreter/thread.ts index 7a01d05..738cd57 100644 --- a/src/interpreter/thread.ts +++ b/src/interpreter/thread.ts @@ -221,12 +221,12 @@ export default class Thread { // We handle promises by parking the thread and resuming it when the promise resolves. We then pass // the resolved value of the promise back into the generator function. - value.then(resolved => { + void value.then(resolved => { // If the thread has been stopped or restarted, we're working with stale state and shouldn't do // anything. if (this.generation !== generation || this.status !== ThreadStatus.PARKED) return; // On the next iteration of step(), this.resolvedValue will be passed back into the generator. - this.resolvedValue = resolved; + this.resolvedValue = resolved as string | number | boolean | void; this.resume(); }); } else if (value === PARK_THREAD) { diff --git a/src/loader.ts b/src/loader.ts index c2135d7..a381e42 100644 --- a/src/loader.ts +++ b/src/loader.ts @@ -19,7 +19,7 @@ export abstract class Loader { async loadAsset(filename: string, contentType: string): Promise { if (this.signal?.aborted) { - throw new Error(this.signal.reason ?? 'The operation was aborted'); + throw new Error(this.signal.reason ? String(this.signal.reason) : 'The operation was aborted'); } const assetKey = `${filename}_${contentType}`; const cachedAsset = this.assetCache.get(assetKey); diff --git a/src/monitor.ts b/src/monitor.ts index 30fa812..f37a711 100644 --- a/src/monitor.ts +++ b/src/monitor.ts @@ -163,7 +163,7 @@ export class ListMonitor extends BaseMonitor<(string | number | boolean)[]> { } get value() { - return this._value as (string | number | boolean)[]; + return this._value; } setValue(value: (string | number | boolean)[]) { @@ -196,7 +196,7 @@ export const listMonitorContents = new ProtoBlock({ execute: function* ({LIST}, ctx) { // TODO: remove this once there's some strict return type validation and blocks can return arbitrary types. // This is fine for now because this block will never be executed outside "update monitor" threads. - // eslint-disable-next-line @typescript-eslint/no-explicit-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return return ctx.lookupOrCreateList(LIST.value) as any; }, monitorLabel: ({LIST}) => LIST.value, diff --git a/src/parser.ts b/src/parser.ts index c30e22c..a25acb5 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -547,9 +547,9 @@ const parseCustomBlockPrototype = ( throw new Error(`Invalid mutation: ${JSON.stringify(mutation)}`); } - const argumentids = JSON.parse(mutation.argumentids); - const argumentnames = JSON.parse(mutation.argumentnames); - const argumentdefaults = JSON.parse(mutation.argumentdefaults); + const argumentids = JSON.parse(mutation.argumentids) as unknown; + const argumentnames = JSON.parse(mutation.argumentnames) as unknown; + const argumentdefaults = JSON.parse(mutation.argumentdefaults) as unknown; if (!validateJson(arrayStringSchema, argumentids)) { throw new Error(`Invalid argumentids: ${JSON.stringify(mutation.argumentids)}`); @@ -586,7 +586,7 @@ const parseCustomBlockDefinition = ( allBlocks.procedures_definition as unknown as ProtoBlock, EMPTY_MAP, ); - return Object.assign(customBlockDefinition as unknown as CustomBlockStub, {jsonBlock, blockId}); + return Object.assign(customBlockDefinition as CustomBlockStub, {jsonBlock, blockId}); }; const parseScript = ( @@ -816,7 +816,7 @@ const parseMonitor = ( param = jsonMonitor.params[inputName]; } if (!input.validate(param)) { - throw new Error(`Monitor input ${inputName} has invalid value ${param}`); + throw new Error(`Monitor input ${inputName} has invalid value ${String(param)}`); } inputValues[inputName] = param; } @@ -846,7 +846,7 @@ const parseMonitor = ( inputValues, target, { - // eslint-disable-next-line @typescript-eslint/no-explicit-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment mode: mode as any, visible: jsonMonitor.visible, position: jsonMonitor.x !== undefined && jsonMonitor.y !== undefined ? diff --git a/src/project.ts b/src/project.ts index 0acfa21..1c65db5 100644 --- a/src/project.ts +++ b/src/project.ts @@ -251,9 +251,11 @@ export default class Project extends TypedEventTarget).value === - // eslint-disable-next-line @typescript-eslint/no-explicit-any + // eslint-disable-next-line @stylistic/max-len + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access (inputValues[key] as any).value : innerBlock.inputValues[key] === inputValues[key]; if (!inputsMatch) { diff --git a/src/renderer/shader.ts b/src/renderer/shader.ts index 828eeac..43417df 100644 --- a/src/renderer/shader.ts +++ b/src/renderer/shader.ts @@ -29,13 +29,13 @@ export default class Shader { this.attribLocations = {}; this.uniformLocations = {}; - const numAttribs = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES); + const numAttribs = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES) as number; for (let i = 0; i < numAttribs; i++) { const activeAttrib = gl.getActiveAttrib(program, i)!; this.attribLocations[activeAttrib.name] = gl.getAttribLocation(program, activeAttrib.name); } - const numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); + const numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS) as number; for (let i = 0; i < numUniforms; i++) { const activeUniform = gl.getActiveUniform(program, i)!; this.uniformLocations[activeUniform.name] = gl.getUniformLocation(program, activeUniform.name)!; diff --git a/src/renderer/silhouette.ts b/src/renderer/silhouette.ts index 47b4ca6..04f373f 100644 --- a/src/renderer/silhouette.ts +++ b/src/renderer/silhouette.ts @@ -11,8 +11,8 @@ export default class Silhouette { constructor(image: HTMLImageElement | ImageData, premultipliedAlpha: boolean) { this.sampleTexel = premultipliedAlpha ? - this.sampleTexelPremultiplied : - this.sampleTexelStraight; + this.sampleTexelPremultiplied.bind(this) : + this.sampleTexelStraight.bind(this); this.update(image); } diff --git a/src/renderer/svg-skin.ts b/src/renderer/svg-skin.ts index c3207f9..d38f231 100644 --- a/src/renderer/svg-skin.ts +++ b/src/renderer/svg-skin.ts @@ -20,7 +20,7 @@ export default class SVGSkin implements Skin { this.costume = costume; // Make sure drawToCanvas always draws something the first time it's called this.canvas.width = this.canvas.height = 0; - this.maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE); + this.maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE) as number; const texture = gl.createTexture(); if (!texture) { throw new Error('Failed to create texture'); diff --git a/src/schema.ts b/src/schema.ts index f0318a0..5d76dce 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -97,7 +97,7 @@ export const validateJson = (schema: S, json: unknown): json i return false; }; -/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return */ export const validateJsonOrError = ( schema: S, json: unknown, @@ -198,6 +198,7 @@ export const validateJsonOrError = ( } const obj: any = {}; for (const key of Object.keys(json)) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access obj[key] = validateJsonOrError(schema2.items, json[key as keyof typeof json], `${path}[${JSON.stringify(key)}]`); } return obj; @@ -205,4 +206,4 @@ export const validateJsonOrError = ( throw new Error(`Unhandled schema type ${(schema2 as any)}`); }; -/* eslint-enable @typescript-eslint/no-explicit-any */ +/* eslint-enable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return */