@elice/material-exercise 1.230307.0 → 1.230313.0

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.
@@ -1,6 +1,7 @@
1
1
  /// <reference types="react" />
2
2
  import type { MaterialCommponentCommonProps } from '@elice/material-shared-utils';
3
3
  import type { GetOrgMaterialExerciseExerciseRunningListResponses, PostOrgMaterialExerciseExerciseRunningSubmitResponses } from '@elice/types';
4
+ import type { CodeHelperError } from "../../../utils";
4
5
  import type { ExerciseProviderNoImageProps } from './ExerciseProviderNoImage';
5
6
  /**
6
7
  * [External]
@@ -63,7 +64,7 @@ export declare type MaterialExerciseCommonPropExerciseImageEmptyOptions = Exerci
63
64
  /**
64
65
  * On code help button click.
65
66
  */
66
- export declare type MaterialExerciseCommonPropOnCodeHelpRequest = (code: string) => void;
67
+ export declare type MaterialExerciseCommonPropOnCodeHelpRequest = (code: string, error?: CodeHelperError) => void;
67
68
  /**
68
69
  * On default exercise room ID set.
69
70
  */
@@ -17,6 +17,7 @@ var context = require('../context/context.js');
17
17
  var recoilTypes = require('../context/recoilTypes.js');
18
18
  var subjects = require('../context/subjects.js');
19
19
  require('../context/ExerciseProvider.js');
20
+ var runner = require('../../../utils/runner.js');
20
21
  var useRunnerRoomWebSocket = require('../../../hooks/useRunnerRoomWebSocket.js');
21
22
  var useStdioWebSocket = require('../../../hooks/useStdioWebSocket.js');
22
23
  require('ot-text-unicode');
@@ -26,6 +27,7 @@ require('humps');
26
27
  require('lodash/debounce');
27
28
  require('random-words');
28
29
  require('unicount');
30
+ var useStdioTextConcator = require('../../../hooks/useStdioTextConcator.js');
29
31
  var ExerciseIntlProvider = require('../context/ExerciseIntlProvider.js');
30
32
  var en = require('./locales/en.json.js');
31
33
  var ko = require('./locales/ko.json.js');
