Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
974d216
Add clean command
leeyi45 Apr 6, 2026
41979c6
Update bundles to work with Typescript 6
leeyi45 Apr 6, 2026
c6e6024
Update tabs to work with typescript 6
leeyi45 Apr 6, 2026
372a933
Update github actions to work with Typescript 6
leeyi45 Apr 6, 2026
1b88ee4
Update libs to work with Typescript 6
leeyi45 Apr 6, 2026
467d090
Update ESLint packages
leeyi45 Apr 6, 2026
77150eb
Needed to revert back to ESLint 9
leeyi45 Apr 6, 2026
3a2ac5a
Update typedoc
leeyi45 Apr 6, 2026
8f6a3d3
Fix dependencies for lintplugin
leeyi45 Apr 6, 2026
e938d2b
Fix broken test
leeyi45 Apr 7, 2026
fbdee21
Test a potential broken action
leeyi45 Apr 7, 2026
6ba6b6c
Try another fix
leeyi45 Apr 7, 2026
3c1ad58
More testing
leeyi45 Apr 7, 2026
99e6f1e
Try adding silent to exec option
leeyi45 Apr 7, 2026
268c945
Augment code to see where execution stopped
leeyi45 Apr 7, 2026
19c176d
Try with more logging
leeyi45 Apr 7, 2026
4c3cf5b
Redo the implementation for getRawPackages to use yarn workspaces list
leeyi45 Apr 7, 2026
0c44216
Fix broken tests
leeyi45 Apr 7, 2026
280f242
Investigate using a try block
leeyi45 Apr 7, 2026
9aa9dd6
Try without memoization
leeyi45 Apr 7, 2026
55fe824
Try testing the yarn why command without silent
leeyi45 Apr 7, 2026
1849e5a
Fix package name extractor
leeyi45 Apr 7, 2026
2a1d7b9
Make package type information available too
leeyi45 Apr 7, 2026
948a6dd
Fix incorrect lib typing in tests
leeyi45 Apr 7, 2026
fea050e
Fix sound test using global
leeyi45 Apr 7, 2026
c105e43
Fix CurveAnimations crashing the frontend
leeyi45 Apr 7, 2026
962e428
Fix types and documentation
leeyi45 Apr 7, 2026
fc4fde8
Add result handling for the clean command
leeyi45 Apr 7, 2026
30447a8
Added documentation about the instanceof issue
leeyi45 Apr 7, 2026
d56aed5
Add Typescript to docs
leeyi45 Apr 7, 2026
5161209
Fix linting config to always require json extension
leeyi45 Apr 7, 2026
d9aec50
Fix toSpawn checks for tabs that weren't working
leeyi45 Apr 8, 2026
ab9ff8a
Fix broken tests
leeyi45 Apr 8, 2026
de6f6ae
Update tab test snapshots
leeyi45 Apr 9, 2026
c37d245
Update the docs about the ModuleTab type
leeyi45 Apr 9, 2026
ab21f78
Fix missing export and incorrect css layout
leeyi45 Apr 9, 2026
b0d6ed3
Fix WASM bundle
RichDom2185 Apr 10, 2026
e867f59
Merge branch 'ts-6' of github.com:source-academy/modules into ts-6
leeyi45 Apr 11, 2026
ae85b05
Update configurations
leeyi45 Apr 11, 2026
4e79ccb
Update --no-allow-only description
leeyi45 Apr 13, 2026
bc68ed8
Deduplicate dependencies
RichDom2185 Apr 13, 2026
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
4 changes: 2 additions & 2 deletions .github/actions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
"devDependencies": {
"@sourceacademy/modules-repotools": "workspace:^",
"@types/node": "^22.15.30",
"typescript": "^5.8.2",
"typescript": "^6.0.2",
"vitest": "4.1.0"
},
"dependencies": {
"@actions/artifact": "^6.0.0",
"@actions/core": "^1.11.1",
"@actions/core": "^3.0.0",
"@actions/exec": "^3.0.0",
"es-toolkit": "^1.44.0",
"snyk-nodejs-lockfile-parser": "^2.4.2"
Expand Down
10 changes: 9 additions & 1 deletion .github/actions/src/info/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@
gitRoot: 'root'
}));

