Skip to content

Commit f70066c

Browse files
authored
Add Full TypeScript chapter (#2379)
* Add full TS chapter * Suppress ts-morph warnings * Add tests * Bump js-slang * Fix workaround * Increase cache size * Remove tabs for full TS
1 parent 02a8ce8 commit f70066c

File tree

11 files changed

+213
-75
lines changed

11 files changed

+213
-75
lines changed

craco.config.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const cracoConfig = (module.exports = {
1818
plugin => plugin.constructor.name === 'InjectManifest'
1919
);
2020
if (injectManifestPlugin) {
21-
injectManifestPlugin.config.maximumFileSizeToCacheInBytes = 10 * 1024 * 1024;
21+
injectManifestPlugin.config.maximumFileSizeToCacheInBytes = 15 * 1024 * 1024;
2222
}
2323

2424
// add rules to pack WASM (for Sourceror)
@@ -77,6 +77,9 @@ const cracoConfig = (module.exports = {
7777
})
7878
];
7979

80+
// Workaround to suppress warnings caused by ts-morph in js-slang
81+
webpackConfig.module.noParse = /typescript\.js$/;
82+
8083
return webpackConfig;
8184
}
8285
},

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"classnames": "^2.3.2",
4444
"flexboxgrid": "^6.3.1",
4545
"flexboxgrid-helpers": "^1.1.3",
46-
"js-slang": "^1.0.15",
46+
"js-slang": "^1.0.16",
4747
"konva": "^8.3.14",
4848
"lodash": "^4.17.21",
4949
"lz-string": "^1.4.4",

src/commons/application/ApplicationTypes.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@ export const fullJSLanguage: SALanguage = {
128128
displayName: 'full JavaScript'
129129
};
130130

