diff --git a/client/serve/serve.json b/client/serve/serve.json
index 2dffd3ddd72..28afb35fc83 100644
--- a/client/serve/serve.json
+++ b/client/serve/serve.json
@@ -19,6 +19,15 @@
}
]
},
+ {
+ "source": "js/test-runner/*/*.js",
+ "headers": [
+ {
+ "key": "Cache-Control",
+ "value": "public, max-age=172800, immutable"
+ }
+ ]
+ },
{
"source": "{misc/*.js,sw.js,python-input-sw.js}",
"headers": [
diff --git a/client/src/templates/Challenges/rechallenge/builders.ts b/client/src/templates/Challenges/rechallenge/builders.ts
index 56496838601..7ba2525ea7c 100644
--- a/client/src/templates/Challenges/rechallenge/builders.ts
+++ b/client/src/templates/Challenges/rechallenge/builders.ts
@@ -10,8 +10,7 @@ interface ConcatHTMLOptions {
export function concatHtml({
required = [],
template,
- contents,
- testRunner
+ contents
}: ConcatHTMLOptions): string {
const embedSource = template
? _template(template)
@@ -33,14 +32,7 @@ A required file can not have both a src and a link: src = ${src}, link = ${link}
})
.join('\n');
- // The script has an id so that tests can look for it, if needed.
- const testRunnerScript = testRunner
- ? ``
- : '';
-
- return `
${head}${
- embedSource({ source: contents }) || ''
- }${testRunnerScript}`;
+ return `${head}${embedSource({ source: contents }) || ''}`;
}
export function createPythonTerminal(pythonRunnerSrc: string): string {
diff --git a/client/src/templates/Challenges/redux/execute-challenge-saga.js b/client/src/templates/Challenges/redux/execute-challenge-saga.js
index a7079a83b14..3aeee3ba3b7 100644
--- a/client/src/templates/Challenges/redux/execute-challenge-saga.js
+++ b/client/src/templates/Challenges/redux/execute-challenge-saga.js
@@ -114,9 +114,6 @@ export function* executeChallengeSaga({ payload }) {
const hooks = yield select(challengeHooksSelector);
yield put(updateTests(tests));
- yield fork(takeEveryLog, consoleProxy);
- const proxyLogger = args => consoleProxy.put(args);
-
const challengeData = yield select(challengeDataSelector);
const challengeMeta = yield select(challengeMetaSelector);
// The buildData is used even if there are build errors, so that lessons
@@ -127,13 +124,7 @@ export function* executeChallengeSaga({ payload }) {
disableLoopProtectPreview: challengeMeta.disableLoopProtectPreview,
usesTestRunner: true
});
- const document = yield getContext('document');
- const testRunner = yield call(
- getTestRunner,
- { ...buildData, hooks },
- { proxyLogger },
- document
- );
+ const testRunner = yield call(getTestRunner, { ...buildData, hooks });
const testResults = yield executeTests(testRunner, tests);
yield put(updateTests(testResults));
@@ -169,14 +160,6 @@ export function* executeChallengeSaga({ payload }) {
}
}
-function* takeEveryLog(channel) {
- // TODO: move all stringifying and escaping into the reducer so there is a
- // single place responsible for formatting the logs.
- yield takeEvery(channel, function* (args) {
- yield put(updateLogs(escape(args)));
- });
-}
-
function* takeEveryConsole(channel) {
// TODO: move all stringifying and escaping into the reducer so there is a
// single place responsible for formatting the console output.
@@ -199,22 +182,27 @@ function* executeTests(testRunner, tests, testTimeout = 5000) {
for (let i = 0; i < tests.length; i++) {
const { text, testString } = tests[i];
const newTest = { text, testString, running: false };
- // only the last test outputs console.logs to avoid log duplication.
- const firstTest = i === 1;
+ // only the first test outputs console.logs to avoid log duplication.
+ const firstTest = i === 0;
try {
- const { pass, err } = yield call(
- testRunner,
- testString,
- testTimeout,
- firstTest
- );
+ const {
+ pass,
+ err,
+ logs = []
+ } = yield call(testRunner, testString, testTimeout);
+
+ const logString = logs.map(log => log.msg).join('\n');
+ if (firstTest && logString) {
+ yield put(updateLogs(logString));
+ }
+
if (pass) {
newTest.pass = true;
} else {
throw err;
}
} catch (err) {
- const { actual, expected, errorType } = err;
+ const { actual, expected, type } = err;
newTest.message = text
.replace('--fcc-expected--', expected)
@@ -222,9 +210,9 @@ function* executeTests(testRunner, tests, testTimeout = 5000) {
if (err === 'timeout') {
newTest.err = 'Test timed out';
newTest.message = `${newTest.message} (${newTest.err})`;
- } else if (errorType) {
+ } else if (type) {
const msgKey =
- errorType === 'indentation'
+ type === 'IndentationError'
? 'learn.indentation-error'
: 'learn.syntax-error';
newTest.message = `${i18next.t(msgKey)}
`;
@@ -300,11 +288,12 @@ export function* previewChallengeSaga(action) {
yield call(updatePreview, buildData, finalDocument, proxyLogger);
}
} else if (isJavaScriptChallenge(challengeData)) {
- const runUserCode = getTestRunner(buildData, {
- proxyLogger
- });
+ const runUserCode = yield call(getTestRunner, buildData);
// without a testString the testRunner just evaluates the user's code
- yield call(runUserCode, null, previewTimeout);
+ const out = yield call(runUserCode, null, previewTimeout);
+
+ if (out)
+ yield put(updateConsole(out.logs?.map(log => log.msg).join('\n')));
}
}
} catch (err) {
diff --git a/client/src/templates/Challenges/utils/build.ts b/client/src/templates/Challenges/utils/build.ts
index 2dcab5945c3..2df6485fb8d 100644
--- a/client/src/templates/Challenges/utils/build.ts
+++ b/client/src/templates/Challenges/utils/build.ts
@@ -1,7 +1,4 @@
import { challengeTypes } from '../../../../../shared/config/challenge-types';
-import frameRunnerData from '../../../../../client/config/browser-scripts/frame-runner.json';
-import jsTestEvaluatorData from '../../../../../client/config/browser-scripts/test-evaluator.json';
-import pyTestEvaluatorData from '../../../../../client/config/browser-scripts/python-test-evaluator.json';
import type { ChallengeFile } from '../../../redux/prop-types';
import { concatHtml } from '../rechallenge/builders';
@@ -12,16 +9,14 @@ import {
getMultifileJSXTransformers
} from '../rechallenge/transformers';
import {
- createTestFramer,
runTestInTestFrame,
createMainPreviewFramer,
createProjectPreviewFramer,
ProxyLogger,
- TestRunnerConfig,
Context,
- Source
+ Source,
+ prepTestRunner
} from './frame';
-import { WorkerExecutor } from './worker-executor';
interface BuildChallengeData extends Context {
challengeType: number;
@@ -38,19 +33,6 @@ interface BuildOptions {
usesTestRunner?: boolean;
}
-const { filename: jsTestEvaluator } = jsTestEvaluatorData;
-const { filename: pyTestEvaluator } = pyTestEvaluatorData;
-
-const frameRunnerSrc = `/js/${frameRunnerData.filename}.js`;
-
-const pythonWorkerExecutor = new WorkerExecutor(pyTestEvaluator, {
- terminateWorker: false,
- maxWorkers: 1
-});
-const jsWorkerExecutor = new WorkerExecutor(jsTestEvaluator, {
- terminateWorker: true
-});
-
type ApplyFunctionProps = (
file: ChallengeFile
) => Promise | ChallengeFile;
@@ -127,91 +109,35 @@ export async function buildChallenge(
throw new Error(`Cannot build challenge of type ${challengeType}`);
}
-const testRunners = {
- [challengeTypes.js]: getJSTestRunner,
- [challengeTypes.html]: getDOMTestRunner,
- [challengeTypes.backend]: getDOMTestRunner,
- [challengeTypes.pythonProject]: getDOMTestRunner,
- [challengeTypes.python]: getPyTestRunner,
- [challengeTypes.multifileCertProject]: getDOMTestRunner,
- [challengeTypes.multifilePythonCertProject]: getPyTestRunner,
- [challengeTypes.lab]: getDOMTestRunner,
- [challengeTypes.pyLab]: getPyTestRunner,
- [challengeTypes.dailyChallengeJs]: getJSTestRunner,
- [challengeTypes.dailyChallengePy]: getPyTestRunner
+export const runnerTypes: Record = {
+ [challengeTypes.js]: 'javascript',
+ [challengeTypes.html]: 'dom',
+ [challengeTypes.backend]: 'dom',
+ [challengeTypes.jsProject]: 'javascript',
+ [challengeTypes.pythonProject]: 'python',
+ [challengeTypes.python]: 'python',
+ [challengeTypes.modern]: 'dom',
+ [challengeTypes.multifileCertProject]: 'dom',
+ [challengeTypes.multifilePythonCertProject]: 'python',
+ [challengeTypes.lab]: 'dom',
+ [challengeTypes.jsLab]: 'javascript',
+ [challengeTypes.pyLab]: 'python',
+ [challengeTypes.dailyChallengeJs]: 'javascript',
+ [challengeTypes.dailyChallengePy]: 'python'
};
-export function getTestRunner(
- buildData: BuildChallengeData,
- runnerConfig: TestRunnerConfig,
- document: Document
-) {
+export async function getTestRunner(buildData: BuildChallengeData) {
const { challengeType } = buildData;
- const testRunner = testRunners[challengeType];
- if (testRunner) {
- return testRunner(buildData, runnerConfig, document);
+ const type = runnerTypes[challengeType];
+ if (!type) {
+ throw new Error(
+ `Cannot get test runner for challenge type ${challengeType}`
+ );
}
- throw new Error(`Cannot get test runner for challenge type ${challengeType}`);
-}
+ await prepTestRunner({ ...buildData, type });
-function getJSTestRunner(
- { build, sources }: BuildChallengeData,
- { proxyLogger }: TestRunnerConfig
-) {
- return getWorkerTestRunner(
- { build, sources },
- { proxyLogger },
- jsWorkerExecutor
- );
-}
-
-function getPyTestRunner(
- { build, sources }: BuildChallengeData,
- { proxyLogger }: TestRunnerConfig
-) {
- return getWorkerTestRunner(
- { build, sources },
- { proxyLogger },
- pythonWorkerExecutor
- );
-}
-
-function getWorkerTestRunner(
- { build, sources }: Pick,
- { proxyLogger }: TestRunnerConfig,
- workerExecutor: WorkerExecutor
-) {
- const code = {
- contents: sources.index,
- editableContents: sources.editableContents
- };
-
- interface TestWorkerExecutor extends WorkerExecutor {
- on: (event: string, listener: (...args: string[]) => void) => void;
- done: () => void;
- }
-
- return (testString: string, testTimeout: number, firstTest = true) => {
- const result = workerExecutor.execute(
- { build, testString, code, sources, firstTest },
- testTimeout
- ) as TestWorkerExecutor;
-
- result.on('LOG', proxyLogger);
- return result.done;
- };
-}
-
-async function getDOMTestRunner(
- buildData: BuildChallengeData,
- { proxyLogger }: TestRunnerConfig,
- document: Document
-) {
- await new Promise(resolve =>
- createTestFramer(document, proxyLogger, resolve)(buildData)
- );
return (testString: string, testTimeout: number) =>
- runTestInTestFrame(document, testString, testTimeout);
+ runTestInTestFrame(testString, testTimeout, type);
}
type BuildResult = {
@@ -226,7 +152,12 @@ type BuildResult = {
// abstraction (function, class, whatever) and then create the various functions
// out of it.
export async function buildDOMChallenge(
- { challengeFiles, required = [], template = '' }: BuildChallengeData,
+ {
+ challengeFiles,
+ required = [],
+ template = '',
+ challengeType
+ }: BuildChallengeData,
options?: BuildOptions
): Promise {
// TODO: make this required in the schema.
@@ -247,7 +178,6 @@ export async function buildDOMChallenge(
: getTransformers(options)) as unknown as ApplyFunctionProps[];
const pipeLine = composeFunctions(...transformers);
- const usesTestRunner = options?.usesTestRunner ?? false;
const finalFiles = await Promise.all(challengeFiles.map(pipeLine));
const error = finalFiles.find(({ error }) => error)?.error;
const contents = (await embedFilesInHtml(finalFiles)) as string;
@@ -255,18 +185,15 @@ export async function buildDOMChallenge(
// if there is an error, we just build the test runner so that it can be
// used to run tests against the code without actually running the code.
const toBuild = error
- ? { ...(usesTestRunner && { testRunner: frameRunnerSrc }) }
+ ? {}
: {
required,
template,
- contents,
- ...(usesTestRunner && { testRunner: frameRunnerSrc })
+ contents
};
return {
- // TODO: Stop overwriting challengeType with 'html'. Figure out why it's
- // necessary at the moment.
- challengeType: challengeTypes.html,
+ challengeType,
build: concatHtml(toBuild),
sources: buildSourceMap(finalFiles),
loadEnzyme: requiresReact16,
@@ -275,7 +202,10 @@ export async function buildDOMChallenge(
}
export async function buildJSChallenge(
- { challengeFiles }: { challengeFiles?: ChallengeFile[] },
+ {
+ challengeFiles,
+ challengeType
+ }: { challengeFiles?: ChallengeFile[]; challengeType: number },
options: BuildOptions
): Promise {
if (!challengeFiles) throw Error('No challenge files provided');
@@ -289,7 +219,7 @@ export async function buildJSChallenge(
const toBuild = error ? [] : finalFiles;
return {
- challengeType: challengeTypes.js,
+ challengeType,
build: toBuild
.reduce(
(body, challengeFile) => [
@@ -306,16 +236,17 @@ export async function buildJSChallenge(
};
}
-function buildBackendChallenge({ url }: BuildChallengeData) {
+function buildBackendChallenge({ url, challengeType }: BuildChallengeData) {
return {
- challengeType: challengeTypes.backend,
- build: concatHtml({ testRunner: frameRunnerSrc }),
+ challengeType,
+ build: '',
sources: { contents: url }
};
}
export async function buildPythonChallenge({
- challengeFiles
+ challengeFiles,
+ challengeType
}: BuildChallengeData): Promise {
if (!challengeFiles) throw new Error('No challenge files provided');
const pipeLine = composeFunctions(
@@ -323,13 +254,12 @@ export async function buildPythonChallenge({
);
const finalFiles = await Promise.all(challengeFiles.map(pipeLine));
const error = finalFiles.find(({ error }) => error)?.error;
+ const sources = buildSourceMap(finalFiles);
return {
- challengeType:
- challengeFiles[0].editableRegionBoundaries?.length === 0
- ? challengeTypes.multifilePythonCertProject
- : challengeTypes.python,
- sources: buildSourceMap(finalFiles),
+ challengeType,
+ sources,
+ build: sources?.contents,
error
};
}
@@ -339,16 +269,7 @@ export function updatePreview(
document: Document,
proxyLogger: ProxyLogger
): Promise {
- // TODO: either create a 'buildType' or use the real challengeType here
- // (buildData.challengeType is set to 'html' for challenges that can be
- // previewed, hence this being true for python challenges, multifile steps and
- // so on).
-
- if (
- buildData.challengeType === challengeTypes.html ||
- buildData.challengeType === challengeTypes.multifileCertProject ||
- buildData.challengeType === challengeTypes.lab
- ) {
+ if (challengeHasPreview(buildData)) {
return new Promise(resolve =>
createMainPreviewFramer(
document,
@@ -379,11 +300,7 @@ export function updateProjectPreview(
buildData: BuildChallengeData,
document: Document
): void {
- if (
- buildData.challengeType === challengeTypes.html ||
- buildData.challengeType === challengeTypes.multifileCertProject ||
- buildData.challengeType === challengeTypes.lab
- ) {
+ if (challengeHasPreview(buildData)) {
createProjectPreviewFramer(
document,
getDocumentTitle(buildData)
diff --git a/client/src/templates/Challenges/utils/frame.ts b/client/src/templates/Challenges/utils/frame.ts
index 1c0078b86cc..e267041f388 100644
--- a/client/src/templates/Challenges/utils/frame.ts
+++ b/client/src/templates/Challenges/utils/frame.ts
@@ -1,12 +1,25 @@
import { flow } from 'lodash-es';
import i18next, { type i18n } from 'i18next';
+import {
+ version as _helperVersion,
+ type FCCTestRunner
+} from '../../../../../tools/client-plugins/browser-scripts/test-runner';
+
import { format } from '../../../utils/format';
import type {
FrameDocument,
PythonDocument
} from '../../../../../tools/client-plugins/browser-scripts';
+export const helperVersion = _helperVersion;
+
+declare global {
+ interface Window {
+ FCCTestRunner: FCCTestRunner;
+ }
+}
+
const utilsFormat: (x: T) => string = format;
export interface Source {
@@ -30,11 +43,8 @@ export interface Context {
build: string;
sources: Source;
hooks?: Hooks;
- loadEnzyme?: () => void;
-}
-
-export interface TestRunnerConfig {
- proxyLogger: ProxyLogger;
+ type: 'dom' | 'javascript' | 'python';
+ loadEnzyme?: boolean;
}
export type ProxyLogger = (msg: string) => void;
@@ -76,10 +86,9 @@ export const scrollManager = new ScrollManager();
// we use two different frames to make them all essentially pure functions
// main iframe is responsible rendering the preview and is where we proxy the
export const mainPreviewId = 'fcc-main-frame';
-// the test frame is responsible for running the assert tests
-export const testId = 'fcc-test-frame';
// the project preview frame demos the finished project
export const projectPreviewId = 'fcc-project-preview-frame';
+const ASSET_PATH = `/js/test-runner/${helperVersion}/`;
const DOCUMENT_NOT_FOUND_ERROR = 'misc.document-notfound';
@@ -149,14 +158,6 @@ const createHeader = (id = mainPreviewId) =>
`;
-const createBeforeAllScript = (beforeAll?: string) => {
- if (!beforeAll) return '';
-
- return ``;
-};
-
type TestResult =
| { pass: boolean }
| { err: { message: string; stack?: string } };
@@ -172,20 +173,43 @@ function getContentDocument(
}
export const runTestInTestFrame = async function (
- document: Document,
test: string,
- timeout: number
+ timeout: number,
+ type: 'dom' | 'javascript' | 'python'
): Promise {
- const contentDocument = getContentDocument(document, testId);
- if (contentDocument) {
- return await Promise.race([
- new Promise<
- { pass: boolean } | { err: { message: string; stack?: string } }
- // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors
- >((_, reject) => setTimeout(() => reject('timeout'), timeout)),
- contentDocument.__runTest(test)
- ]);
- }
+ const runner = window?.FCCTestRunner.getRunner(type);
+
+ return await Promise.race([
+ new Promise<
+ { pass: boolean } | { err: { message: string; stack?: string } }
+ >((_, reject) => setTimeout(() => reject(Error('timeout')), timeout)),
+ runner?.runTest(test)
+ ]);
+};
+
+export const prepTestRunner = async ({
+ sources,
+ loadEnzyme,
+ build,
+ hooks,
+ type
+}: {
+ sources: Source;
+ loadEnzyme?: boolean;
+ build: string;
+ hooks?: Hooks;
+ type: 'dom' | 'javascript' | 'python';
+}) => {
+ const source = type === 'dom' ? prefixDoctype({ build, sources }) : build;
+ await loadTestRunner(document);
+ await window?.FCCTestRunner.createTestRunner({
+ type,
+ code: sources,
+ source,
+ assetPath: ASSET_PATH,
+ hooks,
+ loadEnzyme
+ });
};
export const runPythonInFrame = function (
@@ -200,10 +224,49 @@ export const runPythonInFrame = function (
void contentDocument?.__runPython(code);
};
+const TEST_RUNNER_ID = 'fcc-test-runner';
+const createRunnerScript = (document: Document) => {
+ const script = document.createElement('script');
+ script.src = ASSET_PATH + 'index.js';
+ script.id = TEST_RUNNER_ID;
+ return script;
+};
+
+const loadTestRunner = async (document: Document) => {
+ const done = new Promise((resolve, reject) => {
+ const alreadyLoaded = !!window?.FCCTestRunner;
+
+ if (alreadyLoaded) return resolve();
+
+ const script =
+ document.getElementById(TEST_RUNNER_ID) ?? createRunnerScript(document);
+
+ const errorListener = (err: ErrorEvent) => {
+ console.error(err);
+ reject(new Error('Test runner failed to load'));
+ };
+
+ script.addEventListener(
+ 'load',
+ () => {
+ // Since it's loaded, we no longer need to listen for errors
+ script.removeEventListener('error', errorListener);
+ resolve();
+ },
+ { once: true }
+ );
+ script.addEventListener('error', errorListener, { once: true });
+
+ document.head.appendChild(script);
+ });
+ return done;
+};
+
const createFrame =
(document: Document, id: string, title?: string) =>
(frameContext: Context) => {
const frame = document.createElement('iframe');
+
frame.srcdoc = createContent(id, frameContext);
frame.id = id;
if (typeof title === 'string') {
@@ -216,37 +279,20 @@ const createFrame =
};
};
-const hiddenFrameClassName = 'hide-test-frame';
-const mountFrame =
- (document: Document, id: string) => (frameContext: Context) => {
- const { element }: { element: HTMLIFrameElement } = frameContext;
- const oldFrame = document.getElementById(element.id) as HTMLIFrameElement;
- if (oldFrame) {
- element.className = oldFrame.className || hiddenFrameClassName;
- oldFrame.parentNode!.replaceChild(element, oldFrame);
- // only test frames can be added (and hidden) here, other frames must be
- // added by react
- } else if (id === testId) {
- element.className = hiddenFrameClassName;
- document.body.appendChild(element);
- }
- return {
- ...frameContext,
- element,
- window: element.contentWindow
- };
- };
-
-// Tests should not use functions that directly interact with the user, so
-// they're overridden. If tests need to spy on these functions, they can supply
-// the spy themselves.
-const overrideUserInteractions = (frameContext: Context) => {
- if (frameContext.window) {
- frameContext.window.prompt = () => null;
- frameContext.window.alert = () => {};
- frameContext.window.confirm = () => false;
+const mountFrame = (document: Document) => (frameContext: Context) => {
+ const { element }: { element: HTMLIFrameElement } = frameContext;
+ const oldFrame = document.getElementById(element.id) as HTMLIFrameElement;
+ if (oldFrame) {
+ element.className = oldFrame.className;
+ oldFrame.parentNode!.replaceChild(element, oldFrame);
+ // only test frames can be added (and hidden) here, other frames must be
+ // added by react
}
- return frameContext;
+ return {
+ ...frameContext,
+ element,
+ window: element.contentWindow
+ };
};
const noop = (x: T) => x;
@@ -310,21 +356,6 @@ const updateWindowI18next = (frameContext: Context) => {
return frameContext;
};
-const initTestFrame = (frameReady?: () => void) => (frameContext: Context) => {
- waitForFrame(frameContext)
- .then(async () => {
- const { sources, loadEnzyme } = frameContext;
- await frameContext.window?.document?.__initTestFrame({
- code: sources,
- loadEnzyme
- });
-
- if (frameReady) frameReady();
- })
- .catch(handleDocumentNotFound);
- return frameContext;
-};
-
const initMainFrame =
(frameReady?: () => void, proxyLogger?: ProxyLogger) =>
(frameContext: Context) => {
@@ -386,16 +417,24 @@ const waitForFrame = (frameContext: Context) => {
});
};
-export const createContent = (
- id: string,
- { build, sources, hooks }: { build: string; sources: Source; hooks?: Hooks }
-) => {
+export const prefixDoctype = ({
+ build,
+ sources
+}: {
+ build: string;
+ sources: Source;
+}) => {
// DOCTYPE should be the first thing written to the frame, so if the user code
// includes a DOCTYPE declaration, we need to find it and write it first.
const doctype = sources.contents?.match(/^/i)?.[0] || '';
- return (
- doctype + createBeforeAllScript(hooks?.beforeAll) + createHeader(id) + build
- );
+ return doctype + build;
+};
+
+const createContent = (
+ id: string,
+ { build, sources }: { build: string; sources: Source; hooks?: Hooks }
+) => {
+ return prefixDoctype({ build: createHeader(id) + build, sources });
};
const restoreScrollPosition = (frameContext: Context) => {
@@ -433,20 +472,6 @@ export const createProjectPreviewFramer = (
frameTitle
});
-export const createTestFramer = (
- document: Document,
- proxyLogger: ProxyLogger,
- frameReady: () => void
-): ((args: Context) => void) =>
- createFramer({
- document,
- id: testId,
- init: initTestFrame,
- proxyLogger,
- frameReady,
- updateWindowFunctions: overrideUserInteractions
- });
-
const createFramer = ({
document,
id,
@@ -466,7 +491,7 @@ const createFramer = ({
}) =>
flow(
createFrame(document, id, frameTitle),
- mountFrame(document, id),
+ mountFrame(document),
updateWindowFunctions ?? noop,
updateProxyConsole(proxyLogger),
updateWindowI18next,
diff --git a/client/tsconfig.json b/client/tsconfig.json
index c399cd236b3..f4f14157901 100644
--- a/client/tsconfig.json
+++ b/client/tsconfig.json
@@ -3,7 +3,7 @@
"lib": ["WebWorker", "DOM", "DOM.Iterable", "es2023"],
"target": "ES2023",
"module": "es2020",
- "moduleResolution": "node",
+ "moduleResolution": "bundler",
"allowJs": true,
"jsx": "react",
"strict": true,
diff --git a/curriculum/challenges/english/14-responsive-web-design-22/learn-html-by-building-a-cat-photo-app/5dc174fcf86c76b9248c6eb2.md b/curriculum/challenges/english/14-responsive-web-design-22/learn-html-by-building-a-cat-photo-app/5dc174fcf86c76b9248c6eb2.md
index 83abb16cfdd..2af6314da3a 100644
--- a/curriculum/challenges/english/14-responsive-web-design-22/learn-html-by-building-a-cat-photo-app/5dc174fcf86c76b9248c6eb2.md
+++ b/curriculum/challenges/english/14-responsive-web-design-22/learn-html-by-building-a-cat-photo-app/5dc174fcf86c76b9248c6eb2.md
@@ -46,16 +46,6 @@ Your `h1` element's text should be `CatPhotoApp`. You have either omitted the te
assert(document.querySelector('h1').innerText.toLowerCase() === 'catphotoapp');
```
-You appear to be using a browser extension that is modifying the page. Be sure to turn off all browser extensions.
-
-```js
-if(__checkForBrowserExtensions){
- assert.isAtMost(document.querySelectorAll('script').length, 2);
- assert.equal(document.querySelectorAll('style').length, 1);
- assert.equal(document.querySelectorAll('link').length, 0);
-}
-```
-
# --seed--
## --seed-contents--
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-javascript-by-building-a-role-playing-game/62a2509ba163e020bb9d84ea.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-javascript-by-building-a-role-playing-game/62a2509ba163e020bb9d84ea.md
index bf66f389157..534110c7b28 100644
--- a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-javascript-by-building-a-role-playing-game/62a2509ba163e020bb9d84ea.md
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-javascript-by-building-a-role-playing-game/62a2509ba163e020bb9d84ea.md
@@ -20,7 +20,7 @@ Now you can start writing your JavaScript. Begin by creating a `script` element.
You should have a `script` element.
```js
-assert.isAtLeast(document.querySelectorAll('script').length, 2);
+assert.isAtLeast(document.querySelectorAll('script').length, 1);
```
Your `script` element should have an opening tag.
diff --git a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-javascript-by-building-a-role-playing-game/62b46e3a8d4be31be5af793d.md b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-javascript-by-building-a-role-playing-game/62b46e3a8d4be31be5af793d.md
index 5b9f514bdba..a3e2158bd08 100644
--- a/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-javascript-by-building-a-role-playing-game/62b46e3a8d4be31be5af793d.md
+++ b/curriculum/challenges/english/15-javascript-algorithms-and-data-structures-22/learn-basic-javascript-by-building-a-role-playing-game/62b46e3a8d4be31be5af793d.md
@@ -24,12 +24,8 @@ Your `script` element should come at the end of your `body` element.
```js
const script = document.querySelector('script[data-src$="script.js"]');
-assert.equal(script.previousElementSibling.tagName, "DIV");
-// When building the test frame, the runner script is always inserted after user
-// code. This means the learner's script should be the penultimate element in
-// the body.
-assert.equal(script.nextElementSibling.id, "fcc-test-runner");
-assert.equal(script.parentElement.tagName, "BODY");
+const lastChild = document.querySelector('body').lastElementChild;
+assert.equal(script, lastChild);
```
# --seed--
diff --git a/curriculum/challenges/english/25-front-end-development/lab-markdown-to-html-converter/66f55eac933ff64ce654ca74.md b/curriculum/challenges/english/25-front-end-development/lab-markdown-to-html-converter/66f55eac933ff64ce654ca74.md
index 9a5b5466c2b..f60a0f4d9a6 100644
--- a/curriculum/challenges/english/25-front-end-development/lab-markdown-to-html-converter/66f55eac933ff64ce654ca74.md
+++ b/curriculum/challenges/english/25-front-end-development/lab-markdown-to-html-converter/66f55eac933ff64ce654ca74.md
@@ -848,7 +848,7 @@ assert.equal(italics[0].innerText, "quote");
You should have only one `script` element in your HTML.
```js
-assert.lengthOf(document.querySelectorAll("script"), 3);
+assert.lengthOf(document.querySelectorAll("script"), 1);
```
# --seed--
diff --git a/curriculum/challenges/english/25-front-end-development/lab-video-compilation-page/669e81368e52b3a5c35a2dc5.md b/curriculum/challenges/english/25-front-end-development/lab-video-compilation-page/669e81368e52b3a5c35a2dc5.md
index 66e399765dd..7194e0a97b4 100644
--- a/curriculum/challenges/english/25-front-end-development/lab-video-compilation-page/669e81368e52b3a5c35a2dc5.md
+++ b/curriculum/challenges/english/25-front-end-development/lab-video-compilation-page/669e81368e52b3a5c35a2dc5.md
@@ -32,7 +32,7 @@ assert.equal(document.querySelector('body :first-child').tagName, 'MAIN');
Your `main` element should be the only child of the `body` element.
```js
-assert.equal(document.querySelector('body').children.length, 2);
+assert.equal(document.querySelector('body').children.length, 1);
```
You should have an `h1` element with the topic of your page inside the `main` element.
diff --git a/curriculum/challenges/english/25-front-end-development/workshop-cat-photo-app/5dc174fcf86c76b9248c6eb2.md b/curriculum/challenges/english/25-front-end-development/workshop-cat-photo-app/5dc174fcf86c76b9248c6eb2.md
index dc2c16253d4..6986a0647f0 100644
--- a/curriculum/challenges/english/25-front-end-development/workshop-cat-photo-app/5dc174fcf86c76b9248c6eb2.md
+++ b/curriculum/challenges/english/25-front-end-development/workshop-cat-photo-app/5dc174fcf86c76b9248c6eb2.md
@@ -38,15 +38,6 @@ Your `h1` element's text should be `CatPhotoApp`. You have either omitted the te
assert.equal(document.querySelector('h1')?.innerText.toLowerCase(), 'catphotoapp');
```
-You appear to be using a browser extension that is modifying the page. Be sure to turn off all browser extensions.
-
-```js
-if(__checkForBrowserExtensions){
- assert.isAtMost(document.querySelectorAll('script').length, 2);
- assert.equal(document.querySelectorAll('style').length, 1);
- assert.equal(document.querySelectorAll('link').length, 0);
-}
-```
# --seed--
diff --git a/curriculum/challenges/english/25-front-end-development/workshop-storytelling-app/671fa47e415d88263d349a10.md b/curriculum/challenges/english/25-front-end-development/workshop-storytelling-app/671fa47e415d88263d349a10.md
index b305b452d7d..bec2ba3b341 100644
--- a/curriculum/challenges/english/25-front-end-development/workshop-storytelling-app/671fa47e415d88263d349a10.md
+++ b/curriculum/challenges/english/25-front-end-development/workshop-storytelling-app/671fa47e415d88263d349a10.md
@@ -14,7 +14,7 @@ Next, you will start working on the `JavaScript`. For that, begin by linking the
You should create a `script` element.
```js
-assert.lengthOf(document.querySelectorAll('script'), 3);
+assert.lengthOf(document.querySelectorAll('script'), 1);
```
Your `script` element should have a `src` attribute set to `script.js`.
diff --git a/curriculum/test/stubs/index.html b/curriculum/test/stubs/index.html
index e69de29bb2d..6ecf47f74a2 100644
--- a/curriculum/test/stubs/index.html
+++ b/curriculum/test/stubs/index.html
@@ -0,0 +1,3 @@
+
+
+
diff --git a/curriculum/test/test-challenges.js b/curriculum/test/test-challenges.js
index a8edf0f86f4..55d88a2d1d9 100644
--- a/curriculum/test/test-challenges.js
+++ b/curriculum/test/test-challenges.js
@@ -23,32 +23,20 @@ require('@babel/register')({
only: [clientPath]
});
const {
- buildDOMChallenge,
- buildPythonChallenge,
buildChallenge,
- buildFunctions
+ runnerTypes
} = require('../../client/src/templates/Challenges/utils/build');
-const {
- WorkerExecutor
-} = require('../../client/src/templates/Challenges/utils/worker-executor');
const {
challengeTypes,
hasNoSolution
} = require('../../shared/config/challenge-types');
-// the config files are created during the build, but not before linting
-const javaScriptTestEvaluator =
- require('../../client/config/browser-scripts/test-evaluator.json').filename;
-const pythonTestEvaluator =
- require('../../client/config/browser-scripts/python-test-evaluator.json').filename;
-
const { getLines } = require('../../shared/utils/get-lines');
-
const { getChallengesForLang, getMetaForBlock } = require('../get-challenges');
const { challengeSchemaValidator } = require('../schema/challenge-schema');
const { testedLang, getSuperOrder } = require('../utils');
const {
- createContent,
- testId
+ prefixDoctype,
+ helperVersion
} = require('../../client/src/templates/Challenges/utils/frame');
const { chapterBasedSuperBlocks } = require('../../shared/config/curriculum');
const ChallengeTitles = require('./utils/challenge-titles');
@@ -135,8 +123,6 @@ spinner.text = 'Populate tests.';
let browser;
let page;
-// This worker can be reused since it clears its environment between tests.
-let pythonWorker;
setup()
.then(runTests)
@@ -148,7 +134,13 @@ async function setup() {
host: '127.0.0.1',
port: '8080',
root: path.resolve(__dirname, 'stubs'),
- mount: [['/js', path.join(clientPath, 'static/js')]],
+ mount: [
+ [
+ '/dist',
+ path.join(clientPath, `static/js/test-runner/${helperVersion}`)
+ ],
+ ['/js', path.join(clientPath, 'static/js')]
+ ],
open: false,
logLevel: 0
});
@@ -166,9 +158,6 @@ async function setup() {
});
global.Worker = createPseudoWorker(await newPageContext(browser));
- pythonWorker = new WorkerExecutor(pythonTestEvaluator, {
- terminateWorker: false
- });
page = await newPageContext(browser);
await page.setViewport({ width: 300, height: 150 });
@@ -401,7 +390,11 @@ function populateTestsForLang({ lang, challenges, meta, superBlocks }) {
challenge.challengeFiles,
buildChallenge
);
- } catch {
+ } catch (e) {
+ console.error(
+ `Error creating test runner for initial contents`
+ );
+ console.error(e);
fails = true;
}
if (!fails) {
@@ -540,27 +533,15 @@ async function createTestRunner(
{ usesTestRunner: true }
);
- const code = {
- contents: sources.index,
- editableContents: sources.editableContents
- };
-
- const buildFunction = buildFunctions[challenge.challengeType];
-
- const runsInBrowser = buildFunction === buildDOMChallenge;
- const runsInPythonWorker = buildFunction === buildPythonChallenge;
-
- const evaluator = await (runsInBrowser
- ? getContextEvaluator({
- // passing in challengeId so it's easier to debug timeouts
- challengeId: challenge.id,
- build,
- sources,
- code,
- loadEnzyme,
- hooks: challenge.hooks
- })
- : getWorkerEvaluator({ build, sources, code, runsInPythonWorker }));
+ const evaluator = await getContextEvaluator({
+ // passing in challengeId so it's easier to debug timeouts
+ challengeId: challenge.id,
+ build,
+ sources,
+ type: runnerTypes[challenge.challengeType],
+ loadEnzyme,
+ hooks: challenge.hooks
+ });
return async ({ text, testString }) => {
try {
@@ -569,7 +550,6 @@ async function createTestRunner(
throw err;
}
} catch (err) {
- // add more info to the error so the failing test can be identified.
text = 'Test text: ' + text;
const newMessage = solutionFromNext
? 'Check next step for solution!\n' + text
@@ -625,43 +605,42 @@ ${testString}
timeout
)
),
- await page.evaluate(async testString => {
- return await document.__runTest(testString);
- }, testString)
+ await page.evaluate(
+ async (testString, type) => {
+ return await window.FCCTestRunner.getRunner(type).runTest(
+ testString
+ );
+ },
+ testString,
+ config.type
+ )
])
};
}
-async function getWorkerEvaluator({
+async function initializeTestRunner({
build,
sources,
- code,
- runsInPythonWorker
+ type,
+ hooks,
+ loadEnzyme
}) {
- // The python worker clears the globals between tests, so it should be fine
- // to use the same evaluator for all tests. TODO: check if this is true for
- // sys, since sys.modules is not being reset.
- const testWorker = runsInPythonWorker
- ? pythonWorker
- : new WorkerExecutor(javaScriptTestEvaluator, { terminateWorker: true });
- return {
- evaluate: async (testString, timeout) =>
- await testWorker.execute({ testString, build, code, sources }, timeout)
- .done
- };
-}
+ const source = type === 'dom' ? prefixDoctype({ build, sources }) : build;
-async function initializeTestRunner({ build, sources, loadEnzyme, hooks }) {
- await page.reload();
- await page.setContent(createContent(testId, { build, sources, hooks }));
await page.evaluate(
- async (sources, loadEnzyme) => {
- await document.__initTestFrame({
+ async (sources, source, type, hooks, loadEnzyme) => {
+ await window.FCCTestRunner.createTestRunner({
+ source,
+ type,
code: sources,
+ hooks,
loadEnzyme
});
},
sources,
+ source,
+ type,
+ hooks,
loadEnzyme
);
}
diff --git a/e2e/output.spec.ts b/e2e/output.spec.ts
index 461f2706be9..1404fac3854 100644
--- a/e2e/output.spec.ts
+++ b/e2e/output.spec.ts
@@ -25,6 +25,7 @@ interface InsertTextParameters {
containerId?: string;
isMobile: boolean;
text: string;
+ updatesConsole?: boolean;
}
const replaceTextInCodeEditor = async ({
@@ -32,12 +33,20 @@ const replaceTextInCodeEditor = async ({
browserName,
isMobile,
text,
- containerId = 'editor-container-indexhtml'
+ containerId = 'editor-container-indexhtml',
+ updatesConsole = false
}: InsertTextParameters) => {
await expect(async () => {
await clearEditor({ page, browserName, isMobile });
await getEditors(page).fill(text);
await expect(page.getByTestId(containerId)).toContainText(text);
+ if (updatesConsole) {
+ await expect(
+ page.getByRole('region', {
+ name: translations.learn['editor-tabs'].console
+ })
+ ).not.toContainText('Your test output will go here');
+ }
}).toPass();
};
@@ -151,7 +160,8 @@ test.describe('Challenge Output Component Tests', () => {
page,
isMobile,
text: 'var',
- containerId: 'editor-container-scriptjs'
+ containerId: 'editor-container-scriptjs',
+ updatesConsole: true
});
if (isMobile) {
@@ -165,20 +175,19 @@ test.describe('Challenge Output Component Tests', () => {
).toHaveText(outputTexts.syntaxError);
});
- test('should contain reference error output when var is entered in editor', async ({
+ test('should contain a reference error when an undefined var is entered in editor', async ({
browserName,
page,
isMobile
}) => {
- const referenceErrorRegex =
- /ReferenceError: (myName is not defined|Can't find variable: myName)/;
await focusEditor({ page, isMobile });
await replaceTextInCodeEditor({
browserName,
page,
isMobile,
text: 'myName',
- containerId: 'editor-container-scriptjs'
+ containerId: 'editor-container-scriptjs',
+ updatesConsole: true
});
if (isMobile) {
@@ -189,7 +198,7 @@ test.describe('Challenge Output Component Tests', () => {
page.getByRole('region', {
name: translations.learn['editor-tabs'].console
})
- ).toHaveText(referenceErrorRegex);
+ ).toContainText('ReferenceError: myName is not defined');
});
test('should contain final output after test fail', async ({
@@ -216,7 +225,8 @@ test.describe('Challenge Output Component Tests', () => {
page,
isMobile,
text: 'var myName;',
- containerId: 'editor-container-scriptjs'
+ containerId: 'editor-container-scriptjs',
+ updatesConsole: true
});
await runChallengeTest(page, isMobile);
await closeButton.click();
@@ -284,7 +294,7 @@ test.describe('Custom output for Set and Map', () => {
page.getByRole('region', {
name: translations.learn['editor-tabs'].console
})
- ).toContainText('Set(3) {1, set, 10}');
+ ).toContainText(`Set(3) {1, 'set', 10}`);
await focusEditor({ page, isMobile });
await replaceTextInCodeEditor({
@@ -303,6 +313,6 @@ test.describe('Custom output for Set and Map', () => {
page.getByRole('region', {
name: translations.learn['editor-tabs'].console
})
- ).toContainText('Map(2) {1 => one, two => 2}');
+ ).toContainText(`Map(2) {1 => 'one', 'two' => 2}`);
});
});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c3d1334dd95..3c294bbf44e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -227,7 +227,7 @@ importers:
version: 6.10.0(@aws-sdk/credential-providers@3.521.0)(socks@2.8.3)
nanoid:
specifier: '3'
- version: 3.3.11
+ version: 3.3.7
no-profanity:
specifier: 1.5.1
version: 1.5.1
@@ -297,7 +297,7 @@ importers:
version: 7.23.3(@babel/core@7.23.7)
'@babel/plugin-transform-runtime':
specifier: ^7.19.6
- version: 7.27.4(@babel/core@7.23.7)
+ version: 7.23.7(@babel/core@7.23.7)
'@babel/preset-env':
specifier: 7.23.7
version: 7.23.7(@babel/core@7.23.7)
@@ -637,7 +637,7 @@ importers:
version: 2.0.5
'@types/validator':
specifier: ^13.7.12
- version: 13.15.1
+ version: 13.11.2
autoprefixer:
specifier: 10.4.17
version: 10.4.17(postcss@8.4.35)
@@ -941,6 +941,9 @@ importers:
tools/client-plugins/browser-scripts:
dependencies:
+ '@freecodecamp/curriculum-helpers':
+ specifier: ^4.4.0
+ version: 4.4.0(typescript@5.8.2)
react:
specifier: '16'
version: 16.14.0
@@ -963,24 +966,9 @@ importers:
'@babel/preset-typescript':
specifier: 7.23.3
version: 7.23.3(@babel/core@7.23.7)
- '@freecodecamp/curriculum-helpers':
- specifier: 4.1.0
- version: 4.1.0
- '@types/chai':
- specifier: 4.3.12
- version: 4.3.12
'@types/copy-webpack-plugin':
specifier: ^8.0.1
version: 8.0.1(webpack-cli@4.10.0)
- '@types/enzyme':
- specifier: 3.10.16
- version: 3.10.16
- '@types/enzyme-adapter-react-16':
- specifier: 1.0.9
- version: 1.0.9
- '@types/jquery':
- specifier: 3.5.29
- version: 3.5.29
'@types/lodash-es':
specifier: 4.17.12
version: 4.17.12
@@ -990,21 +978,9 @@ importers:
babel-loader:
specifier: 8.3.0
version: 8.3.0(@babel/core@7.23.7)(webpack@5.90.3)
- chai:
- specifier: 4.4.1
- version: 4.4.1
copy-webpack-plugin:
specifier: 9.1.0
version: 9.1.0(webpack@5.90.3)
- enzyme:
- specifier: 3.11.0
- version: 3.11.0
- enzyme-adapter-react-16:
- specifier: 1.15.8
- version: 1.15.8(enzyme@3.11.0)(react-dom@16.14.0(react@16.14.0))(react@16.14.0)
- jquery:
- specifier: 3.7.1
- version: 3.7.1
lodash-es:
specifier: 4.17.21
version: 4.17.21
@@ -1483,10 +1459,6 @@ packages:
resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==}
engines: {node: '>=6.9.0'}
- '@babel/compat-data@7.27.3':
- resolution: {integrity: sha512-V42wFfx1ymFte+ecf6iXghnnP8kWTO+ZLXIyZq+1LAXHHvTZdVxicn4yiVYdYMGaCO3tmqub11AorKkv+iodqw==}
- engines: {node: '>=6.9.0'}
-
'@babel/core@7.10.5':
resolution: {integrity: sha512-O34LQooYVDXPl7QWCdW9p4NR+QlzOr7xShPPJz8GsuCU3/8ua/wqTr7gmnxXv+WBESiGU/G5s16i6tUvHkNb+w==}
engines: {node: '>=6.9.0'}
@@ -1545,10 +1517,6 @@ packages:
resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==}
engines: {node: '>=6.9.0'}
- '@babel/helper-compilation-targets@7.27.2':
- resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==}
- engines: {node: '>=6.9.0'}
-
'@babel/helper-create-class-features-plugin@7.22.15':
resolution: {integrity: sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==}
engines: {node: '>=6.9.0'}
@@ -1571,11 +1539,6 @@ packages:
peerDependencies:
'@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
- '@babel/helper-define-polyfill-provider@0.6.4':
- resolution: {integrity: sha512-jljfR1rGnXXNWnmQg2K3+bvhkxB51Rl32QRaOTuwwjviGrHzIbSc8+x9CpraDtbT7mfyjXObULP4w/adunNwAw==}
- peerDependencies:
- '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
-
'@babel/helper-environment-visitor@7.22.20':
resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==}
engines: {node: '>=6.9.0'}
@@ -1697,10 +1660,6 @@ packages:
resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==}
engines: {node: '>=6.9.0'}
- '@babel/helper-validator-option@7.27.1':
- resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
- engines: {node: '>=6.9.0'}
-
'@babel/helper-wrap-function@7.22.20':
resolution: {integrity: sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==}
engines: {node: '>=6.9.0'}
@@ -2270,12 +2229,6 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-transform-runtime@7.27.4':
- resolution: {integrity: sha512-D68nR5zxU64EUzV8i7T3R5XP0Xhrou/amNnddsRQssx6GrTLdZl1rLxyjtVZBd+v/NVX4AbTPOB5aU8thAZV1A==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
'@babel/plugin-transform-shorthand-properties@7.23.3':
resolution: {integrity: sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==}
engines: {node: '>=6.9.0'}
@@ -2943,8 +2896,8 @@ packages:
'@fortawesome/fontawesome-svg-core': ~1 || ~6
react: '>=16.3'
- '@freecodecamp/curriculum-helpers@4.1.0':
- resolution: {integrity: sha512-RdYiOJriKy/Bk+s9b79lq+K7z+prFRDDETpgHnb1peqdpiuMxdGTOw63poXj7c4SyXv/wteENP673midxAVdzA==}
+ '@freecodecamp/curriculum-helpers@4.4.0':
+ resolution: {integrity: sha512-TPjPj/Etm/YfFFDdRJUjYketDsbQ4fizrzUYuPpbL4CtAGIrz9gFEdNMpQmgiY4MG18aUAj7eCG05zUmFDdxIQ==}
engines: {pnpm: '>= 10'}
'@freecodecamp/loop-protect@3.0.0':
@@ -3673,6 +3626,11 @@ packages:
peerDependencies:
'@opentelemetry/api': ^1.8
+ '@puppeteer/browsers@2.10.5':
+ resolution: {integrity: sha512-eifa0o+i8dERnngJwKrfp3dEq7ia5XFyoqB17S4gK8GhsQE4/P8nxOfQSE0zQHxzzLo/cmF+7+ywEQ7wK7Fb+w==}
+ engines: {node: '>=18'}
+ hasBin: true
+
'@puppeteer/browsers@2.2.3':
resolution: {integrity: sha512-bJ0UBsk0ESOs6RFcLXOt99a3yTDcOKlzfjad+rhFwdaG1Lu/Wzq58GHYCDTlZ9z6mldf4g+NTb+TXEfe0PpnsQ==}
engines: {node: '>=18'}
@@ -3901,9 +3859,15 @@ packages:
'@sinonjs/commons@3.0.0':
resolution: {integrity: sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==}
+ '@sinonjs/commons@3.0.1':
+ resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==}
+
'@sinonjs/fake-timers@10.3.0':
resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==}
+ '@sinonjs/fake-timers@14.0.0':
+ resolution: {integrity: sha512-QfoXRaUTjMVVn/ZbnD4LS3TPtqOkOdKIYCKldIVPnuClcwRKat6LI2mRZ2s5qiBfO6Fy03An35dSls/2/FEc0Q==}
+
'@smithy/abort-controller@2.1.2':
resolution: {integrity: sha512-iwUxrFm/ZFCXhzhtZ6JnoJzAsqUrVfBAZUTQj8ypXGtIjwXZpKqmgYiuqrDERiydDI5gesqvsC4Rqe57GGhbVg==}
engines: {node: '>=14.0.0'}
@@ -4534,9 +4498,6 @@ packages:
'@types/canvas-confetti@1.9.0':
resolution: {integrity: sha512-aBGj/dULrimR1XDZLtG9JwxX1b4HPRF6CX9Yfwh3NvstZEm1ZL7RBnel4keCPSqs1ANRu1u2Aoz9R+VmtjYuTg==}
- '@types/chai@4.3.12':
- resolution: {integrity: sha512-zNKDHG/1yxm8Il6uCCVsm+dRdEsJlFoDu73X17y09bId6UwoYww+vFBsAcRzl8knM1sab3Dp1VRikFQwDOtDDw==}
-
'@types/chai@4.3.20':
resolution: {integrity: sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==}
@@ -4585,11 +4546,8 @@ packages:
'@types/enzyme-adapter-react-16@1.0.9':
resolution: {integrity: sha512-z24MMxGtUL8HhXdye3tWzjp+19QTsABqLaX2oOZpxMPHRJgLfahQmOeTTrEBQd9ogW20+UmPBXD9j+XOasFHvw==}
- '@types/enzyme@3.10.16':
- resolution: {integrity: sha512-17uMdJjSKjvdn/MhO/G2lRNPZGvJxFpvgONrsRoS1+khtJ6UcnCwC9v3gk2UqPyAkMZb6a1VYxScc/vOgkDl9w==}
-
- '@types/enzyme@3.10.18':
- resolution: {integrity: sha512-RaO/TyyHZvXkpzinbMTZmd/S5biU4zxkvDsn22ujC29t9FMSzq8tnn8f2MxQ2P8GVhFRG5jTAL05DXKyTtpEQQ==}
+ '@types/enzyme@3.10.19':
+ resolution: {integrity: sha512-kIfCo6/DdpgCHgmrLgPTugjzbZ46BUK8S2IP0kYo8+62LD2l1k8mSVsc+zQYNTdjDRoh2E9Spxu6F1NnEiW38Q==}
'@types/eslint-scope@3.7.5':
resolution: {integrity: sha512-JNvhIEyxVW6EoMIFIvj93ZOywYFatlpu9deeH6eSx6PE3WHYvHaQtmHmQeNw7aA81bYGBPPQqdtBm6b1SsQMmA==}
@@ -4684,8 +4642,8 @@ packages:
'@types/jest@29.5.12':
resolution: {integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==}
- '@types/jquery@3.5.29':
- resolution: {integrity: sha512-oXQQC9X9MOPRrMhPHHOsXqeQDnWeCDT3PelUIg/Oy8FAbzSZtFHRjc7IpbfFVmpLtJ+UOoywpRsuO5Jxjybyeg==}
+ '@types/jquery@3.5.32':
+ resolution: {integrity: sha512-b9Xbf4CkMqS02YH8zACqN1xzdxc3cO735Qe5AbSUFmyOiaWAbcpqh9Wna+Uk0vgACvoQHpWDg2rGdHkYPLmCiQ==}
'@types/js-yaml@4.0.5':
resolution: {integrity: sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==}
@@ -4856,6 +4814,9 @@ packages:
'@types/shimmer@1.2.0':
resolution: {integrity: sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg==}
+ '@types/sinonjs__fake-timers@8.1.5':
+ resolution: {integrity: sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==}
+
'@types/sizzle@2.3.4':
resolution: {integrity: sha512-jA2llq2zNkg8HrALI7DtWzhALcVH0l7i89yhY3iBdOz6cBPeACoFq+fkQrjHA39t1hnSFOboZ7A/AY5MMZSlag==}
@@ -4901,9 +4862,6 @@ packages:
'@types/validator@13.11.2':
resolution: {integrity: sha512-nIKVVQKT6kGKysnNt+xLobr+pFJNssJRi2s034wgWeFBUx01fI8BeHTW2TcRp7VcFu9QCYG8IlChTuovcm0oKQ==}
- '@types/validator@13.15.1':
- resolution: {integrity: sha512-9gG6ogYcoI2mCMLdcO0NYI0AYrbxIjv0MDmy/5Ywo6CpWWrqYayc+mmgxRsCgtcGJm9BSbXkMsmxGah1iGHAAQ==}
-
'@types/vfile-message@2.0.0':
resolution: {integrity: sha512-GpTIuDpb9u4zIO165fUy9+fXcULdD8HFRNli04GehoMVbeNq7D6OBnqSmg3lxZnC+UvgUhEWKxdKiwYUkGltIw==}
deprecated: This is a stub types definition. vfile-message provides its own type definitions, so you do not need this installed.
@@ -5429,16 +5387,14 @@ packages:
resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==}
engines: {node: '>= 14'}
+ agent-base@7.1.3:
+ resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==}
+ engines: {node: '>= 14'}
+
aggregate-error@3.1.0:
resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
engines: {node: '>=8'}
- airbnb-prop-types@2.16.0:
- resolution: {integrity: sha512-7WHOFolP/6cS96PhKNrslCLMYAI8yB1Pp6u6XmxozQOiZbsI5ycglZr5cHhBFfuRcQQjzCMith5ZPZdYiJCxUg==}
- deprecated: This package has been renamed to 'prop-types-tools'
- peerDependencies:
- react: ^0.14 || ^15.0.0 || ^16.0.0-alpha
-
ajv-formats@2.1.1:
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
peerDependencies:
@@ -5626,13 +5582,6 @@ packages:
resolution: {integrity: sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==}
engines: {node: '>=0.10.0'}
- array.prototype.filter@1.0.3:
- resolution: {integrity: sha512-VizNcj/RGJiUyQBgzwxzE5oHdeuXY5hSbbmKMlphj1cy1Vl7Pn2asCGbSrru6hSQjmCzqTBPVWAF/whmEOVHbw==}
- engines: {node: '>= 0.4'}
-
- array.prototype.find@2.2.2:
- resolution: {integrity: sha512-DRumkfW97iZGOfn+lIXbkVrXL04sfYKX+EfOodo8XboR5sxPDVvOjZTF/rysusa9lmhmSOeD6Vp6RKQP+eP4Tg==}
-
array.prototype.findlast@1.2.5:
resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==}
engines: {node: '>= 0.4'}
@@ -5719,6 +5668,9 @@ packages:
async@1.5.2:
resolution: {integrity: sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==}
+ async@3.2.6:
+ resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
+
asynciterator.prototype@1.0.0:
resolution: {integrity: sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==}
@@ -5767,6 +5719,9 @@ packages:
axios@0.21.4:
resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==}
+ axios@1.9.0:
+ resolution: {integrity: sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==}
+
axobject-query@3.2.1:
resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==}
@@ -5821,11 +5776,6 @@ packages:
resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==}
engines: {node: '>=10', npm: '>=6'}
- babel-plugin-polyfill-corejs2@0.4.13:
- resolution: {integrity: sha512-3sX/eOms8kd3q2KZ6DAhKPc0dgm525Gqq5NtWKZ7QYYZEv57OQ54KtblzJzH1lQF/eQxO8KjWGIK9IPUJNus5g==}
- peerDependencies:
- '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
-
babel-plugin-polyfill-corejs2@0.4.7:
resolution: {integrity: sha512-LidDk/tEGDfuHW2DWh/Hgo4rmnw3cduK6ZkOI1NPFceSK3n/yAGeOsNT7FLnSGHkXj3RHGSEVkN3FsCTY6w2CQ==}
peerDependencies:
@@ -5836,11 +5786,6 @@ packages:
peerDependencies:
'@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
- babel-plugin-polyfill-corejs3@0.11.1:
- resolution: {integrity: sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==}
- peerDependencies:
- '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
-
babel-plugin-polyfill-corejs3@0.8.7:
resolution: {integrity: sha512-KyDvZYxAzkC0Aj2dAPyDzi2Ym15e5JKZSK+maI7NAwSqofvuFglbSsxE7wUOvTg9oFVnHMzVzBKcqEb4PJgtOA==}
peerDependencies:
@@ -5851,11 +5796,6 @@ packages:
peerDependencies:
'@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
- babel-plugin-polyfill-regenerator@0.6.4:
- resolution: {integrity: sha512-7gD3pRadPrbjhjLyxebmx/WrFYcuSjZ0XbdUujQMZ/fcE9oeewk2U/7PCvez84UeuK3oSjmPZ0Ch0dlupQvGzw==}
- peerDependencies:
- '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
-
babel-plugin-preval@5.1.0:
resolution: {integrity: sha512-G5R+xmo5LS41A4UyZjOjV0mp9AvkuCyUOAJ6TOv/jTZS+VKh7L7HUDRcCSOb0YCM/u0fFarh7Diz0wjY8rFNFg==}
engines: {node: '>=10', npm: '>=6'}
@@ -5908,18 +5848,48 @@ packages:
bare-events@2.4.2:
resolution: {integrity: sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==}
+ bare-events@2.5.4:
+ resolution: {integrity: sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==}
+
bare-fs@2.3.1:
resolution: {integrity: sha512-W/Hfxc/6VehXlsgFtbB5B4xFcsCl+pAh30cYhoFyXErf6oGrwjh8SwiPAdHgpmWonKuYpZgGywN0SXt7dgsADA==}
+ bare-fs@4.1.5:
+ resolution: {integrity: sha512-1zccWBMypln0jEE05LzZt+V/8y8AQsQQqxtklqaIyg5nu6OAYFhZxPXinJTSG+kU5qyNmeLgcn9AW7eHiCHVLA==}
+ engines: {bare: '>=1.16.0'}
+ peerDependencies:
+ bare-buffer: '*'
+ peerDependenciesMeta:
+ bare-buffer:
+ optional: true
+
bare-os@2.4.0:
resolution: {integrity: sha512-v8DTT08AS/G0F9xrhyLtepoo9EJBJ85FRSMbu1pQUlAf6A8T0tEEQGMVObWeqpjhSPXsE0VGlluFBJu2fdoTNg==}
+ bare-os@3.6.1:
+ resolution: {integrity: sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g==}
+ engines: {bare: '>=1.14.0'}
+
bare-path@2.1.3:
resolution: {integrity: sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==}
+ bare-path@3.0.0:
+ resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==}
+
bare-stream@2.1.3:
resolution: {integrity: sha512-tiDAH9H/kP+tvNO5sczyn9ZAA7utrSMobyDchsnyyXBuUe2FSQWbxhtuHB8jwpHYYevVo2UJpcmvvjrbHboUUQ==}
+ bare-stream@2.6.5:
+ resolution: {integrity: sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==}
+ peerDependencies:
+ bare-buffer: '*'
+ bare-events: '*'
+ peerDependenciesMeta:
+ bare-buffer:
+ optional: true
+ bare-events:
+ optional: true
+
base-64@1.0.0:
resolution: {integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==}
@@ -6090,11 +6060,6 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
- browserslist@4.25.0:
- resolution: {integrity: sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==}
- engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
- hasBin: true
-
bs-logger@0.2.6:
resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==}
engines: {node: '>= 6'}
@@ -6285,13 +6250,6 @@ packages:
check-error@1.0.3:
resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==}
- cheerio-select@2.1.0:
- resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==}
-
- cheerio@1.0.0-rc.12:
- resolution: {integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==}
- engines: {node: '>= 6'}
-
chokidar@3.5.3:
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
engines: {node: '>= 8.10.0'}
@@ -6312,6 +6270,11 @@ packages:
peerDependencies:
devtools-protocol: '*'
+ chromium-bidi@5.1.0:
+ resolution: {integrity: sha512-9MSRhWRVoRPDG0TgzkHrshFSJJNZzfY5UFqUMuksg7zL1yoZIZ3jLB0YAgHclbiAxPI86pBnwDX1tbzoiV8aFw==}
+ peerDependencies:
+ devtools-protocol: '*'
+
ci-info@2.0.0:
resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==}
@@ -6459,6 +6422,10 @@ packages:
resolution: {integrity: sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==}
engines: {node: '>=16'}
+ commander@12.1.0:
+ resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==}
+ engines: {node: '>=18'}
+
commander@2.20.3:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
@@ -6596,9 +6563,6 @@ packages:
core-js-compat@3.36.0:
resolution: {integrity: sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==}
- core-js-compat@3.42.0:
- resolution: {integrity: sha512-bQasjMfyDGyaeWKBIu33lHh9qlSR0MFE/Nmc6nMjf/iU9b3rSMdAYz1Baxrv4lPdGUsTqZudHA4jIGSJy0SWZQ==}
-
core-js-compat@3.9.0:
resolution: {integrity: sha512-YK6fwFjCOKWwGnjFUR3c544YsnA/7DoLL0ysncuOJ4pwbriAtOpvM2bygdlcXbvQCQZ7bBU9CL4t7tGl7ETRpQ==}
@@ -6616,6 +6580,10 @@ packages:
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
engines: {node: '>= 0.10'}
+ corser@2.0.1:
+ resolution: {integrity: sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ==}
+ engines: {node: '>= 0.4.0'}
+
cosmiconfig-toml-loader@1.0.0:
resolution: {integrity: sha512-H/2gurFWVi7xXvCyvsWRLCMekl4tITJcX0QEsDMpzxtuxDyM59xLatYNg4s/k9AA/HdtCYfj2su8mgA0GSDLDA==}
@@ -6718,9 +6686,6 @@ packages:
css-select@4.3.0:
resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==}
- css-select@5.1.0:
- resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==}
-
css-selector-parser@1.4.1:
resolution: {integrity: sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g==}
@@ -6785,6 +6750,10 @@ packages:
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
+ cwd@0.10.0:
+ resolution: {integrity: sha512-YGZxdTTL9lmLkCUTpg4j0zQ7IhRB5ZmqNBbGCl3Tg6MP/d5/6sY7L5mmTjzbc6JKgVZYiqTQTNhPFsbXNGlRaA==}
+ engines: {node: '>=0.8'}
+
d@1.0.1:
resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==}
@@ -7048,6 +7017,9 @@ packages:
devtools-protocol@0.0.1299070:
resolution: {integrity: sha512-+qtL3eX50qsJ7c+qVyagqi7AWMoQCBGNfoyJZMwm/NSXVqLYbuitrWEEIzxfUmTNy7//Xe8yhMmQ+elj3uAqSg==}
+ devtools-protocol@0.0.1452169:
+ resolution: {integrity: sha512-FOFDVMGrAUNp0dDKsAU1TorWJUx2JOU1k9xdgBKKJF3IBh/Uhl2yswG5r3TEAOrCiGY2QRp1e6LVDQrCsTKO4g==}
+
dezalgo@1.0.4:
resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==}
@@ -7086,9 +7058,6 @@ packages:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'}
- discontinuous-range@1.0.0:
- resolution: {integrity: sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==}
-
doctrine@2.1.0:
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
engines: {node: '>=0.10.0'}
@@ -7202,9 +7171,6 @@ packages:
electron-to-chromium@1.4.685:
resolution: {integrity: sha512-yDYeobbTEe4TNooEzOQO6xFqg9XnAkVy2Lod1C1B2it8u47JNLYvl9nLDWBamqUakWB8Jc1hhS1uHUNYTNQdfw==}
- electron-to-chromium@1.5.161:
- resolution: {integrity: sha512-hwtetwfKNZo/UlwHIVBlKZVdy7o8bIZxxKs0Mv/ROPiQQQmDgdm5a+KvKtBsxM8ZjFzTaCeLoodZ8jiBE3o9rA==}
-
elliptic@6.5.4:
resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==}
@@ -7268,27 +7234,6 @@ packages:
engines: {node: '>=4'}
hasBin: true
- enzyme-adapter-react-16@1.15.8:
- resolution: {integrity: sha512-uYGC31eGZBp5nGsr4nKhZKvxGQjyHGjS06BJsUlWgE29/hvnpgCsT1BJvnnyny7N3GIIVyxZ4O9GChr6hy2WQA==}
- peerDependencies:
- enzyme: ^3.0.0
- react: ^16.0.0-0
- react-dom: ^16.0.0-0
-
- enzyme-adapter-utils@1.14.2:
- resolution: {integrity: sha512-1ZC++RlsYRaiOWE5NRaF5OgsMt7F5rn/VuaJIgc7eW/fmgg8eS1/Ut7EugSPPi7VMdWMLcymRnMF+mJUJ4B8KA==}
- peerDependencies:
- react: 0.13.x || 0.14.x || ^15.0.0-0 || ^16.0.0-0
-
- enzyme-shallow-equal@1.0.5:
- resolution: {integrity: sha512-i6cwm7hN630JXenxxJFBKzgLC3hMTafFQXflvzHgPmDhOBhxUWDe8AeRv1qp2/uWJ2Y8z5yLWMzmAfkTOiOCZg==}
-
- enzyme-shallow-equal@1.0.7:
- resolution: {integrity: sha512-/um0GFqUXnpM9SvKtje+9Tjoz3f1fpBC3eXRFrNs8kpYn69JljciYP7KZTqM/YQbUY9KUjvKB4jo/q+L6WGGvg==}
-
- enzyme@3.11.0:
- resolution: {integrity: sha512-Dw8/Gs4vRjxY6/6i9wU0V+utmQO9kvh9XLnz3LIudviOnVYDEe2ec+0k+NQoMamn1VrjKgCUOWj5jG/5M5M0Qw==}
-
eol@0.9.1:
resolution: {integrity: sha512-Ds/TEoZjwggRoz/Q2O7SE3i4Jm66mqTDfmdHdq/7DKVk3bro9Q8h6WdXKdPqFLMoqxrDK5SVRzHVPOS6uuGtrg==}
@@ -7306,9 +7251,6 @@ packages:
resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==}
engines: {node: '>= 0.4'}
- es-array-method-boxes-properly@1.0.0:
- resolution: {integrity: sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==}
-
es-define-property@1.0.0:
resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==}
engines: {node: '>= 0.4'}
@@ -7395,10 +7337,6 @@ packages:
resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==}
engines: {node: '>=6'}
- escalade@3.2.0:
- resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
- engines: {node: '>=6'}
-
escape-goat@2.1.1:
resolution: {integrity: sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==}
engines: {node: '>=8'}
@@ -7764,6 +7702,14 @@ packages:
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
engines: {node: '>=6'}
+ expand-tilde@1.2.2:
+ resolution: {integrity: sha512-rtmc+cjLZqnu9dSYosX9EWmSJhTwpACgJQTfj4hgg2JjOD/6SIQalZrt4a3aQeh++oNxkazcaxrhPUj6+g5G/Q==}
+ engines: {node: '>=0.10.0'}
+
+ expect-puppeteer@11.0.0:
+ resolution: {integrity: sha512-fgxsbOD+HqwOCMitYqEDzRoJM2fxKbCKPYfUoukK+qdZm/nC+cTOI74Au2MfmMZmF/5CgQGO4+1Ywq2GgD8zCQ==}
+ engines: {node: '>=18'}
+
expect@29.7.0:
resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -7982,10 +7928,22 @@ packages:
resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==}
engines: {node: '>=8'}
+ find-file-up@0.1.3:
+ resolution: {integrity: sha512-mBxmNbVyjg1LQIIpgO8hN+ybWBgDQK8qjht+EbrTCGmmPV/sc7RF1i9stPTD6bpvXZywBdrwRYxhSdJv867L6A==}
+ engines: {node: '>=0.10.0'}
+
find-my-way@9.3.0:
resolution: {integrity: sha512-eRoFWQw+Yv2tuYlK2pjFS2jGXSxSppAs3hSQjfxVKxM5amECzIgYYc1FEI8ZmhSh/Ig+FrKEz43NLRKJjYCZVg==}
engines: {node: '>=20'}
+ find-pkg@0.1.2:
+ resolution: {integrity: sha512-0rnQWcFwZr7eO0513HahrWafsc3CTFioEB7DRiEYCUM/70QXSY8f3mCST17HXLcPvEhzH/Ty/Bxd72ZZsr/yvw==}
+ engines: {node: '>=0.10.0'}
+
+ find-process@1.4.10:
+ resolution: {integrity: sha512-ncYFnWEIwL7PzmrK1yZtaccN8GhethD37RzBHG6iOZoFYB4vSmLLXfeWJjeN5nMvCJMjOtBvBBF8OgxEcikiZg==}
+ hasBin: true
+
find-up@3.0.0:
resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==}
engines: {node: '>=6'}
@@ -8028,6 +7986,15 @@ packages:
debug:
optional: true
+ follow-redirects@1.15.9:
+ resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
+ engines: {node: '>=4.0'}
+ peerDependencies:
+ debug: '*'
+ peerDependenciesMeta:
+ debug:
+ optional: true
+
for-each@0.3.3:
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
@@ -8108,6 +8075,10 @@ packages:
fs-exists-cached@1.0.0:
resolution: {integrity: sha512-kSxoARUDn4F2RPXX48UXnaFKwVU7Ivd/6qpzZL29MCDmr9sTvybv4gFCp+qaI4fM9m0z9fgz/yJvi56GAz+BZg==}
+ fs-exists-sync@0.1.0:
+ resolution: {integrity: sha512-cR/vflFyPZtrN6b38ZyWxpWdhlXrzZEBawlpBQMq7033xVY7/kg0GDMBK5jg8lDYQckdJ5x/YC88lM3C7VMsLg==}
+ engines: {node: '>=0.10.0'}
+
fs-extra@10.1.0:
resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
engines: {node: '>=12'}
@@ -8397,10 +8368,18 @@ packages:
resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==}
engines: {node: '>=10'}
+ global-modules@0.2.3:
+ resolution: {integrity: sha512-JeXuCbvYzYXcwE6acL9V2bAOeSIGl4dD+iwLY9iUx2VBJJ80R18HCn+JCwHM9Oegdfya3lEkGCdaRkSyc10hDA==}
+ engines: {node: '>=0.10.0'}
+
global-modules@2.0.0:
resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==}
engines: {node: '>=6'}
+ global-prefix@0.1.5:
+ resolution: {integrity: sha512-gOPiyxcD9dJGCEArAhF4Hd0BAqvAe/JzERP7tYumE4yIkmIedPUVXcJFWbV3/p/ovIIvKjkrTk+f1UVkq7vvbw==}
+ engines: {node: '>=0.10.0'}
+
global-prefix@3.0.0:
resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==}
engines: {node: '>=6'}
@@ -8603,10 +8582,6 @@ packages:
resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==}
engines: {node: '>=8'}
- hasown@2.0.0:
- resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==}
- engines: {node: '>= 0.4'}
-
hasown@2.0.1:
resolution: {integrity: sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==}
engines: {node: '>= 0.4'}
@@ -8676,6 +8651,10 @@ packages:
hoist-non-react-statics@3.3.2:
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
+ homedir-polyfill@1.0.3:
+ resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==}
+ engines: {node: '>=0.10.0'}
+
hookified@1.7.1:
resolution: {integrity: sha512-OXcdHsXeOiD7OJ5zvWj8Oy/6RCdLwntAX+wUrfemNcMGn6sux4xbEHi2QXwqePYhjQ/yvxxq2MvCRirdlHscBw==}
@@ -8689,9 +8668,6 @@ packages:
htm@3.1.1:
resolution: {integrity: sha512-983Vyg8NwUE7JkZ6NmOqpCZ+sh1bKv2iYTlUkzlWmA5JD2acKoxd4KVxbMmxX/85mtfdnDmTFoNKcg5DGAvxNQ==}
- html-element-map@1.3.1:
- resolution: {integrity: sha512-6XMlxrAFX4UEEGxctfFnmrFaaZFNf9i5fNuV5wZ3WWQ4FVaNP1aX1LkX9j2mfEx1NpjeE/rL3nmgEn23GdFmrg==}
-
html-encoding-sniffer@2.0.1:
resolution: {integrity: sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==}
engines: {node: '>=10'}
@@ -8774,6 +8750,11 @@ packages:
resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==}
engines: {node: '>=8.0.0'}
+ http-server@14.1.1:
+ resolution: {integrity: sha512-+cbxadF40UXd9T01zUHgA+rlo2Bg1Srer4+B4NwIHdaGxAGGv59nYRnGGDJ9LBk7alpS0US+J+bLLdQOOkJq4A==}
+ engines: {node: '>=12'}
+ hasBin: true
+
http2-wrapper@1.0.3:
resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==}
engines: {node: '>=10.19.0'}
@@ -8789,6 +8770,10 @@ packages:
resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==}
engines: {node: '>= 14'}
+ https-proxy-agent@7.0.6:
+ resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
+ engines: {node: '>= 14'}
+
human-signals@2.1.0:
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
engines: {node: '>=10.17.0'}
@@ -9306,9 +9291,6 @@ packages:
resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==}
engines: {node: '>= 0.4'}
- is-subset@0.1.1:
- resolution: {integrity: sha512-6Ybun0IkarhmEqxXCNw/C0bna6Zb/TkfUX9UbwJtK6ObwAVCxmAP308WWTHviM/zAqXk05cdhYsUsZeGQh99iw==}
-
is-symbol@1.0.4:
resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==}
engines: {node: '>= 0.4'}
@@ -9370,6 +9352,10 @@ packages:
is-whitespace-character@1.0.4:
resolution: {integrity: sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==}
+ is-windows@0.2.0:
+ resolution: {integrity: sha512-n67eJYmXbniZB7RF4I/FTjK1s6RPOCTxhYrVYLRaCt3lF0mpWZPKr3T2LSZAqyjQsxR2qMmGYXXzK0YWwcPM1Q==}
+ engines: {node: '>=0.10.0'}
+
is-windows@1.0.2:
resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==}
engines: {node: '>=0.10.0'}
@@ -9626,6 +9612,9 @@ packages:
joi@17.12.2:
resolution: {integrity: sha512-RonXAIzCiHLc8ss3Ibuz45u28GOsWE1UpfDXLbN/9NKbL4tCJf8TWYVKsoYuuh+sAUt7fsSNpA+r2+TBA6Wjmw==}
+ joi@17.13.3:
+ resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==}
+
joycon@3.1.1:
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
engines: {node: '>=10'}
@@ -9895,9 +9884,6 @@ packages:
lodash.deburr@4.1.0:
resolution: {integrity: sha512-m/M1U1f3ddMCs6Hq2tAsYThTBDaAKFDX3dwDo97GEYzamXi9SqUpjWi/Rrj/gf3X2n8ktwgZrlP1z6E3v/IExQ==}
- lodash.escape@4.0.1:
- resolution: {integrity: sha512-nXEOnb/jK9g0DYMr1/Xvq6l5xMD7GDG55+GSYIYmS0G4tBk/hURD4JR9WCavs04t33WmJx9kCyp9vJ+mr4BOUw==}
-
lodash.every@4.6.0:
resolution: {integrity: sha512-isF82d+65/sNvQ3aaQAW7LLHnnTxSN/2fm4rhYyuufLzA4VtHz6y6S5vFwe6PQVr2xdqUOyxBbTNKDpnmeu50w==}
@@ -9983,6 +9969,10 @@ packages:
resolution: {integrity: sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ loglevel@1.9.2:
+ resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==}
+ engines: {node: '>= 0.6.0'}
+
longest-streak@2.0.4:
resolution: {integrity: sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==}
@@ -10641,9 +10631,6 @@ packages:
socks:
optional: true
- moo@0.5.2:
- resolution: {integrity: sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==}
-
morgan@1.10.0:
resolution: {integrity: sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==}
engines: {node: '>= 0.8.0'}
@@ -10727,10 +10714,6 @@ packages:
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
- nearley@2.20.1:
- resolution: {integrity: sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==}
- hasBin: true
-
negotiator@0.6.3:
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
engines: {node: '>= 0.6'}
@@ -10806,9 +10789,6 @@ packages:
node-releases@2.0.14:
resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
- node-releases@2.0.19:
- resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
-
nodemailer@6.9.10:
resolution: {integrity: sha512-qtoKfGFhvIFW5kLfrkw2R6Nm6Ur4LNUMykyqu6n9BRKJuyQrqEGwdXXUAbwWEKt33dlWUGXb7rzmJP/p4+O+CA==}
engines: {node: '>=6.0.0'}
@@ -11008,6 +10988,10 @@ packages:
os-browserify@0.3.0:
resolution: {integrity: sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==}
+ os-homedir@1.0.2:
+ resolution: {integrity: sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==}
+ engines: {node: '>=0.10.0'}
+
os-tmpdir@1.0.2:
resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==}
engines: {node: '>=0.10.0'}
@@ -11075,6 +11059,10 @@ packages:
resolution: {integrity: sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==}
engines: {node: '>= 14'}
+ pac-proxy-agent@7.2.0:
+ resolution: {integrity: sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==}
+ engines: {node: '>= 14'}
+
pac-resolver@7.0.1:
resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==}
engines: {node: '>= 14'}
@@ -11118,6 +11106,10 @@ packages:
parse-latin@4.3.0:
resolution: {integrity: sha512-TYKL+K98dcAWoCw/Ac1yrPviU8Trk+/gmjQVaoWEFDZmVD4KRg6c/80xKqNNFQObo2mTONgF8trzAf2UTwKafw==}
+ parse-passwd@1.0.0:
+ resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==}
+ engines: {node: '>=0.10.0'}
+
parse-path@4.0.4:
resolution: {integrity: sha512-Z2lWUis7jlmXC1jeOG9giRO2+FsuyNipeQ43HAjqAZjwSe3SEf+q/84FGPHoso3kyntbxa4c4i77t3m6fGf8cw==}
@@ -11127,9 +11119,6 @@ packages:
parse-url@6.0.5:
resolution: {integrity: sha512-e35AeLTSIlkw/5GFq70IN7po8fmDUjpDPY1rIK+VubRfsUvBonjQ+PBZG+vWMACnQSmNlvl524IucoDmcioMxA==}
- parse5-htmlparser2-tree-adapter@7.0.0:
- resolution: {integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==}
-
parse5@6.0.1:
resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==}
@@ -11231,9 +11220,6 @@ packages:
pend@1.2.0:
resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
- performance-now@2.1.0:
- resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
-
pg-int8@1.0.1:
resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==}
engines: {node: '>=4.0.0'}
@@ -11332,6 +11318,10 @@ packages:
resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==}
engines: {node: '>=4'}
+ portfinder@1.0.37:
+ resolution: {integrity: sha512-yuGIEjDAYnnOex9ddMnKZEMFE0CcGo6zbfzDklkmT1m5z734ss6JMzN9rNB3+RR7iS+F10D4/BVIaXOyh8PQKw==}
+ engines: {node: '>= 10.12'}
+
posix-character-classes@0.1.1:
resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==}
engines: {node: '>=0.10.0'}
@@ -11679,9 +11669,6 @@ packages:
resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
engines: {node: '>= 6'}
- prop-types-exact@1.2.0:
- resolution: {integrity: sha512-K+Tk3Kd9V0odiXFP9fwDHUYRyvK3Nun3GVyPapSIs5OBkITAm15W0CPFD/YKTkMUAbc0b9CUwRQp2ybiBIq+eA==}
-
prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
@@ -11705,6 +11692,10 @@ packages:
resolution: {integrity: sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==}
engines: {node: '>= 14'}
+ proxy-agent@6.5.0:
+ resolution: {integrity: sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==}
+ engines: {node: '>= 14'}
+
proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
@@ -11743,14 +11734,26 @@ packages:
resolution: {integrity: sha512-XmqeDPVdC5/3nGJys1jbgeoZ02wP0WV1GBlPtr/ULRbGXJFuqgXMcKQ3eeNtFpBzGRbpeoCGWHge1ZWKWl0Exw==}
engines: {node: '>=18'}
+ puppeteer-core@24.10.0:
+ resolution: {integrity: sha512-xX0QJRc8t19iAwRDsAOR38Q/Zx/W6WVzJCEhKCAwp2XMsaWqfNtQ+rBfQW9PlF+Op24d7c8Zlgq9YNmbnA7hdQ==}
+ engines: {node: '>=18'}
+
puppeteer@22.12.1:
resolution: {integrity: sha512-1GxY8dnEnHr1SLzdSDr0FCjM6JQfAh2E2I/EqzeF8a58DbGVk9oVjj4lFdqNoVbpgFSpAbz7VER9St7S1wDpNg==}
engines: {node: '>=18'}
hasBin: true
+ puppeteer@24.10.0:
+ resolution: {integrity: sha512-Oua9VkGpj0S2psYu5e6mCer6W9AU9POEQh22wRgSXnLXASGH+MwLUVWgLCLeP9QPHHcJ7tySUlg4Sa9OJmaLpw==}
+ engines: {node: '>=18'}
+ hasBin: true
+
pure-rand@6.0.4:
resolution: {integrity: sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==}
+ pyodide@0.23.3:
+ resolution: {integrity: sha512-t95Nu73ENjwoRhThmxvZIHMD7GXTJ3uOt/E0sJ1TxjBvoU/qPys4SV08FtZBMEnpMRKFzE4uecvx2c0qybSZhw==}
+
pyodide@0.23.4:
resolution: {integrity: sha512-WpQUHaIXQ1xede5BMqPAjBcmopxN22s5hEsYOR8T7/UW/fkNLFUn07SaemUgthbtvedD5JGymMMj4VpD9sGMTg==}
@@ -11816,16 +11819,6 @@ packages:
resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
engines: {node: '>=10'}
- raf@3.4.1:
- resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==}
-
- railroad-diagrams@1.0.0:
- resolution: {integrity: sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==}
-
- randexp@0.4.6:
- resolution: {integrity: sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==}
- engines: {node: '>=0.12'}
-
randombytes@2.1.0:
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
@@ -12029,11 +12022,6 @@ packages:
react-spinkit@3.0.0:
resolution: {integrity: sha512-RrfGRPjqxHQiy7quPqhjPynTu0zobgQaZu1QYBMpJJ6pCSRRRK16EZMaxdE6fLVYFRJWpX/eGATWLMoVFFT5uQ==}
- react-test-renderer@16.14.0:
- resolution: {integrity: sha512-L8yPjqPE5CZO6rKsKXRO/rVPiaCOy0tQQJbC+UjPNlobl5mad59lvPjwFsQHTvL03caVDIVr9x9/OSgDe6I5Eg==}
- peerDependencies:
- react: ^16.14.0
-
react-test-renderer@17.0.2:
resolution: {integrity: sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ==}
peerDependencies:
@@ -12157,9 +12145,6 @@ packages:
resolution: {integrity: sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==}
engines: {node: '>= 0.4'}
- reflect.ownkeys@0.2.0:
- resolution: {integrity: sha512-qOLsBKHCpSOFKK1NUOCGC5VyeufB6lEsFe92AL2bhIJsacZS1qdoOZSbPk3MYKuT2cFlRDnulKXuuElIrMjGUg==}
-
regenerate-unicode-properties@10.1.1:
resolution: {integrity: sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==}
engines: {node: '>=4'}
@@ -12307,6 +12292,10 @@ packages:
resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
engines: {node: '>=8'}
+ resolve-dir@0.1.1:
+ resolution: {integrity: sha512-QxMPqI6le2u0dCLyiGzgy92kjkkL6zO0XyvHzjdTNH3zM6e5Hz3BwG6+aEyNgiQ5Xz6PwTwgQEj3U50dByPKIA==}
+ engines: {node: '>=0.10.0'}
+
resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
@@ -12401,9 +12390,6 @@ packages:
resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==}
engines: {node: '>= 18'}
- rst-selector-parser@2.2.3:
- resolution: {integrity: sha512-nDG1rZeP6oFTLN6yNDV/uiAvs1+FS/KlrEwh7+y7dpuApDBy6bI2HTBcc0/V8lv9OTqfyD34eF7au2pm8aBbhA==}
-
run-async@2.4.1:
resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==}
engines: {node: '>=0.12.0'}
@@ -12418,6 +12404,9 @@ packages:
rxjs@7.8.1:
resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
+ rxjs@7.8.2:
+ resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==}
+
sade@1.8.1:
resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
engines: {node: '>=6'}
@@ -12498,6 +12487,9 @@ packages:
resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==}
engines: {node: '>=4'}
+ secure-compare@3.0.1:
+ resolution: {integrity: sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==}
+
secure-json-parse@2.7.0:
resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==}
@@ -12765,6 +12757,10 @@ packages:
resolution: {integrity: sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==}
engines: {node: '>= 14'}
+ socks-proxy-agent@8.0.5:
+ resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==}
+ engines: {node: '>= 14'}
+
socks@2.8.3:
resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==}
engines: {node: '>= 10.0.0', npm: '>= 3.0.0'}
@@ -12822,6 +12818,10 @@ packages:
sparse-bitfield@3.0.3:
resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==}
+ spawnd@11.0.0:
+ resolution: {integrity: sha512-brBHv9HYi8lwNvbI7X52NDZe4yAdsQwvr81b/r98LaN82LzeEnQ0L6YXBvG25zhgWRadTwB+4GsUu9NrNQcVzw==}
+ engines: {node: '>=18'}
+
spdx-correct@3.2.0:
resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==}
@@ -12926,6 +12926,9 @@ packages:
streamx@2.18.0:
resolution: {integrity: sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==}
+ streamx@2.22.1:
+ resolution: {integrity: sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA==}
+
strict-event-emitter@0.5.1:
resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==}
@@ -13187,6 +13190,9 @@ packages:
tar-fs@3.0.5:
resolution: {integrity: sha512-JOgGAmZyMgbqpLwct7ZV8VzkEB6pxXFBVErLtb+XCOqzc6w1xiWKI9GVd6bwk68EX7eJ4DWmfXVmq8K2ziZTGg==}
+ tar-fs@3.0.9:
+ resolution: {integrity: sha512-XF4w9Xp+ZQgifKakjZYmFdkLoSWd34VGKcsTCwlNWM7QG3ZbaxnTsaBwnjFZqHRf/rROxaR8rXnbtwdvaDI+lA==}
+
tar-stream@2.2.0:
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
engines: {node: '>=6'}
@@ -13363,6 +13369,10 @@ packages:
resolution: {integrity: sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==}
engines: {node: '>=14'}
+ tree-kill@1.2.2:
+ resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
+ hasBin: true
+
trim-trailing-lines@1.1.4:
resolution: {integrity: sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==}
@@ -13555,6 +13565,9 @@ packages:
resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==}
engines: {node: '>= 0.4'}
+ typed-query-selector@2.12.0:
+ resolution: {integrity: sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==}
+
typedarray-to-buffer@3.1.5:
resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==}
@@ -13655,6 +13668,10 @@ packages:
resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==}
engines: {node: '>=0.10.0'}
+ union@0.5.0:
+ resolution: {integrity: sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==}
+ engines: {node: '>= 0.8.0'}
+
unique-string@2.0.0:
resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==}
engines: {node: '>=8'}
@@ -13779,12 +13796,6 @@ packages:
peerDependencies:
browserslist: '>= 4.21.0'
- update-browserslist-db@1.1.3:
- resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==}
- hasBin: true
- peerDependencies:
- browserslist: '>= 4.21.0'
-
update-check@1.5.2:
resolution: {integrity: sha512-1TrmYLuLj/5ZovwUS7fFd1jMH3NnFDN1y1A8dboedIDt7zs/zJMo6TwwlhYKkSeEwzleeiSBV5/3c9ufAQWDaQ==}
@@ -13799,6 +13810,9 @@ packages:
resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==}
deprecated: Please see https://github.com/lydell/urix#deprecated
+ url-join@4.0.1:
+ resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==}
+
url-loader@4.1.1:
resolution: {integrity: sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==}
engines: {node: '>= 10.13.0'}
@@ -13949,6 +13963,14 @@ packages:
terser:
optional: true
+ vitest-dev-server@11.0.3:
+ resolution: {integrity: sha512-aRZDLG+Q2T0fLWJSJpZaq3nN0HRzCcbp7ViPWpjIrdQ4ZojCuCxKHiRtV6K8oPgkFRTO/N+ST9lyxc0xtKbRsA==}
+ engines: {node: '>=18'}
+
+ vitest-environment-puppeteer@11.0.3:
+ resolution: {integrity: sha512-Z74YeB1fSk1cF3NSLsK7Yr2q60wvtxHPTv7xj4yhZ4LTe5CZHRC6h6Rbf7gZKjXz6Z9bsM9WVbA3UyxAcPaYDw==}
+ engines: {node: '>=18'}
+
vm-browserify@1.1.2:
resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==}
@@ -13968,6 +13990,11 @@ packages:
resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==}
engines: {node: '>=14'}
+ wait-on@8.0.3:
+ resolution: {integrity: sha512-nQFqAFzZDeRxsu7S3C7LbuxslHhk+gnJZHyethuGKAn2IVleIbTB9I3vJSQiSR+DifUqmdzfPMoMPJfLqMF2vw==}
+ engines: {node: '>=12.0.0'}
+ hasBin: true
+
walker@1.0.8:
resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
@@ -14235,6 +14262,18 @@ packages:
utf-8-validate:
optional: true
+ ws@8.18.2:
+ resolution: {integrity: sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==}
+ engines: {node: '>=10.0.0'}
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: '>=5.0.2'
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+
x-is-string@0.1.0:
resolution: {integrity: sha512-GojqklwG8gpzOVEVki5KudKNoq7MbbjYZCbyWzEz7tyPA7eleiE0+ePwOWQQRb5fm86rD3S8Tc0tSFf3AOv50w==}
@@ -14376,6 +14415,9 @@ packages:
zod@3.23.8:
resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==}
+ zod@3.25.51:
+ resolution: {integrity: sha512-TQSnBldh+XSGL+opiSIq0575wvDPqu09AqWe1F7JhUMKY+M91/aGlK4MhpVNO7MgYfHcVCB1ffwAUTJzllKJqg==}
+
zwitch@1.0.5:
resolution: {integrity: sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==}
@@ -15425,8 +15467,6 @@ snapshots:
'@babel/compat-data@7.23.5': {}
- '@babel/compat-data@7.27.3': {}
-
'@babel/core@7.10.5':
dependencies:
'@babel/code-frame': 7.22.13
@@ -15438,7 +15478,7 @@ snapshots:
'@babel/traverse': 7.27.4
'@babel/types': 7.23.9
convert-source-map: 1.9.0
- debug: 4.4.1
+ debug: 4.3.4(supports-color@8.1.1)
gensync: 1.0.0-beta.2
json5: 2.2.3
lodash: 4.17.21
@@ -15554,14 +15594,6 @@ snapshots:
lru-cache: 5.1.1
semver: 6.3.1
- '@babel/helper-compilation-targets@7.27.2':
- dependencies:
- '@babel/compat-data': 7.27.3
- '@babel/helper-validator-option': 7.27.1
- browserslist: 4.25.0
- lru-cache: 5.1.1
- semver: 6.3.1
-
'@babel/helper-create-class-features-plugin@7.22.15(@babel/core@7.23.0)':
dependencies:
'@babel/core': 7.23.0
@@ -15646,28 +15678,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@babel/helper-define-polyfill-provider@0.6.4(@babel/core@7.23.0)':
- dependencies:
- '@babel/core': 7.23.0
- '@babel/helper-compilation-targets': 7.27.2
- '@babel/helper-plugin-utils': 7.27.1
- debug: 4.4.1
- lodash.debounce: 4.0.8
- resolve: 1.22.10
- transitivePeerDependencies:
- - supports-color
-
- '@babel/helper-define-polyfill-provider@0.6.4(@babel/core@7.23.7)':
- dependencies:
- '@babel/core': 7.23.7
- '@babel/helper-compilation-targets': 7.27.2
- '@babel/helper-plugin-utils': 7.27.1
- debug: 4.4.1
- lodash.debounce: 4.0.8
- resolve: 1.22.10
- transitivePeerDependencies:
- - supports-color
-
'@babel/helper-environment-visitor@7.22.20': {}
'@babel/helper-function-name@7.23.0':
@@ -15808,8 +15818,6 @@ snapshots:
'@babel/helper-validator-option@7.25.9': {}
- '@babel/helper-validator-option@7.27.1': {}
-
'@babel/helper-wrap-function@7.22.20':
dependencies:
'@babel/helper-function-name': 7.23.0
@@ -16823,6 +16831,18 @@ snapshots:
'@babel/core': 7.23.7
'@babel/helper-plugin-utils': 7.22.5
+ '@babel/plugin-transform-runtime@7.23.7(@babel/core@7.23.0)':
+ dependencies:
+ '@babel/core': 7.23.0
+ '@babel/helper-module-imports': 7.22.15
+ '@babel/helper-plugin-utils': 7.22.5
+ babel-plugin-polyfill-corejs2: 0.4.7(@babel/core@7.23.0)
+ babel-plugin-polyfill-corejs3: 0.8.7(@babel/core@7.23.0)
+ babel-plugin-polyfill-regenerator: 0.5.5(@babel/core@7.23.0)
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
'@babel/plugin-transform-runtime@7.23.7(@babel/core@7.23.7)':
dependencies:
'@babel/core': 7.23.7
@@ -16835,30 +16855,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@babel/plugin-transform-runtime@7.27.4(@babel/core@7.23.0)':
- dependencies:
- '@babel/core': 7.23.0
- '@babel/helper-module-imports': 7.27.1
- '@babel/helper-plugin-utils': 7.27.1
- babel-plugin-polyfill-corejs2: 0.4.13(@babel/core@7.23.0)
- babel-plugin-polyfill-corejs3: 0.11.1(@babel/core@7.23.0)
- babel-plugin-polyfill-regenerator: 0.6.4(@babel/core@7.23.0)
- semver: 6.3.1
- transitivePeerDependencies:
- - supports-color
-
- '@babel/plugin-transform-runtime@7.27.4(@babel/core@7.23.7)':
- dependencies:
- '@babel/core': 7.23.7
- '@babel/helper-module-imports': 7.27.1
- '@babel/helper-plugin-utils': 7.27.1
- babel-plugin-polyfill-corejs2: 0.4.13(@babel/core@7.23.7)
- babel-plugin-polyfill-corejs3: 0.11.1(@babel/core@7.23.7)
- babel-plugin-polyfill-regenerator: 0.6.4(@babel/core@7.23.7)
- semver: 6.3.1
- transitivePeerDependencies:
- - supports-color
-
'@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.23.0)':
dependencies:
'@babel/core': 7.23.0
@@ -17282,7 +17278,7 @@ snapshots:
'@babel/parser': 7.26.9
'@babel/template': 7.26.9
'@babel/types': 7.26.9
- debug: 4.4.1
+ debug: 4.3.4(supports-color@8.1.1)
globals: 11.12.0
transitivePeerDependencies:
- supports-color
@@ -17294,7 +17290,7 @@ snapshots:
'@babel/parser': 7.27.4
'@babel/template': 7.27.2
'@babel/types': 7.27.3
- debug: 4.4.1
+ debug: 4.3.4(supports-color@8.1.1)
globals: 11.12.0
transitivePeerDependencies:
- supports-color
@@ -17763,9 +17759,31 @@ snapshots:
prop-types: 15.8.1
react: 17.0.2
- '@freecodecamp/curriculum-helpers@4.1.0':
+ '@freecodecamp/curriculum-helpers@4.4.0(typescript@5.8.2)':
dependencies:
+ '@sinonjs/fake-timers': 14.0.0
+ '@types/enzyme': 3.10.19
+ '@types/enzyme-adapter-react-16': 1.0.9
+ '@types/jquery': 3.5.32
+ '@types/sinonjs__fake-timers': 8.1.5
browserify: 17.0.0
+ chai: 4.4.1
+ expect-puppeteer: 11.0.0
+ http-server: 14.1.1
+ jquery: 3.7.1
+ process: 0.11.10
+ puppeteer: 24.10.0(typescript@5.8.2)
+ pyodide: 0.23.3
+ util: 0.12.5
+ vitest-environment-puppeteer: 11.0.3(typescript@5.8.2)
+ transitivePeerDependencies:
+ - bare-buffer
+ - bufferutil
+ - debug
+ - encoding
+ - supports-color
+ - typescript
+ - utf-8-validate
'@freecodecamp/loop-protect@3.0.0': {}
@@ -18730,6 +18748,19 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@puppeteer/browsers@2.10.5':
+ dependencies:
+ debug: 4.4.1
+ extract-zip: 2.0.1
+ progress: 2.0.3
+ proxy-agent: 6.5.0
+ semver: 7.7.2
+ tar-fs: 3.0.9
+ yargs: 17.7.2
+ transitivePeerDependencies:
+ - bare-buffer
+ - supports-color
+
'@puppeteer/browsers@2.2.3':
dependencies:
debug: 4.3.4(supports-color@8.1.1)
@@ -18976,10 +19007,18 @@ snapshots:
dependencies:
type-detect: 4.0.8
+ '@sinonjs/commons@3.0.1':
+ dependencies:
+ type-detect: 4.0.8
+
'@sinonjs/fake-timers@10.3.0':
dependencies:
'@sinonjs/commons': 3.0.0
+ '@sinonjs/fake-timers@14.0.0':
+ dependencies:
+ '@sinonjs/commons': 3.0.1
+
'@smithy/abort-controller@2.1.2':
dependencies:
'@smithy/types': 2.10.0
@@ -19996,8 +20035,6 @@ snapshots:
'@types/canvas-confetti@1.9.0': {}
- '@types/chai@4.3.12': {}
-
'@types/chai@4.3.20': {}
'@types/cheerio@0.22.35':
@@ -20049,14 +20086,9 @@ snapshots:
'@types/enzyme-adapter-react-16@1.0.9':
dependencies:
- '@types/enzyme': 3.10.18
+ '@types/enzyme': 3.10.19
- '@types/enzyme@3.10.16':
- dependencies:
- '@types/cheerio': 0.22.35
- '@types/react': 16.14.56
-
- '@types/enzyme@3.10.18':
+ '@types/enzyme@3.10.19':
dependencies:
'@types/cheerio': 0.22.35
'@types/react': 16.14.56
@@ -20186,7 +20218,7 @@ snapshots:
expect: 29.7.0
pretty-format: 29.7.0
- '@types/jquery@3.5.29':
+ '@types/jquery@3.5.32':
dependencies:
'@types/sizzle': 2.3.4
@@ -20380,6 +20412,8 @@ snapshots:
'@types/shimmer@1.2.0': {}
+ '@types/sinonjs__fake-timers@8.1.5': {}
+
'@types/sizzle@2.3.4': {}
'@types/stack-utils@2.0.1': {}
@@ -20423,8 +20457,6 @@ snapshots:
'@types/validator@13.11.2': {}
- '@types/validator@13.15.1': {}
-
'@types/vfile-message@2.0.0':
dependencies:
vfile-message: 4.0.2
@@ -20579,7 +20611,7 @@ snapshots:
dependencies:
'@typescript-eslint/tsconfig-utils': 8.33.0(typescript@5.7.3)
'@typescript-eslint/types': 8.33.0
- debug: 4.4.1
+ debug: 4.3.4(supports-color@8.1.1)
transitivePeerDependencies:
- supports-color
- typescript
@@ -20652,7 +20684,7 @@ snapshots:
dependencies:
'@typescript-eslint/types': 3.10.1
'@typescript-eslint/visitor-keys': 3.10.1
- debug: 4.4.1
+ debug: 4.3.4(supports-color@8.1.1)
glob: 7.2.3
is-glob: 4.0.3
lodash: 4.17.21
@@ -21069,24 +21101,13 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ agent-base@7.1.3: {}
+
aggregate-error@3.1.0:
dependencies:
clean-stack: 2.2.0
indent-string: 4.0.0
- airbnb-prop-types@2.16.0(react@16.14.0):
- dependencies:
- array.prototype.find: 2.2.2
- function.prototype.name: 1.1.6
- is-regex: 1.1.4
- object-is: 1.1.5
- object.assign: 4.1.5
- object.entries: 1.1.7
- prop-types: 15.8.1
- prop-types-exact: 1.2.0
- react: 16.14.0
- react-is: 16.13.1
-
ajv-formats@2.1.1(ajv@8.12.0):
optionalDependencies:
ajv: 8.12.0
@@ -21257,21 +21278,6 @@ snapshots:
array-unique@0.3.2: {}
- array.prototype.filter@1.0.3:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.1
- es-abstract: 1.22.2
- es-array-method-boxes-properly: 1.0.0
- is-string: 1.0.7
-
- array.prototype.find@2.2.2:
- dependencies:
- call-bind: 1.0.7
- define-properties: 1.2.1
- es-abstract: 1.22.2
- es-shim-unscopables: 1.0.0
-
array.prototype.findlast@1.2.5:
dependencies:
call-bind: 1.0.7
@@ -21400,6 +21406,8 @@ snapshots:
async@1.5.2: {}
+ async@3.2.6: {}
+
asynciterator.prototype@1.0.0:
dependencies:
has-symbols: 1.0.3
@@ -21452,6 +21460,14 @@ snapshots:
transitivePeerDependencies:
- debug
+ axios@1.9.0:
+ dependencies:
+ follow-redirects: 1.15.9
+ form-data: 4.0.2
+ proxy-from-env: 1.1.0
+ transitivePeerDependencies:
+ - debug
+
axobject-query@3.2.1:
dependencies:
dequal: 2.0.3
@@ -21540,7 +21556,7 @@ snapshots:
dependencies:
'@babel/runtime': 7.23.9
cosmiconfig: 6.0.0
- resolve: 1.22.8
+ resolve: 1.22.10
babel-plugin-macros@3.1.0:
dependencies:
@@ -21548,20 +21564,11 @@ snapshots:
cosmiconfig: 7.1.0
resolve: 1.22.8
- babel-plugin-polyfill-corejs2@0.4.13(@babel/core@7.23.0):
+ babel-plugin-polyfill-corejs2@0.4.7(@babel/core@7.23.0):
dependencies:
- '@babel/compat-data': 7.27.3
+ '@babel/compat-data': 7.23.5
'@babel/core': 7.23.0
- '@babel/helper-define-polyfill-provider': 0.6.4(@babel/core@7.23.0)
- semver: 6.3.1
- transitivePeerDependencies:
- - supports-color
-
- babel-plugin-polyfill-corejs2@0.4.13(@babel/core@7.23.7):
- dependencies:
- '@babel/compat-data': 7.27.3
- '@babel/core': 7.23.7
- '@babel/helper-define-polyfill-provider': 0.6.4(@babel/core@7.23.7)
+ '@babel/helper-define-polyfill-provider': 0.4.4(@babel/core@7.23.0)
semver: 6.3.1
transitivePeerDependencies:
- supports-color
@@ -21593,22 +21600,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- babel-plugin-polyfill-corejs3@0.11.1(@babel/core@7.23.0):
- dependencies:
- '@babel/core': 7.23.0
- '@babel/helper-define-polyfill-provider': 0.6.4(@babel/core@7.23.0)
- core-js-compat: 3.42.0
- transitivePeerDependencies:
- - supports-color
-
- babel-plugin-polyfill-corejs3@0.11.1(@babel/core@7.23.7):
- dependencies:
- '@babel/core': 7.23.7
- '@babel/helper-define-polyfill-provider': 0.6.4(@babel/core@7.23.7)
- core-js-compat: 3.42.0
- transitivePeerDependencies:
- - supports-color
-
babel-plugin-polyfill-corejs3@0.8.7(@babel/core@7.23.0):
dependencies:
'@babel/core': 7.23.0
@@ -21639,20 +21630,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- babel-plugin-polyfill-regenerator@0.6.4(@babel/core@7.23.0):
- dependencies:
- '@babel/core': 7.23.0
- '@babel/helper-define-polyfill-provider': 0.6.4(@babel/core@7.23.0)
- transitivePeerDependencies:
- - supports-color
-
- babel-plugin-polyfill-regenerator@0.6.4(@babel/core@7.23.7):
- dependencies:
- '@babel/core': 7.23.7
- '@babel/helper-define-polyfill-provider': 0.6.4(@babel/core@7.23.7)
- transitivePeerDependencies:
- - supports-color
-
babel-plugin-preval@5.1.0:
dependencies:
'@babel/runtime': 7.23.9
@@ -21710,7 +21687,7 @@ snapshots:
'@babel/plugin-proposal-optional-chaining': 7.17.12(@babel/core@7.23.0)
'@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.23.0)
'@babel/plugin-transform-classes': 7.23.3(@babel/core@7.23.0)
- '@babel/plugin-transform-runtime': 7.27.4(@babel/core@7.23.0)
+ '@babel/plugin-transform-runtime': 7.23.7(@babel/core@7.23.0)
'@babel/plugin-transform-spread': 7.23.3(@babel/core@7.23.0)
'@babel/preset-env': 7.23.7(@babel/core@7.23.0)
'@babel/preset-react': 7.26.3(@babel/core@7.23.0)
@@ -21741,6 +21718,9 @@ snapshots:
bare-events@2.4.2:
optional: true
+ bare-events@2.5.4:
+ optional: true
+
bare-fs@2.3.1:
dependencies:
bare-events: 2.4.2
@@ -21748,19 +21728,41 @@ snapshots:
bare-stream: 2.1.3
optional: true
+ bare-fs@4.1.5:
+ dependencies:
+ bare-events: 2.5.4
+ bare-path: 3.0.0
+ bare-stream: 2.6.5(bare-events@2.5.4)
+ optional: true
+
bare-os@2.4.0:
optional: true
+ bare-os@3.6.1:
+ optional: true
+
bare-path@2.1.3:
dependencies:
bare-os: 2.4.0
optional: true
+ bare-path@3.0.0:
+ dependencies:
+ bare-os: 3.6.1
+ optional: true
+
bare-stream@2.1.3:
dependencies:
streamx: 2.18.0
optional: true
+ bare-stream@2.6.5(bare-events@2.5.4):
+ dependencies:
+ streamx: 2.22.1
+ optionalDependencies:
+ bare-events: 2.5.4
+ optional: true
+
base-64@1.0.0: {}
base64-arraybuffer@0.1.4: {}
@@ -21942,7 +21944,7 @@ snapshots:
browser-resolve@2.0.0:
dependencies:
- resolve: 1.22.8
+ resolve: 1.22.10
browser-stdout@1.3.1: {}
@@ -22024,7 +22026,7 @@ snapshots:
querystring-es3: 0.2.1
read-only-stream: 2.0.0
readable-stream: 2.3.8
- resolve: 1.22.8
+ resolve: 1.22.10
shasum-object: 1.0.0
shell-quote: 1.8.1
stream-browserify: 3.0.0
@@ -22068,13 +22070,6 @@ snapshots:
node-releases: 2.0.14
update-browserslist-db: 1.0.13(browserslist@4.23.0)
- browserslist@4.25.0:
- dependencies:
- caniuse-lite: 1.0.30001720
- electron-to-chromium: 1.5.161
- node-releases: 2.0.19
- update-browserslist-db: 1.1.3(browserslist@4.25.0)
-
bs-logger@0.2.6:
dependencies:
fast-json-stable-stringify: 2.1.0
@@ -22283,25 +22278,6 @@ snapshots:
dependencies:
get-func-name: 2.0.2
- cheerio-select@2.1.0:
- dependencies:
- boolbase: 1.0.0
- css-select: 5.1.0
- css-what: 6.1.0
- domelementtype: 2.3.0
- domhandler: 5.0.3
- domutils: 3.1.0
-
- cheerio@1.0.0-rc.12:
- dependencies:
- cheerio-select: 2.1.0
- dom-serializer: 2.0.0
- domhandler: 5.0.3
- domutils: 3.1.0
- htmlparser2: 8.0.2
- parse5: 7.1.2
- parse5-htmlparser2-tree-adapter: 7.0.0
-
chokidar@3.5.3:
dependencies:
anymatch: 3.1.3
@@ -22337,6 +22313,12 @@ snapshots:
urlpattern-polyfill: 10.0.0
zod: 3.23.8
+ chromium-bidi@5.1.0(devtools-protocol@0.0.1452169):
+ dependencies:
+ devtools-protocol: 0.0.1452169
+ mitt: 3.0.1
+ zod: 3.25.51
+
ci-info@2.0.0: {}
ci-info@3.8.0: {}
@@ -22478,6 +22460,8 @@ snapshots:
commander@11.0.0: {}
+ commander@12.1.0: {}
+
commander@2.20.3: {}
commander@7.2.0: {}
@@ -22622,10 +22606,6 @@ snapshots:
dependencies:
browserslist: 4.23.0
- core-js-compat@3.42.0:
- dependencies:
- browserslist: 4.25.0
-
core-js-compat@3.9.0:
dependencies:
browserslist: 4.23.0
@@ -22642,6 +22622,8 @@ snapshots:
object-assign: 4.1.1
vary: 1.1.2
+ corser@2.0.1: {}
+
cosmiconfig-toml-loader@1.0.0:
dependencies:
'@iarna/toml': 2.2.5
@@ -22827,14 +22809,6 @@ snapshots:
domutils: 2.8.0
nth-check: 2.1.1
- css-select@5.1.0:
- dependencies:
- boolbase: 1.0.0
- css-what: 6.1.0
- domhandler: 5.0.3
- domutils: 3.1.0
- nth-check: 2.1.1
-
css-selector-parser@1.4.1: {}
css-tree@1.1.3:
@@ -22915,6 +22889,11 @@ snapshots:
csstype@3.1.3: {}
+ cwd@0.10.0:
+ dependencies:
+ find-pkg: 0.1.2
+ fs-exists-sync: 0.1.0
+
d@1.0.1:
dependencies:
es5-ext: 0.10.62
@@ -23188,6 +23167,8 @@ snapshots:
devtools-protocol@0.0.1299070: {}
+ devtools-protocol@0.0.1452169: {}
+
dezalgo@1.0.4:
dependencies:
asap: 2.0.6
@@ -23220,8 +23201,6 @@ snapshots:
dependencies:
path-type: 4.0.0
- discontinuous-range@1.0.0: {}
-
doctrine@2.1.0:
dependencies:
esutils: 2.0.3
@@ -23336,8 +23315,6 @@ snapshots:
electron-to-chromium@1.4.685: {}
- electron-to-chromium@1.5.161: {}
-
elliptic@6.5.4:
dependencies:
bn.js: 4.12.0
@@ -23417,67 +23394,6 @@ snapshots:
envinfo@7.10.0: {}
- enzyme-adapter-react-16@1.15.8(enzyme@3.11.0)(react-dom@16.14.0(react@16.14.0))(react@16.14.0):
- dependencies:
- enzyme: 3.11.0
- enzyme-adapter-utils: 1.14.2(react@16.14.0)
- enzyme-shallow-equal: 1.0.7
- hasown: 2.0.0
- object.assign: 4.1.5
- object.values: 1.1.7
- prop-types: 15.8.1
- react: 16.14.0
- react-dom: 16.14.0(react@16.14.0)
- react-is: 16.13.1
- react-test-renderer: 16.14.0(react@16.14.0)
- semver: 5.7.2
-
- enzyme-adapter-utils@1.14.2(react@16.14.0):
- dependencies:
- airbnb-prop-types: 2.16.0(react@16.14.0)
- function.prototype.name: 1.1.6
- hasown: 2.0.1
- object.assign: 4.1.5
- object.fromentries: 2.0.7
- prop-types: 15.8.1
- react: 16.14.0
- semver: 6.3.1
-
- enzyme-shallow-equal@1.0.5:
- dependencies:
- has: 1.0.3
- object-is: 1.1.5
-
- enzyme-shallow-equal@1.0.7:
- dependencies:
- hasown: 2.0.1
- object-is: 1.1.5
-
- enzyme@3.11.0:
- dependencies:
- array.prototype.flat: 1.3.2
- cheerio: 1.0.0-rc.12
- enzyme-shallow-equal: 1.0.5
- function.prototype.name: 1.1.6
- has: 1.0.3
- html-element-map: 1.3.1
- is-boolean-object: 1.1.2
- is-callable: 1.2.7
- is-number-object: 1.0.7
- is-regex: 1.1.4
- is-string: 1.0.7
- is-subset: 0.1.1
- lodash.escape: 4.0.1
- lodash.isequal: 4.5.0
- object-inspect: 1.12.3
- object-is: 1.1.5
- object.assign: 4.1.5
- object.entries: 1.1.7
- object.values: 1.1.7
- raf: 3.4.1
- rst-selector-parser: 2.2.3
- string.prototype.trim: 1.2.8
-
eol@0.9.1: {}
error-ex@1.3.2:
@@ -23584,8 +23500,6 @@ snapshots:
unbox-primitive: 1.1.0
which-typed-array: 1.1.19
- es-array-method-boxes-properly@1.0.0: {}
-
es-define-property@1.0.0:
dependencies:
get-intrinsic: 1.2.4
@@ -23763,8 +23677,6 @@ snapshots:
escalade@3.1.2: {}
- escalade@3.2.0: {}
-
escape-goat@2.1.1: {}
escape-html@1.0.3: {}
@@ -24302,6 +24214,12 @@ snapshots:
expand-template@2.0.3: {}
+ expand-tilde@1.2.2:
+ dependencies:
+ os-homedir: 1.0.2
+
+ expect-puppeteer@11.0.0: {}
+
expect@29.7.0:
dependencies:
'@jest/expect-utils': 29.7.0
@@ -24654,12 +24572,27 @@ snapshots:
make-dir: 3.1.0
pkg-dir: 4.2.0
+ find-file-up@0.1.3:
+ dependencies:
+ fs-exists-sync: 0.1.0
+ resolve-dir: 0.1.1
+
find-my-way@9.3.0:
dependencies:
fast-deep-equal: 3.1.3
fast-querystring: 1.1.2
safe-regex2: 5.0.0
+ find-pkg@0.1.2:
+ dependencies:
+ find-file-up: 0.1.3
+
+ find-process@1.4.10:
+ dependencies:
+ chalk: 4.1.2
+ commander: 12.1.0
+ loglevel: 1.9.2
+
find-up@3.0.0:
dependencies:
locate-path: 3.0.0
@@ -24705,6 +24638,8 @@ snapshots:
optionalDependencies:
debug: 4.4.1
+ follow-redirects@1.15.9: {}
+
for-each@0.3.3:
dependencies:
is-callable: 1.2.7
@@ -24784,6 +24719,8 @@ snapshots:
fs-exists-cached@1.0.0: {}
+ fs-exists-sync@0.1.0: {}
+
fs-extra@10.1.0:
dependencies:
graceful-fs: 4.2.11
@@ -25482,10 +25419,22 @@ snapshots:
dependencies:
ini: 2.0.0
+ global-modules@0.2.3:
+ dependencies:
+ global-prefix: 0.1.5
+ is-windows: 0.2.0
+
global-modules@2.0.0:
dependencies:
global-prefix: 3.0.0
+ global-prefix@0.1.5:
+ dependencies:
+ homedir-polyfill: 1.0.3
+ ini: 1.3.8
+ is-windows: 0.2.0
+ which: 1.3.1
+
global-prefix@3.0.0:
dependencies:
ini: 1.3.8
@@ -25733,10 +25682,6 @@ snapshots:
is-stream: 2.0.1
type-fest: 0.8.1
- hasown@2.0.0:
- dependencies:
- function-bind: 1.1.2
-
hasown@2.0.1:
dependencies:
function-bind: 1.1.2
@@ -25850,6 +25795,10 @@ snapshots:
dependencies:
react-is: 16.13.1
+ homedir-polyfill@1.0.3:
+ dependencies:
+ parse-passwd: 1.0.0
+
hookified@1.7.1: {}
hosted-git-info@2.8.9: {}
@@ -25860,11 +25809,6 @@ snapshots:
htm@3.1.1: {}
- html-element-map@1.3.1:
- dependencies:
- array.prototype.filter: 1.0.3
- call-bind: 1.0.7
-
html-encoding-sniffer@2.0.1:
dependencies:
whatwg-encoding: 1.0.5
@@ -25969,6 +25913,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ http-proxy@1.18.1:
+ dependencies:
+ eventemitter3: 4.0.7
+ follow-redirects: 1.15.3(debug@4.4.1)
+ requires-port: 1.0.0
+ transitivePeerDependencies:
+ - debug
+
http-proxy@1.18.1(debug@3.2.7):
dependencies:
eventemitter3: 4.0.7
@@ -25977,6 +25929,25 @@ snapshots:
transitivePeerDependencies:
- debug
+ http-server@14.1.1:
+ dependencies:
+ basic-auth: 2.0.1
+ chalk: 4.1.2
+ corser: 2.0.1
+ he: 1.2.0
+ html-encoding-sniffer: 3.0.0
+ http-proxy: 1.18.1
+ mime: 1.6.0
+ minimist: 1.2.8
+ opener: 1.5.2
+ portfinder: 1.0.37
+ secure-compare: 3.0.1
+ union: 0.5.0
+ url-join: 4.0.1
+ transitivePeerDependencies:
+ - debug
+ - supports-color
+
http2-wrapper@1.0.3:
dependencies:
quick-lru: 5.1.1
@@ -25998,6 +25969,13 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ https-proxy-agent@7.0.6:
+ dependencies:
+ agent-base: 7.1.3
+ debug: 4.3.4(supports-color@8.1.1)
+ transitivePeerDependencies:
+ - supports-color
+
human-signals@2.1.0: {}
human-signals@4.3.1: {}
@@ -26488,8 +26466,6 @@ snapshots:
call-bound: 1.0.4
has-tostringtag: 1.0.2
- is-subset@0.1.1: {}
-
is-symbol@1.0.4:
dependencies:
has-symbols: 1.0.3
@@ -26550,6 +26526,8 @@ snapshots:
is-whitespace-character@1.0.4: {}
+ is-windows@0.2.0: {}
+
is-windows@1.0.2: {}
is-word-character@1.0.4: {}
@@ -26608,7 +26586,7 @@ snapshots:
istanbul-lib-source-maps@4.0.1:
dependencies:
- debug: 4.4.1
+ debug: 4.3.4(supports-color@8.1.1)
istanbul-lib-coverage: 3.2.0
source-map: 0.6.1
transitivePeerDependencies:
@@ -27085,6 +27063,14 @@ snapshots:
'@sideway/formula': 3.0.1
'@sideway/pinpoint': 2.0.0
+ joi@17.13.3:
+ dependencies:
+ '@hapi/hoek': 9.3.0
+ '@hapi/topo': 5.1.0
+ '@sideway/address': 4.1.5
+ '@sideway/formula': 3.0.1
+ '@sideway/pinpoint': 2.0.0
+
joycon@3.1.1: {}
jquery@3.7.1: {}
@@ -27417,8 +27403,6 @@ snapshots:
lodash.deburr@4.1.0: {}
- lodash.escape@4.0.1: {}
-
lodash.every@4.6.0: {}
lodash.flatten@4.4.0: {}
@@ -27482,6 +27466,8 @@ snapshots:
strip-ansi: 7.1.0
wrap-ansi: 8.1.0
+ loglevel@1.9.2: {}
+
longest-streak@2.0.4: {}
longest-streak@3.1.0: {}
@@ -28225,7 +28211,7 @@ snapshots:
micromark@3.2.0:
dependencies:
'@types/debug': 4.1.9
- debug: 4.4.1
+ debug: 4.3.4(supports-color@8.1.1)
decode-named-character-reference: 1.0.2
micromark-core-commonmark: 1.1.0
micromark-factory-space: 1.1.0
@@ -28431,7 +28417,7 @@ snapshots:
inherits: 2.0.4
parents: 1.0.1
readable-stream: 2.3.8
- resolve: 1.22.8
+ resolve: 1.22.10
stream-combiner2: 1.1.1
subarg: 1.0.0
through2: 2.0.5
@@ -28463,8 +28449,6 @@ snapshots:
'@aws-sdk/credential-providers': 3.521.0
socks: 2.8.3
- moo@0.5.2: {}
-
morgan@1.10.0:
dependencies:
basic-auth: 2.0.1
@@ -28573,13 +28557,6 @@ snapshots:
natural-compare@1.4.0: {}
- nearley@2.20.1:
- dependencies:
- commander: 2.20.3
- moo: 0.5.2
- railroad-diagrams: 1.0.0
- randexp: 0.4.6
-
negotiator@0.6.3: {}
negotiator@1.0.0: {}
@@ -28628,8 +28605,6 @@ snapshots:
node-releases@2.0.14: {}
- node-releases@2.0.19: {}
-
nodemailer@6.9.10: {}
nopt@1.0.10:
@@ -28858,6 +28833,8 @@ snapshots:
os-browserify@0.3.0: {}
+ os-homedir@1.0.2: {}
+
os-tmpdir@1.0.2: {}
outvariant@1.4.3: {}
@@ -28919,6 +28896,19 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ pac-proxy-agent@7.2.0:
+ dependencies:
+ '@tootallnate/quickjs-emscripten': 0.23.0
+ agent-base: 7.1.3
+ debug: 4.3.4(supports-color@8.1.1)
+ get-uri: 6.0.3
+ http-proxy-agent: 7.0.2
+ https-proxy-agent: 7.0.6
+ pac-resolver: 7.0.1
+ socks-proxy-agent: 8.0.5
+ transitivePeerDependencies:
+ - supports-color
+
pac-resolver@7.0.1:
dependencies:
degenerator: 5.0.1
@@ -29000,6 +28990,8 @@ snapshots:
unist-util-modify-children: 2.0.0
unist-util-visit-children: 1.1.4
+ parse-passwd@1.0.0: {}
+
parse-path@4.0.4:
dependencies:
is-ssh: 1.4.0
@@ -29016,11 +29008,6 @@ snapshots:
parse-path: 4.0.4
protocols: 1.4.8
- parse5-htmlparser2-tree-adapter@7.0.0:
- dependencies:
- domhandler: 5.0.3
- parse5: 7.1.2
-
parse5@6.0.1: {}
parse5@7.1.2:
@@ -29098,8 +29085,6 @@ snapshots:
pend@1.2.0: {}
- performance-now@2.1.0: {}
-
pg-int8@1.0.1: {}
pg-protocol@1.8.0: {}
@@ -29200,6 +29185,13 @@ snapshots:
pluralize@8.0.0: {}
+ portfinder@1.0.37:
+ dependencies:
+ async: 3.2.6
+ debug: 4.4.1
+ transitivePeerDependencies:
+ - supports-color
+
posix-character-classes@0.1.1: {}
possible-typed-array-names@1.1.0: {}
@@ -29526,12 +29518,6 @@ snapshots:
kleur: 3.0.3
sisteransi: 1.0.5
- prop-types-exact@1.2.0:
- dependencies:
- has: 1.0.3
- object.assign: 4.1.5
- reflect.ownkeys: 0.2.0
-
prop-types@15.8.1:
dependencies:
loose-envify: 1.4.0
@@ -29570,6 +29556,19 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ proxy-agent@6.5.0:
+ dependencies:
+ agent-base: 7.1.3
+ debug: 4.3.4(supports-color@8.1.1)
+ http-proxy-agent: 7.0.2
+ https-proxy-agent: 7.0.6
+ lru-cache: 7.18.3
+ pac-proxy-agent: 7.2.0
+ proxy-from-env: 1.1.0
+ socks-proxy-agent: 8.0.5
+ transitivePeerDependencies:
+ - supports-color
+
proxy-from-env@1.1.0: {}
proxy-middleware@0.15.0: {}
@@ -29614,6 +29613,20 @@ snapshots:
- supports-color
- utf-8-validate
+ puppeteer-core@24.10.0:
+ dependencies:
+ '@puppeteer/browsers': 2.10.5
+ chromium-bidi: 5.1.0(devtools-protocol@0.0.1452169)
+ debug: 4.4.1
+ devtools-protocol: 0.0.1452169
+ typed-query-selector: 2.12.0
+ ws: 8.18.2
+ transitivePeerDependencies:
+ - bare-buffer
+ - bufferutil
+ - supports-color
+ - utf-8-validate
+
puppeteer@22.12.1(typescript@5.8.2):
dependencies:
'@puppeteer/browsers': 2.2.3
@@ -29626,8 +29639,33 @@ snapshots:
- typescript
- utf-8-validate
+ puppeteer@24.10.0(typescript@5.8.2):
+ dependencies:
+ '@puppeteer/browsers': 2.10.5
+ chromium-bidi: 5.1.0(devtools-protocol@0.0.1452169)
+ cosmiconfig: 9.0.0(typescript@5.8.2)
+ devtools-protocol: 0.0.1452169
+ puppeteer-core: 24.10.0
+ typed-query-selector: 2.12.0
+ transitivePeerDependencies:
+ - bare-buffer
+ - bufferutil
+ - supports-color
+ - typescript
+ - utf-8-validate
+
pure-rand@6.0.4: {}
+ pyodide@0.23.3:
+ dependencies:
+ base-64: 1.0.0
+ node-fetch: 2.7.0
+ ws: 8.18.0
+ transitivePeerDependencies:
+ - bufferutil
+ - encoding
+ - utf-8-validate
+
pyodide@0.23.4:
dependencies:
base-64: 1.0.0
@@ -29692,17 +29730,6 @@ snapshots:
quick-lru@5.1.1: {}
- raf@3.4.1:
- dependencies:
- performance-now: 2.1.0
-
- railroad-diagrams@1.0.0: {}
-
- randexp@0.4.6:
- dependencies:
- discontinuous-range: 1.0.0
- ret: 0.1.15
-
randombytes@2.1.0:
dependencies:
safe-buffer: 5.2.1
@@ -29953,14 +29980,6 @@ snapshots:
object-assign: 4.1.1
prop-types: 15.8.1
- react-test-renderer@16.14.0(react@16.14.0):
- dependencies:
- object-assign: 4.1.1
- prop-types: 15.8.1
- react: 16.14.0
- react-is: 16.13.1
- scheduler: 0.19.1
-
react-test-renderer@17.0.2(react@17.0.2):
dependencies:
object-assign: 4.1.1
@@ -30063,7 +30082,7 @@ snapshots:
rechoir@0.6.2:
dependencies:
- resolve: 1.22.8
+ resolve: 1.22.10
rechoir@0.7.1:
dependencies:
@@ -30134,8 +30153,6 @@ snapshots:
globalthis: 1.0.3
which-builtin-type: 1.1.3
- reflect.ownkeys@0.2.0: {}
-
regenerate-unicode-properties@10.1.1:
dependencies:
regenerate: 1.4.2
@@ -30330,7 +30347,7 @@ snapshots:
dependencies:
debug: 4.4.1
module-details-from-path: 1.0.3
- resolve: 1.22.8
+ resolve: 1.22.10
transitivePeerDependencies:
- supports-color
@@ -30352,6 +30369,11 @@ snapshots:
dependencies:
resolve-from: 5.0.0
+ resolve-dir@0.1.1:
+ dependencies:
+ expand-tilde: 1.2.2
+ global-modules: 0.2.3
+
resolve-from@4.0.0: {}
resolve-from@5.0.0: {}
@@ -30446,11 +30468,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- rst-selector-parser@2.2.3:
- dependencies:
- lodash.flattendeep: 4.4.0
- nearley: 2.20.1
-
run-async@2.4.1: {}
run-parallel@1.2.0:
@@ -30465,6 +30482,10 @@ snapshots:
dependencies:
tslib: 2.6.2
+ rxjs@7.8.2:
+ dependencies:
+ tslib: 2.8.1
+
sade@1.8.1:
dependencies:
mri: 1.2.0
@@ -30572,6 +30593,8 @@ snapshots:
extend-shallow: 2.0.1
kind-of: 6.0.3
+ secure-compare@3.0.1: {}
+
secure-json-parse@2.7.0: {}
secure-json-parse@3.0.2: {}
@@ -30967,6 +30990,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ socks-proxy-agent@8.0.5:
+ dependencies:
+ agent-base: 7.1.3
+ debug: 4.3.4(supports-color@8.1.1)
+ socks: 2.8.3
+ transitivePeerDependencies:
+ - supports-color
+
socks@2.8.3:
dependencies:
ip-address: 9.0.5
@@ -31020,6 +31051,11 @@ snapshots:
dependencies:
memory-pager: 1.5.0
+ spawnd@11.0.0:
+ dependencies:
+ signal-exit: 4.1.0
+ tree-kill: 1.2.2
+
spdx-correct@3.2.0:
dependencies:
spdx-expression-parse: 3.0.1
@@ -31137,6 +31173,14 @@ snapshots:
optionalDependencies:
bare-events: 2.4.2
+ streamx@2.22.1:
+ dependencies:
+ fast-fifo: 1.3.2
+ text-decoder: 1.1.0
+ optionalDependencies:
+ bare-events: 2.5.4
+ optional: true
+
strict-event-emitter@0.5.1: {}
strict-uri-encode@2.0.0: {}
@@ -31508,6 +31552,16 @@ snapshots:
bare-fs: 2.3.1
bare-path: 2.1.3
+ tar-fs@3.0.9:
+ dependencies:
+ pump: 3.0.0
+ tar-stream: 3.1.7
+ optionalDependencies:
+ bare-fs: 4.1.5
+ bare-path: 3.0.0
+ transitivePeerDependencies:
+ - bare-buffer
+
tar-stream@2.2.0:
dependencies:
bl: 4.1.0
@@ -31688,6 +31742,8 @@ snapshots:
dependencies:
punycode: 2.3.0
+ tree-kill@1.2.2: {}
+
trim-trailing-lines@1.1.4: {}
trim@0.0.1: {}
@@ -31910,6 +31966,8 @@ snapshots:
possible-typed-array-names: 1.1.0
reflect.getprototypeof: 1.0.10
+ typed-query-selector@2.12.0: {}
+
typedarray-to-buffer@3.1.5:
dependencies:
is-typedarray: 1.0.0
@@ -32035,6 +32093,10 @@ snapshots:
is-extendable: 0.1.1
set-value: 2.0.1
+ union@0.5.0:
+ dependencies:
+ qs: 6.14.0
+
unique-string@2.0.0:
dependencies:
crypto-random-string: 2.0.0
@@ -32211,12 +32273,6 @@ snapshots:
escalade: 3.1.2
picocolors: 1.1.0
- update-browserslist-db@1.1.3(browserslist@4.25.0):
- dependencies:
- browserslist: 4.25.0
- escalade: 3.2.0
- picocolors: 1.1.1
-
update-check@1.5.2:
dependencies:
registry-auth-token: 3.3.2
@@ -32245,6 +32301,8 @@ snapshots:
urix@0.1.0: {}
+ url-join@4.0.1: {}
+
url-loader@4.1.1(file-loader@6.2.0(webpack@5.90.3))(webpack@5.90.3):
dependencies:
loader-utils: 2.0.4
@@ -32380,6 +32438,28 @@ snapshots:
fsevents: 2.3.3
terser: 5.28.1
+ vitest-dev-server@11.0.3:
+ dependencies:
+ chalk: 4.1.2
+ cwd: 0.10.0
+ find-process: 1.4.10
+ prompts: 2.4.2
+ spawnd: 11.0.0
+ tree-kill: 1.2.2
+ wait-on: 8.0.3
+ transitivePeerDependencies:
+ - debug
+
+ vitest-environment-puppeteer@11.0.3(typescript@5.8.2):
+ dependencies:
+ chalk: 4.1.2
+ cosmiconfig: 9.0.0(typescript@5.8.2)
+ deepmerge: 4.3.1
+ vitest-dev-server: 11.0.3
+ transitivePeerDependencies:
+ - debug
+ - typescript
+
vm-browserify@1.1.2: {}
void-elements@3.1.0: {}
@@ -32396,6 +32476,16 @@ snapshots:
dependencies:
xml-name-validator: 4.0.0
+ wait-on@8.0.3:
+ dependencies:
+ axios: 1.9.0
+ joi: 17.13.3
+ lodash: 4.17.21
+ minimist: 1.2.8
+ rxjs: 7.8.2
+ transitivePeerDependencies:
+ - debug
+
walker@1.0.8:
dependencies:
makeerror: 1.0.12
@@ -32710,6 +32800,8 @@ snapshots:
ws@8.18.0: {}
+ ws@8.18.2: {}
+
x-is-string@0.1.0: {}
xdg-basedir@4.0.0: {}
@@ -32845,6 +32937,8 @@ snapshots:
zod@3.23.8: {}
+ zod@3.25.51: {}
+
zwitch@1.0.5: {}
zwitch@2.0.4: {}
diff --git a/tools/client-plugins/browser-scripts/frame-runner.ts b/tools/client-plugins/browser-scripts/frame-runner.ts
deleted file mode 100644
index 35fb91da292..00000000000
--- a/tools/client-plugins/browser-scripts/frame-runner.ts
+++ /dev/null
@@ -1,110 +0,0 @@
-import jQuery from 'jquery';
-import * as helpers from '@freecodecamp/curriculum-helpers';
-
-import type { FrameDocument, FrameWindow, InitTestFrameArg } from '.';
-
-(window as FrameWindow).$ = jQuery;
-
-const frameDocument = document as FrameDocument;
-
-frameDocument.__initTestFrame = initTestFrame;
-
-async function initTestFrame(e: InitTestFrameArg = { code: {} }) {
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- const code = (e.code.contents || '').slice();
-
- const editableContents = (e.code.editableContents || '').slice();
- // __testEditable allows test authors to run tests against a transitory dom
- // element built using only the code in the editable region.
- const __testEditable = (cb: () => () => unknown) => {
- const div = frameDocument.createElement('div');
- div.id = 'editable-only';
- div.innerHTML = editableContents;
- frameDocument.body.appendChild(div);
- const out = cb();
- frameDocument.body.removeChild(div);
- return out;
- };
-
- /* eslint-disable @typescript-eslint/no-unused-vars */
- // Hardcode Deep Freeze dependency
- const DeepFreeze = (o: Record) => {
- Object.freeze(o);
- Object.getOwnPropertyNames(o).forEach(function (prop) {
- if (
- Object.prototype.hasOwnProperty.call(o, prop) &&
- o[prop] !== null &&
- (typeof o[prop] === 'object' || typeof o[prop] === 'function') &&
- !Object.isFrozen(o[prop])
- ) {
- DeepFreeze(o[prop] as Record);
- }
- });
- return o;
- };
-
- const { default: chai } = await import(/* webpackChunkName: "chai" */ 'chai');
- const assert = chai.assert;
- const __helpers = helpers;
- const __checkForBrowserExtensions = true;
- /* eslint-enable @typescript-eslint/no-unused-vars */
-
- let Enzyme;
- if (e.loadEnzyme) {
- /* eslint-disable prefer-const */
- let Adapter16;
-
- [{ default: Enzyme }, { default: Adapter16 }] = await Promise.all([
- import(/* webpackChunkName: "enzyme" */ 'enzyme'),
- import(/* webpackChunkName: "enzyme-adapter" */ 'enzyme-adapter-react-16')
- ]);
-
- Enzyme.configure({ adapter: new Adapter16() });
- /* eslint-enable prefer-const */
- }
-
- frameDocument.__runTest = async function runTests(testString: string) {
- // uncomment the following line to inspect
- // the frame-runner as it runs tests
- // make sure the dev tools console is open
- // debugger;
- try {
- // eval test string to actual JavaScript
- // This return can be a function
- // i.e. function() { assert(true, 'happy coding'); }
- const testPromise = new Promise((resolve, reject) =>
- // To avoid race conditions, we have to run the test in a final
- // frameDocument ready:
- $(() => {
- try {
- const test: unknown = eval(testString);
- resolve(test);
- } catch (err) {
- reject(err as Error);
- }
- })
- );
- const test = await testPromise;
- if (typeof test === 'function') {
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call
- await test();
- }
- return { pass: true };
- } catch (err) {
- if (!(err instanceof chai.AssertionError)) {
- console.error(err);
- }
- // to provide useful debugging information when debugging the tests, we
- // have to extract the message, stack and, if they exist, expected and
- // actual before returning
- return {
- err: {
- message: (err as Error).message,
- stack: (err as Error).stack,
- expected: (err as { expected?: string }).expected,
- actual: (err as { actual?: string }).actual
- }
- };
- }
- };
-}
diff --git a/tools/client-plugins/browser-scripts/package.json b/tools/client-plugins/browser-scripts/package.json
index d7cfb57a530..ac66a4eb18c 100644
--- a/tools/client-plugins/browser-scripts/package.json
+++ b/tools/client-plugins/browser-scripts/package.json
@@ -29,20 +29,11 @@
"@babel/plugin-transform-runtime": "7.23.7",
"@babel/preset-env": "7.23.7",
"@babel/preset-typescript": "7.23.3",
- "@freecodecamp/curriculum-helpers": "4.1.0",
- "@types/chai": "4.3.12",
"@types/copy-webpack-plugin": "^8.0.1",
- "@types/enzyme": "3.10.16",
- "@types/enzyme-adapter-react-16": "1.0.9",
- "@types/jquery": "3.5.29",
"@types/lodash-es": "4.17.12",
"@typescript/vfs": "^1.6.0",
"babel-loader": "8.3.0",
- "chai": "4.4.1",
"copy-webpack-plugin": "9.1.0",
- "enzyme": "3.11.0",
- "enzyme-adapter-react-16": "1.15.8",
- "jquery": "3.7.1",
"lodash-es": "4.17.21",
"process": "0.11.10",
"pyodide": "^0.23.3",
@@ -52,6 +43,7 @@
"webpack-cli": "4.10.0"
},
"dependencies": {
+ "@freecodecamp/curriculum-helpers": "^4.4.0",
"react": "16",
"react-dom": "16",
"xterm": "^5.2.1"
diff --git a/tools/client-plugins/browser-scripts/python-test-evaluator.ts b/tools/client-plugins/browser-scripts/python-test-evaluator.ts
deleted file mode 100644
index f69c11c210e..00000000000
--- a/tools/client-plugins/browser-scripts/python-test-evaluator.ts
+++ /dev/null
@@ -1,192 +0,0 @@
-// We have to specify pyodide.js because we need to import that file (not .mjs)
-// and 'import' defaults to .mjs
-import { loadPyodide, type PyodideInterface } from 'pyodide/pyodide.js';
-import type { PyProxy, PythonError } from 'pyodide/ffi';
-import pkg from 'pyodide/package.json';
-import * as helpers from '@freecodecamp/curriculum-helpers';
-import chai from 'chai';
-
-const ctx: Worker & typeof globalThis = self as unknown as Worker &
- typeof globalThis;
-
-let pyodide: PyodideInterface;
-
-interface PythonRunEvent extends MessageEvent {
- data: {
- code: {
- contents: string;
- editableContents: string;
- };
- firstTest: unknown;
- testString: string;
- build: string;
- sources: {
- [fileName: string]: unknown;
- };
- };
-}
-
-type EvaluatedTeststring = {
- input: string[];
- test: () => Promise;
-};
-
-async function setupPyodide() {
- if (pyodide) return pyodide;
-
- pyodide = await loadPyodide({
- // TODO: host this ourselves
- indexURL: `https://cdn.jsdelivr.net/pyodide/v${pkg.version}/full/`
- });
-
- // We freeze this to prevent learners from getting the worker into a
- // weird state. NOTE: this has to come after pyodide is loaded, because
- // pyodide modifies self while loading.
- Object.freeze(self);
-
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
- pyodide.FS.writeFile(
- '/home/pyodide/ast_helpers.py',
- helpers.python.astHelpers,
- {
- encoding: 'utf8'
- }
- );
-
- ctx.postMessage({ type: 'contentLoaded' });
-
- return pyodide;
-}
-
-void setupPyodide();
-
-ctx.onmessage = async (e: PythonRunEvent) => {
- const pyodide = await setupPyodide();
- /* eslint-disable @typescript-eslint/no-unused-vars */
- const code = (e.data.code.contents || '').slice();
- const editableContents = (e.data.code.editableContents || '').slice();
- const testString = e.data.testString;
-
- const assert = chai.assert;
- const __helpers = helpers;
-
- // Create fresh globals for each test
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call
- const __userGlobals = pyodide.globals.get('dict')() as PyProxy;
-
- /* eslint-enable @typescript-eslint/no-unused-vars */
- // uncomment the following line to inspect
- // the frame-runner as it runs tests
- // make sure the dev tools console is open
- // debugger;
- try {
- // eval test string to get the dummy input and actual test
- const evaluatedTestString = await new Promise(
- (resolve, reject) => {
- try {
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
- const test: { input: string[]; test: () => Promise } =
- eval(testString);
- resolve(test);
- } catch (err) {
- reject(err as Error);
- }
- }
- );
-
- // If the test string does not evaluate to an object, then we assume that
- // it's a standard JS test and any assertions have already passed.
- if (typeof evaluatedTestString !== 'object') {
- ctx.postMessage({ pass: true });
- return;
- }
-
- if (!evaluatedTestString || !('test' in evaluatedTestString)) {
- throw new Error(
- 'Test string did not evaluate to an object with the test property'
- );
- }
-
- const { input, test } = evaluatedTestString as EvaluatedTeststring;
-
- // Some tests rely on __name__ being set to __main__ and we new dicts do not
- // have this set by default.
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call
- __userGlobals.set('__name__', '__main__');
-
- // The runPython helper is a shortcut for running python code with our
- // custom globals.
- const runPython = (pyCode: string) =>
- pyodide.runPython(pyCode, { globals: __userGlobals }) as unknown;
-
- runPython(`
-def __inputGen(xs):
- def gen():
- for x in xs:
- yield x
- iter = gen()
- def input(arg=None):
- return next(iter)
-
- return input
-
-input = __inputGen(${JSON.stringify(input ?? [])})
-`);
-
- runPython(`from ast_helpers import Node as _Node`);
-
- // The tests need the user's code as a string, so we write it to the virtual
- // filesystem...
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
- pyodide.FS.writeFile('/user_code.py', code, { encoding: 'utf8' });
-
- // ...and then read it back into a variable so that they can evaluate it.
- runPython(`
-with open("/user_code.py", "r") as f:
- _code = f.read()
-`);
-
- try {
- // Evaluates the learner's code so that any variables they define are
- // available to the test.
- runPython(code);
- } catch (e) {
- const err = e as PythonError;
-
- // Quite a lot of lessons can easily lead users to write code that has
- // indentation errors. In these cases we want to provide a more helpful
- // error message. For other errors, we can just provide the standard
- // message.
- const errorType =
- err.type === 'IndentationError' ? 'indentation' : 'other';
- return ctx.postMessage({
- err: {
- message: err.message,
- stack: err.stack,
- errorType
- }
- });
- }
-
- await test();
-
- ctx.postMessage({ pass: true });
- } catch (err) {
- if (!(err instanceof chai.AssertionError)) {
- console.error(err);
- }
- // to provide useful debugging information when debugging the tests, we
- // have to extract the message, stack and, if they exist, expected and
- // actual before returning
- ctx.postMessage({
- err: {
- message: (err as Error).message,
- stack: (err as Error).stack,
- expected: (err as { expected?: string }).expected,
- actual: (err as { actual?: string }).actual
- }
- });
- } finally {
- __userGlobals.destroy();
- }
-};
diff --git a/tools/client-plugins/browser-scripts/test-evaluator.ts b/tools/client-plugins/browser-scripts/test-evaluator.ts
deleted file mode 100644
index 495904f9609..00000000000
--- a/tools/client-plugins/browser-scripts/test-evaluator.ts
+++ /dev/null
@@ -1,163 +0,0 @@
-import chai from 'chai';
-import { toString as __toString } from 'lodash-es';
-import * as curriculumHelpers from '@freecodecamp/curriculum-helpers';
-import { format as __format } from './utils/format';
-
-const ctx: Worker & typeof globalThis = self as unknown as Worker &
- typeof globalThis;
-
-const __utils = (() => {
- const MAX_LOGS_SIZE = 64 * 1024;
-
- let logs: string[] = [];
-
- function flushLogs() {
- if (logs.length) {
- ctx.postMessage({
- type: 'LOG',
- data: logs.join('\n')
- });
- logs = [];
- }
- }
-
- function pushLogs(logs: string[], args: string[]) {
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
- logs.push(args.map(arg => __format(arg)).join(' '));
- if (logs.join('\n').length > MAX_LOGS_SIZE) {
- flushLogs();
- }
- }
-
- const oldLog = ctx.console.log.bind(ctx.console);
- function proxyLog(...args: string[]) {
- pushLogs(logs, args);
- return oldLog(...args);
- }
-
- const oldInfo = ctx.console.info.bind(ctx.console);
- function proxyInfo(...args: string[]) {
- pushLogs(logs, args);
- return oldInfo(...args);
- }
-
- const oldWarn = ctx.console.warn.bind(ctx.console);
- function proxyWarn(...args: string[]) {
- pushLogs(logs, args);
- return oldWarn(...args);
- }
-
- const oldError = ctx.console.error.bind(ctx.console);
- function proxyError(...args: string[]) {
- pushLogs(logs, args);
- return oldError(...args);
- }
-
- function log(...msgs: Error[]) {
- if (msgs && msgs[0] && !(msgs[0] instanceof chai.AssertionError)) {
- // discards the stack trace via toString as it only useful to debug the
- // site, not a specific challenge.
- console.log(...msgs.map(msg => msg.toString()));
- }
- }
-
- const toggleProxyLogger = (on: unknown) => {
- ctx.console.log = on ? proxyLog : oldLog;
- ctx.console.info = on ? proxyInfo : oldInfo;
- ctx.console.warn = on ? proxyWarn : oldWarn;
- ctx.console.error = on ? proxyError : oldError;
- };
-
- return {
- log,
- toggleProxyLogger,
- flushLogs
- };
-})();
-
-// We can't simply import these because of how webpack names them when building
-// the bundle. Since both assert and __helpers have to exist in the global
-// scope, we have to declare them.
-const assert = chai.assert;
-const __helpers = curriculumHelpers;
-
-// We freeze to prevent learners from getting the tester into a weird
-// state by modifying these objects.
-Object.freeze(self);
-Object.freeze(__utils);
-Object.freeze(assert);
-Object.freeze(__helpers);
-
-interface TestEvaluatorEvent extends MessageEvent {
- data: {
- code: {
- contents: string;
- editableContents: string;
- };
- firstTest: unknown;
- testString: string;
- build: string;
- };
-}
-
-/* Run the test if there is one. If not just evaluate the user code */
-ctx.onmessage = async (e: TestEvaluatorEvent) => {
- /* eslint-disable @typescript-eslint/no-unused-vars */
- const code = e.data?.code?.contents || '';
- const editableContents = e.data?.code?.editableContents || '';
-
- // Build errors should be reported, but only once:
- __utils.toggleProxyLogger(e.data.firstTest);
- /* eslint-enable @typescript-eslint/no-unused-vars */
- try {
- // This can be reassigned by the eval inside the try block, so it should be declared as a let
- // eslint-disable-next-line prefer-const
- let __userCodeWasExecuted = false;
- try {
- // Logging is proxyed after the build to catch console.log messages
- // generated during testing.
- await eval(`${e.data.build}
-__utils.flushLogs();
-__userCodeWasExecuted = true;
-__utils.toggleProxyLogger(true);
-(async () => {${e.data.testString}})()`);
- } catch (err) {
- if (__userCodeWasExecuted) {
- // rethrow error, since test failed.
- throw err;
- }
- // log build errors unless they're related to import/export/require (there
- // are challenges that use them and they should not trigger warnings)
- if (
- (err as Error).name !== 'ReferenceError' ||
- ((err as Error).message !== 'require is not defined' &&
- (err as Error).message !== 'exports is not defined')
- ) {
- __utils.log(err as Error);
- }
- // the tests may not require working code, so they are evaluated even if
- // the user code does not get executed.
- eval(e.data.testString);
- }
- __utils.flushLogs();
- ctx.postMessage({ pass: true });
- } catch (err) {
- // Errors from testing go to the browser console only.
- __utils.toggleProxyLogger(false);
- // Report execution errors in case user code has errors that are only
- // uncovered during testing.
- __utils.log(err as Error);
- // Now that all logs have been created we can flush them.
- __utils.flushLogs();
- ctx.postMessage({
- err: {
- message: (err as Error).message,
- stack: (err as Error).stack,
- expected: (err as { expected?: string }).expected,
- actual: (err as { actual?: string }).actual
- }
- });
- }
-};
-
-ctx.postMessage({ type: 'contentLoaded' });
diff --git a/tools/client-plugins/browser-scripts/test-runner.ts b/tools/client-plugins/browser-scripts/test-runner.ts
new file mode 100644
index 00000000000..2a44a42b6fc
--- /dev/null
+++ b/tools/client-plugins/browser-scripts/test-runner.ts
@@ -0,0 +1,3 @@
+export type { FCCTestRunner } from '@freecodecamp/curriculum-helpers/test-runner.js';
+
+export { version } from '@freecodecamp/curriculum-helpers/package.json';
diff --git a/tools/client-plugins/browser-scripts/webpack.config.cjs b/tools/client-plugins/browser-scripts/webpack.config.cjs
index f00689a9abe..89cf2dfb947 100644
--- a/tools/client-plugins/browser-scripts/webpack.config.cjs
+++ b/tools/client-plugins/browser-scripts/webpack.config.cjs
@@ -2,6 +2,9 @@ const { writeFileSync } = require('fs');
const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const webpack = require('webpack');
+const {
+ version: helperVersion
+} = require('@freecodecamp/curriculum-helpers/package.json');
module.exports = (env = {}) => {
const __DEV__ = env.production !== true;
@@ -14,11 +17,8 @@ module.exports = (env = {}) => {
cache: __DEV__ ? { type: 'filesystem' } : false,
mode: __DEV__ ? 'development' : 'production',
entry: {
- 'frame-runner': './frame-runner.ts',
'sass-compile': './sass-compile.ts',
- 'test-evaluator': './test-evaluator.ts',
'python-worker': './python-worker.ts',
- 'python-test-evaluator': './python-test-evaluator.ts',
'typescript-worker': './typescript-worker.ts'
},
devtool: __DEV__ ? 'inline-source-map' : 'source-map',
@@ -71,7 +71,11 @@ module.exports = (env = {}) => {
patterns: [
'./node_modules/sass.js/dist/sass.sync.js',
// TODO: copy this into the css folder, not the js folder
- './node_modules/xterm/css/xterm.css'
+ './node_modules/xterm/css/xterm.css',
+ {
+ from: './node_modules/@freecodecamp/curriculum-helpers/dist/test-runner',
+ to: `test-runner/${helperVersion}/`
+ }
]
}),
new webpack.ProvidePlugin({