Clean up web code errors and make CI enforce them

This commit is contained in:
Keavon Chambers 2024-09-24 01:15:14 -07:00
parent 14de67c5a7
commit 1ee5ffbbe8
18 changed files with 44 additions and 129 deletions

View file

@ -40,7 +40,7 @@ module.exports = {
}, },
{ {
extends: ["plugin:@typescript-eslint/disable-type-checked"], extends: ["plugin:@typescript-eslint/disable-type-checked"],
files: [".eslintrc.cjs"], files: ["./*.js", "./*.cjs"],
}, },
], ],
rules: { rules: {

View file

@ -30,7 +30,7 @@ if (isInstallNeeded()) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log("Finished installing npm packages."); console.log("Finished installing npm packages.");
} catch (error) { } catch (_) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.error("Failed to install npm packages. Please run `npm install` from the `/frontend` directory."); console.error("Failed to install npm packages. Please run `npm install` from the `/frontend` directory.");
process.exit(1); process.exit(1);

View file

@ -15,8 +15,8 @@
"build-profiling": "npm run wasm:build-profiling && vite build", "build-profiling": "npm run wasm:build-profiling && vite build",
"build": "npm run wasm:build-production && vite build", "build": "npm run wasm:build-production && vite build",
"---------- UTILITIES ----------": "", "---------- UTILITIES ----------": "",
"lint": "eslint .", "lint": "eslint . && tsc --noEmit",
"lint-fix": "eslint . --fix", "lint-fix": "eslint . --fix && tsc --noEmit",
"---------- INTERNAL ----------": "", "---------- INTERNAL ----------": "",
"setup": "node package-installer.js", "setup": "node package-installer.js",
"wasm:build-dev": "wasm-pack build ./wasm --dev --target=web", "wasm:build-dev": "wasm-pack build ./wasm --dev --target=web",
@ -30,7 +30,6 @@
"@tauri-apps/api": "^1.6.0", "@tauri-apps/api": "^1.6.0",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"idb-keyval": "^6.2.1", "idb-keyval": "^6.2.1",
"paper": "^0.12.18",
"reflect-metadata": "^0.2.2" "reflect-metadata": "^0.2.2"
}, },
"devDependencies": { "devDependencies": {

View file

@ -203,7 +203,7 @@
function setColorRGB(channel: keyof RGB, strength: number | undefined) { function setColorRGB(channel: keyof RGB, strength: number | undefined) {
// Do nothing if the given value is undefined // Do nothing if the given value is undefined
if (strength === undefined) undefined; if (strength === undefined) return undefined;
// Set the specified channel to the given value // Set the specified channel to the given value
else if (channel === "r") setColor(new Color(strength / 255, newColor.green, newColor.blue, newColor.alpha)); else if (channel === "r") setColor(new Color(strength / 255, newColor.green, newColor.blue, newColor.alpha));
else if (channel === "g") setColor(new Color(newColor.red, strength / 255, newColor.blue, newColor.alpha)); else if (channel === "g") setColor(new Color(newColor.red, strength / 255, newColor.blue, newColor.alpha));
@ -212,7 +212,7 @@
function setColorHSV(channel: keyof HSV, strength: number | undefined) { function setColorHSV(channel: keyof HSV, strength: number | undefined) {
// Do nothing if the given value is undefined // Do nothing if the given value is undefined
if (strength === undefined) undefined; if (strength === undefined) return undefined;
// Set the specified channel to the given value // Set the specified channel to the given value
else if (channel === "h") hue = strength / 360; else if (channel === "h") hue = strength / 360;
else if (channel === "s") saturation = strength / 100; else if (channel === "s") saturation = strength / 100;

View file

@ -219,7 +219,7 @@
childReference.open = true; childReference.open = true;
// The reason we bother taking `highlightdEntry` as an argument is because, when this function is called, it can ensure `highlightedEntry` is not undefined. // The reason we bother taking `highlightdEntry` as an argument is because, when this function is called, it can ensure `highlightedEntry` is not undefined.
// But here we still have to set `highlighted` to itself so Svelte knows to reactively update it after we set its `.ref.open` property. // But here we still have to set `highlighted` to itself so Svelte knows to reactively update it after we set its `childReference.open` property.
highlighted = highlighted; highlighted = highlighted;
// Highlight first item // Highlight first item
@ -452,11 +452,11 @@
{#if entry.children} {#if entry.children}
<MenuList <MenuList
on:naturalWidth={() => { on:naturalWidth={({ detail }) => {
// We do a manual dispatch here instead of just `on:naturalWidth` as a workaround for the <script> tag // We do a manual dispatch here instead of just `on:naturalWidth` as a workaround for the <script> tag
// at the top of this file displaying a "'render' implicitly has return type 'any' because..." error. // at the top of this file displaying a "'render' implicitly has return type 'any' because..." error.
// See explanation at <https://github.com/sveltejs/language-tools/issues/452#issuecomment-723148184>. // See explanation at <https://github.com/sveltejs/language-tools/issues/452#issuecomment-723148184>.
dispatch("naturalWidth"); dispatch("naturalWidth", detail);
}} }}
open={getChildReference(entry)?.open || false} open={getChildReference(entry)?.open || false}
direction="TopRight" direction="TopRight"

View file

@ -178,10 +178,10 @@
const { nodeOutput, nodeInput } = resolveWire(wire); const { nodeOutput, nodeInput } = resolveWire(wire);
if (!nodeOutput || !nodeInput) return []; if (!nodeOutput || !nodeInput) return [];
const wireStartNode = $nodeGraph.nodes.get((wire.wireStart as Node).nodeId); const wireStartNode = wire.wireStart.nodeId !== undefined ? $nodeGraph.nodes.get(wire.wireStart.nodeId) : undefined;
const wireStart = wireStartNode?.isLayer || false; const wireStart = wireStartNode?.isLayer || false;
const wireEndNode = $nodeGraph.nodes.get((wire.wireEnd as Node).nodeId); const wireEndNode = wire.wireEnd.nodeId !== undefined ? $nodeGraph.nodes.get(wire.wireEnd.nodeId) : undefined;
const wireEnd = (wireEndNode?.isLayer && Number(wire.wireEnd.index) === 0) || false; const wireEnd = (wireEndNode?.isLayer && Number(wire.wireEnd.index) === 0) || false;
return [createWirePath(nodeOutput, nodeInput, wireStart, wireEnd, wire.dashed)]; return [createWirePath(nodeOutput, nodeInput, wireStart, wireEnd, wire.dashed)];

View file

@ -42,11 +42,8 @@
(e.target as HTMLElement | undefined)?.focus(); (e.target as HTMLElement | undefined)?.focus();
// Open the menu list floating menu // Open the menu list floating menu
if (self) { if (self) self.open = true;
self.open = true; else throw new Error("The menu bar floating menu has no reference to `self`");
} else {
throw new Error("The menu bar floating menu has no associated ref");
}
} }
</script> </script>

View file

@ -48,7 +48,7 @@
activeEntrySkipWatcher = false; activeEntrySkipWatcher = false;
} else if (activeEntry !== DASH_ENTRY) { } else if (activeEntry !== DASH_ENTRY) {
// We need to set to the initial value first to track a right history step, as if we hover in initial selection. // We need to set to the initial value first to track a right history step, as if we hover in initial selection.
dispatch("hoverInEntry", initialSelectedIndex); if (initialSelectedIndex !== undefined) dispatch("hoverInEntry", initialSelectedIndex);
dispatch("selectedIndex", entries.flat().indexOf(activeEntry)); dispatch("selectedIndex", entries.flat().indexOf(activeEntry));
} }
} }
@ -58,7 +58,7 @@
} }
function dispatchHoverOutEntry() { function dispatchHoverOutEntry() {
dispatch("hoverOutEntry", initialSelectedIndex); if (initialSelectedIndex !== undefined) dispatch("hoverOutEntry", initialSelectedIndex);
} }
function makeActiveEntry(): MenuListEntry { function makeActiveEntry(): MenuListEntry {

View file

@ -14,7 +14,7 @@
const pointerPosition = (direction: ScrollbarDirection, e: PointerEvent): number => (direction === "Vertical" ? e.clientY : e.clientX); const pointerPosition = (direction: ScrollbarDirection, e: PointerEvent): number => (direction === "Vertical" ? e.clientY : e.clientX);
const dispatch = createEventDispatcher<{ handlePosition: number; pressTrack: number; pointerup }>(); const dispatch = createEventDispatcher<{ handlePosition: number; pressTrack: number; pointerup: undefined }>();
export let direction: ScrollbarDirection = "Vertical"; export let direction: ScrollbarDirection = "Vertical";
export let handlePosition = 0.5; export let handlePosition = 0.5;

View file

@ -59,10 +59,9 @@
// New fields in `MenuListEntry` // New fields in `MenuListEntry`
shortcutRequiresLock: entry.shortcut ? shortcutRequiresLock(entry.shortcut.keys) : undefined, shortcutRequiresLock: entry.shortcut ? shortcutRequiresLock(entry.shortcut.keys) : undefined,
value: undefined, value: "",
disabled: entry.disabled ?? undefined, disabled: entry.disabled ?? undefined,
font: undefined, font: undefined,
ref: undefined,
}); });
entries = updateMenuBarLayout.layout.map(menuBarEntryToMenuListEntry); entries = updateMenuBarLayout.layout.map(menuBarEntryToMenuListEntry);

