Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
37 changes: 37 additions & 0 deletions .github/workflows/eslint.js.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: ESLint

on:
push:
paths:
- 'frontend/**/*.ts'
pull_request:
branches:
- main

defaults:
run:
working-directory: frontend

jobs:
eslint:

runs-on: ubuntu-24.04

strategy:
matrix:
node-version: [24.x]

steps:
- uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
cache-dependency-path: 'frontend/pnpm-lock.yaml'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run ESLint
run: pnpm run eslint
22 changes: 21 additions & 1 deletion frontend/eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import tsPlugin from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
import jsdocPlugin from 'eslint-plugin-jsdoc';
import chaiFriendlyPlugin from 'eslint-plugin-chai-friendly';

export default [
jsdocPlugin.configs['flat/recommended'],
{
// tests/html/ is regenerated Sphinx build output (gitignored), not project code.
ignores: ['tests/html/**'],
},
{
...jsdocPlugin.configs['flat/recommended'],
files: ['src/**/*.ts', 'tests/**/*.ts'],
},
{
files: ['src/**/*.ts', 'tests/**/*.ts'],
plugins: {
Expand All @@ -21,6 +29,18 @@ export default [
...tsPlugin.configs.recommended.rules,
'jsdoc/no-undefined-types': 'off',
'max-len': ['error', {ignoreRegExpLiterals: true}],
'@typescript-eslint/no-unused-vars': ['error', {argsIgnorePattern: '^_'}],
},
},
{
// chai-friendly's rule recognizes chai assertions as non-dead expressions.
files: ['tests/**/*.ts'],
plugins: {
'chai-friendly': chaiFriendlyPlugin,
},
rules: {
'@typescript-eslint/no-unused-expressions': 'off',
'chai-friendly/no-unused-expressions': 'error',
},
},
];
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"css-loader": "^7.1.4",
"css-minimizer-webpack-plugin": "^8.0.0",
"eslint": "^10.7.0",
"eslint-plugin-chai-friendly": "^1.2.1",
"eslint-plugin-jsdoc": "^63.2.0",
"eslint-webpack-plugin": "^6.0.0",
"file-loader": "^6.2.0",
Expand Down
13 changes: 13 additions & 0 deletions frontend/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 0 additions & 4 deletions frontend/src/ts/resource.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
/**
* Corresponds to a text file
*
* @export
*/
export type Resource = {
basename: string;
Expand All @@ -10,7 +8,5 @@ export type Resource = {

/**
* Corresponds to a list of Resources
*
* @export
*/
export type ResourceList = Array<Resource>;
2 changes: 1 addition & 1 deletion frontend/tests/ts/areas.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { expect, use } from 'chai';
import chaiDom from 'chai-dom';

const chai = use(chaiDom);
use(chaiDom);

// Import package under test
import {Area, OutputArea, LabArea, makeLabArea, LabContainer}
Expand Down
2 changes: 1 addition & 1 deletion frontend/tests/ts/dom-utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Import testing libs
import { expect, use } from 'chai';
import chaiDom from 'chai-dom';
const chai = use(chaiDom);
use(chaiDom);

import {getElemById, getElemsByClass, getElemsByTag}
from '../../src/ts/dom-utils';
Expand Down
31 changes: 21 additions & 10 deletions frontend/tests/ts/download.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { expect, use } from 'chai';
import chaiDom from 'chai-dom';
import chaiAsPromised from 'chai-as-promised';

const chai = use(chaiDom);
use(chaiDom);

import JSZip from 'jszip';
import FileSaver from 'file-saver';
Expand Down Expand Up @@ -112,7 +111,8 @@ describe('Download', () => {
});

it('should find builder switches', () => {
const parsedSwitches = parseSwitches({Builder: ["test1", "test2"], Compiler: []});
const parsedSwitches = parseSwitches(
{Builder: ["test1", "test2"], Compiler: []});
const expectedBuilder = 'for Switches ("Ada") use ("test1", "test2");';
const expectedCompiler = 'for Switches ("Ada") use ();';
expect(parsedSwitches['--BUILDER_SWITCHES_PLACEHOLDER--']).to.equal(
Expand All @@ -124,7 +124,8 @@ describe('Download', () => {
});

it('should find compiler switches', () => {
const parsedSwitches = parseSwitches({Builder: [], "Compiler": ["test3", "test4"]});
const parsedSwitches = parseSwitches(
{Builder: [], "Compiler": ["test3", "test4"]});
const expectedBuilder = 'for Switches ("Ada") use ();';
const expectedCompiler = 'for Switches ("Ada") use ("test3", "test4");';
expect(parsedSwitches['--BUILDER_SWITCHES_PLACEHOLDER--']).to.equal(
Expand Down Expand Up @@ -213,7 +214,11 @@ describe('Download', () => {
});

it('should find a main (c file)', () => {
const cFile = `#include <stdio.h>\nint main() {\nprintf("Hello, World!");\nreturn 0;\n}`;
const cFile = `#include <stdio.h>
int main() {
printf("Hello, World!");
return 0;
}`;
const files: ResourceList = [
{basename: 'other.c', contents: cFile},
{basename: 'test.ads', contents: ''},
Expand Down Expand Up @@ -259,13 +264,15 @@ describe('Download', () => {
describe('#getGprContents()', () => {
it('should replace all placeholders', () => {
const files: ResourceList = [{basename: 'main.adb', contents: ''}];
const gpr = getGprContents(files, {Builder: [], Compiler: []}, 'main.adb', false);
const gpr =
getGprContents(files, {Builder: [], Compiler: []}, 'main.adb', false);
expect(gpr).to.not.contain('--MAIN_PLACEHOLDER--');
expect(gpr).to.not.contain('--LANGUAGE_PLACEHOLDER--');
expect(gpr).to.not.contain('--COMPILER_SWITCHES_PLACEHOLDER--');
expect(gpr).to.not.contain('--BUILDER_SWITCHES_PLACEHOLDER--');
expect(gpr).to.not.contain('--');
const gpr_spark = getGprContents(files, {Builder: [], Compiler: []}, 'main.adb', true);
const gpr_spark =
getGprContents(files, {Builder: [], Compiler: []}, 'main.adb', true);
expect(gpr_spark).to.not.contain('--MAIN_PLACEHOLDER--');
expect(gpr_spark).to.not.contain('--LANGUAGE_PLACEHOLDER--');
expect(gpr_spark).to.not.contain('--COMPILER_SWITCHES_PLACEHOLDER--');
Expand All @@ -281,7 +288,8 @@ describe('Download', () => {
let origGenerateAsync: any;

const files: ResourceList = [
{basename: 'main.adb', contents: 'procedure Main is begin null; end Main;'},
{basename: 'main.adb',
contents: 'procedure Main is begin null; end Main;'},
];
const switches: UnparsedSwitches = {Builder: [], Compiler: []};

Expand All @@ -299,6 +307,7 @@ describe('Download', () => {
});

after(() => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(JSZip.prototype as any).generateAsync = origGenerateAsync;
});

Expand All @@ -313,7 +322,8 @@ describe('Download', () => {
expect(savedFilename).to.equal('MyProject.zip');
});

it('should include source, main.gpr, and main.adc in non-SPARK mode', async () => {
it('should include source, main.gpr, and main.adc in non-SPARK mode',
async () => {
downloadProject(files, switches, 'main.adb', 'Test', false);
await new Promise((r) => setTimeout(r, 200));
expect(capturedFileNames).to.include('main.adb');
Expand All @@ -323,7 +333,8 @@ describe('Download', () => {
expect(capturedFileNames).not.to.include('main_spark.adc');
});

it('should also include main_spark.gpr and main_spark.adc in SPARK mode', async () => {
it('should also include main_spark.gpr and main_spark.adc in SPARK mode',
async () => {
downloadProject(files, switches, 'main.adb', 'Test', true);
await new Promise((r) => setTimeout(r, 200));
expect(capturedFileNames).to.include('main.gpr');
Expand Down
5 changes: 3 additions & 2 deletions frontend/tests/ts/editor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { expect, use } from 'chai';
import chaiDom from 'chai-dom';

const chai = use(chaiDom);
use(chaiDom);

import * as Ace from 'ace-builds';

Expand Down Expand Up @@ -40,7 +40,8 @@ describe('Editor', () => {
});

it('should set C_CPP mode for a .c file', () => {
const cResource: Resource = {basename: 'main.c', contents: 'int main() { return 0; }'};
const cResource: Resource =
{basename: 'main.c', contents: 'int main() { return 0; }'};
inTest.addSession(cResource.basename, cResource.contents);
inTest.setSession(cResource.basename);
const session = editor.getSession();
Expand Down
8 changes: 3 additions & 5 deletions frontend/tests/ts/scrolltop.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@
import { expect, use } from 'chai';
import chaiDom from 'chai-dom';

const chai = use(chaiDom);
use(chaiDom);

import {scrollTop} from '../../src/ts/scrolltop';

/**
* Helper function to trigger window event
*
* @param {Window} element - The window element
* @param {string} eventName - The event to do
*/
Expand All @@ -20,9 +19,8 @@ function triggerEvent(element: Window, eventName: string): void {

/**
* Helper function used to override default non implemented version in JSDOM
*
* @param {number} x
* @param {number} y
* @param {number} x - The x-coordinate to scroll to
* @param {number} y - The y-coordinate to scroll to
*/
function scrollTo(x: number, y: number): void {
document.body.scrollTop = y;
Expand Down
24 changes: 13 additions & 11 deletions frontend/tests/ts/server.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import chaiAsPromised from 'chai-as-promised';
import chaiDom from 'chai-dom';

use(chaiAsPromised);
const chai = use(chaiDom);
use(chaiDom);

import {Server, WebSocket} from 'mock-socket';

Expand All @@ -14,10 +14,9 @@ import {CheckOutput, RunProgram} from '../../src/ts/server-types';
global.WebSocket = WebSocket as unknown as typeof globalThis.WebSocket;

/**
* Remove all event listeners from the server
*
* @param {Server} server - The server to remove the listeners from
*/
* Remove all event listeners from the server
* @param {Server} server - The server to remove the listeners from
*/
function removeListeners(server: Server): void {
for (let type in server.listeners) {
server.listeners[type] = [];
Expand All @@ -36,7 +35,8 @@ describe('ServerWorker', () => {
lab: false,
};
let server: Server = new Server(baseURL);
let client: ServerWorker = new ServerWorker(baseURL, (data: CheckOutput.FS): boolean => {
let client: ServerWorker = new ServerWorker(baseURL,
(data: CheckOutput.FS): boolean => {
cbCount++;
return data.completed;
});
Expand Down Expand Up @@ -66,7 +66,7 @@ describe('ServerWorker', () => {

before(() => {
server.on('connection', (socket) => {
socket.on('message', (event) => {
socket.on('message', (_event) => {
serverResponses.forEach((msg) => {
socket.send(JSON.stringify(msg));
});
Expand Down Expand Up @@ -95,7 +95,7 @@ describe('ServerWorker', () => {

before(() => {
server.on('connection', (socket) => {
socket.on('message', (event) => {
socket.on('message', (_event) => {
socket.send(JSON.stringify(serverResponse));
});
});
Expand All @@ -106,7 +106,8 @@ describe('ServerWorker', () => {
});

it('should throw an exception when AWS rejects the request', async () => {
await expect(client.execute(tsData, 2000)).to.be.rejectedWith(expectedErrorMsg);
await expect(client.execute(tsData, 2000))
.to.be.rejectedWith(expectedErrorMsg);
});
});

Expand All @@ -117,7 +118,7 @@ describe('ServerWorker', () => {

before(() => {
server.on('connection', (socket) => {
socket.on('message', (event) => {});
socket.on('message', (_event) => {});
});
});

Expand All @@ -126,7 +127,8 @@ describe('ServerWorker', () => {
});

it('should timeout if no response is recieved', async () => {
await expect(client.execute(tsData, timeout)).to.be.rejectedWith(expectedErrorMsg);
await expect(client.execute(tsData, timeout))
.to.be.rejectedWith(expectedErrorMsg);
});
});
});
Loading
Loading