vi.mock(import('@actions/core'), async importOriginal => {
const original = await importOriginal();
return {
...original,
setOutput: vi.fn((_name, _value) => {})
}

Check warning on line 30 in .github/actions/src/info/__tests__/index.test.ts

View workflow job for this annotation

GitHub Actions / Repo Wide Tasks

Missing semicolon
})

Check warning on line 31 in .github/actions/src/info/__tests__/index.test.ts

View workflow job for this annotation

GitHub Actions / Repo Wide Tasks

Missing semicolon

class NodeError extends Error {
constructor(public readonly code: string) {
super();
Expand Down Expand Up @@ -221,7 +229,7 @@
});

describe(main, () => {
const mockedSetOutput = vi.spyOn(core, 'setOutput');
const mockedSetOutput = vi.mocked(core.setOutput);

vi.spyOn(core.summary, 'addHeading').mockImplementation(() => core.summary);
vi.spyOn(core.summary, 'addTable').mockImplementation(() => core.summary);
Expand Down
3 changes: 2 additions & 1 deletion .github/actions/src/info/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import fs from 'fs/promises';
import pathlib from 'path';
import utils from 'util';
import * as core from '@actions/core';
import type { SummaryTableRow } from '@actions/core/lib/summary.js';
import packageJson from '../../../../package.json' with { type: 'json' };
import { checkDirForChanges, type PackageRecord, type RawPackageRecord } from '../commons.js';
import { gitRoot } from '../gitRoot.js';
import { getPackagesWithResolutionChanges, hasLockFileChanged } from '../lockfiles.js';
import { topoSortPackages } from './sorter.js';

type SummaryTableRow = Parameters<(typeof core['summary']['addTable'])>[0][number];

const packageNameRE = /^@sourceacademy\/(.+?)-(.+)$/u;

/**
Expand Down
7 changes: 7 additions & 0 deletions .github/actions/src/lockfiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,20 @@
* Used to determine if the lockfile has changed
*/
export const hasLockFileChanged = memoize(async () => {
try {

const { exitCode } = await getExecOutput(

Check warning on line 166 in .github/actions/src/lockfiles.ts

View workflow job for this annotation

GitHub Actions / Repo Wide Tasks

Expected indentation of 4 spaces but found 2
'git --no-pager diff --quiet origin/master -- yarn.lock',

Check warning on line 167 in .github/actions/src/lockfiles.ts

View workflow job for this annotation

GitHub Actions / Repo Wide Tasks

Expected indentation of 6 spaces but found 4
[],

Check warning on line 168 in .github/actions/src/lockfiles.ts

View workflow job for this annotation

GitHub Actions / Repo Wide Tasks

Expected indentation of 6 spaces but found 4
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The getExecOutput function is called with the entire command as a single string, instead of splitting it into the executable name and an array of arguments.
Severity: HIGH

Suggested Fix

Refactor the getExecOutput call to separate the executable from its arguments. The first argument should be the string 'git', and the second argument should be an array of strings containing the command's flags and parameters: ['--no-pager', 'diff', '--quiet', 'origin/master', '--', 'yarn.lock'].

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: .github/actions/src/lockfiles.ts#L164-L172

Potential issue: In the `hasLockFileChanged` function, the call to `getExecOutput` is
incorrect. The entire git command is passed as a single string to the first argument,
whereas the function expects the executable name (`'git'`) as the first argument and the
command-line arguments as a separate array of strings. This will cause a runtime error
when the system attempts to execute a non-existent file named `"git --no-pager diff
--quiet origin/master -- yarn.lock"`. This error will cause the GitHub Actions workflow
to fail whenever it tries to detect lockfile changes.

{

Check warning on line 169 in .github/actions/src/lockfiles.ts

View workflow job for this annotation

GitHub Actions / Repo Wide Tasks

Expected indentation of 6 spaces but found 4
failOnStdErr: false,

Check warning on line 170 in .github/actions/src/lockfiles.ts

View workflow job for this annotation

GitHub Actions / Repo Wide Tasks

Expected indentation of 8 spaces but found 6
ignoreReturnCode: true

Check warning on line 171 in .github/actions/src/lockfiles.ts

View workflow job for this annotation

GitHub Actions / Repo Wide Tasks

Expected indentation of 8 spaces but found 6
}

Check warning on line 172 in .github/actions/src/lockfiles.ts

View workflow job for this annotation

GitHub Actions / Repo Wide Tasks

Expected indentation of 6 spaces but found 4
);

Check warning on line 173 in .github/actions/src/lockfiles.ts

View workflow job for this annotation

GitHub Actions / Repo Wide Tasks

Expected indentation of 4 spaces but found 2
return exitCode !== 0;
} catch (error) {
core.error('I am here!')
core.error(error as any)
throw error
}
});
1 change: 1 addition & 0 deletions .github/actions/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"skipLibCheck": true,
"strict": true,
"target": "ES2020",
"types": ["node"],
"verbatimModuleSyntax": true
}
}
4 changes: 2 additions & 2 deletions devserver/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"react-ace": "^14.0.0",
"react-dom": "^18.3.1",
"vite": "^8.0.0",
"vite-plugin-node-polyfills": "^0.25.0"
"vite-plugin-node-polyfills": "^0.26.0"
},
"devDependencies": {
"@sourceacademy/modules-buildtools": "workspace:^",
Expand All @@ -33,7 +33,7 @@
"eslint": "^9.35.0",
"playwright": "^1.55.1",
"sass": "^1.85.0",
"typescript": "^5.8.2",
"typescript": "^6.0.2",
"vitest": "4.1.0",
"vitest-browser-react": "^2.1.0"
},
Expand Down
10 changes: 6 additions & 4 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import reactPlugin from 'eslint-plugin-react';
import reactHooksPlugin from 'eslint-plugin-react-hooks';
import ymlPlugin from 'eslint-plugin-yml';
import globals from 'globals';
import jsonParser from 'jsonc-eslint-parser';
import * as jsonParser from 'jsonc-eslint-parser';
import tseslint from 'typescript-eslint';

