Type touchups (#122)

* Type touchups

* Fix some type handling
This commit is contained in:
Will Scullin 2022-06-01 06:28:05 -07:00 committed by GitHub
parent a3f3cfadb3
commit 3bbc77049d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 79 additions and 66 deletions

View File

@ -41,7 +41,7 @@ export const Apple2 = (props: Apple2Props) => {
const [apple2, setApple2] = useState<Apple2Impl>();
const [io, setIO] = useState<Apple2IO>();
const [cpu, setCPU] = useState<CPU6502>();
const [error, setError] = useState<string>();
const [error, setError] = useState<unknown>();
useEffect(() => {
if (screen.current) {
@ -59,13 +59,7 @@ export const Apple2 = (props: Apple2Props) => {
setCPU(cpu);
apple2.reset();
apple2.run();
}).catch((e) => {
if (e instanceof Error) {
setError(e.message);
} else {
console.error(e);
}
});
}).catch((e) => setError(e));
}
}, [props]);

View File

@ -40,19 +40,11 @@ export interface DiskIIProps extends DiskIIData {
export const DiskII = ({ disk2, number, on, name, side }: DiskIIProps) => {
const label = side ? `${name} - ${side}` : name;
const [modalOpen, setModalOpen] = useState(false);
const [error, setError] = useState<string>();
const [error, setError] = useState<unknown>();
const [currentHash, setCurrentHash] = useState<string>();
const hash = useHash();
const handleError = (e: unknown) => {
if (e instanceof Error) {
setError(e.message);
} else {
console.error(e);
}
};
useEffect(() => {
const hashParts = getHashParts(hash);
const newHash = hashParts[number];
@ -61,11 +53,11 @@ export const DiskII = ({ disk2, number, on, name, side }: DiskIIProps) => {
if (hashPart !== currentHash) {
if (hashPart.match(/^https?:/)) {
loadHttpFile(disk2, number, hashPart)
.catch((e) => handleError(e));
.catch((e) => setError(e));
} else {
const filename = `/json/disks/${hashPart}.json`;
loadJSON(disk2, number, filename)
.catch((e) => handleError(e));
.catch((e) => setError(e));
}
setCurrentHash(hashPart);
}

View File

@ -1,34 +1,45 @@
import { h, Fragment } from 'preact';
import { h } from 'preact';
import { useCallback } from 'preact/hooks';
import { Modal, ModalContent, ModalFooter } from './Modal';
export interface ErrorProps {
error: string | undefined;
error: unknown | undefined;
setError: (error: string | undefined) => void;
}
export const ErrorModal = ({ error, setError } : ErrorProps) => {
export const ErrorModal = ({ error, setError }: ErrorProps) => {
const onClose = useCallback(() => setError(undefined), [setError]);
let errorStr = null;
if (error) {
if (error instanceof Error) {
errorStr = error.message;
} else if (typeof error === 'string') {
errorStr = error;
} else {
errorStr = 'Unknown Error';
console.error(error);
}
}
return (
<>
{ error && (
<Modal
title="Error"
icon="triangle-exclamation"
isOpen={true}
onClose={onClose}
>
<ModalContent>
<div style={{ width: 320, fontSize: '1.1em', padding: '5px 11px'}}>
{error}
</div>
</ModalContent>
<ModalFooter>
<button onClick={onClose}>OK</button>
</ModalFooter>
</Modal>
)}
</>
);
if (errorStr) {
return (
<Modal
title="Error"
icon="triangle-exclamation"
isOpen={true}
onClose={onClose}
>
<ModalContent>
<div style={{ width: 320, fontSize: '1.1em', padding: '5px 11px' }}>
{errorStr}
</div>
</ModalContent>
<ModalFooter>
<button onClick={onClose}>OK</button>
</ModalFooter>
</Modal>
);
} else {
return null;
}
};

View File

@ -52,7 +52,7 @@ export const FileModal = ({ disk2, number, onClose, isOpen }: FileModalProps) =>
const [category, setCategory] = useState<string>();
const [handles, setHandles] = useState<FileSystemFileHandleLike[]>();
const [filename, setFilename] = useState<string>();
const [error, setError] = useState<string>();
const [error, setError] = useState<unknown>();
const hash = useHash();
const doCancel = useCallback(() => onClose(true), [onClose]);
@ -72,11 +72,7 @@ export const FileModal = ({ disk2, number, onClose, isOpen }: FileModalProps) =>
await loadJSON(disk2, number, filename);
}
} catch (e) {
if (e instanceof Error) {
setError(e.message);
} else {
console.error(e);
}
setError(e);
} finally {
setHashParts(hashParts);
setBusy(false);

View File

@ -19,10 +19,10 @@ const WOZ_INTEGRITY_CHECK = 0x0a0d0aff;
* @returns ASCII string
*/
function stringFromBytes(data: DataView, start: number, end: number): string {
return String.fromCharCode.apply(
null,
new Uint8Array(data.buffer.slice(data.byteOffset + start, data.byteOffset + end))
) as string;
const byteArray = new Uint8Array(
data.buffer.slice(data.byteOffset + start, data.byteOffset + end)
);
return String.fromCharCode(...byteArray);
}
export class InfoChunk {

View File

@ -622,7 +622,7 @@ function loadDisk(drive: DriveNumber, disk: JSONDisk) {
*/
function updateLocalStorage() {
const diskIndex = JSON.parse(window.localStorage.diskIndex as string || '{}') as LocalDiskIndex;
const diskIndex = JSON.parse(window.localStorage.getItem('diskIndex') || '{}') as LocalDiskIndex;
const names = Object.keys(diskIndex);
const cat: DiskDescriptor[] = disk_categories['Local Saves'] = [];
@ -654,12 +654,12 @@ type LocalDiskIndex = {
};
function saveLocalStorage(drive: DriveNumber, name: string) {
const diskIndex = JSON.parse(window.localStorage.diskIndex as string || '{}') as LocalDiskIndex;
const diskIndex = JSON.parse(window.localStorage.getItem('diskIndex') || '{}') as LocalDiskIndex;
const json = _disk2.getJSON(drive);
diskIndex[name] = json;
window.localStorage.diskIndex = JSON.stringify(diskIndex);
window.localStorage.setItem('diskIndex', JSON.stringify(diskIndex));
driveLights.label(drive, name);
driveLights.dirty(drive, false);
@ -667,17 +667,17 @@ function saveLocalStorage(drive: DriveNumber, name: string) {
}
function deleteLocalStorage(name: string) {
const diskIndex = JSON.parse(window.localStorage.diskIndex as string || '{}') as LocalDiskIndex;
const diskIndex = JSON.parse(window.localStorage.getItem('diskIndex') || '{}') as LocalDiskIndex;
if (diskIndex[name]) {
delete diskIndex[name];
openAlert('Deleted');
}
window.localStorage.diskIndex = JSON.stringify(diskIndex);
window.localStorage.setItem('diskIndex', JSON.stringify(diskIndex));
updateLocalStorage();
}
function loadLocalStorage(drive: DriveNumber, name: string) {
const diskIndex = JSON.parse(window.localStorage.diskIndex as string || '{}') as LocalDiskIndex;
const diskIndex = JSON.parse(window.localStorage.getItem('diskIndex') || '{}') as LocalDiskIndex;
if (diskIndex[name]) {
_disk2.setJSON(drive, diskIndex[name]);
driveLights.label(drive, name);
@ -887,11 +887,12 @@ function onLoaded(apple2: Apple2, disk2: DiskII, massStorage: MassStorage, print
keyboard.setFunction('F3', () => io.keyDown(0x1b)); // Escape
keyboard.setFunction('F4', optionsModal.openModal);
keyboard.setFunction('F6', () => {
window.localStorage.state = base64_json_stringify(_apple2.getState());
window.localStorage.setItem('state', base64_json_stringify(_apple2.getState()));
});
keyboard.setFunction('F9', () => {
if (window.localStorage.state) {
_apple2.setState(base64_json_parse(window.localStorage.state as string) as Apple2State);
const localState = window.localStorage.getItem('state');
if (localState) {
_apple2.setState(base64_json_parse(localState) as Apple2State);
}
});

View File

@ -9,7 +9,17 @@ describe('ErrorModal', () => {
it('renders when there is an error', () => {
const setError = jest.fn();
render(
<ErrorModal error="My Error" setError={setError} />
<ErrorModal error={new Error('My Error')} setError={setError} />
);
expect(screen.queryByRole('banner')).toBeVisible();
expect(screen.queryByRole('banner')).toHaveTextContent('Error');
expect(screen.queryByText('My Error')).toBeVisible();
});
it('renders when there is an error string', () => {
const setError = jest.fn();
render(
<ErrorModal error={'My Error'} setError={setError} />
);
expect(screen.queryByRole('banner')).toBeVisible();
expect(screen.queryByRole('banner')).toHaveTextContent('Error');
@ -18,11 +28,20 @@ describe('ErrorModal', () => {
it('does not render when there is not an error', () => {
const setError = jest.fn();
render(
const { container } = render(
<ErrorModal error={undefined} setError={setError} />
);
expect(screen.queryByRole('banner')).not.toBeInTheDocument();
expect(screen.queryByText('My Error')).not.toBeInTheDocument();
expect(container).toBeEmptyDOMElement();
});
it('handles an invalid error', () => {
jest.spyOn(console, 'error').mockImplementation();
const setError = jest.fn();
render(
<ErrorModal error={{foo: 'My Error'}} setError={setError} />
);
expect(screen.queryByText('Unknown Error')).toBeVisible();
expect(console.error).toHaveBeenCalledWith({foo: 'My Error'});
});
it('calls setError when close is clicked', () => {