Skip to content

Modules Structure

Marcus edited this page Mar 14, 2021 · 3 revisions

Modules

Below shows the structure of the modules. The manifest file of the modules is modules.json in the root folder of the repository. This file will contain the metadata for a module, including its name (as referenced in Source), associated JavaScript bundle and associated tabs.

{ 
  modules: [
    {
      name: "runes",
      bundle: "runes",
      tabs: []
    },
    {
      name: "sounds",
      bundle: "sounds",
      tabs: [
        "tone_matrix"
      ]
    }
  ]
}

This example includes the two modules runes and sounds. The runes module does not include any tabs while the sounds module contains one tab.

In the current design, the js-slang library will read and cache (per session) the modules.json file which contains all the mappings of the available modules to their associated bundle and tabs. When Source code is evaluated, the js-slang library will retrieve a list of imported modules from the transpiler, before referencing this JSON file and retrieving the module’s bundle and tabs.


Bundles

The module bundle contains the logic and the functions that are provided by the module. They can be found in src/bundles located in the root folder of the repository. For example, the repeat module’s bundle is located in src/bundles/repeat.

Every bundle contains an entry point (index.ts) located in the root folder of the bundle (ie. src/bundles/repeat). The module will only expose the default export of the entry point of the bundle. The TypeScript code for an example repeat module’s bundle is presented below to facilitate explanations.

import __Params from "../../typings/__Params"; // Import code from other files

// This function takes in __params which exists to enable js-slang library to
// provide the repeat module with variables that may be needed. (eg. user input)
export default function (__params: __Params): { [key: String]: Function } {
  // Function repeat() to be provided by the repeat module and its logic
  function repeat(f: Function, n: number): Function {
    if (n === 0) return f;
    return (...args: any[]) => f(repeat(f, n - 1)(...args));
  }

  // Function getInput() to be provided by the repeat module and its logic
  function get_input(): String {
    // Retrieve user interface input state from __params
    return __params.input;
  }

  // The returned object is the object that contains all functions provided by
  // the repeat library for use in the Source program.
  return { repeat, get_input };
}

Import Statements
Line 1 is an example of an import statement. Modularise your code by splitting logic into multiple TypeScript files that live inside the module’s bundle folder. Then, consume code from files outside index.ts by importing them. Consuming packages provided by the npm community is also possible (eg. lodash, day.js).

Default Export
The default export of the index.ts file is consumed by js-slang library as explained in the section on the Modules System. The default export function will be evaluated with __params as the argument. The choice of whether the module requires tools provided by __params is based on the discretion of the module’s author.


Tabs

The module tab contains the code related to the side content tabs that will be spawned on the Source Academy frontend. They can be found in src/tabs located in the root folder of the repository. For example, the code related to the repeat module’s RepeatTestTab is located in src/tabs/RepeatTestTab.

Every tab contains an entry point (index.tsx) located in the root folder of the tab. The TypeScript code for an example repeat module’s tab is presented below to facilitate explanations.

Note that not all modules will have tabs. Modules that do not consist of any user interface to be rendered on the side content of the Source Academy frontend will only have a bundle.

import React from 'react'; // Import from any required library
import DebuggerContext from '../../typings/DebuggerContext';

// String displayed in the tooltip of the tab icon in Source Academy frontend.
const label = "Repeat Test Tab"; 

// Icon for side content tab (BlueprintJS icon name)
const iconName = "build"; 

// Determines if the tab should be rendered as part of the side contents 
function toSpawn(debuggerContext: DebuggerContext): boolean {
  return debuggerContext.result?.spawnTab? === true;
} 

// React component to be rendered at the Source Academy frontend side contents
const body: React.FC = (debuggerContext: DebuggerContext) => {
  return <div>Hello World!</div>;
};

export default { label, iconName, toSpawn, body };

Import Statements
Line 1 and 2 is an example of import statements. Modularise your code by splitting logic into multiple TypeScript files that live inside the module’s tab folder. Then, consume code from files outside index.tsx by importing them. Like bundles, consuming packages provided by the npm community in tabs is also possible (eg. lodash, day.js).

Default Export
The default export object must expose the fields described below.

label - A tooltip string that is displayed when the cadet hovers over the spawned tab icon.

iconName - The string that represents the icon to be displayed in the spawned tab icon. The names must come from the BlueprintJS icons library.

toSpawn - The function that returns a boolean which will be used by Source Academy frontend to decide whether to spawn the tab.

function toSpawn(debuggerContext: DebuggerContext): boolean {
  return debuggerContext.result?.value? === "test";
} 

An example of spawning the tab only when the output of the Source program is “test”.

body - The React functional component that consists of the JSX Element to be rendered on the Source Academy frontend as part of its side contents.

Clone this wiki locally