View file

@ -1,26 +0,0 @@
import paper from "paper/dist/paper-core";
// Required setup to be used headlessly
paper.setup(new paper.Size(1, 1));
paper.view.autoUpdate = false;
export function booleanUnion(path1: string, path2: string): string {
return booleanOperation(path1, path2, "unite");
}
export function booleanSubtract(path1: string, path2: string): string {
return booleanOperation(path1, path2, "subtract");
}
export function booleanIntersect(path1: string, path2: string): string {
return booleanOperation(path1, path2, "intersect");
}
function booleanOperation(path1: string, path2: string, operation: "unite" | "subtract" | "intersect"): string {
const paperPath1 = new paper.CompoundPath(path1);
const paperPath2 = new paper.CompoundPath(path2);
const result = paperPath1[operation](paperPath2);
paperPath1.remove();
paperPath2.remove();
return result.pathData;
}

View file

@ -12,31 +12,12 @@ export class JsMessage {
} }
const TupleToVec2 = Transform(({ value }: { value: [number, number] | undefined }) => (value === undefined ? undefined : { x: value[0], y: value[1] })); const TupleToVec2 = Transform(({ value }: { value: [number, number] | undefined }) => (value === undefined ? undefined : { x: value[0], y: value[1] }));
const ImportsToVec2Array = Transform(({ obj }) => { const ImportsToVec2Array = Transform(({ obj: { imports } }: { obj: { imports: [FrontendGraphOutput, number, number][] } }) =>
const imports: { outputMetadata: FrontendGraphOutput; position: XY }[] = []; imports.map(([outputMetadata, x, y]) => ({ outputMetadata, position: { x, y } })),
obj.imports.forEach(([outputMetadata, x, y]: [FrontendGraphOutput, number, number]) => { );
outputMetadata.connectedTo = outputMetadata.connectedTo.map((connector: any) => { const ExportsToVec2Array = Transform(({ obj: { exports } }: { obj: { exports: [FrontendGraphInput, number, number][] } }) =>
if (connector.export !== undefined) return { index: connector.export.index }; exports.map(([inputMetadata, x, y]) => ({ inputMetadata, position: { x, y } })),
return { nodeId: connector.node.nodeId, index: connector.node.inputIndex }; );
});
imports.push({ outputMetadata, position: { x, y } });
});
return imports;
});
const ExportsToVec2Array = Transform(({ obj }) => {
const exports: { inputMetadata: FrontendGraphInput; position: XY }[] = [];
obj.exports.forEach(([inputMetadata, x, y]: [FrontendGraphInput, number, number]) => {
if (inputMetadata.connectedTo !== undefined) {
if (inputMetadata.connectedTo?.import !== undefined) {
inputMetadata.connectedTo = { index: inputMetadata.connectedTo?.import.index };
} else {
inputMetadata.connectedTo = { nodeId: inputMetadata.connectedTo?.node.nodeId, index: inputMetadata.connectedTo?.node.outputIndex };
}
}
exports.push({ inputMetadata, position: { x, y } });
});
return exports;
});
// const BigIntTupleToVec2 = Transform(({ value }: { value: [bigint, bigint] | undefined }) => (value === undefined ? undefined : { x: Number(value[0]), y: Number(value[1]) })); // const BigIntTupleToVec2 = Transform(({ value }: { value: [bigint, bigint] | undefined }) => (value === undefined ? undefined : { x: Number(value[0]), y: Number(value[1]) }));
@ -187,22 +168,11 @@ export type ContextMenuInformation = {
export type FrontendGraphDataType = "General" | "Raster" | "VectorData" | "Number" | "Graphic" | "Artboard"; export type FrontendGraphDataType = "General" | "Raster" | "VectorData" | "Number" | "Graphic" | "Artboard";
export class Node { export class Node {
readonly nodeId!: bigint;
readonly index!: bigint; readonly index!: bigint;
// Omitted if this Node is an Import or Export to/from the node network
readonly nodeId?: bigint;
} }
export class Export {
readonly index!: bigint;
}
export class Import {
readonly index!: bigint;
}
export type OutputConnector = Node | Import;
export type InputConnector = Node | Export;
const CreateOutputConnectorOptional = Transform(({ obj }) => { const CreateOutputConnectorOptional = Transform(({ obj }) => {
if (obj.connectedTo == undefined) { if (obj.connectedTo == undefined) {
return undefined; return undefined;
@ -228,11 +198,11 @@ export class FrontendGraphInput {
readonly resolvedType!: string | undefined; readonly resolvedType!: string | undefined;
@CreateOutputConnectorOptional @CreateOutputConnectorOptional
connectedTo!: OutputConnector | undefined; connectedTo!: Node | undefined;
} }
const CreateInputConnectorArray = Transform(({ obj }) => { const CreateInputConnectorArray = Transform(({ obj }) => {
const newInputConnectors: InputConnector[] = []; const newInputConnectors: Node[] = [];
obj.connectedTo.forEach((connector: any) => { obj.connectedTo.forEach((connector: any) => {
if (connector.export !== undefined) { if (connector.export !== undefined) {
newInputConnectors.push({ index: connector.export }); newInputConnectors.push({ index: connector.export });
@ -257,7 +227,7 @@ export class FrontendGraphOutput {
readonly resolvedType!: string | undefined; readonly resolvedType!: string | undefined;
@CreateInputConnectorArray @CreateInputConnectorArray
readonly connectedTo!: InputConnector[]; connectedTo!: Node[];
} }
export class FrontendNode { export class FrontendNode {
@ -329,10 +299,10 @@ const CreateInputConnector = Transform(({ obj }) => {
export class FrontendNodeWire { export class FrontendNodeWire {
@CreateOutputConnector @CreateOutputConnector
readonly wireStart!: OutputConnector; readonly wireStart!: Node;
@CreateInputConnector @CreateInputConnector
readonly wireEnd!: InputConnector; readonly wireEnd!: Node;
readonly dashed!: boolean; readonly dashed!: boolean;
} }

View file

@ -1,10 +0,0 @@
// #![cfg(target_arch = "wasm32")]
// use wasm_bindgen_test::*;
// wasm_bindgen_test_configure!(run_in_browser);
// #[wasm_bindgen_test]
// fn pass() {
// assert_eq!(1 + 1, 2);
// }

View file

@ -12,12 +12,6 @@ module.exports = {
ecmaVersion: "latest", ecmaVersion: "latest",
project: "./tsconfig.json", project: "./tsconfig.json",
}, },
overrides: [
{
extends: ["plugin:@typescript-eslint/disable-type-checked"],
files: [".eslintrc.cjs"],
},
],
ignorePatterns: [ ignorePatterns: [
// Ignore generated directories // Ignore generated directories
"node_modules/", "node_modules/",
@ -28,6 +22,12 @@ module.exports = {
"!.*.js", "!.*.js",
"!.*.ts", "!.*.ts",
], ],
overrides: [
{
extends: ["plugin:@typescript-eslint/disable-type-checked"],
files: ["./*.js", "./*.cjs"],
},
],
rules: { rules: {
// Standard ESLint config (for ordinary JS syntax linting) // Standard ESLint config (for ordinary JS syntax linting)
indent: "off", indent: "off",

View file

@ -30,7 +30,7 @@ if (isInstallNeeded()) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log("Finished installing npm packages."); console.log("Finished installing npm packages.");
} catch (error) { } catch (_) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.error("Failed to install npm packages. Please run `npm install` from the `/frontend` directory."); console.error("Failed to install npm packages. Please run `npm install` from the `/frontend` directory.");
process.exit(1); process.exit(1);

View file

@ -13,8 +13,8 @@
"build-profiling": "npm run wasm:build-profiling && vite build", "build-profiling": "npm run wasm:build-profiling && vite build",
"build": "npm run wasm:build-production && vite build", "build": "npm run wasm:build-production && vite build",
"---------- UTILITIES ----------": "", "---------- UTILITIES ----------": "",
"lint": "eslint .", "lint": "eslint . && tsc --noEmit",
"lint-fix": "eslint . --fix", "lint-fix": "eslint . --fix && tsc --noEmit",
"---------- INTERNAL ----------": "", "---------- INTERNAL ----------": "",
"setup": "node package-installer.js", "setup": "node package-installer.js",
"wasm:build-dev": "wasm-pack build ./wasm --dev --target=web", "wasm:build-dev": "wasm-pack build ./wasm --dev --target=web",

View file

@ -12,27 +12,12 @@
"sourceMap": true, "sourceMap": true,
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {
"@/*": [ "@/*": ["src/*"]
"src/*"
]
}, },
"lib": [ "lib": ["esnext", "dom", "dom.iterable", "scripthost"]
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}, },
"include": [ "include": ["src/**/*.ts", "src/**/*.d.ts", "*.ts", "*.js", "*.cjs"],
"src/**/*.ts", "exclude": ["node_modules"],
"src/**/*.d.ts",
"*.ts",
"*.js",
"*.cjs"
],
"exclude": [
"node_modules"
],
"ts-node": { "ts-node": {
"compilerOptions": { "compilerOptions": {
"module": "commonjs", "module": "commonjs",

View file

@ -101,6 +101,7 @@
<footer> <footer>
<hr /> <hr />
<nav class="balance-text require-polyfill"> <nav class="balance-text require-polyfill">
<a href="https://github.com/GraphiteEditor/Graphite" class="link not-uppercase">GitHub</a>
<a href="/license" class="link not-uppercase">License</a> <a href="/license" class="link not-uppercase">License</a>
<a href="/logo" class="link not-uppercase">Logo</a> <a href="/logo" class="link not-uppercase">Logo</a>
<a href="/press" class="link not-uppercase">Press</a> <a href="/press" class="link not-uppercase">Press</a>