Skip to content

Conversation

@bhflm
Copy link
Contributor

@bhflm bhflm commented Jan 14, 2025

What
Current is a stab to refactor existing utils/errors.ts,

Why

In an effort to make the sdk more readable, this provides an enhancement for legibility of the current errors file, without the need of hardcoding existing/new errors and make it more extendable for future releases.

How

  • Separate onto a constants.ts to categorize different kind of errors types.
  • Create util functions to match error strings and avoid repetition of several if statements with string matching
  • Create custom error classes to manipulate errors differently, and separate them between Railgun Contract errors and General custom errors.
  • Adds tests for edge cases such as undefined, and ascii characters.

@bhflm bhflm requested review from emilbayes, mattgle and zy0n January 14, 2025 01:48

export const STRING_PREFIX_AFTER_UNICODE_REPLACEMENT = 'y %';

// eslint-disable-next-line no-useless-escape
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this really needed?

Comment on lines 5 to 10
const validAscii = (str: string) => {
return str.replace(
INVALID_ASCII_REGEX,
'',
);
};
Copy link
Contributor

@mattgle mattgle Jan 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const validAscii = (str: string) => {
return str.replace(
INVALID_ASCII_REGEX,
'',
);
};
const validAscii = (str: string) => str.replace(INVALID_ASCII_REGEX, '');

Copy link
Contributor

@mattgle mattgle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few comments, not really a MUST, but improvements IMO

const isRailgunError = (cause: Error): boolean => cause.message.toLowerCase().includes('railgunsmartwallet')

export const sanitizeError = (cause: Error): Error => {
if (isDefined(cause) && cause.message) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, since the "else" here is shorter, early return would make the logic easier to read, eg.

if (cause?.message == null) return new Error('Unknown error. Please try again.', { cause });

if (isRailgunError(cause)) { /* ... */ }

Another question is, do we even need to check if cause is defined and has a message property? The type here says it must be an Error, so we perhaps only need to check the message being defined

export const STRING_PREFIX_AFTER_UNICODE_REPLACEMENT = 'y %';

// eslint-disable-next-line no-useless-escape
export const INVALID_ASCII_REGEX = /[^A-Za-z 0-9 \.,\?""!@#\$%\^&\*\(\)-_=\+;:<>\/\\\|\}\{\[\]`~]*/g;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A neat little trick (that begs a comment), but all the printable ascii characters are in the range from (space) to ~ (tilde), so the regex can be compressed to: /[^ -~]+/g. Is this better? I think so (with a comment explaining what it is) since it ensures no printable ascii chars were missed, despite being more obscure knowledge, where a list like the above requires you to check that all symbols were included.

@@ -0,0 +1,92 @@
import { CustomErrorMapping } from "./types";

export const STRING_PREFIX_AFTER_UNICODE_REPLACEMENT = 'y %';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we know what this means? Looking at the usage, I don't understand how the name of the constant here makes sense (I know you just migrated it from what it historically was)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

given the case that we keep it, a different name would be better IMHO, SANITIZED_MESSAGE_SEPARATOR or similar

but now that I've mentioned, I think we could remove this and be shortened to something that looks like:

const errorMessage = sanitizeAscii(cause.message);

since we're already properly sanitizing ASCII, and we don't need that much string manipulation besides this right??

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah reading again I think either this string used to be placed somehow in the string or it's an artefact from something that emitted errors with that string, and someone replaced it. Anyhow, the purpose is unclear to me. Maybe @zy0n or @mattgle remember seeing this string in errors at some point?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no idea tbh, but @mesquka might know

import { STRING_PREFIX_AFTER_UNICODE_REPLACEMENT, RAILGUN_ERRORS, CUSTOM_ERRORS, INVALID_ASCII_REGEX } from './constants';
import { isDefined } from '../util';

const validAscii = (str: string) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that we are refactoring, perhaps we should give this a more fitting name, perhaps sanitizeAscii

export * from './compare';
export * from './fallback-provider';
export * from './error';
export * from './errors/error';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this is an "internal module" so changing the path is insignificant, but if something is importing the error formatter directly, this is a breaking change

@bhflm bhflm requested a review from emilbayes January 14, 2025 22:22
@bhflm bhflm requested a review from mattgle January 14, 2025 22:40

// Matches any characters that are NOT in the printable ASCII range (space to tilde)
// Printable ASCII characters are in the range of 32 (space) to 126 (tilde)
export const INVALID_ASCII_REGEX = /[^ -~]+/g;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking a bit more about this regex, we also remove LF (ie \n). It was not in the original regex, but I wonder if we actually would want to keep new lines. If so, we can add it to the range as \n

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets keep it as it was before then 👍🏼

export * from './compare';
export * from './fallback-provider';
export * from './error';
export * from './errors';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to call this error per my comment about a potential breaking change?

@mattgle
Copy link
Contributor

mattgle commented Mar 26, 2025

What should we do with this?
CC: @emilbayes @bhflm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants