From d62492f307f739006aa8d8f31822d41d04790e54 Mon Sep 17 00:00:00 2001 From: tohlh Date: Tue, 25 Mar 2025 19:34:00 +0800 Subject: [PATCH 01/10] Add support for language options --- src/commons/assessment/AssessmentTypes.ts | 1 + .../WorkspaceSaga/helpers/clearContext.ts | 13 ++++++----- src/commons/utils/JsSlangHelper.ts | 22 ++++++++++++++++--- src/commons/workspace/WorkspaceReducer.ts | 4 +++- 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/commons/assessment/AssessmentTypes.ts b/src/commons/assessment/AssessmentTypes.ts index c3d5cecbf4..7ea89ac85c 100644 --- a/src/commons/assessment/AssessmentTypes.ts +++ b/src/commons/assessment/AssessmentTypes.ts @@ -175,6 +175,7 @@ export type Library = { 2?: string; // For mission control }>; moduleParams?: any; + languageOptions?: any; }; export type Testcase = { diff --git a/src/commons/sagas/WorkspaceSaga/helpers/clearContext.ts b/src/commons/sagas/WorkspaceSaga/helpers/clearContext.ts index a12b6f3100..e1fabb6c13 100644 --- a/src/commons/sagas/WorkspaceSaga/helpers/clearContext.ts +++ b/src/commons/sagas/WorkspaceSaga/helpers/clearContext.ts @@ -1,6 +1,6 @@ import { Context } from 'js-slang'; import { defineSymbol } from 'js-slang/dist/createContext'; -import { Variant } from 'js-slang/dist/types'; +import { LanguageOptions, Variant } from 'js-slang/dist/types'; import { put, select, take } from 'redux-saga/effects'; import WorkspaceActions from 'src/commons/workspace/WorkspaceActions'; @@ -10,18 +10,20 @@ import { actions } from '../../../utils/ActionsHelper'; import { WorkspaceLocation } from '../../../workspace/WorkspaceTypes'; export function* clearContext(workspaceLocation: WorkspaceLocation, entrypointCode: string) { - const [chapter, symbols, externalLibraryName, globals, variant]: [ + const [chapter, symbols, externalLibraryName, globals, variant, languageOptions]: [ number, string[], ExternalLibraryName, Array<[string, any]>, - Variant + Variant, + LanguageOptions ] = yield select((state: OverallState) => [ state.workspaces[workspaceLocation].context.chapter, state.workspaces[workspaceLocation].context.externalSymbols, state.workspaces[workspaceLocation].externalLibrary, state.workspaces[workspaceLocation].globals, - state.workspaces[workspaceLocation].context.variant + state.workspaces[workspaceLocation].context.variant, + state.workspaces[workspaceLocation].context.languageOptions ]); const library = { @@ -31,7 +33,8 @@ export function* clearContext(workspaceLocation: WorkspaceLocation, entrypointCo name: externalLibraryName, symbols }, - globals + globals, + languageOptions }; // Clear the context, with the same chapter and externalSymbols as before. diff --git a/src/commons/utils/JsSlangHelper.ts b/src/commons/utils/JsSlangHelper.ts index ab88e89db8..a67105583c 100644 --- a/src/commons/utils/JsSlangHelper.ts +++ b/src/commons/utils/JsSlangHelper.ts @@ -1,6 +1,13 @@ /* tslint:disable: ban-types*/ import createSlangContext, { defineBuiltin, importBuiltins } from 'js-slang/dist/createContext'; -import { Chapter, Context, CustomBuiltIns, Value, Variant } from 'js-slang/dist/types'; +import { + Chapter, + Context, + CustomBuiltIns, + LanguageOptions, + Value, + Variant +} from 'js-slang/dist/types'; import { stringify } from 'js-slang/dist/utils/stringify'; import { difference, keys } from 'lodash'; import CseMachine from 'src/features/cseMachine/CseMachine'; @@ -148,9 +155,17 @@ export function createContext( chapter: Chapter, externals: string[], externalContext: T, - variant: Variant = Variant.DEFAULT + variant: Variant = Variant.DEFAULT, + languageOptions?: LanguageOptions ) { - return createSlangContext(chapter, variant, externals, externalContext, externalBuiltIns); + return createSlangContext( + chapter, + variant, + languageOptions, + externals, + externalContext, + externalBuiltIns + ); } // Assumes that the grader doesn't need additional external libraries apart from the standard @@ -166,6 +181,7 @@ function loadStandardLibraries(proxyContext: Context, customBuiltIns: CustomBuil // intercepts reads from the underlying Context and returns desired values export function makeElevatedContext(context: Context) { function ProxyFrame() {} + ProxyFrame.prototype = context.runtime.environments[0].head; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore diff --git a/src/commons/workspace/WorkspaceReducer.ts b/src/commons/workspace/WorkspaceReducer.ts index a4cc98a8c3..10bd5a28d5 100644 --- a/src/commons/workspace/WorkspaceReducer.ts +++ b/src/commons/workspace/WorkspaceReducer.ts @@ -90,6 +90,7 @@ const newWorkspaceReducer = createReducer(defaultWorkspaceManager, builder => { const workspaceLocation = getWorkspaceLocation(action); // For some reason mutating the state directly results in type // errors, so we have to do it the old-fashioned way + console.log('endClearContext', action.payload.library.languageOptions); return { ...state, [workspaceLocation]: { @@ -98,7 +99,8 @@ const newWorkspaceReducer = createReducer(defaultWorkspaceManager, builder => { action.payload.library.chapter, action.payload.library.external.symbols, workspaceLocation, - action.payload.library.variant + action.payload.library.variant, + action.payload.library.languageOptions ), globals: action.payload.library.globals, externalLibrary: action.payload.library.external.name From 9dd4a7df85edfb6dbbf84098878a8be2702c76b0 Mon Sep 17 00:00:00 2001 From: tohlh Date: Tue, 25 Mar 2025 21:13:10 +0800 Subject: [PATCH 02/10] Fix issues with prepend code on typed variant --- .../helpers/blockExtraMethods.ts | 7 ++++-- .../sagas/WorkspaceSaga/helpers/evalEditor.ts | 25 ++++++++++++------- src/commons/utils/JsSlangHelper.ts | 8 ++++++ src/commons/workspace/WorkspaceReducer.ts | 1 - 4 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/commons/sagas/WorkspaceSaga/helpers/blockExtraMethods.ts b/src/commons/sagas/WorkspaceSaga/helpers/blockExtraMethods.ts index 95ec7e6fb7..6ddcb1a38a 100644 --- a/src/commons/sagas/WorkspaceSaga/helpers/blockExtraMethods.ts +++ b/src/commons/sagas/WorkspaceSaga/helpers/blockExtraMethods.ts @@ -2,12 +2,13 @@ import { Context } from 'js-slang'; import { call } from 'redux-saga/effects'; import { - getBlockExtraMethodsString, + getBlockExtraMethodsString, getBlockExtraMethodsStringTypedVariant, getDifferenceInMethods, getStoreExtraMethodsString } from '../../../utils/JsSlangHelper'; import { EVAL_SILENT, WorkspaceLocation } from '../../../workspace/WorkspaceTypes'; import { evalCodeSaga } from './evalCode'; +import { Variant } from 'js-slang/dist/types'; export function* blockExtraMethods( elevatedContext: Context, @@ -35,7 +36,9 @@ export function* blockExtraMethods( ); } - const nullifier = getBlockExtraMethodsString(toBeBlocked); + const nullifier = context.variant === Variant.TYPED + ? getBlockExtraMethodsStringTypedVariant(toBeBlocked) + : getBlockExtraMethodsString(toBeBlocked); const nullifierFilePath = '/nullifier.js'; const nullifierFiles = { [nullifierFilePath]: nullifier diff --git a/src/commons/sagas/WorkspaceSaga/helpers/evalEditor.ts b/src/commons/sagas/WorkspaceSaga/helpers/evalEditor.ts index 4e7cb11ca2..cf4e8bcb6a 100644 --- a/src/commons/sagas/WorkspaceSaga/helpers/evalEditor.ts +++ b/src/commons/sagas/WorkspaceSaga/helpers/evalEditor.ts @@ -14,6 +14,7 @@ import { blockExtraMethods } from './blockExtraMethods'; import { clearContext } from './clearContext'; import { evalCodeSaga } from './evalCode'; import { insertDebuggerStatements } from './insertDebuggerStatements'; +import { Variant } from 'js-slang/dist/types'; export function* evalEditorSaga( workspaceLocation: WorkspaceLocation @@ -93,19 +94,25 @@ export function* evalEditorSaga( const prependFiles = { [prependFilePath]: prepend }; - yield call( - evalCodeSaga, - prependFiles, - prependFilePath, - elevatedContext, - execTime, - workspaceLocation, - EVAL_SILENT - ); + if (context.variant !== Variant.TYPED) { + yield call( + evalCodeSaga, + prependFiles, + prependFilePath, + elevatedContext, + execTime, + workspaceLocation, + EVAL_SILENT, + ); + } + // Block use of methods from privileged context yield* blockExtraMethods(elevatedContext, context, execTime, workspaceLocation); } + if (context.variant === Variant.TYPED) { + files[entrypointFilePath] = prepend + files[entrypointFilePath]; + } yield call( evalCodeSaga, files, diff --git a/src/commons/utils/JsSlangHelper.ts b/src/commons/utils/JsSlangHelper.ts index a67105583c..5c51fe94e4 100644 --- a/src/commons/utils/JsSlangHelper.ts +++ b/src/commons/utils/JsSlangHelper.ts @@ -259,3 +259,11 @@ export function getBlockExtraMethodsString(toRemove: string[]) { ) .join('\n'); } + +export function getBlockExtraMethodsStringTypedVariant(toRemove: string[]) { + return toRemove + .map(x => + x === 'makeUndefinedErrorFunction' ? '' : `const ${x} : string = makeUndefinedErrorFunction('${x}');` + ) + .join('\n'); +} diff --git a/src/commons/workspace/WorkspaceReducer.ts b/src/commons/workspace/WorkspaceReducer.ts index 10bd5a28d5..57f6e557d0 100644 --- a/src/commons/workspace/WorkspaceReducer.ts +++ b/src/commons/workspace/WorkspaceReducer.ts @@ -90,7 +90,6 @@ const newWorkspaceReducer = createReducer(defaultWorkspaceManager, builder => { const workspaceLocation = getWorkspaceLocation(action); // For some reason mutating the state directly results in type // errors, so we have to do it the old-fashioned way - console.log('endClearContext', action.payload.library.languageOptions); return { ...state, [workspaceLocation]: { From f4e162d26d5ab5255e09e21d42fd626a87e8cb7e Mon Sep 17 00:00:00 2001 From: tohlh Date: Wed, 16 Apr 2025 11:54:03 +0800 Subject: [PATCH 03/10] Fix line number issues --- src/commons/sagas/WorkspaceSaga/helpers/evalEditor.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/commons/sagas/WorkspaceSaga/helpers/evalEditor.ts b/src/commons/sagas/WorkspaceSaga/helpers/evalEditor.ts index cf4e8bcb6a..f6d6096e5a 100644 --- a/src/commons/sagas/WorkspaceSaga/helpers/evalEditor.ts +++ b/src/commons/sagas/WorkspaceSaga/helpers/evalEditor.ts @@ -111,7 +111,10 @@ export function* evalEditorSaga( } if (context.variant === Variant.TYPED) { - files[entrypointFilePath] = prepend + files[entrypointFilePath]; + // Prepend was multi-line, now we need to split them by \n and join them + // This is to avoid extra lines in the editor which affects the error message location + const prependSingleLine = prepend.split('\n').join(''); + files[entrypointFilePath] = prependSingleLine + files[entrypointFilePath]; } yield call( evalCodeSaga, From f37927730ffa02989b8215530a5c1a3046c71c9c Mon Sep 17 00:00:00 2001 From: Richard Dominick <34370238+RichDom2185@users.noreply.github.com> Date: Fri, 18 Apr 2025 03:27:31 +0800 Subject: [PATCH 04/10] Fix format and lint --- .../sagas/WorkspaceSaga/helpers/blockExtraMethods.ts | 12 +++++++----- .../sagas/WorkspaceSaga/helpers/evalEditor.ts | 4 ++-- src/commons/utils/JsSlangHelper.ts | 4 +++- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/commons/sagas/WorkspaceSaga/helpers/blockExtraMethods.ts b/src/commons/sagas/WorkspaceSaga/helpers/blockExtraMethods.ts index 6ddcb1a38a..a3b0f2c11f 100644 --- a/src/commons/sagas/WorkspaceSaga/helpers/blockExtraMethods.ts +++ b/src/commons/sagas/WorkspaceSaga/helpers/blockExtraMethods.ts @@ -1,14 +1,15 @@ import { Context } from 'js-slang'; +import { Variant } from 'js-slang/dist/types'; import { call } from 'redux-saga/effects'; import { - getBlockExtraMethodsString, getBlockExtraMethodsStringTypedVariant, + getBlockExtraMethodsString, + getBlockExtraMethodsStringTypedVariant, getDifferenceInMethods, getStoreExtraMethodsString } from '../../../utils/JsSlangHelper'; import { EVAL_SILENT, WorkspaceLocation } from '../../../workspace/WorkspaceTypes'; import { evalCodeSaga } from './evalCode'; -import { Variant } from 'js-slang/dist/types'; export function* blockExtraMethods( elevatedContext: Context, @@ -36,9 +37,10 @@ export function* blockExtraMethods( ); } - const nullifier = context.variant === Variant.TYPED - ? getBlockExtraMethodsStringTypedVariant(toBeBlocked) - : getBlockExtraMethodsString(toBeBlocked); + const nullifier = + context.variant === Variant.TYPED + ? getBlockExtraMethodsStringTypedVariant(toBeBlocked) + : getBlockExtraMethodsString(toBeBlocked); const nullifierFilePath = '/nullifier.js'; const nullifierFiles = { [nullifierFilePath]: nullifier diff --git a/src/commons/sagas/WorkspaceSaga/helpers/evalEditor.ts b/src/commons/sagas/WorkspaceSaga/helpers/evalEditor.ts index cf4e8bcb6a..abf4e6fade 100644 --- a/src/commons/sagas/WorkspaceSaga/helpers/evalEditor.ts +++ b/src/commons/sagas/WorkspaceSaga/helpers/evalEditor.ts @@ -1,4 +1,5 @@ import { FSModule } from 'browserfs/dist/node/core/FS'; +import { Variant } from 'js-slang/dist/types'; import { call, put, select, StrictEffect } from 'redux-saga/effects'; import WorkspaceActions from 'src/commons/workspace/WorkspaceActions'; @@ -14,7 +15,6 @@ import { blockExtraMethods } from './blockExtraMethods'; import { clearContext } from './clearContext'; import { evalCodeSaga } from './evalCode'; import { insertDebuggerStatements } from './insertDebuggerStatements'; -import { Variant } from 'js-slang/dist/types'; export function* evalEditorSaga( workspaceLocation: WorkspaceLocation @@ -102,7 +102,7 @@ export function* evalEditorSaga( elevatedContext, execTime, workspaceLocation, - EVAL_SILENT, + EVAL_SILENT ); } diff --git a/src/commons/utils/JsSlangHelper.ts b/src/commons/utils/JsSlangHelper.ts index 5c51fe94e4..d6c92eaeef 100644 --- a/src/commons/utils/JsSlangHelper.ts +++ b/src/commons/utils/JsSlangHelper.ts @@ -263,7 +263,9 @@ export function getBlockExtraMethodsString(toRemove: string[]) { export function getBlockExtraMethodsStringTypedVariant(toRemove: string[]) { return toRemove .map(x => - x === 'makeUndefinedErrorFunction' ? '' : `const ${x} : string = makeUndefinedErrorFunction('${x}');` + x === 'makeUndefinedErrorFunction' + ? '' + : `const ${x} : string = makeUndefinedErrorFunction('${x}');` ) .join('\n'); } From 94c2b7223126040301fd67e6fb70b03e67abc865 Mon Sep 17 00:00:00 2001 From: tohlh Date: Fri, 18 Apr 2025 11:41:55 +0800 Subject: [PATCH 05/10] Fix languageOptions field type --- src/commons/assessment/AssessmentTypes.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commons/assessment/AssessmentTypes.ts b/src/commons/assessment/AssessmentTypes.ts index 7ea89ac85c..8d73a922b6 100644 --- a/src/commons/assessment/AssessmentTypes.ts +++ b/src/commons/assessment/AssessmentTypes.ts @@ -1,4 +1,4 @@ -import { Chapter, SourceError, Variant } from 'js-slang/dist/types'; +import { Chapter, LanguageOptions, SourceError, Variant } from 'js-slang/dist/types'; import { ExternalLibrary, ExternalLibraryName } from '../application/types/ExternalTypes'; @@ -175,7 +175,7 @@ export type Library = { 2?: string; // For mission control }>; moduleParams?: any; - languageOptions?: any; + languageOptions?: LanguageOptions; }; export type Testcase = { From a01227aadce7160b9f653189945e6a423cb119dd Mon Sep 17 00:00:00 2001 From: tohlh Date: Tue, 4 Nov 2025 22:08:14 +0800 Subject: [PATCH 06/10] fix styles --- src/commons/sagas/WorkspaceSaga/helpers/clearContext.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commons/sagas/WorkspaceSaga/helpers/clearContext.ts b/src/commons/sagas/WorkspaceSaga/helpers/clearContext.ts index ea6e972a44..c42535102b 100644 --- a/src/commons/sagas/WorkspaceSaga/helpers/clearContext.ts +++ b/src/commons/sagas/WorkspaceSaga/helpers/clearContext.ts @@ -2,12 +2,12 @@ import type { Context } from 'js-slang'; import { defineSymbol } from 'js-slang/dist/createContext'; import { LanguageOptions, Variant } from 'js-slang/dist/types'; import { put, select, take } from 'redux-saga/effects'; +import { ExternalLibraryName } from 'src/commons/application/types/ExternalTypes'; import WorkspaceActions from 'src/commons/workspace/WorkspaceActions'; import type { OverallState } from '../../../application/ApplicationTypes'; import { actions } from '../../../utils/ActionsHelper'; import type { WorkspaceLocation } from '../../../workspace/WorkspaceTypes'; -import { ExternalLibraryName } from 'src/commons/application/types/ExternalTypes'; export function* clearContext(workspaceLocation: WorkspaceLocation, entrypointCode: string) { const [chapter, symbols, externalLibraryName, globals, variant, languageOptions]: [ From 3b763c5b3c9809be309566d51e348259eb58ed86 Mon Sep 17 00:00:00 2001 From: tohlh Date: Wed, 5 Nov 2025 20:22:31 +0800 Subject: [PATCH 07/10] Fix evalEditor --- src/commons/sagas/WorkspaceSaga/helpers/evalEditor.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/commons/sagas/WorkspaceSaga/helpers/evalEditor.ts b/src/commons/sagas/WorkspaceSaga/helpers/evalEditor.ts index 52a51eeb23..a9e3612238 100644 --- a/src/commons/sagas/WorkspaceSaga/helpers/evalEditor.ts +++ b/src/commons/sagas/WorkspaceSaga/helpers/evalEditor.ts @@ -1,4 +1,4 @@ -import { FSModule } from 'browserfs/dist/node/core/FS'; +import type { FSModule } from 'browserfs/dist/node/core/FS'; import { Variant } from 'js-slang/dist/types'; import { call, put, select, StrictEffect } from 'redux-saga/effects'; import WorkspaceActions from 'src/commons/workspace/WorkspaceActions'; @@ -90,8 +90,8 @@ export function* evalEditorSaga( prependFilePath, elevatedContext, execTime, - workspaceLocation, - EVAL_SILENT + EVAL_SILENT, + workspaceLocation ); } From dc2ae0dc264c41680c709a88cc8708a4b2dffb8a Mon Sep 17 00:00:00 2001 From: tohlh Date: Wed, 5 Nov 2025 21:10:34 +0800 Subject: [PATCH 08/10] fix test cases --- .../WorkspaceSaga/helpers/clearContext.ts | 23 +++------ .../sagas/__tests__/WorkspaceSaga.test.ts | 50 ++++++++++++------- 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/src/commons/sagas/WorkspaceSaga/helpers/clearContext.ts b/src/commons/sagas/WorkspaceSaga/helpers/clearContext.ts index c42535102b..bfad60408e 100644 --- a/src/commons/sagas/WorkspaceSaga/helpers/clearContext.ts +++ b/src/commons/sagas/WorkspaceSaga/helpers/clearContext.ts @@ -1,30 +1,19 @@ import type { Context } from 'js-slang'; import { defineSymbol } from 'js-slang/dist/createContext'; -import { LanguageOptions, Variant } from 'js-slang/dist/types'; import { put, select, take } from 'redux-saga/effects'; -import { ExternalLibraryName } from 'src/commons/application/types/ExternalTypes'; import WorkspaceActions from 'src/commons/workspace/WorkspaceActions'; import type { OverallState } from '../../../application/ApplicationTypes'; import { actions } from '../../../utils/ActionsHelper'; import type { WorkspaceLocation } from '../../../workspace/WorkspaceTypes'; +import { selectWorkspace } from '../../SafeEffects'; export function* clearContext(workspaceLocation: WorkspaceLocation, entrypointCode: string) { - const [chapter, symbols, externalLibraryName, globals, variant, languageOptions]: [ - number, - string[], - ExternalLibraryName, - Array<[string, any]>, - Variant, - LanguageOptions - ] = yield select((state: OverallState) => [ - state.workspaces[workspaceLocation].context.chapter, - state.workspaces[workspaceLocation].context.externalSymbols, - state.workspaces[workspaceLocation].externalLibrary, - state.workspaces[workspaceLocation].globals, - state.workspaces[workspaceLocation].context.variant, - state.workspaces[workspaceLocation].context.languageOptions - ]); + const { + context: { chapter, externalSymbols: symbols, variant, languageOptions }, + externalLibrary: externalLibraryName, + globals, + } = yield* selectWorkspace(workspaceLocation); const library = { chapter, diff --git a/src/commons/sagas/__tests__/WorkspaceSaga.test.ts b/src/commons/sagas/__tests__/WorkspaceSaga.test.ts index f0aef96179..b14fbaec5b 100644 --- a/src/commons/sagas/__tests__/WorkspaceSaga.test.ts +++ b/src/commons/sagas/__tests__/WorkspaceSaga.test.ts @@ -130,7 +130,8 @@ describe('EVAL_EDITOR', () => { name: ExternalLibraryName.NONE, symbols: context.externalSymbols }, - globals + globals, + languageOptions: context.languageOptions }; const newDefaultState = generateDefaultState(workspaceLocation, { @@ -397,7 +398,8 @@ describe('EVAL_TESTCASE', () => { name: ExternalLibraryName.NONE, symbols: context.externalSymbols }, - globals + globals, + languageOptions: context.languageOptions }; const newDefaultState = generateDefaultState(workspaceLocation, { @@ -689,23 +691,34 @@ describe('PLAYGROUND_EXTERNAL_SELECT', () => { name: newExternalLibraryName, symbols }, - globals + globals, + languageOptions: context.languageOptions }; - return expectSaga(workspaceSaga) - .withState(newDefaultState) - .put(WorkspaceActions.changeExternalLibrary(newExternalLibraryName, workspaceLocation)) - .put(WorkspaceActions.beginClearContext(workspaceLocation, library, true)) - .put(WorkspaceActions.clearReplOutput(workspaceLocation)) - .call(showSuccessMessage, `Switched to ${newExternalLibraryName} library`, 1000) - .dispatch({ - type: WorkspaceActions.externalLibrarySelect.type, - payload: { - externalLibraryName: newExternalLibraryName, - workspaceLocation - } - }) - .silentRun(); + return ( + expectSaga(workspaceSaga) + .withState(newDefaultState) + .put(WorkspaceActions.changeExternalLibrary(newExternalLibraryName, workspaceLocation)) + // beginClearContext is asserted here but the library object can contain + // runtime-specific fields (like languageOptions). Match only the action + // shape we care about (type, workspaceLocation and shouldInitLibrary) + .put.like({ + action: { + type: WorkspaceActions.beginClearContext.type, + payload: { workspaceLocation, shouldInitLibrary: true } + } + }) + .put(WorkspaceActions.clearReplOutput(workspaceLocation)) + .call(showSuccessMessage, `Switched to ${newExternalLibraryName} library`, 1000) + .dispatch({ + type: WorkspaceActions.externalLibrarySelect.type, + payload: { + externalLibraryName: newExternalLibraryName, + workspaceLocation + } + }) + .silentRun() + ); }); test('does not call the above when oldExternalLibraryName === newExternalLibraryName', () => { @@ -770,7 +783,8 @@ describe('BEGIN_CLEAR_CONTEXT', () => { name: newExternalLibraryName, symbols }, - globals + globals, + languageOptions: undefined }; return expectSaga(workspaceSaga) From fa60d2cef471d7d90321ade8eed8709d1452e1d2 Mon Sep 17 00:00:00 2001 From: tohlh Date: Wed, 5 Nov 2025 21:14:09 +0800 Subject: [PATCH 09/10] fix styles --- src/commons/sagas/WorkspaceSaga/helpers/clearContext.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commons/sagas/WorkspaceSaga/helpers/clearContext.ts b/src/commons/sagas/WorkspaceSaga/helpers/clearContext.ts index bfad60408e..b6b8750a6d 100644 --- a/src/commons/sagas/WorkspaceSaga/helpers/clearContext.ts +++ b/src/commons/sagas/WorkspaceSaga/helpers/clearContext.ts @@ -12,7 +12,7 @@ export function* clearContext(workspaceLocation: WorkspaceLocation, entrypointCo const { context: { chapter, externalSymbols: symbols, variant, languageOptions }, externalLibrary: externalLibraryName, - globals, + globals } = yield* selectWorkspace(workspaceLocation); const library = { From f4e15d51b83667f1e11bad98d7d99fd2cb16be15 Mon Sep 17 00:00:00 2001 From: tohlh Date: Wed, 5 Nov 2025 21:16:20 +0800 Subject: [PATCH 10/10] fix styles --- src/commons/sagas/__tests__/WorkspaceSaga.test.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/commons/sagas/__tests__/WorkspaceSaga.test.ts b/src/commons/sagas/__tests__/WorkspaceSaga.test.ts index b14fbaec5b..ab8a2f3cf2 100644 --- a/src/commons/sagas/__tests__/WorkspaceSaga.test.ts +++ b/src/commons/sagas/__tests__/WorkspaceSaga.test.ts @@ -684,17 +684,6 @@ describe('PLAYGROUND_EXTERNAL_SELECT', () => { externalLibrary: oldExternalLibraryName }); - const symbols = externalLibraries.get(newExternalLibraryName)!; - const library: Library = { - chapter, - external: { - name: newExternalLibraryName, - symbols - }, - globals, - languageOptions: context.languageOptions - }; - return ( expectSaga(workspaceSaga) .withState(newDefaultState)