diff --git a/.github/actions/package.json b/.github/actions/package.json index 606f86dca5..91d98d4316 100644 --- a/.github/actions/package.json +++ b/.github/actions/package.json @@ -13,7 +13,8 @@ "@actions/artifact": "^2.3.2", "@actions/core": "^1.11.1", "@actions/exec": "^1.1.1", - "lodash": "^4.17.21" + "lodash": "^4.17.21", + "snyk-nodejs-lockfile-parser": "^2.4.2" }, "scripts": { "build": "node ./build.js", diff --git a/.github/actions/src/__tests__/commons.test.ts b/.github/actions/src/__tests__/commons.test.ts index d7cfb351dd..82447d6487 100644 --- a/.github/actions/src/__tests__/commons.test.ts +++ b/.github/actions/src/__tests__/commons.test.ts @@ -8,7 +8,7 @@ vi.mock(import('lodash/memoize.js'), () => ({ const mockedExecOutput = vi.spyOn(exec, 'getExecOutput'); -describe(commons.checkForChanges, () => { +describe(commons.checkDirForChanges, () => { function mockChanges(value: boolean) { mockedExecOutput.mockResolvedValueOnce({ exitCode: value ? 1 : 0, stdout: '', stderr: '' @@ -17,14 +17,14 @@ describe(commons.checkForChanges, () => { it('should return true if git diff exits with non zero code', async () => { mockChanges(true); - await expect(commons.checkForChanges('/')).resolves.toEqual(true); + await expect(commons.checkDirForChanges('/')).resolves.toEqual(true); expect(mockedExecOutput).toHaveBeenCalledOnce(); }); it('should return false if git diff exits with 0', async () => { mockChanges(false); - await expect(commons.checkForChanges('/')).resolves.toEqual(false); + await expect(commons.checkDirForChanges('/')).resolves.toEqual(false); expect(mockedExecOutput).toHaveBeenCalledOnce(); }); }); diff --git a/.github/actions/src/commons.ts b/.github/actions/src/commons.ts index 8a5bcb6f81..4d02975ea7 100644 --- a/.github/actions/src/commons.ts +++ b/.github/actions/src/commons.ts @@ -60,19 +60,12 @@ export function isPackageRecord(obj: unknown): obj is PackageRecord { return true; } -// Not using the repotools version since this uses @action/exec instead of -// calling execFile from child_process -export async function getGitRoot() { - const { stdout } = await getExecOutput('git rev-parse --show-toplevel'); - return stdout.trim(); -} - /** * Returns `true` if there are changes present in the given directory relative to * the master branch\ * Used to determine, particularly for libraries, if running tests and tsc are necessary */ -export const checkForChanges = memoize(async (directory: string) => { +export const checkDirForChanges = memoize(async (directory: string) => { const { exitCode } = await getExecOutput( 'git', ['--no-pager', 'diff', '--quiet', 'origin/master', '--', directory], diff --git a/.github/actions/src/gitRoot.ts b/.github/actions/src/gitRoot.ts new file mode 100644 index 0000000000..f068b1e6e2 --- /dev/null +++ b/.github/actions/src/gitRoot.ts @@ -0,0 +1,13 @@ +import { getExecOutput } from '@actions/exec'; + +// Not using the repotools version since this uses @action/exec instead of +// calling execFile from child_process +async function getGitRoot() { + const { stdout } = await getExecOutput('git rev-parse --show-toplevel'); + return stdout.trim(); +} + +/** + * Path to the root of the git repository + */ +export const gitRoot = await getGitRoot(); diff --git a/.github/actions/src/info/__tests__/index.test.ts b/.github/actions/src/info/__tests__/index.test.ts index a582b55a98..a68c04b57e 100644 --- a/.github/actions/src/info/__tests__/index.test.ts +++ b/.github/actions/src/info/__tests__/index.test.ts @@ -1,11 +1,13 @@ import type { Dirent } from 'fs'; import fs from 'fs/promises'; import pathlib from 'path'; +import * as core from '@actions/core'; import { describe, expect, test, vi } from 'vitest'; import * as git from '../../commons.js'; -import { getAllPackages, getRawPackages } from '../index.js'; +import * as lockfiles from '../../lockfiles/index.js'; +import { getAllPackages, getRawPackages, main } from '../index.js'; -const mockedCheckChanges = vi.spyOn(git, 'checkForChanges'); +const mockedCheckChanges = vi.spyOn(git, 'checkDirForChanges'); vi.mock(import('path'), async importOriginal => { const { posix } = await importOriginal(); @@ -16,6 +18,10 @@ vi.mock(import('path'), async importOriginal => { }; }); +vi.mock(import('../../gitRoot.js'), () => ({ + gitRoot: 'root' +})); + class NodeError extends Error { constructor(public readonly code: string) { super(); @@ -39,7 +45,7 @@ const mockDirectory: Record> = { 'package.json': JSON.stringify({ name: '@sourceacademy/bundle-bundle0', devDependencies: { - '@sourceacademy/modules-lib': 'workspace:^' + '@sourceacademy/modules-lib': 'workspace:^', } }) }, @@ -49,7 +55,8 @@ const mockDirectory: Record> = { 'package.json': JSON.stringify({ name: '@sourceacademy/tab-Tab0', dependencies: { - '@sourceacademy/bundle-bundle0': 'workspace:^' + lodash: '^4.1.1', + '@sourceacademy/bundle-bundle0': 'workspace:^', }, devDependencies: { playwright: '^1.54.0' @@ -114,6 +121,7 @@ function mockReadFile(path: string) { vi.spyOn(fs, 'readdir').mockImplementation(mockReaddir as any); vi.spyOn(fs, 'readFile').mockImplementation(mockReadFile as any); +vi.spyOn(lockfiles, 'hasLockFileChanged').mockResolvedValue(false); describe(getRawPackages, () => { test('maxDepth = 1', async () => { @@ -125,7 +133,7 @@ describe(getRawPackages, () => { const [[name, packageData]] = results; expect(name).toEqual('@sourceacademy/modules'); expect(packageData.hasChanges).toEqual(true); - expect(git.checkForChanges).toHaveBeenCalledOnce(); + expect(git.checkDirForChanges).toHaveBeenCalledOnce(); }); test('maxDepth = 3', async () => { @@ -211,3 +219,33 @@ describe(getAllPackages, () => { expect(results['@sourceacademy/modules-lib'].changes).toEqual(true); }); }); + +describe(main, () => { + const mockedSetOutput = vi.spyOn(core, 'setOutput'); + + vi.spyOn(core.summary, 'addHeading').mockImplementation(() => core.summary); + vi.spyOn(core.summary, 'addTable').mockImplementation(() => core.summary); + vi.spyOn(core.summary, 'write').mockImplementation(() => Promise.resolve(core.summary)); + + test('Does not write packages with no changes to the output', async () => { + mockedCheckChanges.mockImplementation(path => { + return Promise.resolve(path === 'root/src/tabs/tab0'); + }); + + await main(); + const { mock: { calls } } = mockedSetOutput; + + expect(mockedSetOutput).toHaveBeenCalledTimes(6); + + expect(calls[0]).toEqual(['bundles', []]); + expect(calls[1]).toEqual(['tabs', [expect.objectContaining({ changes: true })]]); + expect(calls[2]).toEqual(['libs', []]); + + // These next two are undefined because the mock implementations + // don't return any info about them + expect(calls[3]).toEqual(['devserver', undefined]); + expect(calls[4]).toEqual(['docserver', undefined]); + + expect(calls[5]).toEqual(['workflows', false]); + }); +}); diff --git a/.github/actions/src/info/action.yml b/.github/actions/src/info/action.yml index de11d4669f..4904cfbd1b 100644 --- a/.github/actions/src/info/action.yml +++ b/.github/actions/src/info/action.yml @@ -3,11 +3,11 @@ description: Gets which packages are currently present in the repository outputs: libs: - description: The list of library packages present + description: The list of library packages that have changes bundles: - description: The list of bundles packages present + description: The list of bundles packages that have changes tabs: - description: The list of tabs packages present + description: The list of tabs packages that have changes devserver: description: Information for the devserver docserver: diff --git a/.github/actions/src/info/index.ts b/.github/actions/src/info/index.ts index 6b6869a0b8..16dcb67a4c 100644 --- a/.github/actions/src/info/index.ts +++ b/.github/actions/src/info/index.ts @@ -4,7 +4,9 @@ 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 { checkForChanges, getGitRoot, type PackageRecord, type RawPackageRecord } from '../commons.js'; +import { checkDirForChanges, type PackageRecord, type RawPackageRecord } from '../commons.js'; +import { gitRoot } from '../gitRoot.js'; +import { getPackagesWithResolutionChanges, hasLockFileChanged } from '../lockfiles/index.js'; import { topoSortPackages } from './sorter.js'; const packageNameRE = /^@sourceacademy\/(.+?)-(.+)$/u; @@ -14,8 +16,19 @@ const packageNameRE = /^@sourceacademy\/(.+?)-(.+)$/u; * an unprocessed format */ export async function getRawPackages(gitRoot: string, maxDepth?: number) { + let packagesWithResolutionChanges: Set | null = null; + + // If there are lock file changes we need to set hasChanges to true for + // that package even if that package's directory has no changes + if (await hasLockFileChanged()) { + packagesWithResolutionChanges = await getPackagesWithResolutionChanges(); + } + const output: Record = {}; + /** + * Search the given directory for package.json files + */ async function recurser(currentDir: string, currentDepth: number) { const items = await fs.readdir(currentDir, { withFileTypes: true }); await Promise.all(items.map(async item => { @@ -23,14 +36,14 @@ export async function getRawPackages(gitRoot: string, maxDepth?: number) { if (item.name === 'package.json') { try { const [hasChanges, packageJson] = await Promise.all([ - checkForChanges(currentDir), + checkDirForChanges(currentDir), fs.readFile(pathlib.join(currentDir, 'package.json'), 'utf-8') .then(JSON.parse) ]); output[packageJson.name] = { directory: currentDir, - hasChanges, + hasChanges: packagesWithResolutionChanges?.has(packageJson.name) ?? hasChanges, package: packageJson }; } catch (error) { @@ -93,16 +106,18 @@ export function processRawPackages(topoOrder: string[], packages: Record x.changes)); + core.setOutput('tabs', tabs.filter(x => x.changes)); + core.setOutput('libs', libs.filter(x => x.changes)); core.setOutput('devserver', devserver); core.setOutput('docserver', docserver); } -async function main() { - const gitRoot = await getGitRoot(); +export async function main() { const { packages, bundles, tabs, libs } = await getAllPackages(gitRoot); const { repository } = packageJson; @@ -260,7 +274,7 @@ async function main() { packages['@sourceacademy/modules-docserver'] ); - const workflows = await checkForChanges(pathlib.join(gitRoot, '.github/workflows')); + const workflows = await checkDirForChanges(pathlib.join(gitRoot, '.github/workflows')); core.setOutput('workflows', workflows); } @@ -269,6 +283,6 @@ if (process.env.GITHUB_ACTIONS) { try { await main(); } catch (error: any) { - core.setFailed(error.message); + core.setFailed(error); } } diff --git a/.github/actions/src/load-artifacts/__tests__/artifact.test.ts b/.github/actions/src/load-artifacts/__tests__/artifact.test.ts index 07f0bb4fd1..3ee0bea269 100644 --- a/.github/actions/src/load-artifacts/__tests__/artifact.test.ts +++ b/.github/actions/src/load-artifacts/__tests__/artifact.test.ts @@ -1,3 +1,4 @@ +import { ArtifactNotFoundError } from '@actions/artifact'; import * as core from '@actions/core'; import * as exec from '@actions/exec'; import * as manifest from '@sourceacademy/modules-repotools/manifest'; @@ -10,10 +11,10 @@ vi.mock(import('@actions/core'), async importOriginal => { ...original, // Mock these functions to remove stdout output error: vi.fn(), - info: () => {}, - startGroup: () => {}, + info: () => { }, + startGroup: () => { }, setFailed: vi.fn(), - endGroup: () => {} + endGroup: () => { } }; }); const mockedResolveAllTabs = vi.spyOn(manifest, 'resolveAllTabs'); @@ -41,6 +42,7 @@ test('tab resolution errors cause setFailed to be called', async () => { await main(); + expect(mockedResolveAllTabs).toHaveBeenCalledOnce(); expect(core.error).toHaveBeenCalledExactlyOnceWith('error1'); expect(core.setFailed).toHaveBeenCalledExactlyOnceWith('Tab resolution failed with errors'); }); @@ -68,22 +70,26 @@ test('tabs that can\'t be found are built', async () => { if (name === 'Tab0-tab') { return { artifact: { id: 0 } }; } - throw new Error(); + throw new ArtifactNotFoundError(); }); await main(); expect(mockedGetArtifact).toHaveBeenCalledTimes(2); + expect(mockedResolveAllTabs).toHaveBeenCalledOnce(); + const [[artifactCall0], [artifactCall1]] = mockedGetArtifact.mock.calls; expect(artifactCall0).toEqual('Tab0-tab'); expect(artifactCall1).toEqual('Tab1-tab'); expect(exec.exec).toHaveBeenCalledTimes(2); - const [[,execCall0], [,execCall1]] = vi.mocked(exec.exec).mock.calls; - console.log('args are', execCall0); + const [[execCmd0, execCall0], [execCmd1, execCall1]] = vi.mocked(exec.exec).mock.calls; + + expect(execCmd0).toEqual('yarn workspaces focus'); expect(execCall0).toContain('@sourceacademy/tab-Tab1'); expect(execCall0).not.toContain('@sourceacademy/tab-Tab0'); + expect(execCmd1).toEqual('yarn workspaces foreach -pA'); expect(execCall1).toContain('@sourceacademy/tab-Tab1'); expect(execCall1).not.toContain('@sourceacademy/tab-Tab0'); }); @@ -101,11 +107,12 @@ test('install failure means build doesn\'t happen', async () => { } }); - mockedGetArtifact.mockRejectedValueOnce(new Error()); - + mockedGetArtifact.mockRejectedValueOnce(new ArtifactNotFoundError()); mockedExec.mockResolvedValueOnce(1); + await main(); + expect(mockedGetArtifact).toHaveBeenCalledOnce(); expect(exec.exec).toHaveBeenCalledOnce(); - expect(core.setFailed).toHaveBeenCalledExactlyOnceWith('yarn workspace focus failed for Tab0'); + expect(core.setFailed).toHaveBeenCalledExactlyOnceWith('yarn workspace focus failed'); }); diff --git a/.github/actions/src/load-artifacts/index.ts b/.github/actions/src/load-artifacts/index.ts index 0fe864063c..6aeadbe373 100644 --- a/.github/actions/src/load-artifacts/index.ts +++ b/.github/actions/src/load-artifacts/index.ts @@ -1,5 +1,5 @@ import pathlib from 'path'; -import { DefaultArtifactClient } from '@actions/artifact'; +import { ArtifactNotFoundError, DefaultArtifactClient } from '@actions/artifact'; import * as core from '@actions/core'; import { exec } from '@actions/exec'; import { bundlesDir, outDir, tabsDir } from '@sourceacademy/modules-repotools/getGitRoot'; @@ -19,33 +19,42 @@ export async function main() { return; } - const tabPromises = Object.keys(tabsResult.tabs).map(async tabName => { + const tabPromises = Object.keys(tabsResult.tabs).map(async (tabName): Promise => { try { const { artifact: { id } } = await artifact.getArtifact(`${tabName}-tab`); await artifact.downloadArtifact(id, { path: pathlib.join(outDir, 'tabs') }); core.info(`Downloaded artifact for ${tabName}`); - return; + return null; } catch (error) { - core.error(`Error retrieving artifact for ${tabName}, will try building`); - core.error(error as Error); + if (!(error instanceof ArtifactNotFoundError)) { + throw error; + } + core.error(`Error retrieving artifact for ${tabName}, need to try building`); + return tabName; } + }); - // Artifact could not be found, we probably need to build it - const focusExitCode = await exec('yarn', ['workspaces', 'focus', `@sourceacademy/tab-${tabName}`]); - if (focusExitCode !== 0) { - core.setFailed(`yarn workspace focus failed for ${tabName}`); - return; - } + // Artifacts could not be found, we probably need to build it + const tabsToBuild = (await Promise.all(tabPromises)).filter(x => x !== null); + if (tabsToBuild.length === 0) return; - const buildExitCode = await exec('yarn', ['workspaces', 'foreach', '-A', '--include', `@sourceacademy/tab-${tabName}`, 'run', 'build']); - if (buildExitCode !== 0) { - core.setFailed(`Building ${tabName} failed`); - return; - } - core.info(`Built ${tabName}`); - }); + // focus all at once + const workspaces = tabsToBuild.map(each => `@sourceacademy/tab-${each}`); + const focusExitCode = await exec('yarn workspaces focus', workspaces, { silent: false }); + if (focusExitCode !== 0) { + core.setFailed('yarn workspace focus failed'); + return; + } - await Promise.all(tabPromises); + const workspaceBuildArgs = workspaces.flatMap(each => ['--include', each]); + const buildExitCode = await exec( + 'yarn workspaces foreach -pA', + [...workspaceBuildArgs, 'run', 'build'], + { silent: false } + ); + if (buildExitCode !== 0) { + core.setFailed('Building tabs failed'); + } } if (process.env.GITHUB_ACTIONS) { @@ -53,6 +62,6 @@ if (process.env.GITHUB_ACTIONS) { try { await main(); } catch (error: any) { - core.setFailed(error.message); + core.setFailed(error); } } diff --git a/.github/actions/src/lockfiles/__tests__/lockfiles.test.ts b/.github/actions/src/lockfiles/__tests__/lockfiles.test.ts new file mode 100644 index 0000000000..cbce681b62 --- /dev/null +++ b/.github/actions/src/lockfiles/__tests__/lockfiles.test.ts @@ -0,0 +1,109 @@ +import type fs from 'fs/promises'; +import type pathlib from 'path'; +import * as exec from '@actions/exec'; +import { describe, expect, it, vi } from 'vitest'; +import * as utils from '../utils.js'; + +vi.mock(import('../../gitRoot.js'), () => ({ + gitRoot: 'root' +})); + +const mockedExec = vi.spyOn(exec, 'getExecOutput'); + +describe(utils.extractPackageName, () => { + it('works with packages that start with @', () => { + expect(utils.extractPackageName('@sourceacademy/tab-Rune@workspace:^')) + .toEqual('@sourceacademy/tab-Rune'); + }); + + it('works with regular package names', () => { + expect(utils.extractPackageName('lodash@npm:^4.17.20')) + .toEqual('lodash'); + }); + + it('throws an error on an invalid package name', () => { + expect(() => utils.extractPackageName('something weird')) + .toThrowError('Invalid package name: something weird'); + }); +}); + +describe(utils.getPackageReason, async () => { + const { join }: typeof pathlib = await vi.importActual('path'); + const { readFile }: typeof fs = await vi.importActual('fs/promises'); + + const textPath = join(import.meta.dirname, 'sample_why.txt'); + const sampleText = await readFile(textPath, 'utf-8'); + + it('works', async () => { + mockedExec.mockResolvedValueOnce({ + stdout: sampleText, + stderr: '', + exitCode: 0 + }); + + const retValue = await utils.getPackageReason('lodash'); + expect(retValue).toMatchInlineSnapshot(` + [ + "@sourceacademy/bundle-ar", + "@sourceacademy/bundle-arcade_2d", + "@sourceacademy/bundle-binary_tree", + "@sourceacademy/bundle-communication", + "@sourceacademy/bundle-copy_gc", + "@sourceacademy/bundle-csg", + "@sourceacademy/bundle-curve", + "@sourceacademy/bundle-game", + "@sourceacademy/bundle-mark_sweep", + "@sourceacademy/bundle-midi", + "@sourceacademy/bundle-nbody", + "@sourceacademy/bundle-painter", + "@sourceacademy/bundle-physics_2d", + "@sourceacademy/bundle-pix_n_flix", + "@sourceacademy/bundle-plotly", + "@sourceacademy/bundle-remote_execution", + "@sourceacademy/bundle-repeat", + "@sourceacademy/bundle-repl", + "@sourceacademy/bundle-robot_simulation", + "@sourceacademy/bundle-rune", + "@sourceacademy/bundle-rune_in_words", + "@sourceacademy/bundle-scrabble", + "@sourceacademy/bundle-sound", + "@sourceacademy/bundle-sound_matrix", + "@sourceacademy/bundle-stereo_sound", + "@sourceacademy/bundle-unittest", + "@sourceacademy/bundle-unity_academy", + "@sourceacademy/bundle-wasm", + "@sourceacademy/lint-plugin", + "@sourceacademy/markdown-plugin-directory-tree", + "@sourceacademy/modules-buildtools", + "@sourceacademy/modules-devserver", + "@sourceacademy/modules-docserver", + "@sourceacademy/modules-github-actions", + "@sourceacademy/modules-lib", + "@sourceacademy/modules-repotools", + "@sourceacademy/modules", + "@sourceacademy/tab-ArcadeTwod", + "@sourceacademy/tab-AugmentedReality", + "@sourceacademy/tab-CopyGc", + "@sourceacademy/tab-Csg", + "@sourceacademy/tab-Curve", + "@sourceacademy/tab-Game", + "@sourceacademy/tab-MarkSweep", + "@sourceacademy/tab-Nbody", + "@sourceacademy/tab-Painter", + "@sourceacademy/tab-Physics2D", + "@sourceacademy/tab-Pixnflix", + "@sourceacademy/tab-Plotly", + "@sourceacademy/tab-Repeat", + "@sourceacademy/tab-Repl", + "@sourceacademy/tab-RobotSimulation", + "@sourceacademy/tab-Rune", + "@sourceacademy/tab-Sound", + "@sourceacademy/tab-SoundMatrix", + "@sourceacademy/tab-StereoSound", + "@sourceacademy/tab-Unittest", + "@sourceacademy/tab-UnityAcademy", + ] + `); + expect(mockedExec).toHaveBeenCalledOnce(); + }); +}); \ No newline at end of file diff --git a/.github/actions/src/lockfiles/__tests__/sample_why.txt b/.github/actions/src/lockfiles/__tests__/sample_why.txt new file mode 100644 index 0000000000..240cec0056 --- /dev/null +++ b/.github/actions/src/lockfiles/__tests__/sample_why.txt @@ -0,0 +1,58 @@ +{"value":"@sourceacademy/bundle-ar@workspace:src/bundles/ar","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/bundle-arcade_2d@workspace:src/bundles/arcade_2d","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/bundle-binary_tree@workspace:src/bundles/binary_tree","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"js-slang@npm:1.0.85":{"value":{"locator":"js-slang@npm:1.0.85","descriptor":"js-slang@npm:^1.0.81"},"children":{"lodash@npm:4.17.21":{"value":{"locator":"lodash@npm:4.17.21","descriptor":"lodash@npm:^4.17.21"},"children":{}}}}}} +{"value":"@sourceacademy/bundle-communication@workspace:src/bundles/communication","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/bundle-copy_gc@workspace:src/bundles/copy_gc","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/bundle-csg@workspace:src/bundles/csg","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/bundle-curve@workspace:src/bundles/curve","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}},"js-slang@npm:1.0.85":{"value":{"locator":"js-slang@npm:1.0.85","descriptor":"js-slang@npm:^1.0.81"},"children":{}}}} +{"value":"@sourceacademy/bundle-game@workspace:src/bundles/game","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"js-slang@npm:1.0.85":{"value":{"locator":"js-slang@npm:1.0.85","descriptor":"js-slang@npm:^1.0.81"},"children":{}}}} +{"value":"@sourceacademy/bundle-mark_sweep@workspace:src/bundles/mark_sweep","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/bundle-midi@workspace:src/bundles/midi","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"js-slang@npm:1.0.85":{"value":{"locator":"js-slang@npm:1.0.85","descriptor":"js-slang@npm:^1.0.81"},"children":{}}}} +{"value":"@sourceacademy/bundle-nbody@workspace:src/bundles/nbody","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/bundle-painter@workspace:src/bundles/painter","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/bundle-physics_2d@workspace:src/bundles/physics_2d","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/bundle-pix_n_flix@workspace:src/bundles/pix_n_flix","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/bundle-plotly@workspace:src/bundles/plotly","children":{"@sourceacademy/bundle-curve@workspace:src/bundles/curve":{"value":{"locator":"@sourceacademy/bundle-curve@workspace:src/bundles/curve","descriptor":"@sourceacademy/bundle-curve@workspace:^"},"children":{}},"@sourceacademy/bundle-sound@workspace:src/bundles/sound":{"value":{"locator":"@sourceacademy/bundle-sound@workspace:src/bundles/sound","descriptor":"@sourceacademy/bundle-sound@workspace:^"},"children":{}},"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"js-slang@npm:1.0.85":{"value":{"locator":"js-slang@npm:1.0.85","descriptor":"js-slang@npm:^1.0.81"},"children":{}}}} +{"value":"@sourceacademy/bundle-remote_execution@workspace:src/bundles/remote_execution","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"js-slang@npm:1.0.85":{"value":{"locator":"js-slang@npm:1.0.85","descriptor":"js-slang@npm:^1.0.81"},"children":{}}}} +{"value":"@sourceacademy/bundle-repeat@workspace:src/bundles/repeat","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/bundle-repl@workspace:src/bundles/repl","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"js-slang@npm:1.0.85":{"value":{"locator":"js-slang@npm:1.0.85","descriptor":"js-slang@npm:^1.0.81"},"children":{}}}} +{"value":"@sourceacademy/bundle-robot_simulation@workspace:src/bundles/robot_simulation","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/bundle-rune@workspace:src/bundles/rune","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}},"js-slang@npm:1.0.85":{"value":{"locator":"js-slang@npm:1.0.85","descriptor":"js-slang@npm:^1.0.81"},"children":{}}}} +{"value":"@sourceacademy/bundle-rune_in_words@workspace:src/bundles/rune_in_words","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/bundle-scrabble@workspace:src/bundles/scrabble","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/bundle-sound@workspace:src/bundles/sound","children":{"@sourceacademy/bundle-midi@workspace:src/bundles/midi":{"value":{"locator":"@sourceacademy/bundle-midi@workspace:src/bundles/midi","descriptor":"@sourceacademy/bundle-midi@workspace:^"},"children":{}},"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}},"js-slang@npm:1.0.85":{"value":{"locator":"js-slang@npm:1.0.85","descriptor":"js-slang@npm:^1.0.81"},"children":{}}}} +{"value":"@sourceacademy/bundle-sound_matrix@workspace:src/bundles/sound_matrix","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"js-slang@npm:1.0.85":{"value":{"locator":"js-slang@npm:1.0.85","descriptor":"js-slang@npm:^1.0.81"},"children":{}}}} +{"value":"@sourceacademy/bundle-stereo_sound@workspace:src/bundles/stereo_sound","children":{"@sourceacademy/bundle-midi@workspace:src/bundles/midi":{"value":{"locator":"@sourceacademy/bundle-midi@workspace:src/bundles/midi","descriptor":"@sourceacademy/bundle-midi@workspace:^"},"children":{}},"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"js-slang@npm:1.0.85":{"value":{"locator":"js-slang@npm:1.0.85","descriptor":"js-slang@npm:^1.0.81"},"children":{}}}} +{"value":"@sourceacademy/bundle-unittest@workspace:src/bundles/unittest","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"js-slang@npm:1.0.85":{"value":{"locator":"js-slang@npm:1.0.85","descriptor":"js-slang@npm:^1.0.81"},"children":{}},"lodash@npm:4.17.21":{"value":{"locator":"lodash@npm:4.17.21","descriptor":"lodash@npm:^4.17.21"},"children":{}}}} +{"value":"@sourceacademy/bundle-unity_academy@workspace:src/bundles/unity_academy","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/bundle-wasm@workspace:src/bundles/wasm","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"source-academy-wabt@npm:1.1.3":{"value":{"locator":"source-academy-wabt@npm:1.1.3","descriptor":"source-academy-wabt@npm:^1.0.4"},"children":{"lodash@npm:4.17.21":{"value":{"locator":"lodash@npm:4.17.21","descriptor":"lodash@npm:^4.17.21"},"children":{}}}}}} +{"value":"@sourceacademy/lint-plugin@workspace:lib/lintplugin","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-repotools@virtual:420fa510eaf06edbb20ddb72fbcd454e937e7e266b8c6b7a55ab314e0562f2688175809f2b44c78563a0467da21b6d34688fe0020ecef5e669997fe518ee56e1#workspace:lib/repotools":{"value":{"locator":"@sourceacademy/modules-repotools@virtual:420fa510eaf06edbb20ddb72fbcd454e937e7e266b8c6b7a55ab314e0562f2688175809f2b44c78563a0467da21b6d34688fe0020ecef5e669997fe518ee56e1#workspace:lib/repotools","descriptor":"@sourceacademy/modules-repotools@virtual:420fa510eaf06edbb20ddb72fbcd454e937e7e266b8c6b7a55ab314e0562f2688175809f2b44c78563a0467da21b6d34688fe0020ecef5e669997fe518ee56e1#workspace:^"},"children":{}}}} +{"value":"@sourceacademy/markdown-plugin-directory-tree@workspace:lib/markdown-tree","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"lodash@npm:4.17.21":{"value":{"locator":"lodash@npm:4.17.21","descriptor":"lodash@npm:^4.17.21"},"children":{}},"@sourceacademy/modules-repotools@virtual:420fa510eaf06edbb20ddb72fbcd454e937e7e266b8c6b7a55ab314e0562f2688175809f2b44c78563a0467da21b6d34688fe0020ecef5e669997fe518ee56e1#workspace:lib/repotools":{"value":{"locator":"@sourceacademy/modules-repotools@virtual:420fa510eaf06edbb20ddb72fbcd454e937e7e266b8c6b7a55ab314e0562f2688175809f2b44c78563a0467da21b6d34688fe0020ecef5e669997fe518ee56e1#workspace:lib/repotools","descriptor":"@sourceacademy/modules-repotools@virtual:420fa510eaf06edbb20ddb72fbcd454e937e7e266b8c6b7a55ab314e0562f2688175809f2b44c78563a0467da21b6d34688fe0020ecef5e669997fe518ee56e1#workspace:^"},"children":{}}}} +{"value":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","children":{"lodash@npm:4.17.21":{"value":{"locator":"lodash@npm:4.17.21","descriptor":"lodash@npm:^4.17.21"},"children":{}},"@sourceacademy/modules-repotools@virtual:1448f4d06c0cf02cc986bce0139b31c0f3c95af1573e69673bc11ad2928a2fc505818a40d3f1caf168c35ce00c20238d52dfdba1940c59c81fd5df1b08ba49d6#workspace:lib/repotools":{"value":{"locator":"@sourceacademy/modules-repotools@virtual:1448f4d06c0cf02cc986bce0139b31c0f3c95af1573e69673bc11ad2928a2fc505818a40d3f1caf168c35ce00c20238d52dfdba1940c59c81fd5df1b08ba49d6#workspace:lib/repotools","descriptor":"@sourceacademy/modules-repotools@virtual:1448f4d06c0cf02cc986bce0139b31c0f3c95af1573e69673bc11ad2928a2fc505818a40d3f1caf168c35ce00c20238d52dfdba1940c59c81fd5df1b08ba49d6#workspace:^"},"children":{}}}} +{"value":"@sourceacademy/modules-devserver@workspace:devserver","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}},"js-slang@npm:1.0.85":{"value":{"locator":"js-slang@npm:1.0.85","descriptor":"js-slang@npm:^1.0.81"},"children":{}}}} +{"value":"@sourceacademy/modules-docserver@workspace:docs","children":{"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}},"@sourceacademy/lint-plugin@virtual:f0562030a653a107496800a80ececfadfd737a6a260bbd2572ca4e42de1d6b97749197bb1c41d0d71c9f18ab009789560666041994678fe1aba63902e9fb15bd#workspace:lib/lintplugin":{"value":{"locator":"@sourceacademy/lint-plugin@virtual:f0562030a653a107496800a80ececfadfd737a6a260bbd2572ca4e42de1d6b97749197bb1c41d0d71c9f18ab009789560666041994678fe1aba63902e9fb15bd#workspace:lib/lintplugin","descriptor":"@sourceacademy/lint-plugin@virtual:f0562030a653a107496800a80ececfadfd737a6a260bbd2572ca4e42de1d6b97749197bb1c41d0d71c9f18ab009789560666041994678fe1aba63902e9fb15bd#workspace:^"},"children":{}},"@sourceacademy/markdown-plugin-directory-tree@virtual:f0562030a653a107496800a80ececfadfd737a6a260bbd2572ca4e42de1d6b97749197bb1c41d0d71c9f18ab009789560666041994678fe1aba63902e9fb15bd#workspace:lib/markdown-tree":{"value":{"locator":"@sourceacademy/markdown-plugin-directory-tree@virtual:f0562030a653a107496800a80ececfadfd737a6a260bbd2572ca4e42de1d6b97749197bb1c41d0d71c9f18ab009789560666041994678fe1aba63902e9fb15bd#workspace:lib/markdown-tree","descriptor":"@sourceacademy/markdown-plugin-directory-tree@virtual:f0562030a653a107496800a80ececfadfd737a6a260bbd2572ca4e42de1d6b97749197bb1c41d0d71c9f18ab009789560666041994678fe1aba63902e9fb15bd#workspace:^"},"children":{}}}} +{"value":"@sourceacademy/modules-github-actions@workspace:.github/actions","children":{"@actions/artifact@npm:2.3.2":{"value":{"locator":"@actions/artifact@npm:2.3.2","descriptor":"@actions/artifact@npm:^2.3.2"},"children":{"archiver@npm:7.0.1":{"value":{"locator":"archiver@npm:7.0.1","descriptor":"archiver@npm:^7.0.1"},"children":{"archiver-utils@npm:5.0.2":{"value":{"locator":"archiver-utils@npm:5.0.2","descriptor":"archiver-utils@npm:^5.0.2"},"children":{"lodash@npm:4.17.21":{"value":{"locator":"lodash@npm:4.17.21","descriptor":"lodash@npm:^4.17.15"},"children":{}}}},"zip-stream@npm:6.0.1":{"value":{"locator":"zip-stream@npm:6.0.1","descriptor":"zip-stream@npm:^6.0.1"},"children":{"archiver-utils@npm:5.0.2":{"value":{"locator":"archiver-utils@npm:5.0.2","descriptor":"archiver-utils@npm:^5.0.0"},"children":{}}}}}}}},"lodash@npm:4.17.21":{"value":{"locator":"lodash@npm:4.17.21","descriptor":"lodash@npm:^4.17.21"},"children":{}},"@sourceacademy/modules-repotools@virtual:420fa510eaf06edbb20ddb72fbcd454e937e7e266b8c6b7a55ab314e0562f2688175809f2b44c78563a0467da21b6d34688fe0020ecef5e669997fe518ee56e1#workspace:lib/repotools":{"value":{"locator":"@sourceacademy/modules-repotools@virtual:420fa510eaf06edbb20ddb72fbcd454e937e7e266b8c6b7a55ab314e0562f2688175809f2b44c78563a0467da21b6d34688fe0020ecef5e669997fe518ee56e1#workspace:lib/repotools","descriptor":"@sourceacademy/modules-repotools@virtual:420fa510eaf06edbb20ddb72fbcd454e937e7e266b8c6b7a55ab314e0562f2688175809f2b44c78563a0467da21b6d34688fe0020ecef5e669997fe518ee56e1#workspace:^"},"children":{}}}} +{"value":"@sourceacademy/modules-lib@workspace:lib/modules-lib","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"js-slang@npm:1.0.85":{"value":{"locator":"js-slang@npm:1.0.85","descriptor":"js-slang@npm:^1.0.81"},"children":{}}}} +{"value":"@sourceacademy/modules-repotools@workspace:lib/repotools","children":{"lodash@npm:4.17.21":{"value":{"locator":"lodash@npm:4.17.21","descriptor":"lodash@npm:^4.17.21"},"children":{}}}} +{"value":"@sourceacademy/modules@workspace:.","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"js-slang@npm:1.0.85":{"value":{"locator":"js-slang@npm:1.0.85","descriptor":"js-slang@npm:^1.0.81"},"children":{}},"lodash@npm:4.17.21":{"value":{"locator":"lodash@npm:4.17.21","descriptor":"lodash@npm:^4.17.21"},"children":{}},"@sourceacademy/lint-plugin@virtual:72a684de9912e8b42da7a581a5478d78ad73e0a505830e61e9b2fbc990fcc10719f71ef5373c26313c28b9295f1381b0d95a4d0ab2ae6e33671c2ba25a5c1dc2#workspace:lib/lintplugin":{"value":{"locator":"@sourceacademy/lint-plugin@virtual:72a684de9912e8b42da7a581a5478d78ad73e0a505830e61e9b2fbc990fcc10719f71ef5373c26313c28b9295f1381b0d95a4d0ab2ae6e33671c2ba25a5c1dc2#workspace:lib/lintplugin","descriptor":"@sourceacademy/lint-plugin@virtual:72a684de9912e8b42da7a581a5478d78ad73e0a505830e61e9b2fbc990fcc10719f71ef5373c26313c28b9295f1381b0d95a4d0ab2ae6e33671c2ba25a5c1dc2#workspace:^"},"children":{}},"@sourceacademy/modules-repotools@virtual:72a684de9912e8b42da7a581a5478d78ad73e0a505830e61e9b2fbc990fcc10719f71ef5373c26313c28b9295f1381b0d95a4d0ab2ae6e33671c2ba25a5c1dc2#workspace:lib/repotools":{"value":{"locator":"@sourceacademy/modules-repotools@virtual:72a684de9912e8b42da7a581a5478d78ad73e0a505830e61e9b2fbc990fcc10719f71ef5373c26313c28b9295f1381b0d95a4d0ab2ae6e33671c2ba25a5c1dc2#workspace:lib/repotools","descriptor":"@sourceacademy/modules-repotools@virtual:72a684de9912e8b42da7a581a5478d78ad73e0a505830e61e9b2fbc990fcc10719f71ef5373c26313c28b9295f1381b0d95a4d0ab2ae6e33671c2ba25a5c1dc2#workspace:^"},"children":{}}}} +{"value":"@sourceacademy/tab-ArcadeTwod@workspace:src/tabs/ArcadeTwod","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/tab-AugmentedReality@workspace:src/tabs/AugmentedReality","children":{"@sourceacademy/bundle-ar@workspace:src/bundles/ar":{"value":{"locator":"@sourceacademy/bundle-ar@workspace:src/bundles/ar","descriptor":"@sourceacademy/bundle-ar@workspace:^"},"children":{}},"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/tab-CopyGc@workspace:src/tabs/CopyGc","children":{"@sourceacademy/bundle-copy_gc@workspace:src/bundles/copy_gc":{"value":{"locator":"@sourceacademy/bundle-copy_gc@workspace:src/bundles/copy_gc","descriptor":"@sourceacademy/bundle-copy_gc@workspace:^"},"children":{}},"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/tab-Csg@workspace:src/tabs/Csg","children":{"@sourceacademy/bundle-csg@workspace:src/bundles/csg":{"value":{"locator":"@sourceacademy/bundle-csg@workspace:src/bundles/csg","descriptor":"@sourceacademy/bundle-csg@workspace:^"},"children":{}},"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/tab-Curve@workspace:src/tabs/Curve","children":{"@sourceacademy/bundle-curve@workspace:src/bundles/curve":{"value":{"locator":"@sourceacademy/bundle-curve@workspace:src/bundles/curve","descriptor":"@sourceacademy/bundle-curve@workspace:^"},"children":{}},"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/tab-Game@workspace:src/tabs/Game","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/tab-MarkSweep@workspace:src/tabs/MarkSweep","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/tab-Nbody@workspace:src/tabs/Nbody","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/tab-Painter@workspace:src/tabs/Painter","children":{"@sourceacademy/bundle-painter@workspace:src/bundles/painter":{"value":{"locator":"@sourceacademy/bundle-painter@workspace:src/bundles/painter","descriptor":"@sourceacademy/bundle-painter@workspace:^"},"children":{}},"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/tab-Physics2D@workspace:src/tabs/Physics2D","children":{"@sourceacademy/bundle-physics_2d@workspace:src/bundles/physics_2d":{"value":{"locator":"@sourceacademy/bundle-physics_2d@workspace:src/bundles/physics_2d","descriptor":"@sourceacademy/bundle-physics_2d@workspace:^"},"children":{}},"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/tab-Pixnflix@workspace:src/tabs/Pixnflix","children":{"@sourceacademy/bundle-pix_n_flix@workspace:src/bundles/pix_n_flix":{"value":{"locator":"@sourceacademy/bundle-pix_n_flix@workspace:src/bundles/pix_n_flix","descriptor":"@sourceacademy/bundle-pix_n_flix@workspace:^"},"children":{}},"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/tab-Plotly@workspace:src/tabs/Plotly","children":{"@sourceacademy/bundle-plotly@workspace:src/bundles/plotly":{"value":{"locator":"@sourceacademy/bundle-plotly@workspace:src/bundles/plotly","descriptor":"@sourceacademy/bundle-plotly@workspace:^"},"children":{}},"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/tab-Repeat@workspace:src/tabs/Repeat","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/tab-Repl@workspace:src/tabs/Repl","children":{"@sourceacademy/bundle-repl@workspace:src/bundles/repl":{"value":{"locator":"@sourceacademy/bundle-repl@workspace:src/bundles/repl","descriptor":"@sourceacademy/bundle-repl@workspace:^"},"children":{}},"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/tab-RobotSimulation@workspace:src/tabs/RobotSimulation","children":{"@sourceacademy/bundle-robot_simulation@workspace:src/bundles/robot_simulation":{"value":{"locator":"@sourceacademy/bundle-robot_simulation@workspace:src/bundles/robot_simulation","descriptor":"@sourceacademy/bundle-robot_simulation@workspace:^"},"children":{}},"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/tab-Rune@workspace:src/tabs/Rune","children":{"@sourceacademy/bundle-rune@workspace:src/bundles/rune":{"value":{"locator":"@sourceacademy/bundle-rune@workspace:src/bundles/rune","descriptor":"@sourceacademy/bundle-rune@workspace:^"},"children":{}},"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/tab-Sound@workspace:src/tabs/Sound","children":{"@sourceacademy/bundle-sound@workspace:src/bundles/sound":{"value":{"locator":"@sourceacademy/bundle-sound@workspace:src/bundles/sound","descriptor":"@sourceacademy/bundle-sound@workspace:^"},"children":{}},"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/tab-SoundMatrix@workspace:src/tabs/SoundMatrix","children":{"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/tab-StereoSound@workspace:src/tabs/StereoSound","children":{"@sourceacademy/bundle-stereo_sound@workspace:src/bundles/stereo_sound":{"value":{"locator":"@sourceacademy/bundle-stereo_sound@workspace:src/bundles/stereo_sound","descriptor":"@sourceacademy/bundle-stereo_sound@workspace:^"},"children":{}},"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/tab-Unittest@workspace:src/tabs/Unittest","children":{"@sourceacademy/bundle-unittest@workspace:src/bundles/unittest":{"value":{"locator":"@sourceacademy/bundle-unittest@workspace:src/bundles/unittest","descriptor":"@sourceacademy/bundle-unittest@workspace:^"},"children":{}},"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} +{"value":"@sourceacademy/tab-UnityAcademy@workspace:src/tabs/UnityAcademy","children":{"@sourceacademy/bundle-unity_academy@workspace:src/bundles/unity_academy":{"value":{"locator":"@sourceacademy/bundle-unity_academy@workspace:src/bundles/unity_academy","descriptor":"@sourceacademy/bundle-unity_academy@workspace:^"},"children":{}},"@sourceacademy/modules-buildtools@workspace:lib/buildtools":{"value":{"locator":"@sourceacademy/modules-buildtools@workspace:lib/buildtools","descriptor":"@sourceacademy/modules-buildtools@workspace:^"},"children":{}},"@sourceacademy/modules-lib@workspace:lib/modules-lib":{"value":{"locator":"@sourceacademy/modules-lib@workspace:lib/modules-lib","descriptor":"@sourceacademy/modules-lib@workspace:^"},"children":{}}}} diff --git a/.github/actions/src/lockfiles/index.ts b/.github/actions/src/lockfiles/index.ts new file mode 100644 index 0000000000..cddb5feae5 --- /dev/null +++ b/.github/actions/src/lockfiles/index.ts @@ -0,0 +1,30 @@ +import { getExecOutput } from '@actions/exec'; +import memoize from 'lodash/memoize.js'; +import { getPackageDiffs, getPackageReason } from './utils.js'; + +/** + * Returns `true` if there are changes present in the given directory relative to + * the master branch\ + * Used to determine, particularly for libraries, if running tests and tsc are necessary + */ +export const hasLockFileChanged = memoize(async () => { + const { exitCode } = await getExecOutput( + 'git --no-pager diff --quiet origin/master -- yarn.lock', + [], + { + failOnStdErr: false, + ignoreReturnCode: true + } + ); + return exitCode !== 0; +}); + +/** + * Gets a list of packages that have had some dependency of theirs + * change according to the lockfile but not their package.json + */ +export async function getPackagesWithResolutionChanges() { + const packages = [...await getPackageDiffs()]; + const workspaces = await Promise.all(packages.map(getPackageReason)); + return new Set(workspaces.flat()); +} diff --git a/.github/actions/src/lockfiles/utils.ts b/.github/actions/src/lockfiles/utils.ts new file mode 100644 index 0000000000..aa22ee712e --- /dev/null +++ b/.github/actions/src/lockfiles/utils.ts @@ -0,0 +1,128 @@ +import fs from 'fs/promises'; +import pathlib from 'path'; +import * as core from '@actions/core'; +import { getExecOutput } from '@actions/exec'; +import { extractPkgsFromYarnLockV2 } from 'snyk-nodejs-lockfile-parser'; +import { gitRoot } from '../gitRoot.js'; + +const packageNameRE = /^(.+)@.+$/; + +/** + * Lockfile specifications come in the form of package_name@resolution, but + * we only want the package name. This function extracts that package name, + * accounting for the fact that package names might start with '@' + */ +export function extractPackageName(raw: string) { + const match = packageNameRE.exec(raw); + if (!match) { + throw new Error(`Invalid package name: ${raw}`); + } + + return match[1]; +} + +/** + * Using `yarn why`, determine which repository package is the reason why the + * given package is present in the lockfile. + */ +export async function getPackageReason(pkg: string) { + const { stdout, stderr, exitCode } = await getExecOutput('yarn why', [pkg, '-R', '--json'], { silent: true }); + if (exitCode !== 0) { + core.error(stderr); + throw new Error(`yarn why for '${pkg}' exited with non-zero exit code!`); + } + + return stdout.trim().split('\n').map(each => { + const entry = JSON.parse(each).value; + return extractPackageName(entry); + }); +} + +/** + * Determines the names of the packages that have changed versions + */ +export async function getPackageDiffs() { + const [currentLockFile, masterLockFile] = await Promise.all([ + getCurrentLockFile(), + getMasterLockFile() + ]); + + const packages = new Set(); + + for (const [depName, versions] of Object.entries(currentLockFile)) { + if (packages.has(depName)) continue; + + if (!(depName in masterLockFile)) { + core.info(`${depName} in current lockfile, not in master lock file`); + continue; + } + + let needToAdd = false; + for (const version of versions) { + if (!masterLockFile[depName].has(version)) { + core.info(`${depName} has ${version} in current lockfile but not in master`); + needToAdd = true; + } + } + + for (const version of masterLockFile[depName]) { + if (!versions.has(version)) { + core.info(`${depName} has ${version} in master lockfile but not in current`); + needToAdd = true; + } + } + + if (needToAdd) packages.add(depName); + } + + return packages; +} + +/** + * Retrieves the contents of the lockfile in the repo + */ +export async function getCurrentLockFile() { + const lockFilePath = pathlib.join(gitRoot, 'yarn.lock'); + const contents = await fs.readFile(lockFilePath, 'utf-8'); + return processLockFileText(contents); +} + +/** + * Retrieves the contents of the lockfile on the master branch + */ +export async function getMasterLockFile() { + const { stdout, stderr, exitCode } = await getExecOutput( + 'git', + [ + '--no-pager', + 'show', + 'origin/master:yarn.lock' + ], + { silent: true } + ); + + if (exitCode !== 0) { + core.error(stderr); + throw new Error('git show exited with non-zero error-code'); + } + + return processLockFileText(stdout); +} + +/** + * Parses and lockfile's contents and extracts all the different dependencies and + * versions + */ +export function processLockFileText(contents: string) { + const lockFile = extractPkgsFromYarnLockV2(contents); + return Object.entries(lockFile).reduce>>((res, [key, { version }]) => { + const newKey = extractPackageName(key); + + if (!(newKey in res)) { + res[newKey] = new Set(); + } + + res[newKey].add(version); + return res; + }, {}); +} diff --git a/.github/actions/tsconfig.json b/.github/actions/tsconfig.json index e0e756fbc8..48f6be9ed0 100644 --- a/.github/actions/tsconfig.json +++ b/.github/actions/tsconfig.json @@ -1,8 +1,13 @@ { - "include": ["src/**/*.ts", "vitest.setup.ts"], + "include": [ + "src/**/*.ts", + "vitest.setup.ts" + ], "compilerOptions": { "forceConsistentCasingInFileNames": true, - "lib": ["ES2020"], + "lib": [ + "ES2020" + ], "module": "esnext", "moduleResolution": "bundler", "noEmit": true, diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index dc24b07ad1..785b7ef138 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -17,7 +17,7 @@ jobs: - name: Check out source code uses: actions/checkout@v5 - - name: Initialize Repo + - name: Initialize Github Actions uses: ./.github/actions/src/init with: package-name: '@sourceacademy/modules-github-actions' @@ -48,6 +48,8 @@ jobs: workflows: ${{ steps.info.outputs.workflows }} libraries: + if: ${{ needs.find-packages.outputs.libs != '[]' }} + needs: find-packages strategy: fail-fast: false @@ -63,11 +65,9 @@ jobs: steps: - name: Check out source code - if: matrix.lib.changes uses: actions/checkout@v5 - - name: Initialize Repo - if: matrix.lib.changes + - name: Initialize ${{ matrix.lib.name }} uses: ./.github/actions/src/init with: package-name: ${{ matrix.lib.name }} @@ -76,18 +76,20 @@ jobs: # Only thing we really need to do on Windows is run tests (without coverage) - name: Run Tests (Windows) - if: matrix.lib.changes && matrix.os == 'windows-latest' + if: matrix.os == 'windows-latest' run: yarn workspaces foreach -A --include ${{ matrix.lib.name }} run test - name: Run Tests (Ubuntu) - if: matrix.lib.changes && matrix.os == 'ubuntu-latest' + if: matrix.os == 'ubuntu-latest' run: yarn workspaces foreach -A --include ${{ matrix.lib.name }} run test --coverage - name: Run Auxillary Tasks - if: matrix.lib.changes && matrix.os == 'ubuntu-latest' + if: matrix.os == 'ubuntu-latest' run: yarn workspaces foreach -A --include ${{ matrix.lib.name }} run tsc tabs: + if: ${{ needs.find-packages.outputs.tabs != '[]' }} + runs-on: ubuntu-latest needs: find-packages strategy: @@ -97,24 +99,20 @@ jobs: name: ${{ matrix.tabInfo.tabName }} Tab steps: - name: Check out source code - if: matrix.tabInfo.changes uses: actions/checkout@v5 - - name: Initialize Repo - if: matrix.tabInfo.changes + - name: Initialize ${{ matrix.tabInfo.tabName }} uses: ./.github/actions/src/init with: package-name: ${{ matrix.tabInfo.name }} playwright: ${{ matrix.tabInfo.needsPlaywright && matrix.tabInfo.changes }} - name: Build Tab - if: matrix.tabInfo.changes run: | cd ${{ matrix.tabInfo.directory }} yarn build - name: Upload Tab Artifact - if: matrix.tabInfo.changes uses: actions/upload-artifact@v4 with: name: ${{ matrix.tabInfo.tabName }}-tab @@ -124,18 +122,18 @@ jobs: # https://github.com/vitest-dev/vitest/issues/5477 # Known Vitest issue for coverage running in browser mode # Momentarily disable coverage checking on Github Actions for tabs - if: matrix.tabInfo.changes run: | cd ${{ matrix.tabInfo.directory }} yarn test - name: Run Auxillary Tasks - if: matrix.tabInfo.changes run: | cd ${{ matrix.tabInfo.directory }} yarn tsc bundles: + if: ${{ needs.find-packages.outputs.bundles != '[]' }} + runs-on: ubuntu-latest needs: find-packages strategy: @@ -145,31 +143,26 @@ jobs: name: ${{ matrix.bundleInfo.bundleName }} Bundle steps: - name: Check out source code - if: matrix.bundleInfo.changes uses: actions/checkout@v5 - - name: Initialize Repo - if: matrix.bundleInfo.changes + - name: Initialize ${{ matrix.bundleInfo.name }} uses: ./.github/actions/src/init with: package-name: ${{ matrix.bundleInfo.name }} playwright: ${{ matrix.bundleInfo.needsPlaywright }} - name: Build Bundle - if: matrix.bundleInfo.changes run: | cd ${{ matrix.bundleInfo.directory }} yarn build yarn tsc - name: Build Bundle Docs - if: matrix.bundleInfo.changes run: | cd ${{ matrix.bundleInfo.directory }} yarn buildtools build docs - name: Run Tests - if: matrix.bundleInfo.changes run: | cd ${{ matrix.bundleInfo.directory }} yarn test --coverage @@ -181,7 +174,14 @@ jobs: - find-packages - tabs - if: ${{ fromJson(needs.find-packages.outputs.devserver).changes }} + if: >- + ${{ + always() && + !cancelled() && + fromJson(needs.find-packages.outputs.devserver).changes && + needs.find-packages.result == 'success' && + (needs.find-packages.outputs.tabs == '[]' || needs.tabs.result == 'success') + }} steps: - name: Check out source code @@ -196,7 +196,7 @@ jobs: - name: Load/Build all tabs uses: ./.github/actions/src/load-artifacts - - name: Initialize Repo + - name: Initialize Devserver uses: ./.github/actions/src/init with: package-name: '@sourceacademy/modules-devserver' @@ -223,13 +223,21 @@ jobs: needs: - libraries - find-packages - if: ${{ fromJson(needs.find-packages.outputs.docserver).changes }} + + if: >- + ${{ + always() && + !cancelled() && + fromJson(needs.find-packages.outputs.docserver).changes && + needs.find-packages.result == 'success' && + (needs.find-packages.outputs.libs == '[]' || needs.libraries.result == 'success') + }} steps: - name: Check out source code uses: actions/checkout@v5 - - name: Initialize Repo + - name: Initialize Docserver uses: ./.github/actions/src/init with: package-name: '@sourceacademy/modules-docserver' @@ -277,12 +285,26 @@ jobs: name: Verify all tests pass and build success runs-on: ubuntu-latest needs: + - find-packages - libraries - tabs - bundles - devserver - docserver - repo-tasks + + if: >- + ${{ + always() && + !cancelled() && + (needs.find-packages.outputs.libs == '[]' || needs.libraries.result == 'success') && + (needs.find-packages.outputs.tabs == '[]' || needs.tabs.result == 'success') && + (needs.find-packages.outputs.bundles == '[]' || needs.bundles.result == 'success') && + !(!fromJson(needs.find-packages.outputs.docserver).changes || needs.docserver.result != 'success') && + !(!fromJson(needs.find-packages.outputs.devserver).changes || needs.devserver.result != 'success') && + needs.repo-tasks.result == 'success' + }} + steps: - name: All done! 🎉 run: echo "All tasks completed successfully!" diff --git a/README.md b/README.md index 6d091cd447..ef92cbe3f5 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ The [Source Academy](https://sourceacademy.org) and [Source Academy @ NUS](https If you are looking for the documentation for the default modules, that can be found [here](https://source-academy.github.io/modules/documentation). -If you are a developer looking to do things like create a new bundle or work with the repository, the developer documentation can be found [here](https://source-academy.github.io/devdocs). +If you are a developer looking to do things like create a new bundle or work with the repository, the developer documentation can be found [here](https://source-academy.github.io/modules/devdocs). ## Quick Links @@ -17,7 +17,7 @@ If you are a developer looking to do things like create a new bundle or work wit | Source Academy | | | Default Modules Deployment | | | Default Modules Documentation | | -| Developer Documentation | | +| Developer Documentation | | | Frontend | | @@ -31,18 +31,12 @@ If you are a developer looking to do things like create a new bundle or work wit ├── build // Output for compiled assets ├── devserver // Development Server ├── docs // Documentation Server -├── lib -│ ├── __test_mocks__ // Mock bundles and tabs used for testing -│ ├── buildtools // Command line tools for bundles and tabs -│ ├── lintplugin // ESLint Plugin -│ ├── markdown-tree // Markdown-It plugin for generating directory trees -│ ├── modules-lib // Common library for utilities used by bundles and tabs -│ └── repotools // Repository wide tooling +├── lib // Common libraries used throughout the repo ├── src // Code for bundles, tabs and java-slang │ ├── bundles │ ├── tabs │ └── java -├── vitest.config.js // Root Vitest Config +├── vitest.config.ts // Root Vitest Config ├── eslint.config.js // ESLint Config └── yarn.config.cjs // Yarn Constraints file ``` diff --git a/devserver/vite.config.ts b/devserver/vite.config.ts index b57fd13b81..97630fc1cf 100644 --- a/devserver/vite.config.ts +++ b/devserver/vite.config.ts @@ -3,17 +3,17 @@ import fs from 'fs/promises'; import pathlib from 'path'; import react from '@vitejs/plugin-react'; -import { nodePolyfills } from 'vite-plugin-node-polyfills'; -import { loadEnv } from 'vite' import { playwright } from '@vitest/browser-playwright'; +import { loadEnv } from 'vite'; +import { nodePolyfills } from 'vite-plugin-node-polyfills'; import { defineProject } from 'vitest/config'; import type { BrowserCommand } from 'vitest/node'; const setLocalStorage: BrowserCommand<[key: string, value: any]> = async (ctx, key, value) => { if (ctx.provider.name === 'playwright') { - await ctx.page.evaluate(([key, value]) => localStorage.setItem(key, value), [key, value]) + await ctx.page.evaluate(([key, value]) => localStorage.setItem(key, value), [key, value]); } -} +}; export default defineProject(({ mode }) => { const env = loadEnv(mode, process.cwd()); @@ -61,13 +61,13 @@ export default defineProject(({ mode }) => { find: /^@sourceacademy\/modules-lib/, replacement: '.', async customResolver(source) { - const newSource = pathlib.resolve(import.meta.dirname, '../lib/modules-lib/src', source) - const extensions = ['.tsx', '.ts', '/index.ts'] + const newSource = pathlib.resolve(import.meta.dirname, '../lib/modules-lib/src', source); + const extensions = ['.tsx', '.ts', '/index.ts']; for (const each of extensions) { try { - await fs.access(`${newSource}${each}`, fs.constants.R_OK) - return `${newSource}${each}` + await fs.access(`${newSource}${each}`, fs.constants.R_OK); + return `${newSource}${each}`; } catch { } } @@ -105,9 +105,9 @@ export default defineProject(({ mode }) => { 'react-ace', 'react-ace/lib/ace', 're-resizable', - "vite-plugin-node-polyfills/shims/buffer", - "vite-plugin-node-polyfills/shims/global", - "vite-plugin-node-polyfills/shims/process", + 'vite-plugin-node-polyfills/shims/buffer', + 'vite-plugin-node-polyfills/shims/global', + 'vite-plugin-node-polyfills/shims/process', 'vitest-browser-react' ], }, @@ -126,5 +126,5 @@ export default defineProject(({ mode }) => { } } } - } + }; }); diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 7b7cf763ca..6ae20e6a79 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -10,9 +10,9 @@ import _package from '../../package.json' with { type: 'json' }; // https://vitepress.dev/reference/site-config const vitepressOptions: UserConfig = { - base: '/devdocs/', + base: '/modules/devdocs/', description: 'Developer documentation for the Source Academy modules repository', - head: [['link', { rel: 'icon', href: '/devdocs/favicon.ico' }]], + head: [['link', { rel: 'icon', href: '/modules/devdocs/favicon.ico' }]], ignoreDeadLinks: 'localhostLinks', lastUpdated: true, markdown: { @@ -88,10 +88,15 @@ const vitepressOptions: UserConfig = { ], siteTitle: 'SA Modules', socialLinks: [ - { icon: 'github', link: _package.repository }, + { + icon: 'github', + link: _package.repository, + title: 'Github Repository' + }, { icon: 'gitbook', - link: 'https://source-academy.github.io/modules/documentation/' + link: 'https://source-academy.github.io/modules/documentation/', + title: 'Modules Documentation' } ], search: { @@ -99,6 +104,7 @@ const vitepressOptions: UserConfig = { } }, vite: { + // @ts-expect-error groupIconVitePlugin is probably built for an incorrect version of Vite plugins: [groupIconVitePlugin()] } }; diff --git a/docs/src/index.md b/docs/src/index.md index 07e1c7390e..cb84b76c3a 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -6,38 +6,39 @@ hero: name: SA Modules Developer Documentation tagline: Developer documentation for the Source Academy modules repository image: - src: ./favicon.ico + src: /favicon.ico features: - title: Your first bundle or tab icon: width: 43 - src: ./icons/tut.png + src: /hero-icons/tut.png details: Instructions for creating a bundle or tab link: /modules/1-getting-started/1-overview - title: Common Modules Libraries icon: - src: ./icons/library.png + src: /hero-icons/library.png width: 40 details: Libraries intended to be shared between SA Modules link: /lib - title: Build Tools icon: - src: ./icons/tools.png + src: /hero-icons/tools.png width: 40 details: Details behind the tooling that compiles SA Modules link: /buildtools - title: Repository Tools icon: - src: ./icons/github.png + src: /hero-icons/github.png width: 40 details: Details for the tools used to aid in developing SA Modules link: /repotools ---

-Not a developer? Documentation for the Source Modules themselves is here + +Not a developer? Documentation for the Source Modules themselves is here

diff --git a/docs/src/icons/github.png b/docs/src/public/hero-icons/github.png similarity index 100% rename from docs/src/icons/github.png rename to docs/src/public/hero-icons/github.png diff --git a/docs/src/icons/library.png b/docs/src/public/hero-icons/library.png similarity index 100% rename from docs/src/icons/library.png rename to docs/src/public/hero-icons/library.png diff --git a/docs/src/icons/tools.png b/docs/src/public/hero-icons/tools.png similarity index 100% rename from docs/src/icons/tools.png rename to docs/src/public/hero-icons/tools.png diff --git a/docs/src/icons/tut.png b/docs/src/public/hero-icons/tut.png similarity index 100% rename from docs/src/icons/tut.png rename to docs/src/public/hero-icons/tut.png diff --git a/docs/src/repotools/7-workflows/1-actions.md b/docs/src/repotools/7-workflows/1-actions.md index ee2ac5fea8..1cfa91dbde 100644 --- a/docs/src/repotools/7-workflows/1-actions.md +++ b/docs/src/repotools/7-workflows/1-actions.md @@ -24,6 +24,9 @@ The information action retrieves information about each package present in the r In the case of bundles or tabs, it also retrieves the name of the bundle or tab. +In case of changes to the lockfile, it also determines which packages need to be rebuilt. This can happen when dependencies of dependencies change, +so no change is present in the package's source code itself, but the lockfile itself has changed. + This information is used by both the initializer action and the workflows to determine the what tasks need to be executed. ## Initializer Action (`init/action.yml`) diff --git a/eslint.config.js b/eslint.config.js index 0bf66c7f11..95ba897d25 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -32,7 +32,6 @@ export default defineConfig( '.yarn', 'build/**', 'docs/.vitepress/cache', - 'devserver/vite.config.ts', // Don't lint this because there's no tsconfig properly configured for it '**/node_modules', 'lib/buildtools/bin', 'lib/buildtools/src/build/__test_mocks__', @@ -489,7 +488,7 @@ export default defineConfig( }, { name: 'Rules for Vitest configs', - files: ['**/vitest.config.ts'], + files: ['**/vitest.config.ts', './devserver/vite.config.ts'], languageOptions: { parserOptions: { project: './tsconfig.json' diff --git a/lib/buildtools/src/commands/__tests__/commandUtils.test.ts b/lib/buildtools/src/commands/__tests__/commandUtils.test.ts index 385052135c..0fc7a259cc 100644 --- a/lib/buildtools/src/commands/__tests__/commandUtils.test.ts +++ b/lib/buildtools/src/commands/__tests__/commandUtils.test.ts @@ -1,6 +1,8 @@ import type { Severity } from '@sourceacademy/modules-repotools/types'; import { describe, expect, test } from 'vitest'; -import { processResult } from '../commandUtils.js'; +import { logLevelOption, processResult } from '../commandUtils.js'; +import { Command } from '@commander-js/extra-typings'; +import { LogLevel } from 'typedoc'; describe(processResult, () => { const testCases: [any, Severity][] = [ @@ -35,3 +37,37 @@ describe(processResult, () => { } }); }); + +describe('Log Level option', () => { + async function parseArgs(...args: string[]) { + return new Promise((resolve, reject) => { + new Command() + .exitOverride(reject) + .configureOutput({ writeErr: () => {} }) + .addOption(logLevelOption) + .action(({ logLevel }) => resolve(logLevel)) + .parse(args, { from: 'user' }) + } + ); + } + + test('no value means LogLevel.Error', () => { + return expect(parseArgs()).resolves.toEqual(LogLevel.Error); + }); + + test('text values ignores case', () => { + return expect(parseArgs('--logLevel', 'info')).resolves.toEqual(LogLevel.Info); + }); + + test('number values work', () => { + return expect(parseArgs('--logLevel', '0')).resolves.toEqual(LogLevel.Verbose); + }); + + test('incorrect numerical value causes error', () => { + return expect(parseArgs('--logLevel', '10')).rejects.toThrowError('Invalid log level: 10'); + }); + + test('incorrect string value causes error', () => { + return expect(parseArgs('--logLevel', 'infox')).rejects.toThrowError('Invalid log level: infox'); + }); +}); diff --git a/lib/buildtools/src/commands/__tests__/testing.test.ts b/lib/buildtools/src/commands/__tests__/testing.test.ts index 9fe37bd982..4d6f89b7ac 100644 --- a/lib/buildtools/src/commands/__tests__/testing.test.ts +++ b/lib/buildtools/src/commands/__tests__/testing.test.ts @@ -141,18 +141,11 @@ describe('Test silent option', () => { const runCommand = (...args: string[]) => new Promise( (resolve, reject) => { const command = new Command() - .exitOverride() + .exitOverride(reject) .addOption(silentOption) .configureOutput({ writeErr: () => { } }) - .action(option => { - resolve(option.silent); - }); - - try { - command.parse(args, { from: 'user' }); - } catch (error) { - reject(error); - } + .action(option => resolve(option.silent)) + .parse(args, { from: 'user' }); } ); @@ -181,6 +174,11 @@ describe('Test silent option', () => { expect(value).toEqual('passed-only'); }); + test('option is case insensitive', async () => { + const value = await runCommand('--silent', 'Passed-OnLy'); + expect(value).toEqual('passed-only'); + }); + test('running command with invalid option', () => { return expect(runCommand('--silent', 'unknown')) .rejects diff --git a/lib/buildtools/src/commands/commandUtils.ts b/lib/buildtools/src/commands/commandUtils.ts index f5da867cf1..cace74b7db 100644 --- a/lib/buildtools/src/commands/commandUtils.ts +++ b/lib/buildtools/src/commands/commandUtils.ts @@ -1,7 +1,8 @@ import { InvalidArgumentError, Option } from '@commander-js/extra-typings'; import type { ErrorResult, Severity } from '@sourceacademy/modules-repotools/types'; -import { isSeverity, objectKeys } from '@sourceacademy/modules-repotools/utils'; +import { isSeverity, objectKeys, objectValues } from '@sourceacademy/modules-repotools/utils'; import chalk from 'chalk'; +import capitalize from 'lodash/capitalize.js'; import { LogLevel } from 'typedoc'; export const lintOption = new Option('--lint', 'Run ESLint when building') @@ -14,12 +15,21 @@ export const watchOption = new Option('-w, --watch', 'Run in watch mode') .default(false); export const logLevelOption = new Option('--logLevel ', 'Log level that Typedoc should use') - .choices(objectKeys(LogLevel)) + .choices(objectKeys(LogLevel).map(x => x.toLowerCase())) .default(LogLevel.Error) .argParser((val): LogLevel => { - if (val in LogLevel) { + const numVal = parseInt(val); + if (!Number.isNaN(numVal)) { + const result = objectValues(LogLevel).some(value => value === numVal) + if (result) { + return numVal as unknown as LogLevel; + } + } + + const capVal = capitalize(val); + if (capVal in LogLevel) { // @ts-expect-error Enums kind of behave weirdly in Typescript - return LogLevel[val]; + return LogLevel[capVal]; } throw new InvalidArgumentError(`Invalid log level: ${val}`); diff --git a/lib/buildtools/src/commands/testing.ts b/lib/buildtools/src/commands/testing.ts index 2a43383b37..1d11e20a52 100644 --- a/lib/buildtools/src/commands/testing.ts +++ b/lib/buildtools/src/commands/testing.ts @@ -19,7 +19,7 @@ const coverageOption = new Option('--coverage', 'Run coverage testing'); export const silentOption = new Option('--silent [option]', 'Silent mode') .choices(['passed-only', 'false', 'true'] as const) .argParser(value => { - switch (value) { + switch (value.toLowerCase()) { case 'passed-only': return 'passed-only'; case 'false': diff --git a/lib/repotools/src/testing/index.ts b/lib/repotools/src/testing/index.ts index 81e9e1d015..11d21ed853 100644 --- a/lib/repotools/src/testing/index.ts +++ b/lib/repotools/src/testing/index.ts @@ -246,7 +246,7 @@ export async function getTestConfiguration(directory: string, watch: boolean): P if (!bundleResult) { return { severity: 'error', - errors: [`Invalid bundle present at ${jsonDir}`] + errors: [`No bundle present at ${jsonDir}`] }; } else if (bundleResult.severity === 'error') { return bundleResult; diff --git a/src/bundles/midi/src/types.ts b/src/bundles/midi/src/types.ts index bc30362a56..6291c6790a 100644 --- a/src/bundles/midi/src/types.ts +++ b/src/bundles/midi/src/types.ts @@ -14,7 +14,7 @@ export type Note = {} & (NoteName | `${NoteName}${Accidental.NATURAL}` | `${Note export type NoteWithOctave = (Note | `${Note}${number}`); /** - * An integer representing a MIDI note value. Refer to {@link https://i.imgur.com/qGQgmYr.png"|this} mapping from + * An integer representing a MIDI note value. Refer to {@link https://i.imgur.com/qGQgmYr.png|this} mapping from * letter name to midi notes. */ export type MIDINote = number; diff --git a/tsconfig.json b/tsconfig.json index a9096470f2..06f9bc7913 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,8 +1,10 @@ -// General tsconfig +// tsconfig for Typescript configuration files +// so that ESLint doesn't complain { "include": [ "**/vitest.config.ts", - "./.github/actions/vitest.config.ts" + "./.github/actions/vitest.config.ts", + "./devserver/vite.config.ts" ], "compilerOptions": { "module": "nodenext", diff --git a/vitest.config.ts b/vitest.config.ts index 0354a6deda..3daddfa3c4 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -39,6 +39,7 @@ export default defineConfig({ reporter: coverageReporters, exclude: [ '**/__mocks__', + '**/__tests__', '**/build/**', '**/dist', '**/src/**/samples/**', diff --git a/yarn.lock b/yarn.lock index dd7c5262d8..6863a163d0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -292,6 +292,15 @@ __metadata: languageName: node linkType: hard +"@arcanis/slice-ansi@npm:^1.1.1": + version: 1.1.1 + resolution: "@arcanis/slice-ansi@npm:1.1.1" + dependencies: + grapheme-splitter: "npm:^1.0.4" + checksum: 10c0/2f222b121b8aaf67e8495e27d60ebfc34e2472033445c3380e93fb06aba9bfef6ab3096aca190a181b3dd505ed4c07f4dc7243fc9cb5369008b649cd1e39e8d8 + languageName: node + linkType: hard + "@asamuzakjp/css-color@npm:^3.1.2": version: 3.2.0 resolution: "@asamuzakjp/css-color@npm:3.2.0" @@ -3437,6 +3446,22 @@ __metadata: languageName: node linkType: hard +"@pnpm/crypto.base32-hash@npm:1.0.1": + version: 1.0.1 + resolution: "@pnpm/crypto.base32-hash@npm:1.0.1" + dependencies: + rfc4648: "npm:^1.5.1" + checksum: 10c0/c3277405b0cc08475dcc732746a13a0d3c06ec898a19030e71ff686f141c4f261a3419d36da5cf5a1c5551aa79a9cf95be135e4bdfd113411b7278c1715243ed + languageName: node + linkType: hard + +"@pnpm/types@npm:8.9.0": + version: 8.9.0 + resolution: "@pnpm/types@npm:8.9.0" + checksum: 10c0/eb5f41f439ff73b247b4a295523d63b5a7ebc229e205f3bee99974c7a18ea05d970c7e56ee0ebfd997a0ed201a6dfdb48298fbda7149bf1c508c8dbc83e6fb27 + languageName: node + linkType: hard + "@polka/url@npm:^1.0.0-next.24": version: 1.0.0-next.29 resolution: "@polka/url@npm:1.0.0-next.29" @@ -4040,6 +4065,73 @@ __metadata: languageName: node linkType: hard +"@sindresorhus/is@npm:^4.0.0": + version: 4.6.0 + resolution: "@sindresorhus/is@npm:4.6.0" + checksum: 10c0/33b6fb1d0834ec8dd7689ddc0e2781c2bfd8b9c4e4bacbcb14111e0ae00621f2c264b8a7d36541799d74888b5dccdf422a891a5cb5a709ace26325eedc81e22e + languageName: node + linkType: hard + +"@snyk/dep-graph@npm:^2.3.0": + version: 2.9.0 + resolution: "@snyk/dep-graph@npm:2.9.0" + dependencies: + event-loop-spinner: "npm:^2.1.0" + lodash.clone: "npm:^4.5.0" + lodash.constant: "npm:^3.0.0" + lodash.filter: "npm:^4.6.0" + lodash.foreach: "npm:^4.5.0" + lodash.isempty: "npm:^4.4.0" + lodash.isequal: "npm:^4.5.0" + lodash.isfunction: "npm:^3.0.9" + lodash.isundefined: "npm:^3.0.1" + lodash.map: "npm:^4.6.0" + lodash.reduce: "npm:^4.6.0" + lodash.size: "npm:^4.2.0" + lodash.transform: "npm:^4.6.0" + lodash.union: "npm:^4.6.0" + lodash.values: "npm:^4.3.0" + object-hash: "npm:^3.0.0" + packageurl-js: "npm:1.2.0" + semver: "npm:^7.0.0" + tslib: "npm:^2" + checksum: 10c0/709116c589216b130e51bc7750bb9151ec382f749a9ccb124950a4390f6bb470e42cb6e64b56a8bff35602056685a97b66eda0b2eee2584f759d1e046293cb6e + languageName: node + linkType: hard + +"@snyk/error-catalog-nodejs-public@npm:^5.16.0": + version: 5.68.1 + resolution: "@snyk/error-catalog-nodejs-public@npm:5.68.1" + dependencies: + tslib: "npm:^2.8.1" + uuid: "npm:^11.1.0" + checksum: 10c0/efd61c7bd219c010e02c857e1ba3011c217572150588594a4d388422c2f380f9d7db9d138ea3ff164f427ff4fe8bcb2f0aa1a67bd4bcd25383c80960262f0aac + languageName: node + linkType: hard + +"@snyk/graphlib@npm:2.1.9-patch.3": + version: 2.1.9-patch.3 + resolution: "@snyk/graphlib@npm:2.1.9-patch.3" + dependencies: + lodash.clone: "npm:^4.5.0" + lodash.constant: "npm:^3.0.0" + lodash.filter: "npm:^4.6.0" + lodash.foreach: "npm:^4.5.0" + lodash.has: "npm:^4.5.2" + lodash.isempty: "npm:^4.4.0" + lodash.isfunction: "npm:^3.0.9" + lodash.isundefined: "npm:^3.0.1" + lodash.keys: "npm:^4.2.0" + lodash.map: "npm:^4.6.0" + lodash.reduce: "npm:^4.6.0" + lodash.size: "npm:^4.2.0" + lodash.transform: "npm:^4.6.0" + lodash.union: "npm:^4.6.0" + lodash.values: "npm:^4.3.0" + checksum: 10c0/d19c40c9be07d2c88be2e91a904f8458162f1c545007ff24ccef429c3452354e990ad2267acb7eb7e852a7e9aedadc73ca33b4bb6ba86e834f87956f978ec9f6 + languageName: node + linkType: hard + "@sourceacademy/bundle-ar@workspace:^, @sourceacademy/bundle-ar@workspace:src/bundles/ar": version: 0.0.0-use.local resolution: "@sourceacademy/bundle-ar@workspace:src/bundles/ar" @@ -4505,6 +4597,7 @@ __metadata: "@sourceacademy/modules-repotools": "workspace:^" "@types/node": "npm:^22.15.30" lodash: "npm:^4.17.21" + snyk-nodejs-lockfile-parser: "npm:^2.4.2" typescript: "npm:^5.8.2" vitest: "npm:^4.0.4" languageName: unknown @@ -4941,6 +5034,15 @@ __metadata: languageName: node linkType: hard +"@szmarczak/http-timer@npm:^4.0.5": + version: 4.0.6 + resolution: "@szmarczak/http-timer@npm:4.0.6" + dependencies: + defer-to-connect: "npm:^2.0.0" + checksum: 10c0/73946918c025339db68b09abd91fa3001e87fc749c619d2e9c2003a663039d4c3cb89836c98a96598b3d47dec2481284ba85355392644911f5ecd2336536697f + languageName: node + linkType: hard + "@ts-morph/bootstrap@npm:^0.18.0": version: 0.18.0 resolution: "@ts-morph/bootstrap@npm:0.18.0" @@ -5010,6 +5112,18 @@ __metadata: languageName: node linkType: hard +"@types/cacheable-request@npm:^6.0.1": + version: 6.0.3 + resolution: "@types/cacheable-request@npm:6.0.3" + dependencies: + "@types/http-cache-semantics": "npm:*" + "@types/keyv": "npm:^3.1.4" + "@types/node": "npm:*" + "@types/responselike": "npm:^1.0.0" + checksum: 10c0/10816a88e4e5b144d43c1d15a81003f86d649776c7f410c9b5e6579d0ad9d4ca71c541962fb403077388b446e41af7ae38d313e46692144985f006ac5e11fa03 + languageName: node + linkType: hard + "@types/chai@npm:^5.2.2": version: 5.2.2 resolution: "@types/chai@npm:5.2.2" @@ -5332,6 +5446,13 @@ __metadata: languageName: node linkType: hard +"@types/emscripten@npm:^1.39.6": + version: 1.41.5 + resolution: "@types/emscripten@npm:1.41.5" + checksum: 10c0/ae816da716f896434e59df7a71b67c71ae7e85ca067a32aef1616572fc4757459515d42ade6f5b8fd8d69733a9dbd0cf23010fec5b2f41ce52c09501aa350e45 + languageName: node + linkType: hard + "@types/estree-jsx@npm:^1.0.0": version: 1.0.5 resolution: "@types/estree-jsx@npm:1.0.5" @@ -5380,6 +5501,13 @@ __metadata: languageName: node linkType: hard +"@types/http-cache-semantics@npm:*": + version: 4.0.4 + resolution: "@types/http-cache-semantics@npm:4.0.4" + checksum: 10c0/51b72568b4b2863e0fe8d6ce8aad72a784b7510d72dc866215642da51d84945a9459fa89f49ec48f1e9a1752e6a78e85a4cda0ded06b1c73e727610c925f9ce6 + languageName: node + linkType: hard + "@types/http-server@npm:^0.12.4": version: 0.12.4 resolution: "@types/http-server@npm:0.12.4" @@ -5435,6 +5563,15 @@ __metadata: languageName: node linkType: hard +"@types/keyv@npm:^3.1.4": + version: 3.1.4 + resolution: "@types/keyv@npm:3.1.4" + dependencies: + "@types/node": "npm:*" + checksum: 10c0/ff8f54fc49621210291f815fe5b15d809fd7d032941b3180743440bd507ecdf08b9e844625fa346af568c84bf34114eb378dcdc3e921a08ba1e2a08d7e3c809c + languageName: node + linkType: hard + "@types/linkify-it@npm:^5": version: 5.0.0 resolution: "@types/linkify-it@npm:5.0.0" @@ -5583,6 +5720,22 @@ __metadata: languageName: node linkType: hard +"@types/responselike@npm:^1.0.0": + version: 1.0.3 + resolution: "@types/responselike@npm:1.0.3" + dependencies: + "@types/node": "npm:*" + checksum: 10c0/a58ba341cb9e7d74f71810a88862da7b2a6fa42e2a1fc0ce40498f6ea1d44382f0640117057da779f74c47039f7166bf48fad02dc876f94e005c7afa50f5e129 + languageName: node + linkType: hard + +"@types/semver@npm:^7.1.0": + version: 7.7.1 + resolution: "@types/semver@npm:7.7.1" + checksum: 10c0/c938aef3bf79a73f0f3f6037c16e2e759ff40c54122ddf0b2583703393d8d3127130823facb880e694caa324eb6845628186aac1997ee8b31dc2d18fafe26268 + languageName: node + linkType: hard + "@types/stats.js@npm:*": version: 0.17.4 resolution: "@types/stats.js@npm:0.17.4" @@ -5638,6 +5791,13 @@ __metadata: languageName: node linkType: hard +"@types/treeify@npm:^1.0.0": + version: 1.0.3 + resolution: "@types/treeify@npm:1.0.3" + checksum: 10c0/758902638ff83a790c13359729d77aeb80aae50f7039670037e3a0ba2bcc7b09dd49173ab21a96946d83af1682fcd70e448e49151ecd46e190f8925077142d4a + languageName: node + linkType: hard + "@types/trusted-types@npm:^2.0.7": version: 2.0.7 resolution: "@types/trusted-types@npm:2.0.7" @@ -6488,6 +6648,97 @@ __metadata: languageName: node linkType: hard +"@yarnpkg/core@npm:^4.4.1": + version: 4.4.4 + resolution: "@yarnpkg/core@npm:4.4.4" + dependencies: + "@arcanis/slice-ansi": "npm:^1.1.1" + "@types/semver": "npm:^7.1.0" + "@types/treeify": "npm:^1.0.0" + "@yarnpkg/fslib": "npm:^3.1.3" + "@yarnpkg/libzip": "npm:^3.2.2" + "@yarnpkg/parsers": "npm:^3.0.3" + "@yarnpkg/shell": "npm:^4.1.3" + camelcase: "npm:^5.3.1" + chalk: "npm:^4.1.2" + ci-info: "npm:^4.0.0" + clipanion: "npm:^4.0.0-rc.2" + cross-spawn: "npm:^7.0.3" + diff: "npm:^5.1.0" + dotenv: "npm:^16.3.1" + es-toolkit: "npm:^1.39.7" + fast-glob: "npm:^3.2.2" + got: "npm:^11.7.0" + hpagent: "npm:^1.2.0" + micromatch: "npm:^4.0.2" + p-limit: "npm:^2.2.0" + semver: "npm:^7.1.2" + strip-ansi: "npm:^6.0.0" + tar: "npm:^6.0.5" + tinylogic: "npm:^2.0.0" + treeify: "npm:^1.1.0" + tslib: "npm:^2.4.0" + checksum: 10c0/1549c8ca03649f7e4e3f55565ec980116236706d96affce74732f2d4739b1f8a391cacaaee733d8e2745760d7cb9c307e65e87534c1529dfcfc5670ce7a72f57 + languageName: node + linkType: hard + +"@yarnpkg/fslib@npm:^3.1.2, @yarnpkg/fslib@npm:^3.1.3": + version: 3.1.3 + resolution: "@yarnpkg/fslib@npm:3.1.3" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/ce4cebede6af53e445515b46ad1467e80cc7dce248de93c97ec42de1e26bae44fd766f07230152566fe4fcfba46a7496d21fa855e750c3d1036087608a56a329 + languageName: node + linkType: hard + +"@yarnpkg/libzip@npm:^3.2.2": + version: 3.2.2 + resolution: "@yarnpkg/libzip@npm:3.2.2" + dependencies: + "@types/emscripten": "npm:^1.39.6" + "@yarnpkg/fslib": "npm:^3.1.3" + tslib: "npm:^2.4.0" + peerDependencies: + "@yarnpkg/fslib": ^3.1.3 + checksum: 10c0/40f5c63520477c9d5ed98e0ad888a5aa48f5641df883664b6892be2b4068b5489ac030123fe3569599269adc3e773a6ca890c41e033c71daf37a9fa51011784a + languageName: node + linkType: hard + +"@yarnpkg/lockfile@npm:^1.1.0": + version: 1.1.0 + resolution: "@yarnpkg/lockfile@npm:1.1.0" + checksum: 10c0/0bfa50a3d756623d1f3409bc23f225a1d069424dbc77c6fd2f14fb377390cd57ec703dc70286e081c564be9051ead9ba85d81d66a3e68eeb6eb506d4e0c0fbda + languageName: node + linkType: hard + +"@yarnpkg/parsers@npm:^3.0.3": + version: 3.0.3 + resolution: "@yarnpkg/parsers@npm:3.0.3" + dependencies: + js-yaml: "npm:^3.10.0" + tslib: "npm:^2.4.0" + checksum: 10c0/70c2fa011bf28a517a8ee4264dd93d7590f6e3d02c6d4feb50533f405ca3b100cb156f11405b9a34f7c51c6893d3d8b051554dddfd5afaae2067f921512447a3 + languageName: node + linkType: hard + +"@yarnpkg/shell@npm:^4.1.3": + version: 4.1.3 + resolution: "@yarnpkg/shell@npm:4.1.3" + dependencies: + "@yarnpkg/fslib": "npm:^3.1.2" + "@yarnpkg/parsers": "npm:^3.0.3" + chalk: "npm:^4.1.2" + clipanion: "npm:^4.0.0-rc.2" + cross-spawn: "npm:^7.0.3" + fast-glob: "npm:^3.2.2" + micromatch: "npm:^4.0.2" + tslib: "npm:^2.4.0" + bin: + shell: ./lib/cli.js + checksum: 10c0/0cbbfa7c446bc0450f5fdc6f892eb4e8ebdc6addce4f4366fdcb6cb63e5e8b33096db80d6c1f27e0277e008f384f2041d6abaae381b31574495c4c3a71e0192b + languageName: node + linkType: hard + "@yarnpkg/types@npm:^4.0.1": version: 4.0.1 resolution: "@yarnpkg/types@npm:4.0.1" @@ -6599,6 +6850,16 @@ __metadata: languageName: node linkType: hard +"aggregate-error@npm:^3.0.0": + version: 3.1.0 + resolution: "aggregate-error@npm:3.1.0" + dependencies: + clean-stack: "npm:^2.0.0" + indent-string: "npm:^4.0.0" + checksum: 10c0/a42f67faa79e3e6687a4923050e7c9807db3848a037076f791d10e092677d65c1d2d863b7848560699f40fc0502c19f40963fb1cd1fb3d338a7423df8e45e039 + languageName: node + linkType: hard + "ajv@npm:^6.12.4, ajv@npm:^6.12.6": version: 6.12.6 resolution: "ajv@npm:6.12.6" @@ -6949,7 +7210,7 @@ __metadata: languageName: node linkType: hard -"async@npm:^3.2.4, async@npm:^3.2.6": +"async@npm:^3.2.2, async@npm:^3.2.4, async@npm:^3.2.6": version: 3.2.6 resolution: "async@npm:3.2.6" checksum: 10c0/36484bb15ceddf07078688d95e27076379cc2f87b10c03b6dd8a83e89475a3c8df5848859dd06a4c95af1e4c16fc973de0171a77f18ea00be899aca2a4f85e70 @@ -7437,6 +7698,28 @@ __metadata: languageName: node linkType: hard +"cacheable-lookup@npm:^5.0.3": + version: 5.0.4 + resolution: "cacheable-lookup@npm:5.0.4" + checksum: 10c0/a6547fb4954b318aa831cbdd2f7b376824bc784fb1fa67610e4147099e3074726072d9af89f12efb69121415a0e1f2918a8ddd4aafcbcf4e91fbeef4a59cd42c + languageName: node + linkType: hard + +"cacheable-request@npm:^7.0.2": + version: 7.0.4 + resolution: "cacheable-request@npm:7.0.4" + dependencies: + clone-response: "npm:^1.0.2" + get-stream: "npm:^5.1.0" + http-cache-semantics: "npm:^4.0.0" + keyv: "npm:^4.0.0" + lowercase-keys: "npm:^2.0.0" + normalize-url: "npm:^6.0.1" + responselike: "npm:^2.0.0" + checksum: 10c0/0834a7d17ae71a177bc34eab06de112a43f9b5ad05ebe929bec983d890a7d9f2bc5f1aa8bb67ea2b65e07a3bc74bea35fa62dd36dbac52876afe36fdcf83da41 + languageName: node + linkType: hard + "call-bind-apply-helpers@npm:^1.0.0, call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2": version: 1.0.2 resolution: "call-bind-apply-helpers@npm:1.0.2" @@ -7681,6 +7964,13 @@ __metadata: languageName: node linkType: hard +"chownr@npm:^2.0.0": + version: 2.0.0 + resolution: "chownr@npm:2.0.0" + checksum: 10c0/594754e1303672171cc04e50f6c398ae16128eb134a88f801bf5354fd96f205320f23536a045d9abd8b51024a149696e51231565891d4efdab8846021ecf88e6 + languageName: node + linkType: hard + "chownr@npm:^3.0.0": version: 3.0.0 resolution: "chownr@npm:3.0.0" @@ -7738,6 +8028,13 @@ __metadata: languageName: node linkType: hard +"clean-stack@npm:^2.0.0": + version: 2.2.0 + resolution: "clean-stack@npm:2.2.0" + checksum: 10c0/1f90262d5f6230a17e27d0c190b09d47ebe7efdd76a03b5a1127863f7b3c9aec4c3e6c8bb3a7bbf81d553d56a1fd35728f5a8ef4c63f867ac8d690109742a8c1 + languageName: node + linkType: hard + "clear-module@npm:^4.1.2": version: 4.1.2 resolution: "clear-module@npm:4.1.2" @@ -7748,6 +8045,26 @@ __metadata: languageName: node linkType: hard +"clipanion@npm:^4.0.0-rc.2": + version: 4.0.0-rc.4 + resolution: "clipanion@npm:4.0.0-rc.4" + dependencies: + typanion: "npm:^3.8.0" + peerDependencies: + typanion: "*" + checksum: 10c0/047b415b59a5e9777d00690fba563ccc850eca6bf27790a88d1deea3ecc8a89840ae9aed554ff284cc698a9f3f20256e43c25ff4a7c4c90a71e5e7d9dca61dd1 + languageName: node + linkType: hard + +"clone-response@npm:^1.0.2": + version: 1.0.3 + resolution: "clone-response@npm:1.0.3" + dependencies: + mimic-response: "npm:^1.0.0" + checksum: 10c0/06a2b611824efb128810708baee3bd169ec9a1bf5976a5258cd7eb3f7db25f00166c6eee5961f075c7e38e194f373d4fdf86b8166ad5b9c7e82bbd2e333a6087 + languageName: node + linkType: hard + "collection-visit@npm:^1.0.0": version: 1.0.0 resolution: "collection-visit@npm:1.0.0" @@ -8065,7 +8382,7 @@ __metadata: languageName: node linkType: hard -"cross-spawn@npm:^7.0.1, cross-spawn@npm:^7.0.6": +"cross-spawn@npm:^7.0.1, cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" dependencies: @@ -8761,6 +9078,15 @@ __metadata: languageName: node linkType: hard +"decompress-response@npm:^6.0.0": + version: 6.0.0 + resolution: "decompress-response@npm:6.0.0" + dependencies: + mimic-response: "npm:^3.1.0" + checksum: 10c0/bd89d23141b96d80577e70c54fb226b2f40e74a6817652b80a116d7befb8758261ad073a8895648a29cc0a5947021ab66705cb542fa9c143c82022b27c5b175e + languageName: node + linkType: hard + "deep-is@npm:^0.1.3": version: 0.1.4 resolution: "deep-is@npm:0.1.4" @@ -8768,6 +9094,13 @@ __metadata: languageName: node linkType: hard +"defer-to-connect@npm:^2.0.0": + version: 2.0.1 + resolution: "defer-to-connect@npm:2.0.1" + checksum: 10c0/625ce28e1b5ad10cf77057b9a6a727bf84780c17660f6644dab61dd34c23de3001f03cedc401f7d30a4ed9965c2e8a7336e220a329146f2cf85d4eddea429782 + languageName: node + linkType: hard + "define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.4": version: 1.1.4 resolution: "define-data-property@npm:1.1.4" @@ -8827,6 +9160,18 @@ __metadata: languageName: node linkType: hard +"dependency-path@npm:^9.2.8": + version: 9.2.8 + resolution: "dependency-path@npm:9.2.8" + dependencies: + "@pnpm/crypto.base32-hash": "npm:1.0.1" + "@pnpm/types": "npm:8.9.0" + encode-registry: "npm:^3.0.0" + semver: "npm:^7.3.8" + checksum: 10c0/6387a7821150872e045a335f8a93a69aed3426bb274b7046f3fc9fbd865e39aa94c1ae14b1d75903f18ced974eaec326f06821049ebf2bf50a752a2e408e75e4 + languageName: node + linkType: hard + "deprecation@npm:^2.0.0, deprecation@npm:^2.3.1": version: 2.3.1 resolution: "deprecation@npm:2.3.1" @@ -8885,7 +9230,7 @@ __metadata: languageName: node linkType: hard -"diff@npm:^5.0.0": +"diff@npm:^5.0.0, diff@npm:^5.1.0": version: 5.2.0 resolution: "diff@npm:5.2.0" checksum: 10c0/aed0941f206fe261ecb258dc8d0ceea8abbde3ace5827518ff8d302f0fc9cc81ce116c4d8f379151171336caf0516b79e01abdc1ed1201b6440d895a66689eb4 @@ -8951,6 +9296,13 @@ __metadata: languageName: node linkType: hard +"dotenv@npm:^16.3.1": + version: 16.6.1 + resolution: "dotenv@npm:16.6.1" + checksum: 10c0/15ce56608326ea0d1d9414a5c8ee6dcf0fffc79d2c16422b4ac2268e7e2d76ff5a572d37ffe747c377de12005f14b3cc22361e79fc7f1061cce81f77d2c973dc + languageName: node + linkType: hard + "draco3d@npm:^1.4.1": version: 1.5.7 resolution: "draco3d@npm:1.5.7" @@ -9045,6 +9397,15 @@ __metadata: languageName: node linkType: hard +"encode-registry@npm:^3.0.0": + version: 3.0.1 + resolution: "encode-registry@npm:3.0.1" + dependencies: + mem: "npm:^8.0.0" + checksum: 10c0/b5f4d51f8da413cfe8ba93838656a72ff282f6abf927a93f8697858bb70ebb18063872c9856c4d93c3fc1862c21f336a82774dd7de2282239f1dbdd8243663f6 + languageName: node + linkType: hard + "encoding@npm:^0.1.13": version: 0.1.13 resolution: "encoding@npm:0.1.13" @@ -9314,6 +9675,18 @@ __metadata: languageName: node linkType: hard +"es-toolkit@npm:^1.39.7": + version: 1.41.0 + resolution: "es-toolkit@npm:1.41.0" + dependenciesMeta: + "@trivago/prettier-plugin-sort-imports@4.3.0": + unplugged: true + prettier-plugin-sort-re-exports@0.0.1: + unplugged: true + checksum: 10c0/4edcc19984df0e521d222082d055f131233cada9277de3f427311ecd43dc99442dc66a39f86b1b10c298c5a72133231928eb91668c0bff4f11e12af8b6d758a3 + languageName: node + linkType: hard + "esbuild@npm:^0.21.3": version: 0.21.5 resolution: "esbuild@npm:0.21.5" @@ -9961,6 +10334,15 @@ __metadata: languageName: node linkType: hard +"event-loop-spinner@npm:^2.0.0, event-loop-spinner@npm:^2.1.0": + version: 2.3.2 + resolution: "event-loop-spinner@npm:2.3.2" + dependencies: + tslib: "npm:^2.6.3" + checksum: 10c0/e60104316958d354e861123058fe45b0a93ddc2a591e666b72d673a89edb7bfef4498e017494f30e406b235afbccfbfa1910ac08e519c5f00a908b1dfdc873ab + languageName: node + linkType: hard + "event-target-shim@npm:^5.0.0": version: 5.0.1 resolution: "event-target-shim@npm:5.0.1" @@ -10121,7 +10503,7 @@ __metadata: languageName: node linkType: hard -"fast-glob@npm:^3.2.12, fast-glob@npm:^3.3.2": +"fast-glob@npm:^3.2.12, fast-glob@npm:^3.2.2, fast-glob@npm:^3.3.2": version: 3.3.3 resolution: "fast-glob@npm:3.3.3" dependencies: @@ -10368,6 +10750,15 @@ __metadata: languageName: node linkType: hard +"fs-minipass@npm:^2.0.0": + version: 2.1.0 + resolution: "fs-minipass@npm:2.1.0" + dependencies: + minipass: "npm:^3.0.0" + checksum: 10c0/703d16522b8282d7299337539c3ed6edddd1afe82435e4f5b76e34a79cd74e488a8a0e26a636afc2440e1a23b03878e2122e3a2cfe375a5cf63c37d92b86a004 + languageName: node + linkType: hard + "fs-minipass@npm:^3.0.0": version: 3.0.3 resolution: "fs-minipass@npm:3.0.3" @@ -10508,6 +10899,15 @@ __metadata: languageName: node linkType: hard +"get-stream@npm:^5.1.0": + version: 5.2.0 + resolution: "get-stream@npm:5.2.0" + dependencies: + pump: "npm:^3.0.0" + checksum: 10c0/43797ffd815fbb26685bf188c8cfebecb8af87b3925091dd7b9a9c915993293d78e3c9e1bce125928ff92f2d0796f3889b92b5ec6d58d1041b574682132e0a80 + languageName: node + linkType: hard + "get-symbol-description@npm:^1.1.0": version: 1.1.0 resolution: "get-symbol-description@npm:1.1.0" @@ -10656,6 +11056,25 @@ __metadata: languageName: node linkType: hard +"got@npm:^11.7.0": + version: 11.8.6 + resolution: "got@npm:11.8.6" + dependencies: + "@sindresorhus/is": "npm:^4.0.0" + "@szmarczak/http-timer": "npm:^4.0.5" + "@types/cacheable-request": "npm:^6.0.1" + "@types/responselike": "npm:^1.0.0" + cacheable-lookup: "npm:^5.0.3" + cacheable-request: "npm:^7.0.2" + decompress-response: "npm:^6.0.0" + http2-wrapper: "npm:^1.0.0-beta.5.2" + lowercase-keys: "npm:^2.0.0" + p-cancelable: "npm:^2.0.0" + responselike: "npm:^2.0.0" + checksum: 10c0/754dd44877e5cf6183f1e989ff01c648d9a4719e357457bd4c78943911168881f1cfb7b2cb15d885e2105b3ad313adb8f017a67265dd7ade771afdb261ee8cb1 + languageName: node + linkType: hard + "graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" @@ -10663,6 +11082,13 @@ __metadata: languageName: node linkType: hard +"grapheme-splitter@npm:^1.0.4": + version: 1.0.4 + resolution: "grapheme-splitter@npm:1.0.4" + checksum: 10c0/108415fb07ac913f17040dc336607772fcea68c7f495ef91887edddb0b0f5ff7bc1d1ab181b125ecb2f0505669ef12c9a178a3bbd2dd8e042d8c5f1d7c90331a + languageName: node + linkType: hard + "graphemer@npm:^1.4.0": version: 1.4.0 resolution: "graphemer@npm:1.4.0" @@ -10907,6 +11333,13 @@ __metadata: languageName: node linkType: hard +"hpagent@npm:^1.2.0": + version: 1.2.0 + resolution: "hpagent@npm:1.2.0" + checksum: 10c0/505ef42e5e067dba701ea21e7df9fa73f6f5080e59d53680829827d34cd7040f1ecf7c3c8391abe9df4eb4682ef4a4321608836b5b70a61b88c1b3a03d77510b + languageName: node + linkType: hard + "html-encoding-sniffer@npm:^3.0.0": version: 3.0.0 resolution: "html-encoding-sniffer@npm:3.0.0" @@ -10939,7 +11372,7 @@ __metadata: languageName: node linkType: hard -"http-cache-semantics@npm:^4.1.1": +"http-cache-semantics@npm:^4.0.0, http-cache-semantics@npm:^4.1.1": version: 4.2.0 resolution: "http-cache-semantics@npm:4.2.0" checksum: 10c0/45b66a945cf13ec2d1f29432277201313babf4a01d9e52f44b31ca923434083afeca03f18417f599c9ab3d0e7b618ceb21257542338b57c54b710463b4a53e37 @@ -10990,6 +11423,16 @@ __metadata: languageName: node linkType: hard +"http2-wrapper@npm:^1.0.0-beta.5.2": + version: 1.0.3 + resolution: "http2-wrapper@npm:1.0.3" + dependencies: + quick-lru: "npm:^5.1.1" + resolve-alpn: "npm:^1.0.0" + checksum: 10c0/6a9b72a033e9812e1476b9d776ce2f387bc94bc46c88aea0d5dab6bd47d0a539b8178830e77054dd26d1142c866d515a28a4dc7c3ff4232c88ff2ebe4f5d12d1 + languageName: node + linkType: hard + "https-browserify@npm:^1.0.0": version: 1.0.0 resolution: "https-browserify@npm:1.0.0" @@ -11098,6 +11541,13 @@ __metadata: languageName: node linkType: hard +"indent-string@npm:^4.0.0": + version: 4.0.0 + resolution: "indent-string@npm:4.0.0" + checksum: 10c0/1e1904ddb0cb3d6cce7cd09e27a90184908b7a5d5c21b92e232c93579d314f0b83c246ffb035493d0504b1e9147ba2c9b21df0030f48673fba0496ecd698161f + languageName: node + linkType: hard + "inflight@npm:^1.0.4": version: 1.0.6 resolution: "inflight@npm:1.0.6" @@ -11909,7 +12359,7 @@ __metadata: languageName: node linkType: hard -"js-yaml@npm:^3.13.1": +"js-yaml@npm:^3.10.0, js-yaml@npm:^3.13.1": version: 3.14.1 resolution: "js-yaml@npm:3.14.1" dependencies: @@ -12085,7 +12535,7 @@ __metadata: languageName: node linkType: hard -"keyv@npm:^4.5.4": +"keyv@npm:^4.0.0, keyv@npm:^4.5.4": version: 4.5.4 resolution: "keyv@npm:4.5.4" dependencies: @@ -12282,6 +12732,48 @@ __metadata: languageName: node linkType: hard +"lodash.clone@npm:^4.5.0": + version: 4.5.0 + resolution: "lodash.clone@npm:4.5.0" + checksum: 10c0/e9e84b8727a24b6bdc6292dc0ff53fbdd379a65c652d9ba7a2cc3c02fb1c135b8dcd2e154c8c4199d4be7410d6f7ce3298df312822bc0e68f00472ec07da7d6d + languageName: node + linkType: hard + +"lodash.clonedeep@npm:^4.5.0": + version: 4.5.0 + resolution: "lodash.clonedeep@npm:4.5.0" + checksum: 10c0/2caf0e4808f319d761d2939ee0642fa6867a4bbf2cfce43276698828380756b99d4c4fa226d881655e6ac298dd453fe12a5ec8ba49861777759494c534936985 + languageName: node + linkType: hard + +"lodash.constant@npm:^3.0.0": + version: 3.0.0 + resolution: "lodash.constant@npm:3.0.0" + checksum: 10c0/4621dad2181fb2ce9adaafdeafca0ed07be35d20af736415691100fa57fea919368d575b84bae203eb60d3248f6de85e6aa08c347c701d889e5bd14c5cf69e14 + languageName: node + linkType: hard + +"lodash.filter@npm:^4.6.0": + version: 4.6.0 + resolution: "lodash.filter@npm:4.6.0" + checksum: 10c0/bb65002f3ee02b94400b9d8728a46d3ac9fc3eb7df387b3c642f36eff82d716714283ca674889a29edae3c28ea8a4048e6c7bb90598670ab9c97b5d125bffda2 + languageName: node + linkType: hard + +"lodash.flatmap@npm:^4.5.0": + version: 4.5.0 + resolution: "lodash.flatmap@npm:4.5.0" + checksum: 10c0/11627ae4ca8332f7bbc9b0c99948127504a17b19720d85979de0184a6992fe706633acd673ce797197c3fb185318a65ad6590a3beae5428a9c8d5d6391f3db80 + languageName: node + linkType: hard + +"lodash.foreach@npm:^4.5.0": + version: 4.5.0 + resolution: "lodash.foreach@npm:4.5.0" + checksum: 10c0/bd9cc83e87e805b21058ce6cf718dd22db137c7ca08eddbd608549db59989911c571b7195707f615cb37f27bb4f9a9fa9980778940d768c24095f5a04b244c84 + languageName: node + linkType: hard + "lodash.get@npm:^4.4.2": version: 4.4.2 resolution: "lodash.get@npm:4.4.2" @@ -12289,6 +12781,20 @@ __metadata: languageName: node linkType: hard +"lodash.has@npm:^4.5.2": + version: 4.5.2 + resolution: "lodash.has@npm:4.5.2" + checksum: 10c0/3ffa9e549f321996a5fdf6204494c035ff550b2df703f936a448c553131bbb55492b4e7995bb13500648b50b268ed8afc974a7a0c0a43744d28d61cc95cb1ffe + languageName: node + linkType: hard + +"lodash.isempty@npm:^4.4.0": + version: 4.4.0 + resolution: "lodash.isempty@npm:4.4.0" + checksum: 10c0/6c7eaa0802398736809b9e8aed8b8ac1abca9be71788fd719ba9d7f5b4c23e8dc63b7f049df4131713dda30a2fdedc2f655268e9deb8cd5a985dfc934afca194 + languageName: node + linkType: hard + "lodash.isequal@npm:^4.5.0": version: 4.5.0 resolution: "lodash.isequal@npm:4.5.0" @@ -12296,6 +12802,34 @@ __metadata: languageName: node linkType: hard +"lodash.isfunction@npm:^3.0.9": + version: 3.0.9 + resolution: "lodash.isfunction@npm:3.0.9" + checksum: 10c0/e88620922f5f104819496884779ca85bfc542efb2946df661ab3e2cd38da5c8375434c6adbedfc76dd3c2b04075d2ba8ec215cfdedf08ddd2e3c3467e8a26ccd + languageName: node + linkType: hard + +"lodash.isundefined@npm:^3.0.1": + version: 3.0.1 + resolution: "lodash.isundefined@npm:3.0.1" + checksum: 10c0/00ca2ae6fc83e10f806769130ee62b5bf419a4aaa52d1a084164b4cf2b2ab1dbf7246e05c72cf0df2ebf4ea38ab565a688c1a7362b54331bb336ea8b492f327f + languageName: node + linkType: hard + +"lodash.keys@npm:^4.2.0": + version: 4.2.0 + resolution: "lodash.keys@npm:4.2.0" + checksum: 10c0/e21565d5076f4afc99e517d2b3dc84f05bc83e036f532c6e691c318f9ffd7eca3006365e0dafae1c5f046e344aaa722b01fe102b9f68e7cc63b79d2f9196f667 + languageName: node + linkType: hard + +"lodash.map@npm:^4.6.0": + version: 4.6.0 + resolution: "lodash.map@npm:4.6.0" + checksum: 10c0/919fe767fa58d3f8369ddd84346636eda71c88a8ef6bde1ca0d87dd37e71614da2ed8bcfc3018ca5b7741ebaf7c01c2d7078b510dca8ab6a0d0ecafd3dc1abcb + languageName: node + linkType: hard + "lodash.merge@npm:4.6.2, lodash.merge@npm:^4.6.2": version: 4.6.2 resolution: "lodash.merge@npm:4.6.2" @@ -12303,6 +12837,48 @@ __metadata: languageName: node linkType: hard +"lodash.reduce@npm:^4.6.0": + version: 4.6.0 + resolution: "lodash.reduce@npm:4.6.0" + checksum: 10c0/5d2dab823523a1a7f81eb5f4c1edcc03aab55504b1299a2385737389644ba6d2ad219169dfc5c16632a67a345d925ef6a5e8816b4e18a36f94ed66f8e7740b36 + languageName: node + linkType: hard + +"lodash.size@npm:^4.2.0": + version: 4.2.0 + resolution: "lodash.size@npm:4.2.0" + checksum: 10c0/01c96e13e066b8fe61485ef2e74f7f2c1140a977e1f71ed332715423feb3968ad0e96b7cf395c203edcf805a4861739f54a19f90fa607683fdb48dd165132362 + languageName: node + linkType: hard + +"lodash.topairs@npm:^4.3.0": + version: 4.3.0 + resolution: "lodash.topairs@npm:4.3.0" + checksum: 10c0/3b517179b60c695c9fac23d932531c2eced5d8c5c3b83ad19bd897fdca1a307f216d29d2c171fd615ad8b393b15161acdc592c1ac612d2d72fa42f0b0c30b183 + languageName: node + linkType: hard + +"lodash.transform@npm:^4.6.0": + version: 4.6.0 + resolution: "lodash.transform@npm:4.6.0" + checksum: 10c0/ad7f376b00dccff09f8597f19a171f2e074756178ae74887346876e10f6f0d83009460cc0793183cc5ee4e24a72ff86e68031c45b5aa2731c2f681a4dc93fe77 + languageName: node + linkType: hard + +"lodash.union@npm:^4.6.0": + version: 4.6.0 + resolution: "lodash.union@npm:4.6.0" + checksum: 10c0/6da7f72d1facd472f6090b49eefff984c9f9179e13172039c0debca6851d21d37d83c7ad5c43af23bd220f184cd80e6897e8e3206509fae491f9068b02ae6319 + languageName: node + linkType: hard + +"lodash.values@npm:^4.3.0": + version: 4.3.0 + resolution: "lodash.values@npm:4.3.0" + checksum: 10c0/f56b3da5bd3aa0006ad544c8e2e890a35b5aefcb6e3528a4c4f191f091b9edea632dd461de79ee121b5b61881cd96b7f911a309dc04f53af0e927d6a599cf1ee + languageName: node + linkType: hard + "lodash@npm:^4.17.15, lodash@npm:^4.17.21": version: 4.17.21 resolution: "lodash@npm:4.17.21" @@ -12337,6 +12913,13 @@ __metadata: languageName: node linkType: hard +"lowercase-keys@npm:^2.0.0": + version: 2.0.0 + resolution: "lowercase-keys@npm:2.0.0" + checksum: 10c0/f82a2b3568910509da4b7906362efa40f5b54ea14c2584778ddb313226f9cbf21020a5db35f9b9a0e95847a9b781d548601f31793d736b22a2b8ae8eb9ab1082 + languageName: node + linkType: hard + "lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0, lru-cache@npm:^10.4.3": version: 10.4.3 resolution: "lru-cache@npm:10.4.3" @@ -12445,6 +13028,15 @@ __metadata: languageName: node linkType: hard +"map-age-cleaner@npm:^0.1.3": + version: 0.1.3 + resolution: "map-age-cleaner@npm:0.1.3" + dependencies: + p-defer: "npm:^1.0.0" + checksum: 10c0/7495236c7b0950956c144fd8b4bc6399d4e78072a8840a4232fe1c4faccbb5eb5d842e5c0a56a60afc36d723f315c1c672325ca03c1b328650f7fcc478f385fd + languageName: node + linkType: hard + "map-cache@npm:^0.2.2": version: 0.2.2 resolution: "map-cache@npm:0.2.2" @@ -12762,6 +13354,16 @@ __metadata: languageName: node linkType: hard +"mem@npm:^8.0.0": + version: 8.1.1 + resolution: "mem@npm:8.1.1" + dependencies: + map-age-cleaner: "npm:^0.1.3" + mimic-fn: "npm:^3.1.0" + checksum: 10c0/5829c404d024c1accaf76ebacbc7eae9b59e5ce5722d184aa24e8387a8097a499f6aa7e181021003c51eb87b2dcdc9a2270050c58753cce761de206643cba91c + languageName: node + linkType: hard + "merge-stream@npm:^2.0.0": version: 2.0.0 resolution: "merge-stream@npm:2.0.0" @@ -13321,6 +13923,27 @@ __metadata: languageName: node linkType: hard +"mimic-fn@npm:^3.1.0": + version: 3.1.0 + resolution: "mimic-fn@npm:3.1.0" + checksum: 10c0/a07cdd8ed6490c2dff5b11f889b245d9556b80f5a653a552a651d17cff5a2d156e632d235106c2369f00cccef4071704589574cf3601bc1b1400a1f620dff067 + languageName: node + linkType: hard + +"mimic-response@npm:^1.0.0": + version: 1.0.1 + resolution: "mimic-response@npm:1.0.1" + checksum: 10c0/c5381a5eae997f1c3b5e90ca7f209ed58c3615caeee850e85329c598f0c000ae7bec40196580eef1781c60c709f47258131dab237cad8786f8f56750594f27fa + languageName: node + linkType: hard + +"mimic-response@npm:^3.1.0": + version: 3.1.0 + resolution: "mimic-response@npm:3.1.0" + checksum: 10c0/0d6f07ce6e03e9e4445bee655202153bdb8a98d67ee8dc965ac140900d7a2688343e6b4c9a72cfc9ef2f7944dfd76eef4ab2482eb7b293a68b84916bac735362 + languageName: node + linkType: hard + "minimalistic-assert@npm:^1.0.0, minimalistic-assert@npm:^1.0.1": version: 1.0.1 resolution: "minimalistic-assert@npm:1.0.1" @@ -13429,6 +14052,13 @@ __metadata: languageName: node linkType: hard +"minipass@npm:^5.0.0": + version: 5.0.0 + resolution: "minipass@npm:5.0.0" + checksum: 10c0/a91d8043f691796a8ac88df039da19933ef0f633e3d7f0d35dcd5373af49131cf2399bfc355f41515dc495e3990369c3858cd319e5c2722b4753c90bf3152462 + languageName: node + linkType: hard + "minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2": version: 7.1.2 resolution: "minipass@npm:7.1.2" @@ -13443,6 +14073,16 @@ __metadata: languageName: node linkType: hard +"minizlib@npm:^2.1.1": + version: 2.1.2 + resolution: "minizlib@npm:2.1.2" + dependencies: + minipass: "npm:^3.0.0" + yallist: "npm:^4.0.0" + checksum: 10c0/64fae024e1a7d0346a1102bb670085b17b7f95bf6cfdf5b128772ec8faf9ea211464ea4add406a3a6384a7d87a0cd1a96263692134323477b4fb43659a6cab78 + languageName: node + linkType: hard + "minizlib@npm:^3.0.1": version: 3.0.2 resolution: "minizlib@npm:3.0.2" @@ -13480,7 +14120,7 @@ __metadata: languageName: node linkType: hard -"mkdirp@npm:^1.0.4": +"mkdirp@npm:^1.0.3, mkdirp@npm:^1.0.4": version: 1.0.4 resolution: "mkdirp@npm:1.0.4" bin: @@ -13800,6 +14440,13 @@ __metadata: languageName: node linkType: hard +"normalize-url@npm:^6.0.1": + version: 6.1.0 + resolution: "normalize-url@npm:6.1.0" + checksum: 10c0/95d948f9bdd2cfde91aa786d1816ae40f8262946e13700bf6628105994fe0ff361662c20af3961161c38a119dc977adeb41fc0b41b1745eb77edaaf9cb22db23 + languageName: node + linkType: hard + "normalize.css@npm:^8.0.1": version: 8.0.1 resolution: "normalize.css@npm:8.0.1" @@ -13891,6 +14538,13 @@ __metadata: languageName: node linkType: hard +"object-hash@npm:^3.0.0": + version: 3.0.0 + resolution: "object-hash@npm:3.0.0" + checksum: 10c0/a06844537107b960c1c8b96cd2ac8592a265186bfa0f6ccafe0d34eabdb526f6fa81da1f37c43df7ed13b12a4ae3457a16071603bcd39d8beddb5f08c37b0f47 + languageName: node + linkType: hard + "object-inspect@npm:^1.13.3, object-inspect@npm:^1.13.4": version: 1.13.4 resolution: "object-inspect@npm:1.13.4" @@ -14062,6 +14716,20 @@ __metadata: languageName: node linkType: hard +"p-cancelable@npm:^2.0.0": + version: 2.1.1 + resolution: "p-cancelable@npm:2.1.1" + checksum: 10c0/8c6dc1f8dd4154fd8b96a10e55a3a832684c4365fb9108056d89e79fbf21a2465027c04a59d0d797b5ffe10b54a61a32043af287d5c4860f1e996cbdbc847f01 + languageName: node + linkType: hard + +"p-defer@npm:^1.0.0": + version: 1.0.0 + resolution: "p-defer@npm:1.0.0" + checksum: 10c0/ed603c3790e74b061ac2cb07eb6e65802cf58dce0fbee646c113a7b71edb711101329ad38f99e462bd2e343a74f6e9366b496a35f1d766c187084d3109900487 + languageName: node + linkType: hard + "p-finally@npm:^1.0.0": version: 1.0.0 resolution: "p-finally@npm:1.0.0" @@ -14105,6 +14773,15 @@ __metadata: languageName: node linkType: hard +"p-map@npm:^4.0.0": + version: 4.0.0 + resolution: "p-map@npm:4.0.0" + dependencies: + aggregate-error: "npm:^3.0.0" + checksum: 10c0/592c05bd6262c466ce269ff172bb8de7c6975afca9b50c975135b974e9bdaafbfe80e61aaaf5be6d1200ba08b30ead04b88cfa7e25ff1e3b93ab28c9f62a2c75 + languageName: node + linkType: hard + "p-map@npm:^7.0.2": version: 7.0.3 resolution: "p-map@npm:7.0.3" @@ -14133,6 +14810,13 @@ __metadata: languageName: node linkType: hard +"packageurl-js@npm:1.2.0": + version: 1.2.0 + resolution: "packageurl-js@npm:1.2.0" + checksum: 10c0/4ab4f63483e3ae516ec458bc8113d7e86c199698fa66a4b290c039f92415a9d8908a9421155677fe56bc6ba682c5930bf1db432401ad8dbf0a3350a6d92bd3d8 + languageName: node + linkType: hard + "pako@npm:~1.0.5": version: 1.0.11 resolution: "pako@npm:1.0.11" @@ -14725,6 +15409,13 @@ __metadata: languageName: node linkType: hard +"quick-lru@npm:^5.1.1": + version: 5.1.1 + resolution: "quick-lru@npm:5.1.1" + checksum: 10c0/a24cba5da8cec30d70d2484be37622580f64765fb6390a928b17f60cd69e8dbd32a954b3ff9176fa1b86d86ff2ba05252fae55dc4d40d0291c60412b0ad096da + languageName: node + linkType: hard + "randombytes@npm:^2.0.0, randombytes@npm:^2.0.1, randombytes@npm:^2.0.5, randombytes@npm:^2.1.0": version: 2.1.0 resolution: "randombytes@npm:2.1.0" @@ -15111,6 +15802,13 @@ __metadata: languageName: node linkType: hard +"resolve-alpn@npm:^1.0.0": + version: 1.2.1 + resolution: "resolve-alpn@npm:1.2.1" + checksum: 10c0/b70b29c1843bc39781ef946c8cd4482e6d425976599c0f9c138cec8209e4e0736161bf39319b01676a847000085dfdaf63583c6fb4427bf751a10635bd2aa0c4 + languageName: node + linkType: hard + "resolve-from@npm:^4.0.0": version: 4.0.0 resolution: "resolve-from@npm:4.0.0" @@ -15184,6 +15882,15 @@ __metadata: languageName: node linkType: hard +"responselike@npm:^2.0.0": + version: 2.0.1 + resolution: "responselike@npm:2.0.1" + dependencies: + lowercase-keys: "npm:^2.0.0" + checksum: 10c0/360b6deb5f101a9f8a4174f7837c523c3ec78b7ca8a7c1d45a1062b303659308a23757e318b1e91ed8684ad1205721142dd664d94771cd63499353fd4ee732b5 + languageName: node + linkType: hard + "ret@npm:~0.1.10": version: 0.1.15 resolution: "ret@npm:0.1.15" @@ -15205,6 +15912,13 @@ __metadata: languageName: node linkType: hard +"rfc4648@npm:^1.5.1": + version: 1.5.4 + resolution: "rfc4648@npm:1.5.4" + checksum: 10c0/8683e82ed9c3cb23844720d04eaeee12025146bfdfdf250b1cce80d56e16c6431530ba3033cbb0e7ca3a25223107847f14c6cac11a255ea7d219dc7ba11cd43d + languageName: node + linkType: hard + "rfdc@npm:^1.3.0, rfdc@npm:^1.4.1": version: 1.4.1 resolution: "rfdc@npm:1.4.1" @@ -15554,6 +16268,15 @@ __metadata: languageName: node linkType: hard +"semver@npm:^7.0.0, semver@npm:^7.1.2, semver@npm:^7.3.8": + version: 7.7.3 + resolution: "semver@npm:7.7.3" + bin: + semver: bin/semver.js + checksum: 10c0/4afe5c986567db82f44c8c6faef8fe9df2a9b1d98098fc1721f57c696c4c21cebd572f297fc21002f81889492345b8470473bc6f4aff5fb032a6ea59ea2bc45e + languageName: node + linkType: hard + "semver@npm:^7.1.1, semver@npm:^7.3.5, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.7.2": version: 7.7.2 resolution: "semver@npm:7.7.2" @@ -15844,6 +16567,46 @@ __metadata: languageName: node linkType: hard +"snyk-config@npm:^5.2.0": + version: 5.3.0 + resolution: "snyk-config@npm:5.3.0" + dependencies: + async: "npm:^3.2.2" + debug: "npm:^4.3.4" + lodash.merge: "npm:^4.6.2" + minimist: "npm:^1.2.6" + checksum: 10c0/65e386350a056c115291f89ec4dbc57ee664c1b1bd9aea9a117151bdb27f8202b5590a69f5425821f5b85dee4e9f8d59f011922f1a2047dde0d8446766ed2e60 + languageName: node + linkType: hard + +"snyk-nodejs-lockfile-parser@npm:^2.4.2": + version: 2.4.2 + resolution: "snyk-nodejs-lockfile-parser@npm:2.4.2" + dependencies: + "@snyk/dep-graph": "npm:^2.3.0" + "@snyk/error-catalog-nodejs-public": "npm:^5.16.0" + "@snyk/graphlib": "npm:2.1.9-patch.3" + "@yarnpkg/core": "npm:^4.4.1" + "@yarnpkg/lockfile": "npm:^1.1.0" + dependency-path: "npm:^9.2.8" + event-loop-spinner: "npm:^2.0.0" + js-yaml: "npm:^4.1.0" + lodash.clonedeep: "npm:^4.5.0" + lodash.flatmap: "npm:^4.5.0" + lodash.isempty: "npm:^4.4.0" + lodash.topairs: "npm:^4.3.0" + micromatch: "npm:^4.0.8" + p-map: "npm:^4.0.0" + semver: "npm:^7.6.0" + snyk-config: "npm:^5.2.0" + tslib: "npm:^1.9.3" + uuid: "npm:^8.3.0" + bin: + parse-nodejs-lockfile: bin/index.js + checksum: 10c0/205aff1ea79306975a881f63d857af446e61ff7537d94efb591b993bd152e413b8688f360d58f5bcaef833e00395898c35b31ab179d6aa07dce9d1f753617fe0 + languageName: node + linkType: hard + "socks-proxy-agent@npm:^8.0.3": version: 8.0.5 resolution: "socks-proxy-agent@npm:8.0.5" @@ -16411,6 +17174,20 @@ __metadata: languageName: node linkType: hard +"tar@npm:^6.0.5": + version: 6.2.1 + resolution: "tar@npm:6.2.1" + dependencies: + chownr: "npm:^2.0.0" + fs-minipass: "npm:^2.0.0" + minipass: "npm:^5.0.0" + minizlib: "npm:^2.1.1" + mkdirp: "npm:^1.0.3" + yallist: "npm:^4.0.0" + checksum: 10c0/a5eca3eb50bc11552d453488344e6507156b9193efd7635e98e867fab275d527af53d8866e2370cd09dfe74378a18111622ace35af6a608e5223a7d27fe99537 + languageName: node + linkType: hard + "tar@npm:^7.4.3": version: 7.4.3 resolution: "tar@npm:7.4.3" @@ -16551,6 +17328,13 @@ __metadata: languageName: node linkType: hard +"tinylogic@npm:^2.0.0": + version: 2.0.0 + resolution: "tinylogic@npm:2.0.0" + checksum: 10c0/c9417c4b65dfc469c71c9eba4d43d44813ab8baceb80ba2c0e6c286de2e93e9c4b8522e4b0a7b91cb4a85353368ee93838a862262ce54bac431b884e694d1c89 + languageName: node + linkType: hard + "tinyrainbow@npm:^3.0.3": version: 3.0.3 resolution: "tinyrainbow@npm:3.0.3" @@ -16673,6 +17457,13 @@ __metadata: languageName: node linkType: hard +"treeify@npm:^1.1.0": + version: 1.1.0 + resolution: "treeify@npm:1.1.0" + checksum: 10c0/2f0dea9e89328b8a42296a3963d341ab19897a05b723d6b0bced6b28701a340d2a7b03241aef807844198e46009aaf3755139274eb082cfce6fdc1935cbd69dd + languageName: node + linkType: hard + "trim-lines@npm:^3.0.0": version: 3.0.1 resolution: "trim-lines@npm:3.0.1" @@ -16745,7 +17536,14 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.0.0, tslib@npm:^2.0.3, tslib@npm:^2.4.0, tslib@npm:^2.6.2, tslib@npm:^2.8.1": +"tslib@npm:^1.9.3": + version: 1.14.1 + resolution: "tslib@npm:1.14.1" + checksum: 10c0/69ae09c49eea644bc5ebe1bca4fa4cc2c82b7b3e02f43b84bd891504edf66dbc6b2ec0eef31a957042de2269139e4acff911e6d186a258fb14069cd7f6febce2 + languageName: node + linkType: hard + +"tslib@npm:^2, tslib@npm:^2.0.0, tslib@npm:^2.0.3, tslib@npm:^2.4.0, tslib@npm:^2.6.2, tslib@npm:^2.6.3, tslib@npm:^2.8.1": version: 2.8.1 resolution: "tslib@npm:2.8.1" checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 @@ -16782,6 +17580,13 @@ __metadata: languageName: node linkType: hard +"typanion@npm:^3.8.0": + version: 3.14.0 + resolution: "typanion@npm:3.14.0" + checksum: 10c0/8b03b19844e6955bfd906c31dc781bae6d7f1fb3ce4fe24b7501557013d4889ae5cefe671dafe98d87ead0adceb8afcb8bc16df7dc0bd2b7331bac96f3a7cae2 + languageName: node + linkType: hard + "type-check@npm:^0.4.0, type-check@npm:~0.4.0": version: 0.4.0 resolution: "type-check@npm:0.4.0" @@ -17351,6 +18156,15 @@ __metadata: languageName: node linkType: hard +"uuid@npm:^8.3.0": + version: 8.3.2 + resolution: "uuid@npm:8.3.2" + bin: + uuid: dist/bin/uuid + checksum: 10c0/bcbb807a917d374a49f475fae2e87fdca7da5e5530820ef53f65ba1d12131bd81a92ecf259cc7ce317cbe0f289e7d79fdfebcef9bfa3087c8c8a2fa304c9be54 + languageName: node + linkType: hard + "uvu@npm:^0.5.6": version: 0.5.6 resolution: "uvu@npm:0.5.6"