Skip to content

System Implementation in Source Academy Frontend

Bryan Loh edited this page Apr 18, 2021 · 4 revisions

This page contains developer information regarding the interaction between the Source Modules system and the Source Academy frontend cadet-frontend.

The debuggerContext Object

In the Redux store of the Source Academy frontend, there is the debuggerContext that Source Module developers should be concerned about. The debuggerContext is collected from the Saga middleware, specifically at WorkspaceSaga during evaluation of any Source program. After evaluation of the Source program, an action loaded with debuggerContext is dispatched. The corresponding reducer, WorkspaceReducer, saves the debuggerContext into the Redux store.

Previously, there is almost no information passed by frontend to the Source Module's tabs. In other words, the Source Module tabs and bundle do not have direct access to the program being evaluated.

 ---> = data flow
 ---+ = child component (no data flow)               
                                    
program ---> sagas ---> front-end ---+ source module tab

In the event that the source module tab requires additional information, they have to invent a way to collect the information and pass it to their corresponding module tab. This introduces many 'inventive' ways throughout the code base for their data collection.

 ---> = data flow
 ---+ = child component (no data flow)

                      _______________________
                     |                       |  'inventive' collection of data from sagas
                     |                       v               
program ---> sagas ---> front-end ---+ source module tab

As such, the solution is to introduce a formalised pipeline such that module tabs are able to easily access their required information. The front-end now saves the required data and save it into the store, where module tabs can easily access the required information. This eliminates the need for other 'inventive' ways to be deployed and clutter the code base.

 ---> = data flow
 ---+ = child component (no data flow)

                            ------> redux store     
                            |            |               
program ---> sagas ---> front-end        | debuggerContext passed as react component props
                            |            v
                            ---+ source module tab

Interaction with the Source Module's Bundle

Most likely, there is going to be a need for interaction between the Source Module tab and the Source Module bundle. For example, in the pix_n_flix module, we would need a way to somehow let the Source Module tab know that we need to render the HTMLVideoElement with the provided video filter. This is achieved through the debuggerContext object where information related to the evaluation of the Source program is saved. A more detailed explanation of the debuggerContext object is available in the previous section.

Within the debuggerContext object received in the Source Module tab as react component props, there exists a result property that contains the result of the evaluation of the last statement of the Source program string. The interaction between the Source Module bundles and tabs currently take advantage of this. Currently, the system mandates that the Source program's last statement returns an object that looks similar to the following type.

{
  toReplString: () => string;
  init: ( ... ) => any;
}

As described in the paragraphs above, this return value of the init() function will be stored within the debuggerContext in debuggerContext.result.value. As a result, the Source Module tab will have to access the result's value in the debuggerContext to retrieve information related to the imported instance of the Source Module bundle.

Example

In the Source Module's Bundle

const arrayData = [];

function save(array: any[]): void {
  arrayData.push([...array]);
}

function start(): any {
  return () => arrayData;
}

export default function (__params) {
  return { save, start }
}

In the Source program evaluated

import { save, start } from "bundle";

// This program saves [0], [0,1], [0,1,2], [0,1,2,3] and [0,1,2,3,4] into the Source Module's bundle
const newArray = [];
for (let counter = 0; counter < 5; counter = counter + 1) {
  newArray[counter] = counter;
  save(newArray);
}

start();

In the Source Module's tab

import React from "react";

...

class Tab extends React.Component<Props,State> {
  constructor(props) { ... }

  // this.props.debuggerContext.result.value is the function () => arrayData
  // since start(); was the last statement evaluated in the Source program and
  // the implementation of the start() function in the bundle returns the function
  
  const getArraysState = () => this.props.debuggerContext.result.value();

  ...
}
Clone this wiki locally