-
Notifications
You must be signed in to change notification settings - Fork 174
Description
Currently, the js-slang evaluation context is mutable. This is unfortunately stored in the Redux state, thereby violating both golden rules of Redux:
- State must be immutable; and
- State must only consist of simple objects/arrays/primitives
More importantly, as Redux slowly enforces more and more of its rules through things like Immer and Redux Toolkit, the auto-freezing behavior of Immer has led to a lot of things being broken for program evaluation.
Automatically freezing objects has been disabled using setAutoFreeze
in createStore.ts
, but Immer also prevents things like circular data structures, so it doesn't work for us.
Instead, we want to simply store a "reference" to the js-slang context in the Redux state. That way this reference can be a primitive and doesn't violate any Redux rules. Instead, whenever any part of our program wants to access the mutable js-slang context, it uses the ID stored in the redux store to get the actual mutable object from a global service instead.
Requirements
We want to, as a starting step, move this mutable js-slang (program evaluation) context out of Redux, and into a standard global object for the following reasons:
- Allows it to be mutable; and
- Can be accessed outside the React context in functions, unlike React's
useContext
We can then create a module (file) that achieves something like the following:
const jsSlangContextStore = new Map();
export function putJsSlangContext(obj) {
const newId = // UUID;
jsSlangContextStore.set(newId, obj);
return newId // to be stored in Redux
}
export function getJsSlangContext(id) {
return jsSlangContextStore.get(id);
}
export function deleteJsSlangContext(id) {
jsSlangContextStore.delete(id);
}
The singleton will then serves as a single source of truth to store and provide the js-slang evaluation context.
- Identify everywhere the js-slang
context
is used; it may be helpful to use calls to js-slang'screateContext
as a starting point - Create the singleton provider as shown above
- Refactor the Redux slice (e.g. including but not limited to the workspace slice) to simply store an store the generated ID instead.
- Refactor usages of
useTypedSelector
/useSelector
(and others as necessary) to get the mutable state from the global provider using the key provided by the redux store instead. It might be helpful to write auseJsSlangContext()
custom hook, or something similar, to keep the changes as transparent as possible (by internally callinguseTypedSelector
to get the key, and using the key to extract and return the object from the provider.
If a push/commit fails, skip the git hooks by using --no-verify
. At least push something to a PR. Preferably, always skip git hooks and run any commands manually instead. It's fine if tests fails, they are flaky to begin with; push anyway.
Important: Installing dependencies might fails as the project uses external (non-NPM) dependencies (e.g. including but not limited to xlsx
, as well as dependencies from GitHub – conductor
, languages-directory
). Simply remove these dependencies from package.json
(it's okay to commit the changes) and ignore all type errors associated with them. Don't forget to run yarn install
WITHOUT --immutable
or --frozen-lockfile
flags as the package.json
contents have changed. Do this in order to prioritize being able to install the latest versions of Blueprint and resolve type errors correctly.