@@ -54,6 +56,9 @@ const ExerciseRunner = ({
54
56
  var _a, _b, _c;
55
57
 
56
58
  const intl = reactIntl.useIntl();
59
+ const {
60
+ onCodeHelpRequest
61
+ } = React__default["default"].useContext(context.ExerciseContext);
57
62
  const {
58
63
  materialExerciseId,
59
64
  exerciseRoomId,
@@ -76,7 +81,19 @@ const ExerciseRunner = ({
76
81
  const exercisePreviewDisplayMode = recoil.useRecoilValue(recoil$1.exercisePreviewDisplayModeState); // websockets
77
82
 
78
83
  const setRunnerRoomWebSocketState = recoil.useSetRecoilState(recoil$1.exerciseWebsocketQuery('runnerRoom'));
79
- const setStdioWebSocketState = recoil.useSetRecoilState(recoil$1.exerciseWebsocketQuery('stdio')); // etc
84
+ const setStdioWebSocketState = recoil.useSetRecoilState(recoil$1.exerciseWebsocketQuery('stdio'));
85
+
86
+ const handleAiHelpibotError = text => {
87
+ const error = runner.getProgrammingErrorResult(text);
88
+
89
+ if (!!error && typeof onCodeHelpRequest === 'function') {
90
+ onCodeHelpRequest(text, error);
91
+ }
92
+ };
93
+
94
+ const {
95
+ updateStdioTextConcator
96
+ } = useStdioTextConcator.useStdioTextConcator(handleAiHelpibotError); // etc
80
97
 
81
98
  const exerciseContainerSize = recoil.useRecoilValue(recoil$1.exerciseContainerSizeState);
82
99
  const [runnerSubmitErrorDialog, setRunnerSubmitErrorDialog] = React__default["default"].useState(null);
@@ -117,6 +134,7 @@ const ExerciseRunner = ({
117
134
  switch (type) {
118
135
  case 'text':
119
136
  (_a = xterm.current) === null || _a === void 0 ? void 0 : _a[runnerRunTypeRef.current !== types.enums.ExerciseRunType.Run ? 'writeEmphasized' : 'write'](text);
137
+ updateStdioTextConcator(text);
120
138
  break;
121
139
 
122
140
  case 'grader':
@@ -0,0 +1,4 @@
1
+ export declare const useStdioTextConcator: (done: (text: string) => void) => {
2
+ updateStdioTextConcator: (text: string) => void;
3
+ done: (text: string) => void;
4
+ };
@@ -0,0 +1,40 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var React = require('react');
6
+ var recoil = require('recoil');
7
+ var recoil$1 = require('../components/material-exercise/context/recoil.js');
8
+ require('../components/material-exercise/context/context.js');
9
+ require('../components/material-exercise/context/recoilTypes.js');
10
+ require('../components/material-exercise/context/subjects.js');
11
+ require('../components/material-exercise/context/ExerciseProvider.js');
12
+
13
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
14
+
15
+ var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
16
+
17
+ const useStdioTextConcator = done => {
18
+ const RUNNER_AND_STDIO_DELAY_SAFETY_FACTOR = 1000;
19
+ const [text, setText] = React__default["default"].useState('');
20
+ const isRunning = recoil.useRecoilValue(recoil$1.exerciseRunnerRunningState);
21
+ React__default["default"].useEffect(() => {
22
+ if (isRunning) {
23
+ setText('');
24
+ } else {
25
+ setTimeout(() => {
26
+ done(text);
27
+ }, RUNNER_AND_STDIO_DELAY_SAFETY_FACTOR);
28
+ } // eslint-disable-next-line react-hooks/exhaustive-deps
29
+
30
+ }, [isRunning]);
31
+ const updateStdioTextConcator = React__default["default"].useCallback(text => {
32
+ setText(state => state.concat(text));
33
+ }, []);
34
+ return {
35
+ updateStdioTextConcator,
36
+ done
37
+ };
38
+ };
39
+
40
+ exports.useStdioTextConcator = useStdioTextConcator;
@@ -1 +1,2 @@
1
1
  export * from './exerciseFile';
2
+ export * from './runner';
@@ -0,0 +1,11 @@
1
+ declare type ErrorType = 'runtime' | 'compile' | 'syntax';
2
+ declare type ErrorLangType = 'python' | 'c/cpp' | 'java' | 'javascript';
3
+ export declare type CodeHelperError = {
4
+ errorLangType: ErrorLangType;
5
+ errorType: ErrorType;
6
+ };
7
+ /**
8
+ * Get Programming Error Results from text.
9
+ */
10
+ export declare function getProgrammingErrorResult(text: string): CodeHelperError | null;
11
+ export {};
@@ -0,0 +1,71 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ //
6
+ // This logic is based on the following spreadsheet.
7
+ // https://docs.google.com/spreadsheets/d/1AeIf1eIlxp2MFR5hZijr-s304xVHMdtuAzcODS6nL-g/edit#gid=0
8
+ //
9
+
10
+ /**
11
+ * Get Programming Error Results from text.
12
+ */
13
+ function getProgrammingErrorResult(text) {
14
+ const escapedText = text.replace(/[\r|\\]/gm, '');
15
+ const PythonRuntimeErrorRegex = new RegExp(/Traceback \(most recent call last\):\n\s*File "\S+", line \d+, in \S+\n\s*.*\n(.+\n)*\S+Error:\s.+/gm);
16
+ const PythonSyntaxErrorRegex = new RegExp(/File "(.*?)", line (\d+)\n\s*.+\n\s*(\^+)\n(.+)Error:\s(.+)/gm);
17
+ const CCCPCompileErrorRegex = new RegExp(/(.*?):(\d+):(\d+):\s+(warning|error|note):\s+(.*)(\n.+\n.+)?/gm);
18
+ const CCCPRuntimeErrorRegex = new RegExp(/(\w+ fault)\s+\(.*\)/gm);
19
+ const JavaCompileErrorRegex = new RegExp(/(.*?):(\d+):\s+error:\s+(.*)\n.+\n.+(\n\s*symbol.+)?(\n\s*location.+)?/gm);
20
+ const JavaRuntimeErrorRegex = new RegExp(/^Exception in thread ".+" (.+)$\n((?:\s+at .+$\n)+)/gm);
21
+ const JavascriptRuntimeErrorRegex = new RegExp(/(Uncaught )?(\w+Error):\s+(.*)\n((?:\s+at .+$\n)+)/gm);
22
+
23
+ switch (true) {
24
+ case PythonRuntimeErrorRegex.test(escapedText):
25
+ return {
26
+ errorLangType: 'python',
27
+ errorType: 'runtime'
28
+ };
29
+
30
+ case PythonSyntaxErrorRegex.test(escapedText):
31
+ return {
32
+ errorLangType: 'python',
33
+ errorType: 'syntax'
34
+ };
35
+
36
+ case CCCPCompileErrorRegex.test(escapedText):
37
+ return {
38
+ errorLangType: 'c/cpp',
39
+ errorType: 'compile'
40
+ };
41
+
42
+ case CCCPRuntimeErrorRegex.test(escapedText):
43
+ return {
44
+ errorLangType: 'c/cpp',
45
+ errorType: 'runtime'
46
+ };
47
+
48
+ case JavaCompileErrorRegex.test(escapedText):
49
+ return {
50
+ errorLangType: 'java',
51
+ errorType: 'compile'
52
+ };
53
+
54
+ case JavaRuntimeErrorRegex.test(escapedText):
55
+ return {
56
+ errorLangType: 'java',
57
+ errorType: 'runtime'
58
+ };
59
+
60
+ case JavascriptRuntimeErrorRegex.test(escapedText):
61
+ return {
62
+ errorLangType: 'javascript',
63
+ errorType: 'runtime'
64
+ };
65
+
66
+ default:
67
+ return null;
68
+ }
69
+ }
70
+
71
+ exports.getProgrammingErrorResult = getProgrammingErrorResult;
@@ -1,6 +1,7 @@
1
1
  /// <reference types="react" />
2
2
  import type { MaterialCommponentCommonProps } from '@elice/material-shared-utils';
3
3
  import type { GetOrgMaterialExerciseExerciseRunningListResponses, PostOrgMaterialExerciseExerciseRunningSubmitResponses } from '@elice/types';
4
+ import type { CodeHelperError } from "../../../utils";
4
5
  import type { ExerciseProviderNoImageProps } from './ExerciseProviderNoImage';
5
6
  /**
6
7
  * [External]
@@ -63,7 +64,7 @@ export declare type MaterialExerciseCommonPropExerciseImageEmptyOptions = Exerci
63
64
  /**
64
65
  * On code help button click.
65
66
  */
66
- export declare type MaterialExerciseCommonPropOnCodeHelpRequest = (code: string) => void;
67
+ export declare type MaterialExerciseCommonPropOnCodeHelpRequest = (code: string, error?: CodeHelperError) => void;
67
68
  /**
68
69
  * On default exercise room ID set.
69
70
  */
@@ -15,6 +15,7 @@ import { ExerciseContext } from '../context/context.js';
15
15
  import { ExercisePreviewType, ExercisePreviewDisplayMode } from '../context/recoilTypes.js';
16
16
  import { exerciseRunnerTextSend$ } from '../context/subjects.js';
17
17
  import '../context/ExerciseProvider.js';
18
+ import { getProgrammingErrorResult } from '../../../utils/runner.js';
18
19
  import { useRunnerRoomWebSocket } from '../../../hooks/useRunnerRoomWebSocket.js';
19
20
  import { useStdioWebSocket } from '../../../hooks/useStdioWebSocket.js';
20
21
  import 'ot-text-unicode';
@@ -24,6 +25,7 @@ import 'humps';
24
25
  import 'lodash/debounce';
25
26
  import 'random-words';
26
27
  import 'unicount';
28
+ import { useStdioTextConcator } from '../../../hooks/useStdioTextConcator.js';
27
29
  import { withExerciseIntlProvider } from '../context/ExerciseIntlProvider.js';
28
30
  import phrasesEn from './locales/en.json.js';
29
31
  import phrasesKo from './locales/ko.json.js';
@@ -47,6 +49,9 @@ const ExerciseRunner = ({
47
49
  var _a, _b, _c;
48
50
 
49
51
  const intl = useIntl();
52
+ const {
53
+ onCodeHelpRequest
54
+ } = React.useContext(ExerciseContext);
50
55
  const {
51
56
  materialExerciseId,
52
57
  exerciseRoomId,
@@ -69,7 +74,19 @@ const ExerciseRunner = ({
69
74
  const exercisePreviewDisplayMode = useRecoilValue(exercisePreviewDisplayModeState); // websockets
70
75
 
71
76
  const setRunnerRoomWebSocketState = useSetRecoilState(exerciseWebsocketQuery('runnerRoom'));
72
- const setStdioWebSocketState = useSetRecoilState(exerciseWebsocketQuery('stdio')); // etc
77
+ const setStdioWebSocketState = useSetRecoilState(exerciseWebsocketQuery('stdio'));
78
+
79
+ const handleAiHelpibotError = text => {
80
+ const error = getProgrammingErrorResult(text);
81
+
82
+ if (!!error && typeof onCodeHelpRequest === 'function') {
83
+ onCodeHelpRequest(text, error);
84
+ }
85
+ };
86
+
87
+ const {
88
+ updateStdioTextConcator
89
+ } = useStdioTextConcator(handleAiHelpibotError); // etc
73
90
 
74
91
  const exerciseContainerSize = useRecoilValue(exerciseContainerSizeState);
75
92
  const [runnerSubmitErrorDialog, setRunnerSubmitErrorDialog] = React.useState(null);
@@ -110,6 +127,7 @@ const ExerciseRunner = ({
110
127
  switch (type) {
111
128
  case 'text':
112
129
  (_a = xterm.current) === null || _a === void 0 ? void 0 : _a[runnerRunTypeRef.current !== enums.ExerciseRunType.Run ? 'writeEmphasized' : 'write'](text);
130
+ updateStdioTextConcator(text);
113
131
  break;
114
132
 
115
133
  case 'grader':
@@ -0,0 +1,4 @@
1
+ export declare const useStdioTextConcator: (done: (text: string) => void) => {
2
+ updateStdioTextConcator: (text: string) => void;
3
+ done: (text: string) => void;
4
+ };
@@ -0,0 +1,32 @@
1
+ import React from 'react';
2
+ import { useRecoilValue } from 'recoil';
3
+ import { exerciseRunnerRunningState } from '../components/material-exercise/context/recoil.js';
4
+ import '../components/material-exercise/context/context.js';
5
+ import '../components/material-exercise/context/recoilTypes.js';
6
+ import '../components/material-exercise/context/subjects.js';
7
+ import '../components/material-exercise/context/ExerciseProvider.js';
8
+
9
+ const useStdioTextConcator = done => {
10
+ const RUNNER_AND_STDIO_DELAY_SAFETY_FACTOR = 1000;
11
+ const [text, setText] = React.useState('');
12
+ const isRunning = useRecoilValue(exerciseRunnerRunningState);
13
+ React.useEffect(() => {
14
+ if (isRunning) {
15
+ setText('');
16
+ } else {
17
+ setTimeout(() => {
18
+ done(text);
19
+ }, RUNNER_AND_STDIO_DELAY_SAFETY_FACTOR);
20
+ } // eslint-disable-next-line react-hooks/exhaustive-deps
21
+
22
+ }, [isRunning]);
23
+ const updateStdioTextConcator = React.useCallback(text => {
24
+ setText(state => state.concat(text));
25
+ }, []);
26
+ return {
27
+ updateStdioTextConcator,
28
+ done
29
+ };
30
+ };
31
+
32
+ export { useStdioTextConcator };
@@ -1 +1,2 @@
1
1
  export * from './exerciseFile';
2
+ export * from './runner';
@@ -0,0 +1,11 @@
1
+ declare type ErrorType = 'runtime' | 'compile' | 'syntax';
2
+ declare type ErrorLangType = 'python' | 'c/cpp' | 'java' | 'javascript';
3
+ export declare type CodeHelperError = {
4
+ errorLangType: ErrorLangType;
5
+ errorType: ErrorType;
6
+ };
7
+ /**
8
+ * Get Programming Error Results from text.
9
+ */
10
+ export declare function getProgrammingErrorResult(text: string): CodeHelperError | null;
11
+ export {};
@@ -0,0 +1,67 @@
1
+ //
2
+ // This logic is based on the following spreadsheet.
3
+ // https://docs.google.com/spreadsheets/d/1AeIf1eIlxp2MFR5hZijr-s304xVHMdtuAzcODS6nL-g/edit#gid=0
4
+ //
5
+
6
+ /**
7
+ * Get Programming Error Results from text.
8
+ */
9
+ function getProgrammingErrorResult(text) {
10
+ const escapedText = text.replace(/[\r|\\]/gm, '');
11
+ const PythonRuntimeErrorRegex = new RegExp(/Traceback \(most recent call last\):\n\s*File "\S+", line \d+, in \S+\n\s*.*\n(.+\n)*\S+Error:\s.+/gm);
12
+ const PythonSyntaxErrorRegex = new RegExp(/File "(.*?)", line (\d+)\n\s*.+\n\s*(\^+)\n(.+)Error:\s(.+)/gm);
13
+ const CCCPCompileErrorRegex = new RegExp(/(.*?):(\d+):(\d+):\s+(warning|error|note):\s+(.*)(\n.+\n.+)?/gm);
14
+ const CCCPRuntimeErrorRegex = new RegExp(/(\w+ fault)\s+\(.*\)/gm);
15
+ const JavaCompileErrorRegex = new RegExp(/(.*?):(\d+):\s+error:\s+(.*)\n.+\n.+(\n\s*symbol.+)?(\n\s*location.+)?/gm);
16
+ const JavaRuntimeErrorRegex = new RegExp(/^Exception in thread ".+" (.+)$\n((?:\s+at .+$\n)+)/gm);
17
+ const JavascriptRuntimeErrorRegex = new RegExp(/(Uncaught )?(\w+Error):\s+(.*)\n((?:\s+at .+$\n)+)/gm);
18
+
19
+ switch (true) {
20
+ case PythonRuntimeErrorRegex.test(escapedText):
21
+ return {
22
+ errorLangType: 'python',
23
+ errorType: 'runtime'
24
+ };
25
+
26
+ case PythonSyntaxErrorRegex.test(escapedText):
27
+ return {
28
+ errorLangType: 'python',
29
+ errorType: 'syntax'
30
+ };
31
+
32
+ case CCCPCompileErrorRegex.test(escapedText):
33
+ return {
34
+ errorLangType: 'c/cpp',
35
+ errorType: 'compile'
36
+ };
37
+
38
+ case CCCPRuntimeErrorRegex.test(escapedText):
39
+ return {
40
+ errorLangType: 'c/cpp',
41
+ errorType: 'runtime'
42
+ };
43
+
44
+ case JavaCompileErrorRegex.test(escapedText):
45
+ return {
46
+ errorLangType: 'java',
47
+ errorType: 'compile'
48
+ };
49
+
50
+ case JavaRuntimeErrorRegex.test(escapedText):
51
+ return {
52
+ errorLangType: 'java',
53
+ errorType: 'runtime'
54
+ };
55
+
56
+ case JavascriptRuntimeErrorRegex.test(escapedText):
57
+ return {
58
+ errorLangType: 'javascript',
59
+ errorType: 'runtime'
60
+ };
61
+
62
+ default:
63
+ return null;
64
+ }
65
+ }
66
+
67
+ export { getProgrammingErrorResult };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elice/material-exercise",
3
- "version": "1.230307.0",
3
+ "version": "1.230313.0",
4
4
  "description": "User view and editing components of Elice material exercise",
5
5
  "repository": "https://git.elicer.io/elice/frontend/library/elice-material",
6
6
  "license": "UNLICENSED",
@@ -79,8 +79,8 @@
79
79
  "@elice/design-tokens": "^1.220803.0",
80
80
  "@elice/icons": "^1.220803.0",
81
81
  "@elice/markdown": "^1.220803.0",
82
- "@elice/material-shared-types": "1.230307.0",
83
- "@elice/material-shared-utils": "1.230307.0",
82
+ "@elice/material-shared-types": "1.230313.0",
83
+ "@elice/material-shared-utils": "1.230313.0",
84
84
  "@elice/types": "^1.230306.0",
85
85
  "@elice/websocket": "^1.220803.0",
86
86
  "@types/classnames": "^2.3.1",
@@ -102,5 +102,5 @@
102
102
  "recoil": "^0.6.1",
103
103
  "styled-components": "^5.2.0"
104
104
  },
105
- "gitHead": "e7777b1586edece39b8c7610aa165fc2ae7044a1"
105
+ "gitHead": "ea7a377780b94fdfabc46af4d565c56f09e0f639"
106
106
  }