Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ env:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
lint:
if: github.event.pull_request.draft == false
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ To start contributing, create a fork from our repo and send a PR. Refer to [this

The frontend comes with an extensive test suite. To run the tests after you made your modifications, run
`yarn test`. Regression tests are run automatically when you want to push changes to this repository.
The regression tests are generated using `jest` and stored as snapshots in `src/\_\_tests\_\_`. After modifying the frontend, carefully inspect any failing regression tests reported in red in the command line. If you are convinced that the regression tests and not your changes are at fault, you can update the regression tests by running:
The regression tests are generated using `jest` and stored as snapshots in `src/\_\_tests\_\_`. After modifying the frontend, carefully inspect any failing regression tests reported in red in the command line. If you are convinced that the regression tests and not your changes are at fault, you can update the regression tests by running:

```bash
yarn test --updateSnapshot
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ The Source Academy (<https://sourceacademy.org/>) is an immersive online experie

1. Clone this repository and navigate to it using your command line

1. Install the version of `yarn` as specified in `package.json`, `packageManager`.
1. Install the version of `yarn` as specified in `package.json`, `packageManager`.

> We recommend using `corepack` to manage the version of `yarn`, you may simply run `corepack enable` to complete this step.

Expand Down
2 changes: 1 addition & 1 deletion _config.yml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
theme: jekyll-theme-cayman
theme: jekyll-theme-cayman
59 changes: 30 additions & 29 deletions craco.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,17 @@ const cracoConfig = {
// Polyfill Node.js core modules.
// An empty implementation (false) is provided when there is no browser equivalent.
webpackConfig.resolve.fallback = {
'child_process': false,
'constants': require.resolve('constants-browserify'),
'fs': false,
'http': require.resolve('stream-http'),
'https': require.resolve('https-browserify'),
'os': require.resolve('os-browserify/browser'),
child_process: false,
constants: require.resolve('constants-browserify'),
fs: false,
http: require.resolve('stream-http'),
https: require.resolve('https-browserify'),
os: require.resolve('os-browserify/browser'),
'path/posix': require.resolve('path-browserify'),
'process/browser': require.resolve('process/browser'),
'stream': require.resolve('stream-browserify'),
'timers': require.resolve('timers-browserify'),
'url': require.resolve('url/'),
stream: require.resolve('stream-browserify'),
timers: require.resolve('timers-browserify'),
url: require.resolve('url/')
};

// workaround .mjs files by Acorn
Expand All @@ -60,31 +60,34 @@ const cracoConfig = {
type: 'javascript/auto',
resolve: {
fullySpecified: false
},
}
});

webpackConfig.ignoreWarnings = [{
// Ignore warnings for dependencies that do not ship with a source map.
// This is because we cannot do anything about our dependencies.
module: /node_modules/,
message: /Failed to parse source map/
}, {
// Ignore the warnings that occur because js-slang uses dynamic imports
// to load Source modules
module: /js-slang\/dist\/modules\/loader\/loaders.js/,
message: /Critical dependency: the request of a dependency is an expression/
}];
webpackConfig.ignoreWarnings = [
{
// Ignore warnings for dependencies that do not ship with a source map.
// This is because we cannot do anything about our dependencies.
module: /node_modules/,
message: /Failed to parse source map/
},
{
// Ignore the warnings that occur because js-slang uses dynamic imports
// to load Source modules
module: /js-slang\/dist\/modules\/loader\/loaders.js/,
message: /Critical dependency: the request of a dependency is an expression/
}
];

webpackConfig.plugins = [
...webpackConfig.plugins,
// Make environment variables available in the browser by polyfilling the 'process' Node.js module.
new webpack.ProvidePlugin({
process: 'process/browser',
process: 'process/browser'
}),
// Make the 'buffer' Node.js module available in the browser.
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer'],
}),
Buffer: ['buffer', 'Buffer']
})
];

// Workaround to suppress warnings caused by ts-morph in js-slang
Expand Down Expand Up @@ -156,16 +159,14 @@ const cracoConfig = {
jestConfig.setupFiles = [
...jestConfig.setupFiles,
'./src/i18n/i18n.ts' // Setup i18next configuration
]
];
return jestConfig;
}
},
babel: {
presets: [
['@babel/preset-typescript']
]
presets: [['@babel/preset-typescript']]
}
}
};

const ignoreModulePaths = (...paths) => {
const moduleRoot = replaceSlashes('/node_modules/');
Expand Down
4 changes: 2 additions & 2 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { config, configs } from 'typescript-eslint';
import reactPlugin from 'eslint-plugin-react';
import reactHooksPlugin from 'eslint-plugin-react-hooks';
import simpleImportSort from 'eslint-plugin-simple-import-sort'
import simpleImportSort from 'eslint-plugin-simple-import-sort';
// import reactRefresh from 'eslint-plugin-react-refresh';

export default config(
Expand All @@ -24,7 +24,7 @@ export default config(
files: ['**/*.ts*'],
plugins: {
'react-hooks': reactHooksPlugin,
'react': reactPlugin,
react: reactPlugin,
'simple-import-sort': simpleImportSort
},
rules: {
Expand Down
6 changes: 3 additions & 3 deletions public/externalLibs/sound/soundToneMatrix.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ var timeout_matrix;
// for coloring the matrix accordingly while it's being played
var timeout_color;

var timeout_objects = new Array();
var timeout_objects = [];

// vector_to_list returns a list that contains the elements of the argument vector
// in the given order.
Expand All @@ -54,7 +54,7 @@ function vector_to_list(vector) {
function x_y_to_row_column(x, y) {
var row = Math.floor((y - margin_length) / (square_side_length + distance_between_squares));
var column = Math.floor((x - margin_length) / (square_side_length + distance_between_squares));
return Array(row, column);
return [row, column];
}

// given the row number of a square, return the leftmost coordinate
Expand Down Expand Up @@ -365,5 +365,5 @@ function clear_all_timeout() {
clearTimeout(timeout_objects[i]);
}

timeout_objects = new Array();
timeout_objects = [];
}
8 changes: 4 additions & 4 deletions public/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@
"type": "image/png"
},
{
"src": "icons/android-chrome-256x256.png",
"sizes": "256x256",
"type": "image/png"
"src": "icons/android-chrome-256x256.png",
"sizes": "256x256",
"type": "image/png"
},
{
"src": "icons/maskable.png",
"sizes": "196x196",
"type": "image/png",
"purpose": "maskable"
}
}
],
"start_url": "./",
"display": "standalone",
Expand Down
35 changes: 35 additions & 0 deletions src/features/cseMachine/CseMachineAnimation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import React from 'react';

import { ArrayAccessAnimation } from './animationComponents/ArrayAccessAnimation';
import { ArrayAssignmentAnimation } from './animationComponents/ArrayAssignmentAnimation';
import { ArraySpreadAnimation } from './animationComponents/ArraySpreadAnimation';
import { AssignmentAnimation } from './animationComponents/AssignmentAnimation';
import { Animatable } from './animationComponents/base/Animatable';
import { lookupBinding } from './animationComponents/base/AnimationUtils';
Expand Down Expand Up @@ -112,6 +113,11 @@ export class CseAnimation {
);
}
break;
case 'SpreadElement':
CseAnimation.animations.push(
new ControlExpansionAnimation(lastControlComponent, CseAnimation.getNewControlItems())
);
break;
case 'AssignmentExpression':
case 'ArrayExpression':
case 'BinaryExpression':
Expand Down Expand Up @@ -276,6 +282,35 @@ export class CseAnimation {
)
);
break;
case InstrType.SPREAD:
const control = Layout.controlComponent.stackItemComponents;
const array = Layout.previousStashComponent.stashItemComponents.at(-1)!.arrow!
.target! as ArrayValue;

let currCallInstr;

for (let i = 1; control.at(-i) != undefined; i++) {
if (control.at(-i)?.text.includes('call ')) {
// find call instr above
currCallInstr = control.at(-i);
break;
}
}

const resultItems =
array.data.length !== 0
? Layout.stashComponent.stashItemComponents.slice(-array.data.length)
: [];

CseAnimation.animations.push(
new ArraySpreadAnimation(
lastControlComponent,
Layout.previousStashComponent.stashItemComponents.at(-1)!,
resultItems!,
currCallInstr!
)
);
break;
case InstrType.ARRAY_LENGTH:
case InstrType.BREAK:
case InstrType.BREAK_MARKER:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export class ArrayAccessAnimation extends Animatable {
private resultAnimation: AnimatedTextbox;
private resultArrowAnimation?: AnimatedGenericArrow<StashItemComponent, Visible>;
private arrayUnit: ArrayUnit;
private out: boolean;

constructor(
private accInstr: ControlItemComponent,
Expand All @@ -46,12 +47,29 @@ export class ArrayAccessAnimation extends Animatable {
rectProps: { stroke: defaultDangerColor() }
});
this.arrayArrowAnimation = new AnimatedGenericArrow(arrayItem.arrow!);
// if index is out of range
this.out = false;
// the target should always be an array value
const array = arrayItem.arrow!.target! as ArrayValue;
this.arrayUnit = array.units[parseInt(indexItem.text)];

// if index access is out of range. if index access is negative, error should be thrown from js-slang at this point
const arraylen = array.data.length;

if (parseInt(indexItem.text) >= arraylen) {
this.out = true;
this.arrayUnit = array.units[arraylen - 1];
} else {
this.arrayUnit = array.units[parseInt(indexItem.text)];
}

this.resultAnimation = new AnimatedTextbox(resultItem.text, {
...getNodeDimensions(resultItem),
x: this.arrayUnit.x() + this.arrayUnit.width() / 2 - this.resultItem.width() / 2,
// if array index out of range, animate to one unit beyond array
x:
this.arrayUnit.x() +
this.arrayUnit.width() / 2 -
this.resultItem.width() / 2 +
(this.out ? this.arrayUnit.width() : 0),
y: this.arrayUnit.y() + this.arrayUnit.height() / 2 - this.resultItem.height() / 2,
opacity: 0
});
Expand Down Expand Up @@ -79,7 +97,12 @@ export class ArrayAccessAnimation extends Animatable {
const minInstrItemWidth =
getTextWidth(this.accInstr.text) + ControlStashConfig.ControlItemTextPadding * 2;
const indexAboveArrayLocation = {
x: this.arrayUnit.x() + this.arrayUnit.width() / 2 - this.indexItem.width() / 2,
// if array index out of range, animate to one unit beyond array
x:
this.arrayUnit.x() +
this.arrayUnit.width() / 2 -
this.indexItem.width() / 2 +
(this.out ? this.arrayUnit.width() : 0),
y: this.arrayUnit.y() - this.indexItem.height() - 8
};
const indexInArrayLocation = {
Expand Down
Loading
Loading