Skip to content

pr05 Typescript #3: Migrate client/utils folder #3553

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 54 commits into
base: develop
Choose a base branch
from

Conversation

clairep94
Copy link
Collaborator

@clairep94 clairep94 commented Jul 26, 2025

pr05 Typescript Migration 3: Migrate the client/utils folder

IMPORTANT: Should be reviewed after #3540 for clarity

Context:

  • Rebuild of Pr05/migrate client utils clairep94/p5.js-web-editor#5 --> forgot to do git mv for the first few files and directly renamed, so this looks like deleting and creating a new file for git, and erases the previous history.

  • Migrate as much of the client/utils folder with the following steps:

  1. git mv someUtil.js someUtil.ts. If possible, commit without the no-verify flag, otherwise with no-verify.
    I forgot to add no-verify to my commit message in some of these initial ones
  2. Add unit test to secure current behaviour
  3. Check for all instances of useage for the utility function to determine types & edgecases of types
  4. Add types & handle edgecases & update test
  5. Refactor if beneficial
  6. Add JSDocs
  • I skipped the intellisense autogen files & the codemirror utility files due to unfamiliarity, but migrated most of the rest of the folder

Changes:

Please see annotations on files

  • apiClient
  • device
  • metaKey
  • language-utils
  • formatDate
  • consoleUtils
  • dispatcher
  • evaluateExpression
  • reduxFormUtils
  • getConfig (+ many instances of useage throughout the client folder)
  • NEW: parseStringToType

Notes:

I have verified that this pull request:

  • has no linting errors (npm run lint)
  • has no test errors (npm run test)
  • is from a uniquely-named feature branch and is up to date with the develop branch.
  • is descriptively named and links to an issue number, i.e. Fixes #123

@khanniie khanniie requested a review from raclim August 1, 2025 16:14
Copy link
Collaborator

@khanniie khanniie left a comment

Choose a reason for hiding this comment

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

still working through the files but thought I'd sent a first wave!

@@ -15,7 +15,7 @@ import {
} from './ide';
import { clearState, saveState } from '../../../persistState';

const ROOT_URL = getConfig('API_URL');
const ROOT_URL = getConfig('API_URL', { nullishString: true });
Copy link
Collaborator

Choose a reason for hiding this comment

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

what do we think the "correct" or expected behavior would be if there was no API_URL? like is "/projects/${projectId}/zip" a valid ROOT_URL or would that cause a different error down the line? or in what cases is it undefined?

@@ -307,6 +307,8 @@ export function cloneProject(project) {
(file, callback) => {
if (
file.url &&
S3_BUCKET &&
S3_BUCKET_URL_BASE &&
Copy link
Collaborator

Choose a reason for hiding this comment

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

good call!!

} = {};
let frameIndex = 1;

/** Codesandbox dispatcher message types */
Copy link
Collaborator

Choose a reason for hiding this comment

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

wonder if we can just use typescript enums here instead?

enum MessageTypes = {
START,
STOP,
etc
}

*/
export type Message = {
type: MessageType,
payload?: any
Copy link
Collaborator

Choose a reason for hiding this comment

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

is there any way to use unknown instead of any ?

function eventListener(e: MessageEvent) {
const { data } = e;

// should also store origin of parent? idk
Copy link
Collaborator

Choose a reason for hiding this comment

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

i assume this is leftover from the js file but should we remove the dead code comments?

function __makeEvaluateExpression(evalInClosure) {
return (expr) =>
type EvalResult = {
result: any,
Copy link
Collaborator

Choose a reason for hiding this comment

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

i haven't looked closely enough at where this is used, but is there any way to avoid using any here as well? can we do unknown and then cast it later after doing some type guard checks?

https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-differentiating-types

@@ -19,7 +26,11 @@ function evaluateExpression() {
}
result = (0, eval)(newExpr); // eslint-disable-line
Copy link
Collaborator

Choose a reason for hiding this comment

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

can we change this eslint disable to be more specific to what it's disabling?

return null;
}

export default {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not sure exactly how this is getting imported but i wonder if we can just export these individually instead of in a dict wrapped as one default? totally understand that it's a holdover from the js file though

Copy link
Collaborator

@khanniie khanniie left a comment

Choose a reason for hiding this comment

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

still working through the files but have a few more comments!

*/
function _getConfig(key: string): string | undefined {
const env: Record<string, string | undefined> =
(typeof global !== 'undefined' ? global : window)?.process?.env || {};
Copy link
Collaborator

Choose a reason for hiding this comment

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

why not do global !== undefined ?

Copy link
Collaborator

Choose a reason for hiding this comment

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

or even

const configSource = global ?? window;
const env = configSource?.process?.env ?? {}

return env[key];
}

type GetConfigOptions = {
Copy link
Collaborator

Choose a reason for hiding this comment

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

should this be an interface? maybe using optional?

https://google.github.io/styleguide/tsguide.html#prefer-optional-over-undefined

return value;
}

export default getConfig;
Copy link
Collaborator

Choose a reason for hiding this comment

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

same here can we convert to named export? https://google.github.io/styleguide/tsguide.html#exports

supportedLanguages: string[] = [],
defaultLanguage: string = 'en'
): string | undefined {
if (typeof navigator === 'undefined') {
Copy link
Collaborator

Choose a reason for hiding this comment

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

same here i think we should be able to do something like if (!navigator) return defaultLanguage

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Screenshot 2025-08-13 at 22 24 46

I tried updating to !navigator but it seemed to cause this error above whereas the typeof check seems to circumvent this

Copy link
Collaborator

@khanniie khanniie Aug 13, 2025

Choose a reason for hiding this comment

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

i actually wonder if they're right that we should be using jsdom as the test environment? it makes sense that navigator is a window element in the browser only and thus would be undefined in the default jest testing env : O if that's too high lift though i don't mind switching back. i guess tldr i think the more "correct" solution is to switch the test env to jsdom but typeof seems like a fair hack around it

return defaultLanguage;
}

export default getPreferredLanguage;
Copy link
Collaborator

Choose a reason for hiding this comment

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

can we put the default export on the function itself here too?

Copy link
Collaborator

Choose a reason for hiding this comment

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

or even better... maybe we can make it a named export instead

https://google.github.io/styleguide/tsguide.html#exports

@@ -0,0 +1,156 @@
import i18n from 'i18next';

/* eslint-disable */
Copy link
Collaborator

Choose a reason for hiding this comment

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

what are we disabling here? can we be more specific about the rule?

/** Processes form & mutates errors to add any `username` & `email` errors */
function validateUsernameEmail(
formProps: Partial<UsernameAndEmail>,
errors: Partial<FormErrors>
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not sure i understand what happens when we do Partial<Partial<....>> do we need the double partial?


/** Validation for the Account Form */
export function validateSettings(
formProps: Partial<AccountForm>
Copy link
Collaborator

Choose a reason for hiding this comment

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

if AccountFormErrors is already Partial<AccountForm> then can we also just use it for formProps?

export type LoginFormErrors = Partial<LoginForm>;

/** Validation for the Login Form */
export function validateLogin(formProps: Partial<LoginForm>): LoginFormErrors {
Copy link
Collaborator

Choose a reason for hiding this comment

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

same here, why not reuse LoginFormErrors? or rename it to be more general?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pr05 Grant Projects pr05 Grant Projects
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants