@sourceacademy/runner-module-loader 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,46 @@
1
+ <h1 align="center">Module Loader</h1>
2
+
3
+ <p align="center">Runner-side plugin for loading Source Academy modules</p>
4
+
5
+ <p align="center">
6
+ <a href="https://www.npmjs.com/package/@sourceacademy/runner-module-loader"><img src="https://img.shields.io/npm/v/@sourceacademy/runner-module-loader?color=1a2530&label=npm"></a>
7
+ <a href="https://github.com/source-academy/plugins/tree/main/src/runner/module-loader"><img src="https://img.shields.io/badge/github-repo-blue?logo=github"></a>
8
+ </p>
9
+
10
+ ## Features
11
+ The plugin provides an interface to load modules with a module ID
12
+
13
+ ## Installation
14
+ ```bash
15
+ yarn add @sourceacademy/runner-module-loader
16
+ # OR
17
+ npm i @sourceacademy/runner-module-loader
18
+ # OR
19
+ pnpm add @sourceacademy/runner-module-loader
20
+ ```
21
+
22
+ ## Structure
23
+ This package ([`@sourceacademy/runner-module-loader`](https://github.com/source-academy/plugins/tree/main/src/runner/module-loader)) contains the `ModuleLoaderRunnerPlugin` class — a Conductor runner plugin that an evaluator can call to load modules.
24
+
25
+ ### API Reference
26
+ | Name | Description |
27
+ |------|-------------|
28
+ | `instance` | The singleton instance of the plugin. |
29
+ | `async requestModule(moduleName: string): Promise<IModulePlugin>` | Request a module by name from the host plugin. Rejects with an error if the module is not found. |
30
+
31
+ ## Usage
32
+ After installation, import `ModuleLoaderRunnerPlugin` and register it with the Conductor evaluator. When evaluating `import` statements, call `requestModule` to load the module.
33
+
34
+ ```ts
35
+ ...
36
+ const pluginObj = await ModuleLoaderRunnerPlugin.instance.requestModule(moduleName);
37
+ context.nativeStorage.loadedModules[moduleName] = Object.fromEntries(
38
+ pluginObj?.exports.map(t => [t.symbol, t]) || [],
39
+ );
40
+ ...
41
+ ```
42
+
43
+ ## Further reading
44
+ - For the shared protocol types and IDs, see [`@sourceacademy/common-module-loader`](https://github.com/source-academy/plugins/tree/main/src/common/module-loader)
45
+ - For the host-side plugin that accepts the module directory URL, see [`@sourceacademy/web-module-loader`](https://github.com/source-academy/plugins/tree/main/src/web/module-loader)
46
+ - The [plugins wiki](https://github.com/source-academy/plugins/wiki) covers how Conductor plugins communicate
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";function e(e,t,n,o){return new(n||(n=Promise))(function(_,u){function i(e){try{s(o.next(e))}catch(e){u(e)}}function r(e){try{s(o.throw(e))}catch(e){u(e)}}function s(e){var t;e.done?_(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(i,r)}s((o=o.apply(e,t||[])).next())})}"function"==typeof SuppressedError&&SuppressedError;var t,n,o,_,u;(n=t||(t={})).REQUEST_MODULE="request_module",n.MODULE_RESPONSE="module_response",n.MODULE_ERROR="module_error",function(e){e[e.CALL=0]="CALL",e[e.RETURN=1]="RETURN",e[e.RETURN_ERR=2]="RETURN_ERR"}(o||(o={})),function(e){e.UNKNOWN="__unknown",e.INTERNAL="__internal",e.EVALUATOR="__evaluator",e.EVALUATOR_SYNTAX="__evaluator_syntax",e.EVALUATOR_TYPE="__evaluator_type",e.EVALUATOR_RUNTIME="__evaluator_runtime"}(_||(_={})),function(e){e[e.PROTOCOL_VERSION=0]="PROTOCOL_VERSION",e[e.PROTOCOL_MIN_VERSION=0]="PROTOCOL_MIN_VERSION",e[e.SETUP_MESSAGES_BUFFER_SIZE=10]="SETUP_MESSAGES_BUFFER_SIZE"}(u||(u={}));class i{constructor(e,[t],n,o){this.id="__runner_module_loader",this.__loadedPlugins=new Map,this.__moduleRequestChannel=t,this.__conductor=n,this.__evaluator=o,i.instance=this}requestModule(n){return e(this,void 0,void 0,function*(){return this.__loadedPlugins.has(n)||this.__loadedPlugins.set(n,new Promise((o,_)=>{const u=i=>e(this,void 0,void 0,function*(){try{if(i.moduleName!==n)return;if(this.__moduleRequestChannel.unsubscribe(u),i.type===t.MODULE_RESPONSE){const e=yield import(i.moduleURL).then(e=>e.default(()=>{}).default),t=this.__conductor.registerPlugin(e,this.__evaluator,{tabs:i.tabs,loadTab:e=>{if(!i.tabs.includes(e))throw new Error(`Tab ${e} not found in module ${n}`);this.__conductor.hostLoadPlugin(e)}});yield t.initialise(),o(t)}else if(i.type===t.MODULE_ERROR)throw Error(i.error)}catch(e){this.__loadedPlugins.delete(n),_(e)}});this.__moduleRequestChannel.subscribe(u),this.__moduleRequestChannel.send({type:t.REQUEST_MODULE,moduleName:n})})),this.__loadedPlugins.get(n)})}}i.channelAttach=["module_config"],i.instance=null,exports.ModuleLoaderRunnerPlugin=i;
@@ -0,0 +1,14 @@
1
+ import { type IChannel, type IConduit, type IPlugin } from "@sourceacademy/conductor/conduit";
2
+ import type { IModulePlugin } from "@sourceacademy/conductor/module";
3
+ import type { IInterfacableEvaluator, IRunnerPlugin } from "@sourceacademy/conductor/runner";
4
+ export declare class ModuleLoaderRunnerPlugin implements IPlugin {
5
+ readonly id: string;
6
+ static readonly channelAttach: string[];
7
+ private readonly __moduleRequestChannel;
8
+ private readonly __conductor;
9
+ private readonly __evaluator;
10
+ private readonly __loadedPlugins;
11
+ static instance: ModuleLoaderRunnerPlugin | null;
12
+ constructor(conduit: IConduit, [moduleRequestChannel]: IChannel<any>[], conductor: IRunnerPlugin, evaluator: IInterfacableEvaluator);
13
+ requestModule(moduleName: string): Promise<IModulePlugin>;
14
+ }
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ function e(e,t,n,o){return new(n||(n=Promise))(function(_,u){function i(e){try{s(o.next(e))}catch(e){u(e)}}function r(e){try{s(o.throw(e))}catch(e){u(e)}}function s(e){var t;e.done?_(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(i,r)}s((o=o.apply(e,t||[])).next())})}"function"==typeof SuppressedError&&SuppressedError;var t,n,o,_,u;(n=t||(t={})).REQUEST_MODULE="request_module",n.MODULE_RESPONSE="module_response",n.MODULE_ERROR="module_error",function(e){e[e.CALL=0]="CALL",e[e.RETURN=1]="RETURN",e[e.RETURN_ERR=2]="RETURN_ERR"}(o||(o={})),function(e){e.UNKNOWN="__unknown",e.INTERNAL="__internal",e.EVALUATOR="__evaluator",e.EVALUATOR_SYNTAX="__evaluator_syntax",e.EVALUATOR_TYPE="__evaluator_type",e.EVALUATOR_RUNTIME="__evaluator_runtime"}(_||(_={})),function(e){e[e.PROTOCOL_VERSION=0]="PROTOCOL_VERSION",e[e.PROTOCOL_MIN_VERSION=0]="PROTOCOL_MIN_VERSION",e[e.SETUP_MESSAGES_BUFFER_SIZE=10]="SETUP_MESSAGES_BUFFER_SIZE"}(u||(u={}));class i{constructor(e,[t],n,o){this.id="__runner_module_loader",this.__loadedPlugins=new Map,this.__moduleRequestChannel=t,this.__conductor=n,this.__evaluator=o,i.instance=this}requestModule(n){return e(this,void 0,void 0,function*(){return this.__loadedPlugins.has(n)||this.__loadedPlugins.set(n,new Promise((o,_)=>{const u=i=>e(this,void 0,void 0,function*(){try{if(i.moduleName!==n)return;if(this.__moduleRequestChannel.unsubscribe(u),i.type===t.MODULE_RESPONSE){const e=yield import(i.moduleURL).then(e=>e.default(()=>{}).default),t=this.__conductor.registerPlugin(e,this.__evaluator,{tabs:i.tabs,loadTab:e=>{if(!i.tabs.includes(e))throw new Error(`Tab ${e} not found in module ${n}`);this.__conductor.hostLoadPlugin(e)}});yield t.initialise(),o(t)}else if(i.type===t.MODULE_ERROR)throw Error(i.error)}catch(e){this.__loadedPlugins.delete(n),_(e)}});this.__moduleRequestChannel.subscribe(u),this.__moduleRequestChannel.send({type:t.REQUEST_MODULE,moduleName:n})})),this.__loadedPlugins.get(n)})}}i.channelAttach=["module_config"],i.instance=null;export{i as ModuleLoaderRunnerPlugin};
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@sourceacademy/runner-module-loader",
3
+ "version": "0.0.1",
4
+ "packageManager": "yarn@4.6.0",
5
+ "description": "The runner plugin for the module loader in Source Academy",
6
+ "scripts": {
7
+ "build": "rollup -c",
8
+ "prepack": "yarn build"
9
+ },
10
+ "license": "ISC",
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "main": "dist/index.cjs",
15
+ "module": "dist/index.mjs",
16
+ "types": "dist/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "import": "./dist/index.mjs",
20
+ "require": "./dist/index.cjs",
21
+ "types": "./dist/index.d.ts"
22
+ }
23
+ },
24
+ "peerDependencies": {
25
+ "@sourceacademy/conductor": ">=0.3.0"
26
+ },
27
+ "devDependencies": {
28
+ "@rollup/plugin-node-resolve": "^16.0.3",
29
+ "@rollup/plugin-terser": "^1.0.0",
30
+ "@rollup/plugin-typescript": "^12.3.0",
31
+ "@sourceacademy/common-module-loader": "workspace:*",
32
+ "@sourceacademy/conductor": ">=0.3.0",
33
+ "@sourceacademy/runner-remote-execution": "workspace:*",
34
+ "@vitest/coverage-istanbul": "^4.1.9",
35
+ "rollup": "^4.60.2",
36
+ "tslib": "^2.8.1",
37
+ "typescript": "^6.0.3",
38
+ "vitest": "^4.1.9"
39
+ }
40
+ }