const todoTreeKeywordsWarning = ['TODO', 'TODOS', 'TODO WIP', 'FIXME', 'WIP'];
Expand Down Expand Up @@ -168,8 +168,8 @@ export default defineConfig(
}
],
'@stylistic/no-extra-parens': ['warn', 'all', {
enforceForArrowConditionals: false,
ignoreJSX: 'all',
ignoredNodes: ['ArrowFunctionExpression[body.type=ConditionalExpression]'],
nestedBinaryExpressions: false,
}],
'@stylistic/nonblock-statement-body-position': ['error', 'beside'],
Expand Down Expand Up @@ -336,7 +336,9 @@ export default defineConfig(
// This rule doesn't seem to fail locally but fails on the CI
// '@typescript-eslint/no-unnecessary-type-assertion': 'error',
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }], // Was 'error'
'@typescript-eslint/only-throw-error': 'error'

// TODO: Turn this back on
'@typescript-eslint/only-throw-error': 'off'
Comment thread
leeyi45 marked this conversation as resolved.
},
settings: {
'import/resolver': {
Expand All @@ -351,6 +353,7 @@ export default defineConfig(
files: ['**/*.tsx'],
ignores: ['**/*.md/**/*.tsx'],
plugins: {
// @ts-expect-error React hooks plugin wrong type
'react-hooks': reactHooksPlugin,
'react': reactPlugin
},
Expand All @@ -371,7 +374,6 @@ export default defineConfig(

'@stylistic/jsx-equals-spacing': ['warn', 'never'],
'@stylistic/jsx-indent-props': ['warn', 2],
'@stylistic/jsx-props-no-multi-spaces': 'warn',
'@stylistic/jsx-self-closing-comp': 'warn',
},
settings: {
Expand Down
4 changes: 2 additions & 2 deletions lib/buildtools/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"@types/estree": "^1.0.0",
"@types/http-server": "^0.12.4",
"@types/node": "^22.15.30",
"typescript": "^5.8.2"
"typescript": "^6.0.2"
},
"exports": null,
"bin": {
Expand All @@ -30,7 +30,7 @@
"eslint": "^9.35.0",
"http-server": "^14.1.1",
"jsdom": "^29.0.0",
"typedoc": "^0.28.9",
"typedoc": "^0.28.18",
"vite": "^8.0.0",
"vitest": "4.1.0"
},
Expand Down
132 changes: 132 additions & 0 deletions lib/buildtools/src/commands/clean.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import fs from 'fs/promises';
import pathlib from 'path';
import { Argument, Command } from '@commander-js/extra-typings';
import { bundlesDir, outDir, tabsDir } from '@sourceacademy/modules-repotools/getGitRoot';
import { resolveAllBundles, resolveAllTabs } from '@sourceacademy/modules-repotools/manifest';
import type { ResultType } from '@sourceacademy/modules-repotools/types';
import { isNodeError } from '@sourceacademy/modules-repotools/utils';
import { mapAsync } from 'es-toolkit';

type HandleEnoentResult<T> = {
ok: true;
result?: T;
} | {
ok: false;
error: unknown;
};

/**
* Wrapper for handling fs operations that ignore 'ENOENT' errors
*/
async function handleEnoent<T>(promise: Promise<T>): Promise<HandleEnoentResult<T>> {
try {
const result = await promise;
return {
ok: true,
result
};
} catch (error) {
if (!isNodeError(error) || error.code !== 'ENOENT') {
return {
ok: false,
error
};
};

return { ok: true };
}
}

type CleanResult = ResultType<object>;

async function cleanBundles(bundlesDir: string, outDir: string): Promise<CleanResult> {
const bundleResult = await resolveAllBundles(bundlesDir);
Comment thread
leeyi45 marked this conversation as resolved.

if (bundleResult.severity === 'error') {
return bundleResult;
}

const results = await mapAsync(Object.values(bundleResult.bundles), async (bundle): Promise<string | undefined> => {
const tsPath = pathlib.join(bundle.directory, 'dist');

const dirStats = await handleEnoent(fs.stat(tsPath));
if (!dirStats.ok) {
return `Error occurred while cleaning ${bundle.name}: ${dirStats.error}`;
}

try {
if (dirStats.result?.isDirectory()) {
await fs.rm(tsPath, { recursive: true, force: true });
}
} catch (error) {
return `Error occurred while cleaning ${bundle.name}: ${error}`;
}
Comment thread
leeyi45 marked this conversation as resolved.
Outdated

const buildPath = pathlib.join(outDir, 'bundles', `${bundle.name}.js`);
const rmbuildResult = await handleEnoent(fs.rm(buildPath));

if (!rmbuildResult.ok) {
return `Error occurred while cleaning ${bundle.name}: ${rmbuildResult.error}`;
}

return undefined;
});

const errors = results.filter(x => x !== undefined);
if (errors.length > 0) {
return {
severity: 'error',
errors
};
}

return {
severity: 'success'
};
}

async function cleanTabs(bundlesDir: string, tabsDir: string, outDir: string): Promise<CleanResult> {
const tabResult = await resolveAllTabs(bundlesDir, tabsDir);
if (tabResult.severity === 'error') {
return tabResult;
}

const results = await mapAsync(Object.values(tabResult.tabs), async tab => {
const buildPath = pathlib.join(outDir, 'tabs', `${tab.name}.js`);
const rmResult = await handleEnoent(fs.rm(buildPath));

if (rmResult.ok) return undefined;

return `Error while cleaning ${tab.name} tab: ${rmResult.error}`;
});

const errors = results.filter(x => x !== undefined);
if (errors.length > 0) {
return {
severity: 'error',
errors
};
}

return { severity: 'success' };
}

export const getCleanCommand = () => new Command('clean')
.description('Remove existing compiled and built assets')
.addArgument(
new Argument('[type]', 'Type of Asset to clean')
.choices(['tabs', 'bundles'])
.default('bundles')
)
.action(async asset => {
switch (asset) {
case 'bundles': {
await cleanBundles(bundlesDir, outDir);
break;
}
case 'tabs': {
await cleanTabs(bundlesDir, tabsDir, outDir);
break;
}
}
Comment thread
leeyi45 marked this conversation as resolved.
});
Comment thread
leeyi45 marked this conversation as resolved.
2 changes: 2 additions & 0 deletions lib/buildtools/src/commands/main.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Command } from '@commander-js/extra-typings';
import { getBuildCommand, getBuildHtmlCommand, getCompileCommand, getManifestCommand } from './build.js';
import { getCleanCommand } from './clean.js';
import { getListCommand, getValidateCommand } from './list.js';
import { getLintCommand, getLintGlobalCommand, getPrebuildAllCommand, getTscCommand } from './prebuild.js';
import getHttpServerCommand from './server.js';
Expand All @@ -9,6 +10,7 @@ import { getTestAllCommand, getTestCommand } from './testing.js';
const commands: (() => Command<any>)[] = [
getBuildCommand,
getBuildHtmlCommand,
getCleanCommand,
getCompileCommand,
getHttpServerCommand,
getLintCommand,
Expand Down
22 changes: 11 additions & 11 deletions lib/lintplugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,31 @@
},
"peerDependencies": {
"@eslint/markdown": "^7.0.0",
"@stylistic/eslint-plugin": "^5.0.0",
"@vitest/eslint-plugin": "^1.6.12",
"@stylistic/eslint-plugin": "^5.10.0",
"@vitest/eslint-plugin": "^1.6.14",
"eslint": ">=9",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jsdoc": "^62.0.0",
"eslint-plugin-react": "^7.37.4",
"eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-react-hooks": "^7.0.0",
"globals": "^17.0.0",
"typescript-eslint": "^8.56.1"
"typescript-eslint": "^8.58.0"
},
"devDependencies": {
"@eslint/markdown": "^7.5.1",
"@sourceacademy/modules-buildtools": "workspace:^",
"@sourceacademy/modules-repotools": "workspace:^",
"@stylistic/eslint-plugin": "^5.0.0",
"@typescript-eslint/rule-tester": "^8.56.1",
"@typescript-eslint/utils": "^8.56.1",
"@vitest/eslint-plugin": "^1.6.12",
"@stylistic/eslint-plugin": "^5.10.0",
"@typescript-eslint/rule-tester": "^8.58.0",
"@typescript-eslint/utils": "^8.58.0",
"@vitest/eslint-plugin": "^1.6.14",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jsdoc": "^62.0.0",
"eslint-plugin-react": "^7.37.4",
"eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-react-hooks": "^7.0.1",
"globals": "^17.0.0",
"typescript": "^5.8.2",
"typescript-eslint": "^8.56.1"
"typescript": "^6.0.2",
"typescript-eslint": "^8.58.0"
},
"scripts": {
"build": "node ./build.js",
Expand Down
1 change: 1 addition & 0 deletions lib/lintplugin/src/configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ export const tsxConfig = defineConfig({
name: 'SA TSX Config',
files: ['**/*.tsx'],
plugins: {
// @ts-expect-error React hooks plugin wrong type
'react-hooks': reactHooksPlugin,
Comment thread
RichDom2185 marked this conversation as resolved.
'react': reactPlugin
},
Expand Down
2 changes: 1 addition & 1 deletion lib/markdown-tree/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"@sourceacademy/modules-repotools": "workspace:^",
"@types/markdown-it": "^14.1.2",
"shiki": "^3.15.0",
"typescript": "^5.8.2"
"typescript": "^6.0.2"
},
"exports": {
".": {
Expand Down
2 changes: 1 addition & 1 deletion lib/modules-lib/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"typedoc-plugin-frontmatter": "^1.3.0",
"typedoc-plugin-markdown": "^4.7.0",
"typedoc-plugin-rename-defaults": "^0.7.3",
"typescript": "^5.8.2",
"typescript": "^6.0.2",
"vitest": "4.1.0",
"vitest-browser-react": "^2.1.0"
},
Expand Down
1 change: 0 additions & 1 deletion lib/modules-lib/src/specialErrors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,5 @@
* and display a message that the program is stopped by a module.
*/
export function interrupt(): never {
// eslint-disable-next-line @typescript-eslint/only-throw-error
throw 'source_academy_interrupt';
}
1 change: 1 addition & 0 deletions lib/modules-lib/tsconfig.prod.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"declaration": true,
"noEmit": false,
"outDir": "./dist",
"rootDir": "./src",
"removeComments": false
},
"extends": "./tsconfig.json",
Expand Down
Loading
Loading