131+
export const fullTSLanguage: SALanguage = {
132+
chapter: Chapter.FULL_TS,
133+
variant: Variant.DEFAULT,
134+
displayName: 'full TypeScript'
135+
};
136+
131137
export const htmlLanguage: SALanguage = {
132138
chapter: Chapter.HTML,
133139
variant: Variant.DEFAULT,
@@ -138,6 +144,8 @@ export const styliseSublanguage = (chapter: Chapter, variant: Variant = Variant.
138144
switch (chapter) {
139145
case Chapter.FULL_JS:
140146
return fullJSLanguage.displayName;
147+
case Chapter.FULL_TS:
148+
return fullTSLanguage.displayName;
141149
case Chapter.HTML:
142150
return htmlLanguage.displayName;
143151
default:

src/commons/controlBar/ControlBarChapterSelect.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import React from 'react';
77
import {
88
defaultLanguages,
99
fullJSLanguage,
10+
fullTSLanguage,
1011
htmlLanguage,
1112
SALanguage,
1213
sourceLanguages,
@@ -31,11 +32,13 @@ const chapterListRenderer: ItemListRenderer<SALanguage> = ({ itemsParentRef, ren
3132
const defaultChoices = defaultLanguages.map(renderItem);
3233
const variantChoices = variantLanguages.map(renderItem);
3334
const fullJSChoice = renderItem(fullJSLanguage, 0);
35+
const fullTSChoice = renderItem(fullTSLanguage, 0);
3436
const htmlChoice = renderItem(htmlLanguage, 0);
3537
return (
3638
<Menu ulRef={itemsParentRef}>
3739
{defaultChoices}
3840
{Constants.playgroundOnly && fullJSChoice}
41+
{Constants.playgroundOnly && fullTSChoice}
3942
{Constants.playgroundOnly && htmlChoice}
4043
<MenuItem key="variant-menu" text="Variants" icon="cog">
4144
{variantChoices}

src/commons/fullJS/FullJSUtils.tsx

Lines changed: 0 additions & 33 deletions
This file was deleted.

src/commons/html/HTMLUtils.tsx

Lines changed: 0 additions & 25 deletions
This file was deleted.

src/commons/sagas/WorkspaceSaga.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ import {
4242
} from '../application/types/InterpreterTypes';
4343
import { Library, Testcase, TestcaseType, TestcaseTypes } from '../assessment/AssessmentTypes';
4444
import { Documentation } from '../documentation/Documentation';
45-
import { showFullJSDisclaimer } from '../fullJS/FullJSUtils';
4645
import { SideContentType } from '../sideContent/SideContentTypes';
4746
import { actions } from '../utils/ActionsHelper';
4847
import DisplayBufferService from '../utils/DisplayBufferService';
@@ -58,6 +57,7 @@ import {
5857
} from '../utils/JsSlangHelper';
5958
import { showSuccessMessage, showWarningMessage } from '../utils/NotificationsHelper';
6059
import { makeExternalBuiltins as makeSourcerorExternalBuiltins } from '../utils/SourcerorHelper';
60+
import { showFullJSDisclaimer, showFullTSDisclaimer } from '../utils/WarningDialogHelper';
6161
import { notifyProgramEvaluated } from '../workspace/WorkspaceActions';
6262
import {
6363
ADD_HTML_CONSOLE_ERROR,
@@ -309,6 +309,8 @@ export default function* WorkspaceSaga(): SagaIterator {
309309
const toChangeChapter: boolean =
310310
newChapter === Chapter.FULL_JS
311311
? chapterChanged && (yield call(showFullJSDisclaimer))
312+
: newChapter === Chapter.FULL_TS
313+
? chapterChanged && (yield call(showFullTSDisclaimer))
312314
: chapterChanged;
313315

314316
if (toChangeChapter) {

src/commons/sagas/__tests__/WorkspaceSaga.ts

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Chapter, Finished, Variant } from 'js-slang/dist/types';
44
import { call } from 'redux-saga/effects';
55
import { expectSaga } from 'redux-saga-test-plan';
66
import * as matchers from 'redux-saga-test-plan/matchers';
7-
import * as fullJSUtils from 'src/commons/fullJS/FullJSUtils';
7+
import { showFullJSDisclaimer, showFullTSDisclaimer } from 'src/commons/utils/WarningDialogHelper';
88

99
import {
1010
beginInterruptExecution,
@@ -16,7 +16,12 @@ import {
1616
evalTestcaseFailure,
1717
evalTestcaseSuccess
1818
} from '../../application/actions/InterpreterActions';
19-
import { defaultState, fullJSLanguage, OverallState } from '../../application/ApplicationTypes';
19+
import {
20+
defaultState,
21+
fullJSLanguage,
22+
fullTSLanguage,
23+
OverallState
24+
} from '../../application/ApplicationTypes';
2025
import { externalLibraries, ExternalLibraryName } from '../../application/types/ExternalTypes';
2126
import {
2227
BEGIN_DEBUG_PAUSE,
@@ -539,9 +544,9 @@ describe('CHAPTER_SELECT', () => {
539544
};
540545

541546
return expectSaga(workspaceSaga)
542-
.provide([[matchers.call.fn(fullJSUtils.showFullJSDisclaimer), true]])
547+
.provide([[matchers.call.fn(showFullJSDisclaimer), true]])
543548
.withState(newDefaultState)
544-
.call(fullJSUtils.showFullJSDisclaimer)
549+
.call(showFullJSDisclaimer)
545550
.put(beginClearContext(workspaceLocation, library, false))
546551
.put(clearReplOutput(workspaceLocation))
547552
.call(showSuccessMessage, `Switched to full JavaScript`, 1000)
@@ -560,9 +565,9 @@ describe('CHAPTER_SELECT', () => {
560565
const newDefaultState = generateDefaultState(workspaceLocation, { context, globals });
561566

562567
return expectSaga(workspaceSaga)
563-
.provide([[matchers.call.fn(fullJSUtils.showFullJSDisclaimer), false]])
568+
.provide([[matchers.call.fn(showFullJSDisclaimer), false]])
564569
.withState(newDefaultState)
565-
.call(fullJSUtils.showFullJSDisclaimer)
570+
.call(showFullJSDisclaimer)
566571
.not.put.actionType(BEGIN_CLEAR_CONTEXT)
567572
.not.put.actionType(CLEAR_REPL_OUTPUT)
568573
.not.call.fn(showSuccessMessage)
@@ -577,6 +582,59 @@ describe('CHAPTER_SELECT', () => {
577582
.silentRun();
578583
});
579584
});
585+
586+
describe('show disclaimer when fullTS is chosen', () => {
587+
test('correct actions when user proceeds', () => {
588+
const newDefaultState = generateDefaultState(workspaceLocation, { context, globals });
589+
const library: Library = {
590+
chapter: fullTSLanguage.chapter,
591+
variant: fullTSLanguage.variant,
592+
external: {
593+
name: 'NONE' as ExternalLibraryName,
594+
symbols: context.externalSymbols
595+
},
596+
globals
597+
};
598+
599+
return expectSaga(workspaceSaga)
600+
.provide([[matchers.call.fn(showFullTSDisclaimer), true]])
601+
.withState(newDefaultState)
602+
.call(showFullTSDisclaimer)
603+
.put(beginClearContext(workspaceLocation, library, false))
604+
.put(clearReplOutput(workspaceLocation))
605+
.call(showSuccessMessage, `Switched to full TypeScript`, 1000)
606+
.dispatch({
607+
type: CHAPTER_SELECT,
608+
payload: {
609+
chapter: fullTSLanguage.chapter,
610+
variant: fullTSLanguage.variant,
611+
workspaceLocation
612+
}
613+
})
614+
.silentRun();
615+
});
616+
617+
test('correct actions when user cancels', () => {
618+
const newDefaultState = generateDefaultState(workspaceLocation, { context, globals });
619+
620+
return expectSaga(workspaceSaga)
621+
.provide([[matchers.call.fn(showFullTSDisclaimer), false]])
622+
.withState(newDefaultState)
623+
.call(showFullTSDisclaimer)
624+
.not.put.actionType(BEGIN_CLEAR_CONTEXT)
625+
.not.put.actionType(CLEAR_REPL_OUTPUT)
626+
.not.call.fn(showSuccessMessage)
627+
.dispatch({
628+
type: CHAPTER_SELECT,
629+
payload: {
630+
chapter: fullTSLanguage.chapter,
631+
variant: fullTSLanguage.variant,
632+
workspaceLocation
633+
}
634+
})
635+
.silentRun();
636+
});
637+
});
580638
});
581639

582640
describe('PLAYGROUND_EXTERNAL_SELECT', () => {
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { showSimpleConfirmDialog, SimpleConfirmDialogProps } from './DialogHelper';
2+
import { showWarningMessage } from './NotificationsHelper';
3+
4+
// Full JS
5+
const FULL_JS_DISCLAIMER_DIALOG_PROPS: SimpleConfirmDialogProps = {
6+
icon: 'warning-sign',
7+
title: 'You are switching to a unsafe feature!',
8+
contents: (
9+
<p>
10+
<code>full JavaScript</code> allows you to run arbitrary JS code beyond source.
11+
<br />
12+
<br />
13+
This might pose a security concern if you are not careful and fully aware of what program you
14+
are running!
15+
<br />
16+
<br />
17+
<strong>Do you still want to proceed?</strong>
18+
</p>
19+
),
20+
positiveIntent: 'danger',
21+
positiveLabel: 'Proceed',
22+
negativeLabel: 'Cancel'
23+
};
24+
25+
const FULL_JS_URL_LOAD_INFO: string =
26+
'For security concerns, users are not allowed to load full JavaScript code from shared links';
27+
28+
export function showFullJSDisclaimer(): Promise<boolean> {
29+
return showSimpleConfirmDialog(FULL_JS_DISCLAIMER_DIALOG_PROPS);
30+
}
31+
32+
export function showFullJSWarningOnUrlLoad(): void {
33+
showWarningMessage(FULL_JS_URL_LOAD_INFO);
34+
}
35+
36+
// Full TS
37+
const FULL_TS_DISCLAIMER_DIALOG_PROPS: SimpleConfirmDialogProps = {
38+
icon: 'warning-sign',
39+
title: 'You are switching to a unsafe feature!',
40+
contents: (
41+
<p>
42+
<code>full TypeScript</code> allows you to run arbitrary JS code beyond source.
43+
<br />
44+
<br />
45+
This might pose a security concern if you are not careful and fully aware of what program you
46+
are running!
47+
<br />
48+
<br />
49+
<strong>Do you still want to proceed?</strong>
50+
</p>
51+
),
52+
positiveIntent: 'danger',
53+
positiveLabel: 'Proceed',
54+
negativeLabel: 'Cancel'
55+
};
56+
57+
const FULL_TS_URL_LOAD_INFO: string =
58+
'For security concerns, users are not allowed to load full JavaScript code from shared links';
59+
60+
export function showFullTSDisclaimer(): Promise<boolean> {
61+
return showSimpleConfirmDialog(FULL_TS_DISCLAIMER_DIALOG_PROPS);
62+
}
63+
64+
export function showFulTSWarningOnUrlLoad(): void {
65+
showWarningMessage(FULL_TS_URL_LOAD_INFO);
66+
}
67+
68+
// HTML
69+
const HTML_DISCLAIMER_DIALOG_PROPS: SimpleConfirmDialogProps = {
70+
icon: 'warning-sign',
71+
title: 'Beware when running shared HTML code!',
72+
contents: (
73+
<p>
74+
You are about to access HTML code written by others, which may contain malicious scripts.
75+
<br />
76+
<br />
77+
This might pose a security concern if you are not careful and fully aware of what the shared
78+
HTML code contains!
79+
<br />
80+
<br />
81+
<strong>Do you still want to proceed?</strong>
82+
</p>
83+
),
84+
positiveIntent: 'danger',
85+
positiveLabel: 'Proceed',
86+
negativeLabel: 'Cancel'
87+
};
88+
89+
export function showHTMLDisclaimer(): Promise<boolean> {
90+
return showSimpleConfirmDialog(HTML_DISCLAIMER_DIALOG_PROPS);
91+
}

src/pages/playground/Playground.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,13 @@ import {
2626
setEditorSessionId,
2727
setSharedbConnected
2828
} from 'src/commons/collabEditing/CollabEditingActions';
29-
import { showFullJSWarningOnUrlLoad } from 'src/commons/fullJS/FullJSUtils';
30-
import { showHTMLDisclaimer } from 'src/commons/html/HTMLUtils';
3129
import SideContentHtmlDisplay from 'src/commons/sideContent/SideContentHtmlDisplay';
3230
import { useResponsive, useTypedSelector } from 'src/commons/utils/Hooks';
31+
import {
32+
showFullJSWarningOnUrlLoad,
33+
showFulTSWarningOnUrlLoad,
34+
showHTMLDisclaimer
35+
} from 'src/commons/utils/WarningDialogHelper';
3336
import {
3437
addHtmlConsoleError,
3538
browseReplHistoryDown,
@@ -173,6 +176,8 @@ export async function handleHash(hash: string, props: PlaygroundProps) {
173176
const chapter = stringParamToInt(qs.chap) || undefined;
174177
if (chapter === Chapter.FULL_JS) {
175178
showFullJSWarningOnUrlLoad();
179+
} else if (chapter === Chapter.FULL_TS) {
180+
showFulTSWarningOnUrlLoad();
176181
} else {
177182
if (chapter === Chapter.HTML) {
178183
const continueToHtml = await showHTMLDisclaimer();
@@ -656,7 +661,10 @@ const Playground: React.FC<PlaygroundProps> = ({ workspaceLocation = 'playground
656661
}
657662

658663
// (TEMP) Remove tabs for fullJS until support is integrated
659-
if (props.playgroundSourceChapter === Chapter.FULL_JS) {
664+
if (
665+
props.playgroundSourceChapter === Chapter.FULL_JS ||
666+
props.playgroundSourceChapter === Chapter.FULL_TS
667+
) {
660668
return [...tabs, dataVisualizerTab];
661669
}
662670

0 commit comments

Comments
 (0)