Skip to content
Merged
3 changes: 2 additions & 1 deletion src/commons/assessment/AssessmentTypes.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand Down Expand Up @@ -177,6 +177,7 @@ export type Library = {
2?: string; // For mission control
}>;
moduleParams?: any;
languageOptions?: LanguageOptions;
};

export type Testcase = {
Expand Down
9 changes: 7 additions & 2 deletions src/commons/sagas/WorkspaceSaga/helpers/blockExtraMethods.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import type { Context } from 'js-slang';
import { Context } from 'js-slang';
import { Variant } from 'js-slang/dist/types';
import { call } from 'redux-saga/effects';

import {
getBlockExtraMethodsString,
getBlockExtraMethodsStringTypedVariant,
getDifferenceInMethods,
getStoreExtraMethodsString
} from '../../../utils/JsSlangHelper';
Expand Down Expand Up @@ -35,7 +37,10 @@ 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
Expand Down
5 changes: 3 additions & 2 deletions src/commons/sagas/WorkspaceSaga/helpers/clearContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { selectWorkspace } from '../../SafeEffects';

export function* clearContext(workspaceLocation: WorkspaceLocation, entrypointCode: string) {
const {
context: { chapter, externalSymbols: symbols, variant },
context: { chapter, externalSymbols: symbols, variant, languageOptions },
externalLibrary: externalLibraryName,
globals
} = yield* selectWorkspace(workspaceLocation);
Expand All @@ -22,7 +22,8 @@ export function* clearContext(workspaceLocation: WorkspaceLocation, entrypointCo
name: externalLibraryName,
symbols
},
globals
globals,
languageOptions
};

// Clear the context, with the same chapter and externalSymbols as before.
Expand Down
28 changes: 19 additions & 9 deletions src/commons/sagas/WorkspaceSaga/helpers/evalEditor.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
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';

Expand Down Expand Up @@ -82,19 +83,28 @@ export function* evalEditorSaga(
const prependFiles = {
[prependFilePath]: prepend
};
yield call(
evalCodeSaga,
prependFiles,
prependFilePath,
elevatedContext,
execTime,
EVAL_SILENT,
workspaceLocation
);
if (context.variant !== Variant.TYPED) {
yield call(
evalCodeSaga,
prependFiles,
prependFilePath,
elevatedContext,
execTime,
EVAL_SILENT,
workspaceLocation
);
}

// Block use of methods from privileged context
yield* blockExtraMethods(elevatedContext, context, execTime, workspaceLocation);
}

if (context.variant === Variant.TYPED) {
// 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,
files,
Expand Down
57 changes: 30 additions & 27 deletions src/commons/sagas/__tests__/WorkspaceSaga.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ describe('EVAL_EDITOR', () => {
name: ExternalLibraryName.NONE,
symbols: context.externalSymbols
},
globals
globals,
languageOptions: context.languageOptions
};

const newDefaultState = generateDefaultState(workspaceLocation, {
Expand Down Expand Up @@ -397,7 +398,8 @@ describe('EVAL_TESTCASE', () => {
name: ExternalLibraryName.NONE,
symbols: context.externalSymbols
},
globals
globals,
languageOptions: context.languageOptions
};

const newDefaultState = generateDefaultState(workspaceLocation, {
Expand Down Expand Up @@ -682,30 +684,30 @@ describe('PLAYGROUND_EXTERNAL_SELECT', () => {
externalLibrary: oldExternalLibraryName
});

const symbols = externalLibraries.get(newExternalLibraryName)!;
const library: Library = {
chapter,
external: {
name: newExternalLibraryName,
symbols
},
globals
};

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', () => {
Expand Down Expand Up @@ -770,7 +772,8 @@ describe('BEGIN_CLEAR_CONTEXT', () => {
name: newExternalLibraryName,
symbols
},
globals
globals,
languageOptions: undefined
};

return expectSaga(workspaceSaga)
Expand Down
11 changes: 11 additions & 0 deletions src/commons/utils/JsSlangHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,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
Expand Down Expand Up @@ -258,3 +259,13 @@ 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');
}
3 changes: 2 additions & 1 deletion src/commons/workspace/WorkspaceReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,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
Expand Down
Loading