diff --git a/packages/cursorless-engine/src/index.ts b/packages/cursorless-engine/src/index.ts index e00aaf5fce..f762351b0c 100644 --- a/packages/cursorless-engine/src/index.ts +++ b/packages/cursorless-engine/src/index.ts @@ -16,3 +16,4 @@ export * from "./testUtil/plainObjectToTarget"; export * from "./util/getPartialTargetDescriptors"; export * from "./util/getPrimitiveTargets"; export * from "./util/grammarHelpers"; +export * from "./scripts/transformRecordedTests/transformations/upgrade"; \ No newline at end of file diff --git a/packages/cursorless-org/package.json b/packages/cursorless-org/package.json index 3438d74658..541efea357 100644 --- a/packages/cursorless-org/package.json +++ b/packages/cursorless-org/package.json @@ -13,7 +13,9 @@ "clean": "rm -rf ./out tsconfig.tsbuildinfo ./dist ./build" }, "dependencies": { + "@cursorless/common": "workspace:*", "@cursorless/cheatsheet": "workspace:*", + "@cursorless/test-case-component": "workspace:*", "@mdx-js/loader": "3.0.1", "@mdx-js/react": "3.0.1", "@next/mdx": "14.2.15", @@ -24,6 +26,7 @@ }, "devDependencies": { "@svgr/webpack": "8.1.0", + "@types/js-yaml": "^4.0.9", "@types/mdx": "2.0.13", "@types/node": "20.16.0", "@types/react": "18.3.11", diff --git a/packages/cursorless-org/src/pages/allowList.tsx b/packages/cursorless-org/src/pages/allowList.tsx new file mode 100644 index 0000000000..6d748b79c3 --- /dev/null +++ b/packages/cursorless-org/src/pages/allowList.tsx @@ -0,0 +1,19 @@ +export const testSelectedFiles = [ + "bringArgMadeAfterLook.yml", + "chuckBlockAirUntilBatt.yml", + "cutFine.yml", + "chuckLineFine.yml", + "bringAirAndBatAndCapToAfterItemEach.yml", + "carveLineHarp.yml", + "chuckBlockAir.yml", + "chuckBlockAirUntilBatt.yml", + "chuckBlockBatt.yml", + "chuckBlockBattUntilAir.yml", + "chuckFine.yml", + "chuckLineFineBetweenRisk.yml", + "clearBlockFine.yml", + "clearFine.yml", + "clearLineFine.yml", + // "bringAirToEndOfAir.yml", // Shiki intersect error + // "chuckBlockBatt2.yml", // Shiki intersect error +]; diff --git a/packages/cursorless-org/src/pages/component-sheet.tsx b/packages/cursorless-org/src/pages/component-sheet.tsx new file mode 100644 index 0000000000..55736598d4 --- /dev/null +++ b/packages/cursorless-org/src/pages/component-sheet.tsx @@ -0,0 +1,87 @@ +import * as yaml from "js-yaml"; +import fs from "fs"; +import path from "path"; +import Head from "next/head"; + +import { loadTestCaseFixture } from "@cursorless/test-case-component"; +import { TestCaseComponentPage } from "@cursorless/test-case-component"; +import type { TestCaseFixture } from "@cursorless/common"; +import { testSelectedFiles } from "./allowList"; + +import { cheatsheetBodyClasses } from "@cursorless/cheatsheet"; + +const fixturesDir = path.join("../", "../", "data", "fixtures", "recorded"); + +async function loadYamlFiles(dir: string, selectedFiles?: string[]) { + const directoryPath = path.join(process.cwd(), dir); + const files = fs.readdirSync(directoryPath); + const data: any[] = []; + + files.forEach((file) => { + if ( + path.extname(file) === ".yml" && + (!selectedFiles || selectedFiles.includes(file)) + ) { + try { + const filePath = path.join(directoryPath, file); + const fileContents = fs.readFileSync(filePath, "utf8"); + const yamlData: any = yaml.load(fileContents); + yamlData.filename = file; + data.push(yamlData); + } catch { + console.error("File load failure", file); + } + } + }); + + return data; +} + +// See https://github.com/vercel/next.js/discussions/12325#discussioncomment-1116108 +export async function getStaticProps() { + const itemsDirActions = path.join(fixturesDir, "actions"); + const itemsDirDecorations = path.join(fixturesDir, "decorations"); + + const dataActions = await loadYamlFiles(itemsDirActions, testSelectedFiles); + const dataDecorations = await loadYamlFiles( + itemsDirDecorations, + testSelectedFiles, + ); + + const data_errors: any[] = []; + + const data = ( + await Promise.all( + [...dataActions, ...dataDecorations].map(async (val) => { + try { + // const upgraded = upgrade(data); + const fixture = await loadTestCaseFixture(val); + return { ...fixture, raw: val }; + } catch (err) { + console.error(err); + data_errors.push(val); + return null; + } + }), + ) + ).filter((test) => test !== undefined); + + if (data_errors.length > 0) { + console.error("data errors:", data_errors); + } + + return { props: { data, bodyClasses: cheatsheetBodyClasses } }; +} + +export function App({ data }: { data: TestCaseFixture[] }) { + return ( + <> + + Cursorless Test Case Component Page + + + + ); +} + +export default App; diff --git a/packages/cursorless-org/tsconfig.json b/packages/cursorless-org/tsconfig.json index 2ce4454b4f..3d03265117 100644 --- a/packages/cursorless-org/tsconfig.json +++ b/packages/cursorless-org/tsconfig.json @@ -23,6 +23,12 @@ "references": [ { "path": "../cheatsheet" + }, + { + "path": "../cursorless-engine" + }, + { + "path": "../test-case-component" } ], "exclude": ["node_modules"] diff --git a/packages/cursorless-vscode/package.json b/packages/cursorless-vscode/package.json index 593bcbdc1a..3cf8ca9ad1 100644 --- a/packages/cursorless-vscode/package.json +++ b/packages/cursorless-vscode/package.json @@ -1261,7 +1261,9 @@ "clean": "rm -rf ./out tsconfig.tsbuildinfo ./dist ./build" }, "devDependencies": { - "@types/fs-extra": "11.0.4", + "@types/chai": "^4.3.14", + "@types/fs-extra": "^11.0.4", + "@types/glob": "^8.1.0", "@types/js-yaml": "^4.0.9", "@types/lodash-es": "4.17.12", "@types/nearley": "2.11.5", diff --git a/packages/test-case-component/jest.config.ts b/packages/test-case-component/jest.config.ts new file mode 100644 index 0000000000..f7a6a00f40 --- /dev/null +++ b/packages/test-case-component/jest.config.ts @@ -0,0 +1,8 @@ +import type { Config } from "jest"; + +const config: Config = { + preset: "ts-jest", + testEnvironment: "jsdom", +}; + +export default config; diff --git a/packages/test-case-component/package.json b/packages/test-case-component/package.json new file mode 100644 index 0000000000..3d37d70a07 --- /dev/null +++ b/packages/test-case-component/package.json @@ -0,0 +1,49 @@ +{ + "name": "@cursorless/test-case-component", + "version": "0.0.1", + "type": "module", + "description": "Component for displaying results of test cases in cursorless-vscode-e2e", + "main": "./out/index.js", + "scripts": { + "build": "my-ts-node src/buildDictionary.ts", + "test": "jest", + "test:watch": "jest --watch", + "compile:tsc": "tsc --build", + "compile:esbuild": "esbuild ./src/index.ts --sourcemap --format=esm --bundle --packages=external --outfile=./out/index.js", + "compile": "pnpm compile:tsc && pnpm compile:esbuild", + "watch:tsc": "pnpm compile:tsc --watch", + "watch:esbuild": "pnpm compile:esbuild --watch", + "watch": "pnpm run --filter @cursorless/test-case-component --parallel '/^watch:.*/'", + "clean": "rm -rf ./out tsconfig.tsbuildinfo ./dist ./build" + }, + "keywords": [], + "author": "", + "license": "MIT", + "dependencies": { + "@cursorless/common": "workspace:*", + "@cursorless/node-common": "workspace:*", + "escape-goat": "4.0.0", + "fs-extra": "11.2.0", + "js-yaml": "^4.1.0", + "prettier": "3.2.5", + "react": "^18.2.0", + "tsx": "3.12.7", + "yaml": "2.2.1" + }, + "types": "./out/index.d.ts", + "exports": { + ".": { + "cursorless:bundler": "./src/index.ts", + "default": "./out/index.js" + } + }, + "devDependencies": { + "@types/fs-extra": "^11.0.4", + "@types/jest": "29.5.12", + "@types/react": "18.2.71", + "jest": "29.7.0", + "jest-environment-jsdom": "29.7.0", + "shiki": "^3.2.2", + "ts-jest": "29.1.2" + } +} diff --git a/packages/test-case-component/src/components/TestCaseComponentPage.tsx b/packages/test-case-component/src/components/TestCaseComponentPage.tsx new file mode 100644 index 0000000000..02ffbc7648 --- /dev/null +++ b/packages/test-case-component/src/components/TestCaseComponentPage.tsx @@ -0,0 +1,25 @@ +import * as React from "react"; +import { ShikiComponent } from "./shikiComponent"; +import "../shiki.css"; +import "../styles.css"; +import type { TestCaseFixture } from "@cursorless/common"; + +export function TestCaseComponentPage({ data }: { data: TestCaseFixture[] }) { + return ( +
+

+ Test Component Sheet{" "} + + See the {/* */} + full documentation + {/* {" "} */} + to learn more. + +

+ + {data.map((item: any) => { + return ; + })} +
+ ); +} diff --git a/packages/test-case-component/src/components/shikiComponent.tsx b/packages/test-case-component/src/components/shikiComponent.tsx new file mode 100644 index 0000000000..045b8ea734 --- /dev/null +++ b/packages/test-case-component/src/components/shikiComponent.tsx @@ -0,0 +1,45 @@ +export function ShikiComponent({ data }: { data: any }) { + return ( +
+
+

{data.command}

+
+ +
{data.command}
+ + +
+
+
+ JSON +
+          {JSON.stringify(data, null, 2)}
+        
+
+
+ ); +} + +const Before = ({ content }: { content: string }) => { + return
; +}; + +const During = ({ content }: { content: string }) => { + if (content) { + console.log("🧄", content); + + return ( +
+ ); + } + return <>; +}; + +const After = ({ content }: { content: string }) => { + return ( +
+ ); +}; diff --git a/packages/test-case-component/src/generateHtml.spec.ts b/packages/test-case-component/src/generateHtml.spec.ts new file mode 100644 index 0000000000..a6bdaa1bea --- /dev/null +++ b/packages/test-case-component/src/generateHtml.spec.ts @@ -0,0 +1,314 @@ +import prettier from "prettier"; +import { generateHtml as unformettedFunc } from "./generateHtml"; + +async function generateHtml(...args: Parameters) { + return prettier.format(await unformettedFunc(...args), { + singleAttributePerLine: true, + htmlWhitespaceSensitivity: "ignore", + parser: "babel", + }); +} + +// uses mocha for most tests +// okay to stick with Jest if needed +// cheatsheet might use Jest? + +describe("generateHtml", () => { + it("should select whole line", async () => { + expect( + await generateHtml( + { + documentContents: " const oneLine = 1;\nconst line2 = 2;", + selections: [ + { + type: "line", + anchor: { line: 1, character: 0 }, + active: { line: 1, character: 22 }, + }, + ], + }, + + "typescript", + ), + ).toMatchInlineSnapshot(` + "
+        
+          
+             
+            const
+             
+            oneLine
+             
+            =
+             
+            1
+            ;
+          
+          
+            const
+             
+            line2
+             
+            =
+             
+            2
+            ;
+          
+        
+      
; + " + `); + }); + it("should select single token", async () => { + expect( + await generateHtml( + { + documentContents: " const oneLine = 1;\nconst line2 = 2;", + selections: [ + { + type: "selection", + anchor: { line: 0, character: 8 }, + active: { line: 0, character: 15 }, + }, + ], + }, + + "typescript", + ), + ).toMatchInlineSnapshot(` + "
+        
+          
+             
+            const
+             
+            
+              oneLine
+            
+             
+            =
+             
+            1
+            ;
+          
+          
+            const
+             
+            line2
+             
+            =
+             
+            2
+            ;
+          
+        
+      
; + " + `); + }); + + it("should select multiple tokens", async () => { + expect( + await generateHtml( + { + documentContents: "const oneLine = 1;", + selections: [ + { + type: "selection", + anchor: { line: 0, character: 6 }, + active: { line: 0, character: 17 }, + }, + ], + }, + + "typescript", + ), + ).toMatchInlineSnapshot(` + "
+        
+          
+            const
+             
+            
+              oneLine
+               
+              =
+               
+              1
+            
+            ;
+          
+        
+      
; + " + `); + }); + + it("should select inside tokens", async () => { + expect( + await generateHtml( + { + documentContents: 'const oneLine = "line";', + selections: [ + { + type: "selection", + anchor: { line: 0, character: 9 }, + active: { line: 0, character: 19 }, + }, + ], + }, + + "typescript", + ), + ).toMatchInlineSnapshot(` + "
+        
+          
+            const
+             
+            one
+            
+              Line
+               
+              =
+               
+              
+                "li
+              
+            
+            ne"
+            ;
+          
+        
+      
; + " + `); + }); + + it("should select inside single token", async () => { + expect( + await generateHtml( + { + documentContents: "const oneLine = 1;", + selections: [ + { + type: "selection", + anchor: { line: 0, character: 9 }, + active: { line: 0, character: 11 }, + }, + ], + }, + + "typescript", + ), + ).toMatchInlineSnapshot(` + "
+        
+          
+            const
+             
+            one
+            
+              Li
+            
+            ne
+             
+            =
+             
+            1
+            ;
+          
+        
+      
; + " + `); + }); + it("should select superset ranges", async () => { + expect( + await generateHtml( + { + documentContents: "const oneLine = 1;", + selections: [ + { + type: "selection", + anchor: { line: 0, character: 9 }, + active: { line: 0, character: 11 }, + }, + ], + thatMark: [ + { + type: "selection", + anchor: { line: 0, character: 6 }, + active: { line: 0, character: 13 }, + }, + ], + }, + + "typescript", + ), + ).toMatchInlineSnapshot(` + "
+        
+          
+            const
+             
+            
+              one
+            
+            
+              Li
+            
+            
+              ne
+            
+             
+            =
+             
+            1
+            ;
+          
+        
+      
; + " + `); + }); +}); diff --git a/packages/test-case-component/src/generateHtml.ts b/packages/test-case-component/src/generateHtml.ts new file mode 100644 index 0000000000..c89dcd39d8 --- /dev/null +++ b/packages/test-case-component/src/generateHtml.ts @@ -0,0 +1,109 @@ +import { createHighlighter, createCssVariablesTheme } from "shiki"; +import type { BundledLanguage } from "shiki"; + +import type { TargetPlainObject, TestCaseSnapshot } from "@cursorless/common"; + +import { createDecorations } from "./helpers"; + +type Lang = BundledLanguage; + +const myTheme = createCssVariablesTheme({ + name: "css-variables", + variablePrefix: "--shiki-", + variableDefaults: {}, + fontStyle: true, +}); + +/** + * Generates HTML content based on the provided state, language, command, and ide. + * + * @param {TestCaseSnapshot} state - The state object containing the necessary data for HTML generation. + * @param {Lang} lang - The language object specifying the language for the HTML content. + * @param {any} [command] - (Optional) The command object specifying the command details. + * @param {any} [ide] - (Optional) The ide object specifying the IDE details. + * @returns {Promise} A promise that resolves to the generated HTML content. + */ +export async function generateHtml({ + stateName, + state, + languageId: lang, + command, + ide, + raw +}: { + stateName: string; + state: TestCaseSnapshot; + languageId: BundledLanguage; + command?: any; // Replace `any` with the appropriate type if with + ide?: any; // Replace `any` with the appropriate type if known + raw: any; +}) { + return new HTMLGenerator({ state, lang, command, ide, raw }).generate(); +} + +const highlighter = createHighlighter({ + themes: [myTheme], + langs: ["javascript", "typescript"], +}); + +class HTMLGenerator { + private state: TestCaseSnapshot; + private lang: Lang; + private command?: any; + private ide?: any; + private raw: any; + + constructor({ + state, + lang, + command, + ide, + raw + }: { + state: TestCaseSnapshot, + lang: Lang, + command?: any, + ide?: any, + raw?: any + }) { + this.state = state; + this.lang = lang; + this.command = command; // Optional command parameter + this.ide = ide; // Optional ide parameter + this.raw = raw + } + + + async generate() { + const decorations = await this.getDecorations(); + const options = { + theme: "css-variables", + lang: this.lang, + decorations + }; + + const marker = await highlighter + const codeBody = marker.codeToHtml(this.state.documentContents, options) + let clipboard = "" + if (this.state.clipboard) { + clipboard = `
clipboard: ${this.state.clipboard}
` + } + const output = clipboard !== "" ? codeBody + clipboard : codeBody + return output + } + + async getDecorations() { + const potentialMarks = this.state.marks || {} + const lines = this.state.documentContents.split("\n") + console.log("💎", this.state.thatMark) + const decorations = createDecorations({ + marks: potentialMarks, + ide: this.ide, + command: this.command, + lines, + selections: this.state.selections, + thatMark: this.state.thatMark + }) + return decorations + } +} diff --git a/packages/test-case-component/src/helpers.ts b/packages/test-case-component/src/helpers.ts new file mode 100644 index 0000000000..a27f05e3c3 --- /dev/null +++ b/packages/test-case-component/src/helpers.ts @@ -0,0 +1,275 @@ +import type { + // PositionPlainObject, + SelectionPlainObject, + SerializedMarks, + TargetPlainObject, +} from "@cursorless/common"; + +import type { DecorationItem } from "shiki" + +/** + * Splits a string into an array of objects containing the line content + * and the cumulative offset from the start of the string. + * + * @param {string} documentContents - The string to split into lines. + * @returns {{ line: string, offset: number }[]} An array of objects with line content and cumulative offset. + */ +function splitDocumentWithOffsets(documentContents: string): { line: string; offset: number }[] { + const lines = documentContents.split("\n"); + let cumulativeOffset = 0; + + return lines.map((line) => { + const result = { line, offset: cumulativeOffset }; + cumulativeOffset += line.length + 1; // +1 for the newline character + return result; + }); +} + +/** + * Creates decorations based on the split document with offsets and marks. + * + * @param {Object} options - An object containing optional fields like marks, command, or ide. + * @param {SerializedMarks} [options.marks] - An object containing marks with line, start, and end positions. + * @param {any} [options.command] - (Optional) The command object specifying the command details. + * @param {any} [options.ide] - (Optional) The ide object specifying the IDE details. + * @returns {DecorationItem[]} An array of decoration objects. + */ +function createDecorations( + options: { + marks?: SerializedMarks; + command?: any; + ide?: any; + lines?: string[] + selections?: SelectionPlainObject[] + thatMark?: TargetPlainObject[] + } = {} // Default to an empty object +): DecorationItem[] { + const { marks, ide, lines, selections, thatMark /* command */ } = options + if (thatMark) { + console.log("📅", thatMark) + } + + const decorations: DecorationItem[] = []; + const markDecorations = getMarkDecorations({ marks, lines }) + const ideFlashDecorations = getIdeFlashDecorations({ lines, ide }) + decorations.push(...markDecorations); + decorations.push(...ideFlashDecorations); + const selectionRanges = getSlections({ selections }) + decorations.push(...selectionRanges); + + if (thatMark) { + const modificationReferences = getThatMarks({ thatMark }) + decorations.push(...modificationReferences); + } + + return decorations + +} + +/** + * Generates Shiki decorations for marks on a specific line. + * + * @param {Object} params - The parameters for generating decorations. + * @param {SerializedMarks} [params.marks] - An object containing serialized marks with start and end positions. + * @param {number} params.index - The index of the current line being processed. + * @param {{ line: string; offset: number }} params.lineData - The line content and its cumulative offset. + * @returns {DecorationItem[]} An array of Shiki decorations for the specified line. + * + */ +function getMarkDecorations({ + marks, + lines +}: { + marks?: SerializedMarks; + lines?: string[] +}): DecorationItem[] { + const decorations: DecorationItem[] = []; + + Object.entries(marks || {}).forEach(([key, { start, end }]) => { + const [hatType, letter] = key.split(".") as [keyof typeof classesMap, string]; + console.log("🔑", key, start, end); + + const markLineStart = start.line + + if (!lines) { + console.warn("Lines are undefined. Skipping decoration generation."); + return []; + } + const currentLine = lines[markLineStart] + + const searchStart = start.character; + const nextLetterIndex = currentLine.indexOf(letter, searchStart); + + if (nextLetterIndex === -1) { + console.warn( + `Letter "${letter}" not found after position ${searchStart} in line: "${currentLine}"` + ); + return; // Skip this mark if the letter is not found + } + + const decorationItem: DecorationItem = { + start, + end: { line: start.line, character: nextLetterIndex + 1 }, + properties: { + class: getDecorationClass(hatType), // Replace with the desired class name for marks + }, + alwaysWrap: true, + } + + console.log("🔑🔑", decorationItem) + + decorations.push(decorationItem); + }); + + return decorations; +} + +type LineRange = { type: string; start: number; end: number } +type PositionRange = { type: string; start: { line: number; character: number }; end: { line: number; character: number } }; + +type RangeType = + | LineRange + | PositionRange + + +function getIdeFlashDecorations({ + ide, + lines, +}: { + ide?: { + flashes?: { style: keyof typeof classesMap; range: RangeType }[]; + }; + lines?: string[]; +} = {}): DecorationItem[] { + if (!lines) { + console.warn("Lines are undefined. Skipping line decorations."); + return []; + } + + if (!ide?.flashes || !Array.isArray(ide.flashes)) { + console.warn("No flashes found in IDE. Skipping line decorations."); + return []; + } + + const decorations: DecorationItem[] = []; + + const { flashes } = ide + + flashes.forEach(({ style, range }) => { + const { type } = range; + + if (isLineRange(range)) { + const { start: lineStart, end: lineEnd } = range + + /* Split a multi-line range into single lines so that shiki doesn't add + * multiple classes to the same span causing CSS conflicts + */ + for (let line = lineStart; line <= lineEnd; line++) { + const contentLine = lines[line]; + const startPosition = { line, character: 0 }; + const endPosition = { line, character: contentLine.length }; + const decorationItem = { + start: startPosition, + end: endPosition, + properties: { + class: `${getDecorationClass(style)} full`, + }, + alwaysWrap: true, + }; + console.log("🔥🔥", decorationItem); + decorations.push(decorationItem); + } + + } else if (isPositionRange(range)) { + const { start: rangeStart, end: rangeEnd } = range; + const decorationItem = { + start: rangeStart, + end: rangeEnd, + properties: { + class: getDecorationClass(style), + }, + alwaysWrap: true, + } + console.log("🔥🔥", decorationItem) + decorations.push(decorationItem); + } else { + console.warn(`Unknown range type "${type}". Skipping this flash.`); + } + }); + + return decorations; +} + +function getSlections( + { + selections, + }: { + selections?: SelectionPlainObject[]; + lines?: string[] + }): DecorationItem[] { + const decorations: DecorationItem[] = []; + if (selections === undefined || selections.length === 0) { + console.warn("Lines are undefined. Skipping decoration generation."); + return [] + } + selections.forEach(({ anchor, active }) => { + const decorationItem = { + start: anchor, + end: active, + properties: { + class: getDecorationClass("selection"), + }, + alwaysWrap: true, + } + decorations.push(decorationItem) + console.log("🟦", decorationItem) + }) + + return decorations +} + +function getThatMarks({ thatMark }: { thatMark: TargetPlainObject[] }): DecorationItem[] { + console.log("☝️", thatMark) + const decorations: DecorationItem[] = []; + if (thatMark === undefined) { + console.warn("thatMarks are undefined. Skipping decoration generation."); + return [] + } + + return decorations +} + +// Type guard for line range +function isLineRange(range: RangeType): range is LineRange { + return typeof range.start === "number" + && typeof range.end === "number" + && range.type === "line"; +} + +// Type guard for position range +function isPositionRange( + range: RangeType +): range is PositionRange { + return typeof range.start === "object" + && typeof range.end === "object" + && range.type === "character"; +} + + +const DEFAULT_HAT_CLASS = "hat default"; +const classesMap = { + default: DEFAULT_HAT_CLASS, + pendingDelete: "decoration pendingDeleteBackground", + referenced: "decoration referencedBackground", + selection: "selection" +}; + +function getDecorationClass(key: keyof typeof classesMap): string { + return classesMap[key] || DEFAULT_HAT_CLASS; +} + + +export { + splitDocumentWithOffsets, + createDecorations +} \ No newline at end of file diff --git a/packages/test-case-component/src/index.ts b/packages/test-case-component/src/index.ts new file mode 100644 index 0000000000..a98f0c68a6 --- /dev/null +++ b/packages/test-case-component/src/index.ts @@ -0,0 +1,2 @@ +export * from "./components/TestCaseComponentPage"; +export * from "./loadTestCaseFixture"; \ No newline at end of file diff --git a/packages/test-case-component/src/loadTestCaseFixture.ts b/packages/test-case-component/src/loadTestCaseFixture.ts new file mode 100644 index 0000000000..4a5e48457a --- /dev/null +++ b/packages/test-case-component/src/loadTestCaseFixture.ts @@ -0,0 +1,114 @@ +import type { TargetPlainObject, TestCaseFixture, TestCaseSnapshot } from "@cursorless/common"; +import { generateHtml } from "./generateHtml"; +import type { BundledLanguage } from "shiki"; + +async function safeGenerateHtml({ + stateName, + state, + languageId, + command, + ide, + thatMarkFinalState +}: { + stateName: string; + state: TestCaseSnapshot; + languageId: BundledLanguage; + command?: any; // Replace `any` with the appropriate type if known + ide?: any; // Replace `any` with the appropriate type if known + thatMarkFinalState?: TargetPlainObject +}) { + console.log("✨" + stateName + "✨"); + try { + const genObj = { stateName, state, languageId, command, ide } + return await generateHtml(genObj); + } catch (e) { + console.error("error in state", stateName, e); + console.error(JSON.stringify(state, null, 2)); + throw e; + } +} + +interface loadFixtureProps extends TestCaseFixture { + filename: string; + languageId: BundledLanguage; + initialState: TestCaseSnapshot; + finalState: TestCaseSnapshot; +} + +export async function loadTestCaseFixture(data: loadFixtureProps) { + try { + const before = await getBefore({ + stateName: "initialState", + state: data.initialState, + languageId: data.languageId, + }); + + const during = await getDuring(data); + + const after = await getAfter({ + stateName: "finalState", + state: data.finalState, + languageId: data.languageId, + }); + + return { + language: data.languageId, + command: data.command.spokenForm, + during, + before, + after, + filename: data.filename, + }; + } catch (e) { + console.log("error", e); + console.log(JSON.stringify(data, null, 2)); + throw e; + } +} + +type Foo = TestCaseSnapshot & TargetPlainObject; + +async function getAfter({ + stateName, + state, + languageId, +}: { + stateName: string; + state: Foo; + languageId: BundledLanguage; +}) { + if (!state) { + throw new Error("finalState is undefined"); + } + return await safeGenerateHtml({ stateName, state, languageId }); +} + +type DataFixture = Partial + +async function getDuring(data: DataFixture) { + const { command, ide } = data + const stateName = "middleState" + const state = data.initialState + const languageId = data.languageId as BundledLanguage + const genObj: TestCaseSnapshot & { stateName: string } = { stateName, state, languageId, raw: data } + if (command) { + genObj.command = command + } + if (ide) { + genObj.ide = ide + } + + return await generateHtml(genObj); +} + +async function getBefore({ + stateName, + state, + languageId, +}: { + stateName: string; + state: TestCaseSnapshot; + languageId: BundledLanguage; +}) { + return await safeGenerateHtml({ stateName, state, languageId }); +} \ No newline at end of file diff --git a/packages/test-case-component/src/shiki.css b/packages/test-case-component/src/shiki.css new file mode 100644 index 0000000000..3ff520baf7 --- /dev/null +++ b/packages/test-case-component/src/shiki.css @@ -0,0 +1,48 @@ +:root { + --shiki-foreground: #eeeeee; + --shiki-color-text: #eeeeee; + --shiki-background: #1f1f1f; + --shiki-token-constant: #ff6666; + --shiki-token-string: #c2ff6d; + --shiki-token-comment: #15bc28; + --shiki-token-keyword: #f3ff4c; + --shiki-token-parameter: #ff8741; + --shiki-token-function: #ff2828; + --shiki-token-string-expression: #cc0000; + --shiki-token-punctuation: #f958ff; + --shiki-token-link: #ee0000; + + /* Only required if using lang: 'ansi' */ + --shiki-ansi-black: #000000; + --shiki-ansi-black-dim: #00000080; + --shiki-ansi-red: #bb0000; + --shiki-ansi-red-dim: #bb000080; + --shiki-ansi-green: #00bb00; + --shiki-ansi-green-dim: #00bb0080; + --shiki-ansi-yellow: #bbbb00; + --shiki-ansi-yellow-dim: #bbbb0080; + --shiki-ansi-blue: #0000bb; + --shiki-ansi-blue-dim: #0000bb80; + --shiki-ansi-magenta: #ff00ff; + --shiki-ansi-magenta-dim: #ff00ff80; + --shiki-ansi-cyan: #00bbbb; + --shiki-ansi-cyan-dim: #00bbbb80; + --shiki-ansi-white: #eeeeee; + --shiki-ansi-white-dim: #eeeeee80; + --shiki-ansi-bright-black: #555555; + --shiki-ansi-bright-black-dim: #55555580; + --shiki-ansi-bright-red: #ff5555; + --shiki-ansi-bright-red-dim: #ff555580; + --shiki-ansi-bright-green: #00ff00; + --shiki-ansi-bright-green-dim: #00ff0080; + --shiki-ansi-bright-yellow: #ffff55; + --shiki-ansi-bright-yellow-dim: #ffff5580; + --shiki-ansi-bright-blue: #5555ff; + --shiki-ansi-bright-blue-dim: #5555ff80; + --shiki-ansi-bright-magenta: #ff55ff; + --shiki-ansi-bright-magenta-dim: #ff55ff80; + --shiki-ansi-bright-cyan: #55ffff; + --shiki-ansi-bright-cyan-dim: #55ffff80; + --shiki-ansi-bright-white: #ffffff; + --shiki-ansi-bright-white-dim: #ffffff80; +} diff --git a/packages/test-case-component/src/styles.css b/packages/test-case-component/src/styles.css new file mode 100644 index 0000000000..eaef0b4343 --- /dev/null +++ b/packages/test-case-component/src/styles.css @@ -0,0 +1,177 @@ +:root { + --line-height: 2rem; + --color-border: #0003; +} + +body { + display: grid; + height: 100vh; + gap: 24px; + place-items: flex-start; + justify-items: stretch; + padding: 42px; + font-family: firacode, SFMono-Regular, Consolas, "Liberation Mono", Menlo, + monospace; + /* background-image: radial-gradient(at 30% 89%, hsla(220,76%,68%,1) 0px, transparent 50%), radial-gradient(at 35% 0%, hsla(242,68%,61%,1) 0px, transparent 50%), radial-gradient(at 93% 46%, hsla(129,87%,73%,1) 0px, transparent 50%), radial-gradient(at 23% 49%, hsla(50,77%,67%,1) 0px, transparent 50%), radial-gradient(at 17% 27%, hsla(331,64%,60%,1) 0px, transparent 50%), radial-gradient(at 79% 30%, hsla(151,61%,77%,1) 0px, transparent 50%), radial-gradient(at 26% 40%, hsla(36,65%,63%,1) 0px, transparent 50%); */ +} + +pre code { + display: grid; /* Ensure each line is treated as a block */ +} + +pre { + counter-reset: line; /* Initialize a counter for line numbers */ +} + +.line::before { + counter-increment: line; /* Increment the line counter */ + content: counter(line); /* Display the current line number */ + padding-inline: 1em; + text-align: right; + color: gray; /* Style the line numbers */ + font-size: 0.9em; + position: absolute; + left: -40px; /* Align line numbers to the left */ +} + +.line { + margin-left: 1.5rem; + position: relative; + width: 100%; + display: inline-block; + /* display: block; */ + /* padding-top: 1rem; */ +} + +pre.shiki, +pre.shiki span { + line-height: var(--line-height); + min-height: var(--line-height); + font-size: 20px; +} + +.wrapper { + display: flex; + flex-direction: column; + gap: 16px; + padding: 16px; + border: 1px solid var(--color-border); + box-shadow: 0px 0px 6px #000a; + border-radius: 8px; + background: #ccc9; + & > div { + background: #fff; + border: 1px solid var(--color-border); + border-radius: 8px; + } +} + +pre.shiki { + padding: 12px 16px; + display: flex; + flex-direction: column; + .line { + display: inline-block; + } +} + +.command { + /* border-top: 1px solid var(--color-border); */ + padding: 8px; + font-weight: bold; + text-align: center; +} + +@keyframes blink { + 0%, + 60% { + border-color: #667f; + } + 61%, + 100% { + border-color: #6670; + } +} + +.selection { + /* display: inline-block; */ + border-right: 2px solid #00b; + animation: blink 1400ms infinite; + padding: 0px 0.5px 0px 0; + margin: 0 0px 0 -1px; + height: var(--line-height); +} + +.selection:not(:empty) { + background: #55f2; + padding-left: 0.5px; +} +.decoration { + display: inline-block; + /* padding: 0px 0.5px 0px 0.5px; */ + /* margin: 0 0px 0 -1px; */ + /* height: var(--line-height); */ + /* width: 100%; */ +} + +.full { + width: 100%; +} + +.decoration.pendingDeleteBackground { + background-color: #ff00008a; +} + +.decoration.referencedBackground { + background-color: #00a2ff4d; +} + +.decoration.justAddedBackground { + background-color: #09ff005b; +} + +.decoration.pendingModification0Background { + background-color: #8c00ff86; +} + +.decoration.pendingModification1Background { + background-color: #ff009d7e; +} + +.decoration.highlight0Background { + background-color: #d449ff42; +} + +.decoration.highlight1Background { + background-color: #60daff7a; +} + +.decoration.timingCalibrationBackground { + background-color: #230026; +} + +.hat { + position: relative; + display: inline-block; + &::after { + content: ""; + /* display: inline; */ + /* top: 0px; */ + /* left: 50%; */ + position: absolute; + transform: translate(-110%, -50%); + background-color: #b8b6cd; + mask-repeat: no-repeat; + width: 0.5rem; + height: 0.5rem; + } +} +.hat.default::after { + mask-image: url('data:image/svg+xml;utf8,'); + top: 0.2rem; + width: 0.5rem; + height: 0.5rem; +} +.hat.wing::after { + mask-image: url('data:image/svg+xml;utf8,'); +} diff --git a/packages/test-case-component/src/types.ts b/packages/test-case-component/src/types.ts new file mode 100644 index 0000000000..16a03c7680 --- /dev/null +++ b/packages/test-case-component/src/types.ts @@ -0,0 +1,213 @@ +export type Lang = + | "abap" + | "actionscript-3" + | "ada" + | "apache" + | "apex" + | "apl" + | "applescript" + | "ara" + | "asm" + | "astro" + | "awk" + | "ballerina" + | "bat" + | "batch" + | "beancount" + | "berry" + | "be" + | "bibtex" + | "bicep" + | "blade" + | "c" + | "cadence" + | "cdc" + | "clarity" + | "clojure" + | "clj" + | "cmake" + | "cobol" + | "codeql" + | "ql" + | "coffee" + | "cpp" + | "crystal" + | "csharp" + | "c#" + | "cs" + | "css" + | "cue" + | "cypher" + | "cql" + | "d" + | "dart" + | "dax" + | "diff" + | "docker" + | "dockerfile" + | "dream-maker" + | "elixir" + | "elm" + | "erb" + | "erlang" + | "erl" + | "fish" + | "fsharp" + | "f#" + | "fs" + | "gdresource" + | "gdscript" + | "gdshader" + | "gherkin" + | "git-commit" + | "git-rebase" + | "glimmer-js" + | "gjs" + | "glimmer-ts" + | "gts" + | "glsl" + | "gnuplot" + | "go" + | "graphql" + | "groovy" + | "hack" + | "haml" + | "handlebars" + | "hbs" + | "haskell" + | "hs" + | "hcl" + | "hjson" + | "hlsl" + | "html" + | "http" + | "imba" + | "ini" + | "properties" + | "java" + | "javascript" + | "js" + | "jinja-html" + | "jison" + | "json" + | "json5" + | "jsonc" + | "jsonl" + | "jsonnet" + | "jssm" + | "fsl" + | "jsx" + | "julia" + | "kotlin" + | "kusto" + | "kql" + | "latex" + | "less" + | "liquid" + | "lisp" + | "logo" + | "lua" + | "make" + | "makefile" + | "markdown" + | "md" + | "marko" + | "matlab" + | "mdx" + | "mermaid" + | "narrat" + | "nar" + | "nextflow" + | "nf" + | "nginx" + | "nim" + | "nix" + | "objective-c" + | "objc" + | "objective-cpp" + | "ocaml" + | "pascal" + | "perl" + | "php" + | "plsql" + | "postcss" + | "powerquery" + | "powershell" + | "ps" + | "ps1" + | "prisma" + | "prolog" + | "proto" + | "pug" + | "jade" + | "puppet" + | "purescript" + | "python" + | "py" + | "r" + | "raku" + | "perl6" + | "razor" + | "reg" + | "rel" + | "riscv" + | "rst" + | "ruby" + | "rb" + | "rust" + | "rs" + | "sas" + | "sass" + | "scala" + | "scheme" + | "scss" + | "shaderlab" + | "shader" + | "shellscript" + | "bash" + | "console" + | "sh" + | "shell" + | "zsh" + | "smalltalk" + | "solidity" + | "sparql" + | "sql" + | "ssh-config" + | "stata" + | "stylus" + | "styl" + | "svelte" + | "swift" + | "system-verilog" + | "tasl" + | "tcl" + | "tex" + | "toml" + | "tsx" + | "turtle" + | "twig" + | "typescript" + | "ts" + | "v" + | "vb" + | "cmd" + | "verilog" + | "vhdl" + | "viml" + | "vim" + | "vimscript" + | "vue-html" + | "vue" + | "vyper" + | "vy" + | "wasm" + | "wenyan" + | "文言" + | "wgsl" + | "wolfram" + | "xml" + | "xsl" + | "yaml" + | "yml" + | "zenscript"; diff --git a/packages/test-case-component/tsconfig.json b/packages/test-case-component/tsconfig.json new file mode 100644 index 0000000000..ba7a4452d7 --- /dev/null +++ b/packages/test-case-component/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "jsx": "react-jsx", + "esModuleInterop": true, + "skipLibCheck": true, + "lib": ["es5", "es6", "dom"] + }, + "references": [ + { + "path": "../common" + }, + { + "path": "../node-common" + } + ], + "include": [ + "src/**/*.ts", + "src/**/*.json", + "src/**/*.tsx", + "../../typings/**/*.d.ts" + ] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b2a5d2a1aa..80f826fc52 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -457,6 +457,12 @@ importers: '@cursorless/cheatsheet': specifier: workspace:* version: link:../cheatsheet + '@cursorless/common': + specifier: workspace:* + version: link:../common + '@cursorless/test-case-component': + specifier: workspace:* + version: link:../test-case-component '@mdx-js/loader': specifier: 3.0.1 version: 3.0.1(webpack@5.95.0(esbuild@0.25.0)) @@ -482,6 +488,9 @@ importers: '@svgr/webpack': specifier: 8.1.0 version: 8.1.0(typescript@5.6.3) + '@types/js-yaml': + specifier: ^4.0.9 + version: 4.0.9 '@types/mdx': specifier: 2.0.13 version: 2.0.13 @@ -659,9 +668,15 @@ importers: specifier: ^3.0.8 version: 3.0.8 devDependencies: + '@types/chai': + specifier: ^4.3.14 + version: 4.3.20 '@types/fs-extra': - specifier: 11.0.4 + specifier: ^11.0.4 version: 11.0.4 + '@types/glob': + specifier: ^8.1.0 + version: 8.1.0 '@types/js-yaml': specifier: ^4.0.9 version: 4.0.9 @@ -892,6 +907,58 @@ importers: specifier: ^10.7.3 version: 10.7.3 + packages/test-case-component: + dependencies: + '@cursorless/common': + specifier: workspace:* + version: link:../common + '@cursorless/node-common': + specifier: workspace:* + version: link:../node-common + escape-goat: + specifier: 4.0.0 + version: 4.0.0 + fs-extra: + specifier: 11.2.0 + version: 11.2.0 + js-yaml: + specifier: ^4.1.0 + version: 4.1.0 + prettier: + specifier: 3.2.5 + version: 3.2.5 + react: + specifier: ^18.2.0 + version: 18.3.1 + tsx: + specifier: 3.12.7 + version: 3.12.7 + yaml: + specifier: 2.2.1 + version: 2.2.1 + devDependencies: + '@types/fs-extra': + specifier: ^11.0.4 + version: 11.0.4 + '@types/jest': + specifier: 29.5.12 + version: 29.5.12 + '@types/react': + specifier: 18.2.71 + version: 18.2.71 + jest: + specifier: 29.7.0 + version: 29.7.0(@types/node@20.16.0)(ts-node@10.9.2(@types/node@20.16.0)(typescript@5.6.3)) + jest-environment-jsdom: + specifier: 29.7.0 + version: 29.7.0 + shiki: + specifier: ^3.2.2 + version: 3.2.2 + ts-jest: + specifier: 29.1.2 + version: 29.1.2(@babel/core@7.25.8)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.8))(esbuild@0.25.0)(jest@29.7.0(@types/node@20.16.0)(ts-node@10.9.2(@types/node@20.16.0)(typescript@5.6.3)))(typescript@5.6.3) + packages/test-case-recorder: dependencies: '@cursorless/common': @@ -1918,102 +1985,210 @@ packages: html-webpack-plugin: '>=5' webpack: '>=5' + '@esbuild-kit/cjs-loader@2.4.4': + resolution: {integrity: sha512-NfsJX4PdzhwSkfJukczyUiZGc7zNNWZcEAyqeISpDnn0PTfzMJR1aR8xAIPskBejIxBJbIgCCMzbaYa9SXepIg==} + deprecated: 'Merged into tsx: https://tsx.is' + + '@esbuild-kit/core-utils@3.3.2': + resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} + deprecated: 'Merged into tsx: https://tsx.is' + + '@esbuild-kit/esm-loader@2.6.5': + resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} + deprecated: 'Merged into tsx: https://tsx.is' + '@esbuild/aix-ppc64@0.25.0': resolution: {integrity: sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] + '@esbuild/android-arm64@0.18.20': + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm64@0.25.0': resolution: {integrity: sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm@0.18.20': + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + '@esbuild/android-arm@0.25.0': resolution: {integrity: sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-x64@0.18.20': + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + '@esbuild/android-x64@0.25.0': resolution: {integrity: sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/darwin-arm64@0.18.20': + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-arm64@0.25.0': resolution: {integrity: sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-x64@0.18.20': + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + '@esbuild/darwin-x64@0.25.0': resolution: {integrity: sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/freebsd-arm64@0.18.20': + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-arm64@0.25.0': resolution: {integrity: sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-x64@0.18.20': + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.0': resolution: {integrity: sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/linux-arm64@0.18.20': + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm64@0.25.0': resolution: {integrity: sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm@0.18.20': + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + '@esbuild/linux-arm@0.25.0': resolution: {integrity: sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-ia32@0.18.20': + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-ia32@0.25.0': resolution: {integrity: sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-loong64@0.18.20': + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-loong64@0.25.0': resolution: {integrity: sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-mips64el@0.18.20': + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-mips64el@0.25.0': resolution: {integrity: sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-ppc64@0.18.20': + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-ppc64@0.25.0': resolution: {integrity: sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-riscv64@0.18.20': + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-riscv64@0.25.0': resolution: {integrity: sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-s390x@0.18.20': + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-s390x@0.25.0': resolution: {integrity: sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-x64@0.18.20': + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + '@esbuild/linux-x64@0.25.0': resolution: {integrity: sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==} engines: {node: '>=18'} @@ -2026,6 +2201,12 @@ packages: cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-x64@0.18.20': + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.0': resolution: {integrity: sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==} engines: {node: '>=18'} @@ -2038,30 +2219,60 @@ packages: cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-x64@0.18.20': + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.0': resolution: {integrity: sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/sunos-x64@0.18.20': + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + '@esbuild/sunos-x64@0.25.0': resolution: {integrity: sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/win32-arm64@0.18.20': + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-arm64@0.25.0': resolution: {integrity: sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-ia32@0.18.20': + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-ia32@0.25.0': resolution: {integrity: sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-x64@0.18.20': + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + '@esbuild/win32-x64@0.25.0': resolution: {integrity: sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==} engines: {node: '>=18'} @@ -2813,6 +3024,27 @@ packages: '@rushstack/eslint-patch@1.10.4': resolution: {integrity: sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==} + '@shikijs/core@3.2.2': + resolution: {integrity: sha512-yvlSKVMLjddAGBa2Yu+vUZxuu3sClOWW1AG+UtJkvejYuGM5BVL35s6Ijiwb75O9QdEx6IkMxinHZSi8ZyrBaA==} + + '@shikijs/engine-javascript@3.2.2': + resolution: {integrity: sha512-tlDKfhWpF4jKLUyVAnmL+ggIC+0VyteNsUpBzh1iwWLZu4i+PelIRr0TNur6pRRo5UZIv3ss/PLMuwahg9S2hg==} + + '@shikijs/engine-oniguruma@3.2.2': + resolution: {integrity: sha512-vyXRnWVCSvokwbaUD/8uPn6Gqsf5Hv7XwcW4AgiU4Z2qwy19sdr6VGzMdheKKN58tJOOe5MIKiNb901bgcUXYQ==} + + '@shikijs/langs@3.2.2': + resolution: {integrity: sha512-NY0Urg2dV9ETt3JIOWoMPuoDNwte3geLZ4M1nrPHbkDS8dWMpKcEwlqiEIGqtwZNmt5gKyWpR26ln2Bg2ecPgw==} + + '@shikijs/themes@3.2.2': + resolution: {integrity: sha512-Zuq4lgAxVKkb0FFdhHSdDkALuRpsj1so1JdihjKNQfgM78EHxV2JhO10qPsMrm01FkE3mDRTdF68wfmsqjt6HA==} + + '@shikijs/types@3.2.2': + resolution: {integrity: sha512-a5TiHk7EH5Lso8sHcLHbVNNhWKP0Wi3yVnXnu73g86n3WoDgEra7n3KszyeCGuyoagspQ2fzvy4cpSc8pKhb0A==} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + '@sideway/address@4.1.5': resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} @@ -3037,6 +3269,9 @@ packages: '@types/bonjour@3.5.13': resolution: {integrity: sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==} + '@types/chai@4.3.20': + resolution: {integrity: sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==} + '@types/chai@5.0.0': resolution: {integrity: sha512-+DwhEHAaFPPdJ2ral3kNHFQXnTfscEEFsUxzD+d7nlcLrFK23JtNjH71RGasTcHb88b4vVi4mTyfpf8u2L8bdA==} @@ -3109,6 +3344,9 @@ packages: '@types/istanbul-reports@3.0.4': resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + '@types/jest@29.5.12': + resolution: {integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==} + '@types/jest@29.5.13': resolution: {integrity: sha512-wd+MVEZCHt23V0/L642O5APvspWply/rGY5BcW4SUETo2UzPU3Z26qr8jC2qxpimI2jjx9h7+2cj2FwIr01bXg==} @@ -3214,6 +3452,9 @@ packages: '@types/react-router@5.1.20': resolution: {integrity: sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==} + '@types/react@18.2.71': + resolution: {integrity: sha512-PxEsB9OjmQeYGffoWnYAd/r5FiJuUw2niFQHPc2v2idwh8wGPkkYzOHuinNJJY6NZqfoTCiOIizDOz38gYNsyw==} + '@types/react@18.3.11': resolution: {integrity: sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ==} @@ -3226,6 +3467,9 @@ packages: '@types/sax@1.2.7': resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==} + '@types/scheduler@0.26.0': + resolution: {integrity: sha512-WFHp9YUJQ6CKshqoC37iOlHnQSmxNc795UhB26CyBBttrN9svdIrUjl/NjnNmfcwtncN0h/0PPAFWv9ovP8mLA==} + '@types/semver@7.5.8': resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} @@ -4834,6 +5078,9 @@ packages: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} engines: {node: '>=12'} + emoji-regex-xs@1.0.0: + resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==} + emoji-regex@10.4.0: resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} @@ -4940,6 +5187,11 @@ packages: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} engines: {node: '>= 0.4'} + esbuild@0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + esbuild@0.25.0: resolution: {integrity: sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==} engines: {node: '>=18'} @@ -5696,6 +5948,9 @@ packages: hast-util-to-estree@3.1.0: resolution: {integrity: sha512-lfX5g6hqVh9kjS/B9E2gSkvHH4SZNiQFiqWS0x9fENzEl+8W12RqdRxX6d/Cwxi30tPQs3bIO+aolQJNp1bIyw==} + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + hast-util-to-jsx-runtime@2.3.2: resolution: {integrity: sha512-1ngXYb+V9UT5h+PxNRa1O1FYguZK/XL+gkeqvp7EdHlB9oHUG0eYRo/vY5inBdcqo3RkPMC58/H94HvkbfGdyg==} @@ -7521,6 +7776,12 @@ packages: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} + oniguruma-parser@0.11.2: + resolution: {integrity: sha512-F7Ld4oDZJCI5/wCZ8AOffQbqjSzIRpKH7I/iuSs1SkhZeCj0wS6PMZ4W6VA16TWHrAo0Y9bBKEJOe7tvwcTXnw==} + + oniguruma-to-es@4.2.0: + resolution: {integrity: sha512-MDPs6KSOLS0tKQ7joqg44dRIRZUyotfTy0r+7oEEs6VwWWP0+E2PPDYWMFN0aqOjRyWHBYq7RfKw9GQk2S2z5g==} + open@10.1.0: resolution: {integrity: sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==} engines: {node: '>=18'} @@ -8150,6 +8411,11 @@ packages: prettier-plugin-svelte: optional: true + prettier@3.2.5: + resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} + engines: {node: '>=14'} + hasBin: true + prettier@3.3.3: resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} engines: {node: '>=14'} @@ -8240,6 +8506,9 @@ packages: property-information@6.5.0: resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==} + property-information@7.0.0: + resolution: {integrity: sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg==} + proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} @@ -8516,6 +8785,15 @@ packages: regenerator-transform@0.15.2: resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} + regex-recursion@6.0.2: + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} + + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + + regex@6.0.1: + resolution: {integrity: sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==} + regexp-tree@0.1.27: resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} hasBin: true @@ -8858,6 +9136,9 @@ packages: engines: {node: '>=4'} hasBin: true + shiki@3.2.2: + resolution: {integrity: sha512-0qWBkM2t/0NXPRcVgtLhtHv6Ak3Q5yI4K/ggMqcgLRKm4+pCs3namgZlhlat/7u2CuqNtlShNs9lENOG6n7UaQ==} + side-channel@1.0.6: resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} engines: {node: '>= 0.4'} @@ -9429,6 +9710,27 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + ts-jest@29.1.2: + resolution: {integrity: sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g==} + engines: {node: ^16.10.0 || ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@babel/core': '>=7.0.0-beta.0 <8' + '@jest/types': ^29.0.0 + babel-jest: ^29.0.0 + esbuild: '*' + jest: ^29.0.0 + typescript: '>=4.3 <6' + peerDependenciesMeta: + '@babel/core': + optional: true + '@jest/types': + optional: true + babel-jest: + optional: true + esbuild: + optional: true + ts-jest@29.2.5: resolution: {integrity: sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==} engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} @@ -9486,6 +9788,10 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsx@3.12.7: + resolution: {integrity: sha512-C2Ip+jPmqKd1GWVQDvz/Eyc6QJbGfE7NrR3fx5BpEHMZsEHoIxHL1j+lKdGobr8ovEyqeNkPLSKp6SCSOt7gmw==} + hasBin: true + tuf-js@1.1.7: resolution: {integrity: sha512-i3P9Kgw3ytjELUfpuKVDNBJvk4u5bXL6gskv572mcevPbSKCV3zt3djhmlEQ65yERjIbOSncy7U4cQJaB1CBCg==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -10054,6 +10360,10 @@ packages: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} + yaml@2.2.1: + resolution: {integrity: sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==} + engines: {node: '>= 14'} + yaml@2.6.0: resolution: {integrity: sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==} engines: {node: '>= 14'} @@ -11780,78 +12090,159 @@ snapshots: source-map-url: 0.4.1 webpack: 5.95.0(esbuild@0.25.0)(webpack-cli@5.1.4) + '@esbuild-kit/cjs-loader@2.4.4': + dependencies: + '@esbuild-kit/core-utils': 3.3.2 + get-tsconfig: 4.8.1 + + '@esbuild-kit/core-utils@3.3.2': + dependencies: + esbuild: 0.18.20 + source-map-support: 0.5.21 + + '@esbuild-kit/esm-loader@2.6.5': + dependencies: + '@esbuild-kit/core-utils': 3.3.2 + get-tsconfig: 4.8.1 + '@esbuild/aix-ppc64@0.25.0': optional: true + '@esbuild/android-arm64@0.18.20': + optional: true + '@esbuild/android-arm64@0.25.0': optional: true + '@esbuild/android-arm@0.18.20': + optional: true + '@esbuild/android-arm@0.25.0': optional: true + '@esbuild/android-x64@0.18.20': + optional: true + '@esbuild/android-x64@0.25.0': optional: true + '@esbuild/darwin-arm64@0.18.20': + optional: true + '@esbuild/darwin-arm64@0.25.0': optional: true + '@esbuild/darwin-x64@0.18.20': + optional: true + '@esbuild/darwin-x64@0.25.0': optional: true + '@esbuild/freebsd-arm64@0.18.20': + optional: true + '@esbuild/freebsd-arm64@0.25.0': optional: true + '@esbuild/freebsd-x64@0.18.20': + optional: true + '@esbuild/freebsd-x64@0.25.0': optional: true + '@esbuild/linux-arm64@0.18.20': + optional: true + '@esbuild/linux-arm64@0.25.0': optional: true + '@esbuild/linux-arm@0.18.20': + optional: true + '@esbuild/linux-arm@0.25.0': optional: true + '@esbuild/linux-ia32@0.18.20': + optional: true + '@esbuild/linux-ia32@0.25.0': optional: true + '@esbuild/linux-loong64@0.18.20': + optional: true + '@esbuild/linux-loong64@0.25.0': optional: true + '@esbuild/linux-mips64el@0.18.20': + optional: true + '@esbuild/linux-mips64el@0.25.0': optional: true + '@esbuild/linux-ppc64@0.18.20': + optional: true + '@esbuild/linux-ppc64@0.25.0': optional: true + '@esbuild/linux-riscv64@0.18.20': + optional: true + '@esbuild/linux-riscv64@0.25.0': optional: true + '@esbuild/linux-s390x@0.18.20': + optional: true + '@esbuild/linux-s390x@0.25.0': optional: true + '@esbuild/linux-x64@0.18.20': + optional: true + '@esbuild/linux-x64@0.25.0': optional: true '@esbuild/netbsd-arm64@0.25.0': optional: true + '@esbuild/netbsd-x64@0.18.20': + optional: true + '@esbuild/netbsd-x64@0.25.0': optional: true '@esbuild/openbsd-arm64@0.25.0': optional: true + '@esbuild/openbsd-x64@0.18.20': + optional: true + '@esbuild/openbsd-x64@0.25.0': optional: true + '@esbuild/sunos-x64@0.18.20': + optional: true + '@esbuild/sunos-x64@0.25.0': optional: true + '@esbuild/win32-arm64@0.18.20': + optional: true + '@esbuild/win32-arm64@0.25.0': optional: true + '@esbuild/win32-ia32@0.18.20': + optional: true + '@esbuild/win32-ia32@0.25.0': optional: true + '@esbuild/win32-x64@0.18.20': + optional: true + '@esbuild/win32-x64@0.25.0': optional: true @@ -12985,6 +13376,39 @@ snapshots: '@rushstack/eslint-patch@1.10.4': {} + '@shikijs/core@3.2.2': + dependencies: + '@shikijs/types': 3.2.2 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + + '@shikijs/engine-javascript@3.2.2': + dependencies: + '@shikijs/types': 3.2.2 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 4.2.0 + + '@shikijs/engine-oniguruma@3.2.2': + dependencies: + '@shikijs/types': 3.2.2 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@3.2.2': + dependencies: + '@shikijs/types': 3.2.2 + + '@shikijs/themes@3.2.2': + dependencies: + '@shikijs/types': 3.2.2 + + '@shikijs/types@3.2.2': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/vscode-textmate@10.0.2': {} + '@sideway/address@4.1.5': dependencies: '@hapi/hoek': 9.3.0 @@ -13232,6 +13656,8 @@ snapshots: dependencies: '@types/node': 20.16.0 + '@types/chai@4.3.20': {} + '@types/chai@5.0.0': {} '@types/connect-history-api-fallback@1.5.4': @@ -13322,6 +13748,11 @@ snapshots: dependencies: '@types/istanbul-lib-report': 3.0.3 + '@types/jest@29.5.12': + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + '@types/jest@29.5.13': dependencies: expect: 29.7.0 @@ -13424,6 +13855,12 @@ snapshots: '@types/history': 4.7.11 '@types/react': 18.3.11 + '@types/react@18.2.71': + dependencies: + '@types/prop-types': 15.7.13 + '@types/scheduler': 0.26.0 + csstype: 3.1.3 + '@types/react@18.3.11': dependencies: '@types/prop-types': 15.7.13 @@ -13437,6 +13874,8 @@ snapshots: dependencies: '@types/node': 20.16.0 + '@types/scheduler@0.26.0': {} + '@types/semver@7.5.8': {} '@types/send@0.17.4': @@ -15239,6 +15678,8 @@ snapshots: emittery@0.13.1: {} + emoji-regex-xs@1.0.0: {} + emoji-regex@10.4.0: {} emoji-regex@8.0.0: {} @@ -15398,6 +15839,31 @@ snapshots: is-date-object: 1.0.5 is-symbol: 1.0.4 + esbuild@0.18.20: + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + esbuild@0.25.0: optionalDependencies: '@esbuild/aix-ppc64': 0.25.0 @@ -16423,6 +16889,20 @@ snapshots: transitivePeerDependencies: - supports-color + hast-util-to-html@9.0.5: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.0 + property-information: 7.0.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + hast-util-to-jsx-runtime@2.3.2: dependencies: '@types/estree': 1.0.7 @@ -18914,6 +19394,15 @@ snapshots: dependencies: mimic-fn: 2.1.0 + oniguruma-parser@0.11.2: {} + + oniguruma-to-es@4.2.0: + dependencies: + emoji-regex-xs: 1.0.0 + oniguruma-parser: 0.11.2 + regex: 6.0.1 + regex-recursion: 6.0.2 + open@10.1.0: dependencies: default-browser: 5.2.1 @@ -19523,6 +20012,8 @@ snapshots: dependencies: prettier: 3.3.3 + prettier@3.2.5: {} + prettier@3.3.3: {} pretty-bytes@5.6.0: {} @@ -19598,6 +20089,8 @@ snapshots: property-information@6.5.0: {} + property-information@7.0.0: {} + proto-list@1.2.4: {} proxy-addr@2.0.7: @@ -19949,6 +20442,16 @@ snapshots: dependencies: '@babel/runtime': 7.25.7 + regex-recursion@6.0.2: + dependencies: + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@6.0.1: + dependencies: + regex-utilities: 2.3.0 + regexp-tree@0.1.27: {} regexp.prototype.flags@1.5.3: @@ -20354,6 +20857,17 @@ snapshots: interpret: 1.4.0 rechoir: 0.6.2 + shiki@3.2.2: + dependencies: + '@shikijs/core': 3.2.2 + '@shikijs/engine-javascript': 3.2.2 + '@shikijs/engine-oniguruma': 3.2.2 + '@shikijs/langs': 3.2.2 + '@shikijs/themes': 3.2.2 + '@shikijs/types': 3.2.2 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + side-channel@1.0.6: dependencies: call-bind: 1.0.7 @@ -20994,6 +21508,24 @@ snapshots: ts-interface-checker@0.1.13: {} + ts-jest@29.1.2(@babel/core@7.25.8)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.8))(esbuild@0.25.0)(jest@29.7.0(@types/node@20.16.0)(ts-node@10.9.2(@types/node@20.16.0)(typescript@5.6.3)))(typescript@5.6.3): + dependencies: + bs-logger: 0.2.6 + fast-json-stable-stringify: 2.1.0 + jest: 29.7.0(@types/node@20.16.0)(ts-node@10.9.2(@types/node@20.16.0)(typescript@5.6.3)) + jest-util: 29.7.0 + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.6.3 + typescript: 5.6.3 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.25.8 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.25.8) + esbuild: 0.25.0 + ts-jest@29.2.5(@babel/core@7.25.8)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.8))(esbuild@0.25.0)(jest@29.7.0(@types/node@20.16.0)(ts-node@10.9.2(@types/node@20.16.0)(typescript@5.6.3)))(typescript@5.6.3): dependencies: bs-logger: 0.2.6 @@ -21055,6 +21587,14 @@ snapshots: tslib@2.8.1: {} + tsx@3.12.7: + dependencies: + '@esbuild-kit/cjs-loader': 2.4.4 + '@esbuild-kit/core-utils': 3.3.2 + '@esbuild-kit/esm-loader': 2.6.5 + optionalDependencies: + fsevents: 2.3.3 + tuf-js@1.1.7: dependencies: '@tufjs/models': 1.0.4 @@ -21785,6 +22325,8 @@ snapshots: yaml@1.10.2: {} + yaml@2.2.1: {} + yaml@2.6.0: {} yargs-parser@20.2.9: {} diff --git a/tsconfig.json b/tsconfig.json index 20ea84c510..1bdd00ddfb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -65,6 +65,9 @@ { "path": "./packages/sentence-parser" }, + { + "path": "./packages/test-case-component" + }, { "path": "./packages/test-case-recorder" },