@continuit/testreport
Version:
Generates a test report and badges from your test and coverage results. Allows checking the report in your CI pipeline.
4 lines • 207 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../src/mod.ts", "../src/utilities/miscUtils.ts", "https://jsr.io/@std/encoding/1.0.6/_validate_binary_like.ts", "https://jsr.io/@std/encoding/1.0.6/base64.ts", "../src/utilities/markdownUtils.ts", "../src/utilities/createBadgeSvg.ts", "../src/testReportToBadges.ts", "../src/testReportToMarkdown.ts", "https://jsr.io/@valibot/valibot/0.42.1/src/storages/globalConfig/globalConfig.ts", "https://jsr.io/@valibot/valibot/0.42.1/src/storages/globalMessage/globalMessage.ts", "https://jsr.io/@valibot/valibot/0.42.1/src/storages/schemaMessage/schemaMessage.ts", "https://jsr.io/@valibot/valibot/0.42.1/src/storages/specificMessage/specificMessage.ts", "https://jsr.io/@valibot/valibot/0.42.1/src/utils/_stringify/_stringify.ts", "https://jsr.io/@valibot/valibot/0.42.1/src/utils/_addIssue/_addIssue.ts", "https://jsr.io/@valibot/valibot/0.42.1/src/utils/_joinExpects/_joinExpects.ts", "https://jsr.io/@valibot/valibot/0.42.1/src/utils/ValiError/ValiError.ts", "https://jsr.io/@valibot/valibot/0.42.1/src/methods/getDefault/getDefault.ts", "https://jsr.io/@valibot/valibot/0.42.1/src/schemas/array/array.ts", "https://jsr.io/@valibot/valibot/0.42.1/src/schemas/boolean/boolean.ts", "https://jsr.io/@valibot/valibot/0.42.1/src/schemas/literal/literal.ts", "https://jsr.io/@valibot/valibot/0.42.1/src/schemas/number/number.ts", "https://jsr.io/@valibot/valibot/0.42.1/src/schemas/object/object.ts", "https://jsr.io/@valibot/valibot/0.42.1/src/schemas/optional/optional.ts", "https://jsr.io/@valibot/valibot/0.42.1/src/schemas/string/string.ts", "https://jsr.io/@valibot/valibot/0.42.1/src/schemas/union/utils/_subIssues/_subIssues.ts", "https://jsr.io/@valibot/valibot/0.42.1/src/schemas/union/union.ts", "https://jsr.io/@valibot/valibot/0.42.1/src/methods/parse/parse.ts", "../src/testReportConfig.ts", "https://jsr.io/@std/path/1.0.8/_os.ts", "https://jsr.io/@std/path/1.0.8/_common/assert_path.ts", "https://jsr.io/@std/path/1.0.8/_common/basename.ts", "https://jsr.io/@std/path/1.0.8/_common/strip_trailing_separators.ts", "https://jsr.io/@std/path/1.0.8/posix/_util.ts", "https://jsr.io/@std/path/1.0.8/posix/basename.ts", "https://jsr.io/@std/path/1.0.8/windows/_util.ts", "https://jsr.io/@std/path/1.0.8/windows/basename.ts", "https://jsr.io/@std/path/1.0.8/basename.ts", "../src/utilities/lcov_parser.ts", "https://jsr.io/@continuit/xmlscanner/1.0.0/src/unEntity.ts", "https://jsr.io/@continuit/xmlscanner/1.0.0/src/XmlParsingError.ts", "https://jsr.io/@continuit/xmlscanner/1.0.0/src/characterBits.ts", "https://jsr.io/@continuit/xmlscanner/1.0.0/src/xmlScanner.ts", "https://jsr.io/@continuit/xmlscanner/1.0.0/src/xmlEventsBuilder.ts", "../src/utilities/junit_parser.ts", "../src/testReportData.ts", "../src/testReportToManifest.ts", "../src/createTestReport.ts", "https://jsr.io/@std/assert/1.0.10/equal.ts", "https://jsr.io/@std/internal/1.0.5/styles.ts", "../src/checkTestReport.ts", "https://jsr.io/@std/cli/1.0.9/parse_args.ts", "../src/execute.ts"],
"sourcesContent": ["import * as process from 'node:process';\nimport { execute } from './execute.ts';\n\nexecute(process.argv.slice(2)).then((exitCode) => {\n process.exit(exitCode);\n}).catch((error) => {\n console.error(error);\n process.exit(1);\n});\n", "import { readFile, writeFile } from 'node:fs/promises';\n\nconst invalidPercentage = 'N/A';\n\nexport const percentageNoZero = (value: number, total: number) => {\n if (!total) return invalidPercentage;\n return value ? `${(value * 100 / total).toFixed(1)}%` : '';\n};\n\nexport const percentage = (value: number, total: number) => {\n if (!total) return invalidPercentage;\n return `${(value * 100 / total).toFixed(1)}%`;\n};\n\nexport class TextFileError extends Error {}\nexport class WriteTextFileError extends TextFileError {}\nexport class ReadTextFileError extends TextFileError {}\n\nexport async function exportOutput(filename: string | undefined, createData: () => string) {\n if (!filename) return;\n try {\n const utf8Encoder = new TextEncoder();\n const dataBytes = utf8Encoder.encode(createData());\n await writeFile(filename, dataBytes);\n } catch (error) {\n throw new WriteTextFileError(`Error writing file ${filename}`, { cause: error });\n }\n}\n\nexport async function readTextFile(filename: string): Promise<string> {\n try {\n const fileBytes = await readFile(filename);\n const utf8decoder = new TextDecoder();\n return utf8decoder.decode(fileBytes);\n } catch (error) {\n throw new ReadTextFileError(`Error reading file ${filename}`, { cause: error });\n }\n}\n", "// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.\n\nconst encoder = new TextEncoder();\n\nfunction getTypeName(value: unknown): string {\n const type = typeof value;\n if (type !== \"object\") {\n return type;\n } else if (value === null) {\n return \"null\";\n } else {\n return value?.constructor?.name ?? \"object\";\n }\n}\n\nexport function validateBinaryLike(source: unknown): Uint8Array {\n if (typeof source === \"string\") {\n return encoder.encode(source);\n } else if (source instanceof Uint8Array) {\n return source;\n } else if (source instanceof ArrayBuffer) {\n return new Uint8Array(source);\n }\n throw new TypeError(\n `Cannot validate the input as it must be a Uint8Array, a string, or an ArrayBuffer: received a value of the type ${\n getTypeName(source)\n }`,\n );\n}\n", "// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.\n// This module is browser compatible.\n\n/**\n * Utilities for\n * {@link https://www.rfc-editor.org/rfc/rfc4648.html#section-4 | base64}\n * encoding and decoding.\n *\n * ```ts\n * import {\n * encodeBase64,\n * decodeBase64,\n * } from \"@std/encoding/base64\";\n * import { assertEquals } from \"@std/assert\";\n *\n * const foobar = new TextEncoder().encode(\"foobar\");\n *\n * assertEquals(encodeBase64(foobar), \"Zm9vYmFy\");\n * assertEquals(decodeBase64(\"Zm9vYmFy\"), foobar);\n * ```\n *\n * @module\n */\n\nimport { validateBinaryLike } from \"./_validate_binary_like.ts\";\n\nconst base64abc = [\n \"A\",\n \"B\",\n \"C\",\n \"D\",\n \"E\",\n \"F\",\n \"G\",\n \"H\",\n \"I\",\n \"J\",\n \"K\",\n \"L\",\n \"M\",\n \"N\",\n \"O\",\n \"P\",\n \"Q\",\n \"R\",\n \"S\",\n \"T\",\n \"U\",\n \"V\",\n \"W\",\n \"X\",\n \"Y\",\n \"Z\",\n \"a\",\n \"b\",\n \"c\",\n \"d\",\n \"e\",\n \"f\",\n \"g\",\n \"h\",\n \"i\",\n \"j\",\n \"k\",\n \"l\",\n \"m\",\n \"n\",\n \"o\",\n \"p\",\n \"q\",\n \"r\",\n \"s\",\n \"t\",\n \"u\",\n \"v\",\n \"w\",\n \"x\",\n \"y\",\n \"z\",\n \"0\",\n \"1\",\n \"2\",\n \"3\",\n \"4\",\n \"5\",\n \"6\",\n \"7\",\n \"8\",\n \"9\",\n \"+\",\n \"/\",\n];\n\n/**\n * Converts data into a base64-encoded string.\n *\n * @see {@link https://www.rfc-editor.org/rfc/rfc4648.html#section-4}\n *\n * @param data The data to encode.\n * @returns The base64-encoded string.\n *\n * @example Usage\n * ```ts\n * import { encodeBase64 } from \"@std/encoding/base64\";\n * import { assertEquals } from \"@std/assert\";\n *\n * assertEquals(encodeBase64(\"foobar\"), \"Zm9vYmFy\");\n * ```\n */\nexport function encodeBase64(data: ArrayBuffer | Uint8Array | string): string {\n // CREDIT: https://gist.github.com/enepomnyaschih/72c423f727d395eeaa09697058238727\n const uint8 = validateBinaryLike(data);\n let result = \"\";\n let i;\n const l = uint8.length;\n for (i = 2; i < l; i += 3) {\n result += base64abc[(uint8[i - 2]!) >> 2];\n result += base64abc[\n (((uint8[i - 2]!) & 0x03) << 4) |\n ((uint8[i - 1]!) >> 4)\n ];\n result += base64abc[\n (((uint8[i - 1]!) & 0x0f) << 2) |\n ((uint8[i]!) >> 6)\n ];\n result += base64abc[(uint8[i]!) & 0x3f];\n }\n if (i === l + 1) {\n // 1 octet yet to write\n result += base64abc[(uint8[i - 2]!) >> 2];\n result += base64abc[((uint8[i - 2]!) & 0x03) << 4];\n result += \"==\";\n }\n if (i === l) {\n // 2 octets yet to write\n result += base64abc[(uint8[i - 2]!) >> 2];\n result += base64abc[\n (((uint8[i - 2]!) & 0x03) << 4) |\n ((uint8[i - 1]!) >> 4)\n ];\n result += base64abc[((uint8[i - 1]!) & 0x0f) << 2];\n result += \"=\";\n }\n return result;\n}\n\n/**\n * Decodes a base64-encoded string.\n *\n * @see {@link https://www.rfc-editor.org/rfc/rfc4648.html#section-4}\n *\n * @param b64 The base64-encoded string to decode.\n * @returns The decoded data.\n *\n * @example Usage\n * ```ts\n * import { decodeBase64 } from \"@std/encoding/base64\";\n * import { assertEquals } from \"@std/assert\";\n *\n * assertEquals(\n * decodeBase64(\"Zm9vYmFy\"),\n * new TextEncoder().encode(\"foobar\")\n * );\n * ```\n */\nexport function decodeBase64(b64: string): Uint8Array {\n const binString = atob(b64);\n const size = binString.length;\n const bytes = new Uint8Array(size);\n for (let i = 0; i < size; i++) {\n bytes[i] = binString.charCodeAt(i);\n }\n return bytes;\n}\n", "export type Alignment = 'left' | 'right' | 'center' | 'default';\n\nexport const alignmentStr = (alignment: Alignment, width: number) => {\n switch (alignment) {\n case 'left':\n return `:${'-'.repeat(width - 1)}`;\n case 'right':\n return `${'-'.repeat(width - 1)}:`;\n case 'center':\n return `:${'-'.repeat(width - 2)}:`;\n default:\n return '-'.repeat(width);\n }\n};\n\nconst strLenCodePoints = (str: string) => [...str].length;\n\nexport const padString = (str: string, alignment: Alignment, width: number) => {\n const l = strLenCodePoints(str);\n switch (alignment) {\n case 'left':\n return str + ' '.repeat(width - l);\n case 'right':\n return ' '.repeat(width - l) + str;\n case 'center': {\n const left = Math.floor((width - l) / 2);\n return ' '.repeat(left) + str + ' '.repeat(width - l - left);\n }\n default:\n return str + ' '.repeat(width - l);\n }\n};\n\nconst TABLESTART = '| ';\nconst TABLEEND = ' |';\nconst TABLESEP = ' | ';\n\nexport const buildMarkdownTable = (headers: string[], alignment: Alignment[], data: string[][]): string[] => {\n const maxWidths = new Array(headers.length).fill(3);\n for (let i = 0; i < headers.length; i++) maxWidths[i] = Math.max(maxWidths[i], strLenCodePoints(headers[i]));\n for (const row of data) {\n const len = Math.min(headers.length, row.length);\n for (let i = 0; i < len; i++) maxWidths[i] = Math.max(maxWidths[i], strLenCodePoints(row[i]));\n }\n return [\n TABLESTART + headers.map((s, i) => s.padEnd(maxWidths[i])).join(TABLESEP) + TABLEEND,\n TABLESTART + maxWidths.map((w, i) => alignmentStr(alignment[i], w)).join(TABLESEP) + TABLEEND,\n ...data.map((row) =>\n TABLESTART + row.map((s, i) => padString(s, alignment[i], maxWidths[i])).join(TABLESEP) + TABLEEND\n ),\n '',\n ];\n};\n\nexport const markdownTitle = (title: string, level: number = 1) => [`${'#'.repeat(level)} ${title}`, ''];\n\nexport const markdownCollapsibleTitle = (title: string, level: number = 1, collapsible: boolean = false) =>\n collapsible ? ['<details>', `<summary>${title}</summary>`, ''] : [`${'#'.repeat(level)} ${title}`, ''];\n\nexport const markdownCollapsibleEnd = (collapsible: boolean = false) => collapsible ? ['</details>', ''] : [];\n", "// Widths of the characters in the font Verdana 110pt as bytes encoded in base64.\nconst verdanaWidthsBase64 = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnKzJaRnhQHjIyRlooMigyRkZGRkZGRkZGRjIy' +\n 'WlpaPG5LS01VRj9VUy4yTD1dUldCV0xLRFFLbktESzIyMlpGRkJFOUVCJ0VGHiZBHm5GQ0VFLzkrRkFa' +\n 'QUE6RjJGWgA9bm5ubm5ubm5ubm5ubjdubm5ubm5ubm5ubm5ubm43bicrRkZGRjJGRm48R1oAbkY8Wjw8' +\n 'RkdGKEY8PEdubm48S0tLS0tLbk1GRkZGLi4uLlVSV1dXV1daV1FRUVFEQ0RCQkJCQkJuOUJCQkIeHh4e' +\n 'Q0ZDQ0NDQ1pDRkZGRkFFQUtCS0JLQk05TTlNOU05VUdVRUZCRkJGQkZCRkJVRVVFVUVVRVNGU0YuHi4e' +\n 'Lh4uHi4eYEQyJkxBQT0ePR49IT0yPh9SRlJGUkZQUkZXQ1dDV0N4bkwvTC9ML0s5SzlLOUs5RCtEK0Qr' +\n 'UUZRRlFFUUZRRlFFblpEQURLOks6SzohRU1ARUs+TEw7U2BARUE8Uzo7Rk9IZCsrSUAqQXhRRFZZQ3hi' +\n 'SkVGOzhBOilKKUZTSVZOREpDPz09ODlGRjQyQx0wMiCMjIJeWj1ubmNMPSAgVURMRExEUUZMRFFGPUw9' +\n 'TD1kXlhFT0VIQFVEVUQ9OByMjIJVRW49UkZLQm5uV0NIPEw9Pzo8PR4bICBMP1VERCVGLUc9TERLOUQr' +\n 'OjdRRFFkVURDP0w9PD1VRFVEVURVREU5P2Q/HGRkS1E4PkQ3Nz4+UV9LSz49GWBFVyxWRT1FRUU4PUZG' +\n 'PUJWMzNHQC1GRUE7QURERCopLTg1IUhkZGRFRkVEWVZULS0vLS0tLT09OC8wNTspKUhJRDlVOTU/TTg7' +\n 'MTExNVU6QUNFNUAzRjIxbm6CWE5gbkpNREBHRygoGhsbIyMzJBo0IxYcHR0fHyYnKChGRhRGHx8UKB8f' +\n 'KiofHzIyMjJGRkZGRkYXJikUIygfKysrKysqKiUuMBgYGhogHy8vKRsfHx8fKioyAAA1ADNENCcxAC4z' +\n 'NSYvADQ0JycnCy4vLCwaESkwMDAwGRkAMS4VKCkmKDk1NTQ0NDNERD4+RD5PKQAoOTApRAAANCo1Jigz' +\n 'Ly00NDQ5LAAtKTQwLS04KRQwMy9TNDMzMzMzLSwkLSwsLSwzKCktLS4lQTMgIE9AT09EODg4MkJPT09P' +\n 'RkZLMlNgO09hT1NkHktLPk1GS1NXLkxLXVJHV1NCT0pERFpLYFouREU4Rh5FRURBQzgyRkUeQUFGQTdD' +\n 'RkU4RTdFV0FaWR5FQ0VZPjlAOztGVVY9VURJOzs4PDhJWGJcSj1KN0lJQ0JRPTMtPUM4IVY6Oj9DTF9Q' +\n 'TlFRUUZGVz5NSy4uMnh4WkxTRFNLS0s+UkZuRFNTTFFdU1dTQk1ERFpLVE5ublZkS01uTkJEQTREQlg6' +\n 'RkZBRE1GQ0ZFOzdBXEFHQ2BiRlc/PFxCQkJGNDw5Hh4mZGRGQUZBRmFVRTxjUkI7YVNeUXhuOTVMTUs/' +\n 'RTdFN4JuSz5gVGFVRztFAAAAAAAAAE4/RTxGPj40PjRDN25YQThMQUxBSDlaTFNGbk5uYFJCSDpCNURB' +\n 'REFLQWNKSzxOQ05GVUFVQR5kVEU8TkBOPk4/SzxgUh5IPEg8ZF0/OlNCTDpkVEE4QEBOP04/TD9XQ0s/' +\n 'SjtFNEU0RTRLPD0uX1VBLUU3RTdEPlpfV0c7N25ZbltEOU5GSjtOQFRMW0tuUVVEZFdLRW5YeGRMQkpE' +\n 'MSxiWT46SUFPVD9RUURHPzxQS0A5UEhCQU1PRFA9UUY7QklDUURRPTY/RUtFQE1PTywlISodJgBPUjhD' +\n 'Rjc6NDg/PzceVDo2NzM5OjoeODA6LVEwQzo6U0Y4K1FBN0U7TycsT09PT1hPAAAAAAAAAAAAAAAAAAAA' +\n 'AAALAAAAAAAAAAAAAAAOAAAAAAAAAAAAAAMPAAAAJgAcAAAcAAUsDE9PT09PT09PRz4vN04jJU5HIzo/' +\n 'O01MIi1JQjo/NT9JOE9MT09PT09EREIfNU9PT09PT09PT09PYb5dUSJ4R0dWOjo1IDFdOgAAAQAAAAAA' +\n 'AAAJIABPGydZIyAgKyBGIEYnRkZAQEAtLS0tZGR4eEJCQEBNTUZGRhZWPDw0LTsnK0ZGAAAAAAAAAAAA' +\n 'AAAAAAAAAAAAAAAAOjo6Ojo6Ojo6Ojo6OjlGPAAgICAALzo2RkZGRkZGRkZGQEBAQEBAQC0tLS0tLS0t' +\n 'LS0tLS0tLS0tLWRkZHh4QkBWVlZWVlY8PE1NTTw8PE1NTU1NTTQ0NDQ7Ozs7OzlAJzExMSsrKysrKysr' +\n 'Rk9GK0ZGQEAjJwcEAAAAAABfPQAAAAAYABkmAABGAAAAAC0tMzM6Ojo6Ojo6OmR4QDMwOU9PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PRkZGRkZGRkBALS0tZEBAQFZWTU1NLS07Ozs0LS1kQEBkLUAgIEZGRisrQEBAZGQ8' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PYGBKVGRKRjZTUz0v' +\n 'QBo0eFw0JUlYT2BgYCZTZEpCT09PT09PT09PT09PT09PT09PT09PT086KCkiIU9PT09PTzg+TwAAAAAA' +\n 'AAAAAAAAAAAAAAAAAAAAAAAATwAAAAAASUlJZFBQbjo6NEpbTzw8PDxubm5uVVc9RkRHS1JVTTc/PDpT' +\n 'PUc6Rjg4Plc+QEBDLC1OUVE8Tz9LOElkSTZkZGRJSUlJSUlJSWRkZGRJZGSCAABJSUlJSVVXPVI8OldD' +\n 'W09JSTRSMzU2Njg7Okg1NDciUFBublBQOVJDPVAyPT4+SXh4T2KCNkhJS1NET09OU09PQk5MSEZFTDpB' +\n 'WFVkPDxJPENLSjxDRU9IUzxPQD48T1FPT09NPkg2T09JM2RkZElJSUlPT2RkT0+Cgkk5T09PT09PT09k' +\n 'T09PT0k8Tz5TRElJT09BOjVQN0NGPkxFPTwuQixLRh4+OkYeT09PT08iFyBPWW5hYk5OT09PT0lZT09O' +\n 'WUxMWlxLTE9MT0lJT0tMTktMTExPT0xLTUtLW0lPTk5PTEtPS0lPTwxPGhcyQEBPT09PPj5PT0M6E09P' +\n 'TxNPT09PT09PTFpMS09LT09PT09PT11ERUZNTEZGUE0kGklOqi5PT09PT09PT09PT1lZHE9eeEdOUl9Y' +\n 'U15PXl54T3h4P1RPRkFKVlxcTEZPP0xiR0o/R0lPSj9VWUNKOE9KWk9KT0pRQU9PWTh4ZHhZWVlZWU9Z' +\n 'WXhPeHhZT094T09PT09PT09PT09PT09PX1NZWU9PSi44PkhKOVU7Sy9kT09PT09PT09PT09PT09PHC4w' +\n 'T1RkWFpbWlo+T09GW09PS19XVFRUXlNGV1RPVFVUVE9USlVJT09LXlVYS1JXT1dXT1VQS0tVT08FMmJO' +\n 'Yk5OTk5PT4yMT0+Wlk5PT09PT09PT05iT09PT1RUT1pZQE5OT09DODhbRTtGPjc9UT8TLEY5UVtPT09P' +\n 'T09PT09PPkxPYnhkRWR4T09PTk5WT1NTqk5PT09bR09TT2RVT09PjEtPT09KZEBPT09JTDtGWF1JUGRk' +\n 'boJPT09PeFBAbnhPT0+MgqBPvrTmPk9PXE9PT09PT5ZPT09PT09PT09PT08kNztFRUFCUVtGX1pOTFVb' +\n 'UKBRgoxRbk9PT09PSW6Mbk9hXlVuY4Kgbk9UVFlPU1NVOWNCeFVYWFSMbl1EWlpcWlpaWlRPVFRaWniM' +\n 'RGFVR2FUPVRUeE9PT0ZuSUlujHiWT0lJSU9JSW5JT09PT09PT0lJT1hUWk9PT09PyJZJSU9PQD5NN0FH' +\n 'MjlBMk9PT09PT09POhw0UkpKSVYqPXhdT1pVXHh4jHhuT1FRVE9RUVREXkZXUVFfUYx4VUlSUlVRWFhY' +\n 'UE9RUVZWeIxJWlpTT1NIUVNXT089NHhHbmSCWYJPSm54T4y0bm5PT09PT09PYVlPT09PT09PWk+WlkVQ' +\n 'T09IQ1VTU1xVUmNDTztPT09PT09PT09PT09PT09PKh9PjJZjtEaWWG5PeHi0T0Z4lmFYU4JuW4JYoIw5' +\n 'QHh4jGBRPVxcZE5ugkBAYUM/VEg/WF5ueHhRT08qbllYYGBkZE+CeLRPqqDIQhNPT09PT09PT5ZPT09P' +\n 'T09PT1h4RlFPT0BWWG5EYYIwWGRcYIJMUm5PT094lmREbl5uT09EME9bgoKCXFpflpbIbqpkbqBkZKpP' +\n 'T094bmRebnhkWli0qpZkX2RuZIyCbmBTbmRPZFhkbnhuZGNYT2NPT2FuWGR4bmRPT09WT09PT3iCgllZ' +\n 'WU9ZT4ygoNy+vtyWT09PT09PT09PT09PT09PT09PyD+gT09PT09PT09PT08VQj8/RkVGNDpDQEFaWklJ' +\n 'O0xeWkVFQkU9REhIQUFKSklFQzVCQEk4RUdCRUpAP0QwODhuODg4ODg4OE9PT09LI0A4PS45Qzg4ODg4' +\n 'ODg4UUBESEtEQkBURElVjE9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09EPE8+T084' +\n 'PU88T08+T09PT09PQEJFR09EOjpKSUlKT0Q9PE89TztPTz1UTz09OjgALy8AAAAAAABPAAA2T08mQSUl' +\n 'JU9BTwAAAAAkAE9PPTg3Pzg6RUVJRU9Pbm5PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'RTZVVYJCgqAqP0cSEhsyGxsieEEoRzRTLSUgNzciNzomJjw5TDc/PzQ4ODw5TDc/Pzg4NzopNyE8BpaW' +\n 'NjYfLzk5OTg0Ozk0TzM0NDQ4NDQ0NDg0OTk5ODk7OTQ4NDQ2ND42Ozk5OTRCODY6Ok9PT088Nzw9eDh4' +\n 'OHg1Njk5FjM2PCkpDzkpJQA6NDpPT09PODg4ODg4ODhPODg4ODg4ODg4ODg4ODg4ODs4ODg4ODg4ODg4' +\n 'ODg4ODg4ODg4Tzg4QCs2QS0kMkcnPUJARE9GN9w0F4I1RkhDRk9PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT3hCRHhCRHhCVG54S0JLRIJ4eD9ERURERHhEeEN4RHh4Qm5PeIJCQkFPgvBP' +\n 'eEFBQUF4QU9PT0FBWkRBTFFBQapEQkJCQkJEREREFytCUUJhREREREJeeKpBQU9PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09JSk5N' +\n 'Q1dJVj5GVk1FS05MUURBS0tOR0VFRUZVQUlFSlE/Q0NKV09PT09PT09PT08zP0BkODxQbkE1gjc4Xzk7' +\n 'WzZVXFY4WDM6NT44OD83VzRKPzw2PF1CQkJCO0JPT09fX19fX19fX19fX19fX19fX19fbm5ubm5ubm5u' +\n 'bm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5u' +\n 'bm5PT09PTwAAX19fX19fX19fX19fX19fX19fX19fbm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5u' +\n 'bm5ubm5ubm5ubl9ubm5fT09PT09fX19fX19fX19fX19fX19fX19fX19fX19fX19ubm5ubm5ubm5ubm5u' +\n 'bm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubm5uT09PT09PTGNHSUhQY3hHW1tH' +\n 'XlF4X26Cgm6Cbm6CeJaCeIJ4eIJugm5ubnhubkNOTGNcRFpjSmFhSmBKSmFUZGRUZFhUZF5eXl5eXl5e' +\n 'bk+CXl6CT09hYWFhYW5hT25PjGFheE9PTmNjTmJkTmNUZGRUZGRUZFVVVVZWVVVVVVZVVlVkV1VMX1pM' +\n 'WUpubm5PblNZbk9POk1IRkdLV1FTYFtTWVNkVkZfX0ZeSEdXT2RkT2RPT2N4T25fZG5PT2J4eGJ4YmJP' +\n 'jE+CeHiCT09keGRkZIJkgkpiX0hfSE5PUmRkUmRjUmR4eHh4eIx4eEBQW0FkTVpuVG5uUmRdW25UbmRO' +\n 'ZGNbZFVublRuZFxuQFxDRkJYQE9uT2RFUWRPT1FkUVFRYVdReIyMeIx4eIyWlpaWtJaWlklhX0hfXUpf' +\n 'TGJhSWBfTV9KYkxDTEhNW15fZF9uXF5cVVZVVlVVVVVZgmRPT09PTmQhRCcnJzchZD04OzxIQkNHPi5S' +\n 'UmA8R1daOj5uT09PqqCCqnhuYoxubniMbmFWeCA8ICA8TDNjbjhPT09PT09RSkdNbilGUDtFUTZCZERh' +\n 'Mj54ZEZCUGM5W1pbRE5TO1NkST9EWEiCWWRuOVd4P0c4SEo2ZD9MVFRROlxOQ0NMSV8+TFtQUEdWWnhT' +\n 'Xj8/gkpYSVhET09POEMuSjJPT09PV1dXV1JSUlJSUlJYWFhYWFhhZGFkUmRhZGFSSUE2IyMyMiY1NyMX' +\n 'LC0seGJueFtbW1tUVFRUVFRUXFxcXlxbX2RfZGRfZF9ULg8oWlpaWk1NTU1NTU1uZGRuZG5bXFtcXFtc' +\n 'W10mbm5gYEVFRUVFRUVFRVRUUVdRV1RUVFRUVFRUVCsrVVhXV0hISEhISEhISFdXV1dXV1dXV1dXV1dX' +\n 'VykpR0REREREREREUFZUTVRNTVRNVFRNVE1SJiYmL0NkZGRkZGRkZGR4eHhkeGRkPDI8YGBgYGBgYGBg' +\n 'bm5ubm5uYG5gbm5hbmE3MUpBQUFBQUFBQUFNUFBNUU1GVUZVUVNWTlAnLSc3JycneHhubl9fX0tLS0tu' +\n 'bm5ubm5aWlpaWlpaWjlAQEBAQEBAQEBPT09PT09ST1JPT09PT08mMyUlZGRkZGRkREREREREU1MoMUpZ' +\n 'WVlZXl5eXm5uNlxcXFxcXFJSUlJiYjJaWk1NQlpaTU1WVlZUVFRUNk4lbm5ubm5ublJFRUVFWVlZWYKC' +\n 'gm5ugoI8XUVFRUVkZGRkPGBgYGBgYDdAQEBAQEBAJj84ODg4Pz8/P1BQUFBQUFBQUFBQUFtbU1NTU1tb' +\n 'U1NTU1tbVFRUVFtbVFRUVFhYS0tLS1hYR0dHR1paTExMTCxubj4+Pj5ubklJSUlubklJSUk0SEhiYmJi' +\n 'bm4+Pj4+WlpLS0tLRkZGZGRkZGRKSmRkZGRkZEVFRUVkZEdHR0dgYEVEREVubkZGRkaCgkBAQEBUVExM' +\n 'TEwtLVRUTExMTG5uPj4+Pm5uRERERClubkZGRkZubj4+Pj5ubkZGRkZFNW6goKqMjKCgT09PT09PT09P' +\n 'NjZMYniMNkxieIw2TGJ4jDZMYniMUYxueIxiUVFPT09DQzQ0ND81NSs3NztFLS1FQzcyQUFBRkVFNSkp' +\n 'Rx5HLUcUHlJURy1HQE87KRQgQ0MrMjUtNS1BQTggKzJCNkNBbkduT0VBOBRDNT4gID5FODBPT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT0JCQmRCQkJCjGRCQkJkjEJCREJCQkJCQkJkJ2QnQkJkZG5AQmRCZEJCTkRC' +\n 'QkJCQkJCQkIAAF49PT09NDQ0Y25uW1tigow0V080QjQ0NTQ0NDQ0NDNEJjrIR4IqOjZPTzo6SWFBQUFN' +\n 'QT5PT09PT08pLRJILSwfOx8xT09PT09PPhggISo9FCEkJRQAAAAAbjpFNi8+Lz05OT9ubm5ubm5FQjUv' +\n 'Ly80NjsrMzQyRjo9LzgrKikqKCsnPTE1LC81PEcsIyAvNDI/MTI4OTI5OjcwKi8xJykpLjEsPTYwQygt' +\n 'Myo5UjAwMjAwLSo3PT45MTI4OypUKzM5bm5ubm5ubm4xIzY6OSpALDQzOi4tJS0oKio1PD83LzEqNjAu' +\n 'PzM4OjgvQzQ/PiAtM0Jubm5ubm5PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PRzpJYUFBQU1BPoyMjKCMjEY6SWFBQUFNQT6MjIygjIxPT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09P' +\n 'T09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT08+TV1AQEZIOTQgJT40UEVJ' +\n 'QElJSmREQkI4Pj42REpcSj1VPzkwQDY5RTg/QSMwIScoHx8lJxMYIx0tJiYqKCAjISYsJycoOSgoJCQf' +\n 'HygVJjwoKCEoKCgbKCw8IygoJyc2KBUcKSQoKCc3JmRERihcPUUsKDcoNz0qPWIYGD08Pz09H043GFw9' +\n 'PSU3Kzc3Nz09PT0yMkgYNxg9PCknJikjGRkpKhEREREeEREePz8qKioqKSURGCorKicjJycnKSs0NAAA' +\n 'NDQ0NDg4Jjk5MCkrT09PPDo7NS4wME8sLiEqLy0sKy8tKi1PT09PT09PT09PT09PT09PT09PT09PTwAA' +\n 'SDw/RUtFP0VNOVJFVUVSRVJFUkVGQkZCPD08PTw9OyhPRVFEU0ZRRFFEUUQgIC4eTEFMQUhAPR47IDsg' +\n 'OyBdbl9kXW5RRFJGUURRRFdDVURXQ1dDQkU9RUYtTC9GLUYtOzhLOTs4Ozg7OEYpRCtGKUYpTERMRExE' +\n 'UUZMREtBS0FuWm5ablpeVW5aRUNFQ0U5Qz9LOkM/RClVOT0kLy5cN0tCS0JLQktCS0JLQktCS0JLQktC' +\n 'S0JLQkZCRkJGQkZCRkJGQkZCRkIuHi4eV0NXQ1dDV0NXQ1dDV0NZQ1lDWUNZQ1lDUUZRRlNJU0lTSVNJ' +\n 'U0lEQURBREFEQWRBODEyMkxMTExMTExMTE9kZGFiVlQ0NDQ0NDRPT09PZGRkZE9PRERERERERERkZHh4' +\n 'eHhuZCgoKCgoKCgoMzNJS0lKPDhERERERERPT2RkgoJ4TE9PQkJCQkJCQkJPYE94T3hPZGNjY2NjY2Nj' +\n 'ZG6Cgnh4bm5FRTg4RkYeHkNDRUVZWU9PTExMTExMTEx4eIyMjIyCeEREREREREREjIygoKCglpZjY2Nj' +\n 'Y2NjY4yWqqqgoJaWTExMTExPTExMTEtLeEQeRERERERET0RERlNTYHhEREQoKB4eT08oKCAgLjtPRERE' +\n 'QkJFRUNDQkJGRkRTUEZGRk9PY2NjT2NjV2FaZIJGRE83bjduJRwSRigWBwAAAAAAQEBGRm5uQUYeHh4e' +\n 'MjIyMkZGPDQlNFojAAAAAAAAABOqlig9PSQ8UycyMk9FLkY3NzNkJCgkJFlOTkZGPDw1Izc1PW43TUFu' +\n 'QUFuQU1uHxgAAAAAAAAAAAAAAAAAAAAALhhPTzw8Ljw8Li4uLhkZPC4uLi4uLi4uLi4uLi4ZGU8fHx8c' +\n 'H0JCQkJCQkJCT09PRk1NRkZuUoKCblxF';\n\nconst widths = atob(verdanaWidthsBase64).split('').map((c) => c.charCodeAt(0));\nconst missingWidth = widths['x'.charCodeAt(0)];\n// Future: collect info from kern table to get kerning information\n\nexport const getWidthVerdana110 = (str: string) => {\n let i = 0;\n let width = 0;\n const l = str.length;\n while (i < l) {\n const code = str.charCodeAt(i);\n if (code >= 0xD800 && code <= 0xDBFF) { // first part of a surrogate pair\n width += missingWidth;\n } else if (code >= 0xDC00 && code <= 0xDFFF) { // second part of a surrogate pair\n // do nothing\n } else {\n width += widths[code] ?? missingWidth;\n }\n i++;\n }\n return width;\n};\n\nexport type BadgeSvgOptions = {\n label: string;\n message?: string;\n labelColor: string;\n messageColor?: string;\n rounded: boolean;\n};\n\nconst margin = 50;\nconst shift = 10;\nconst bottom = 138;\n\nconst emitText = (svg: string[], text: string, width: number, x: number) => {\n svg.push(\n `<text x=\"${(x + shift).toFixed(0)}\" y=\"${(bottom + shift).toFixed(0)}\" textLength=\"${\n width.toFixed(0)\n }\" fill=\"#000\" opacity=\"0.1\">${text}</text>`,\n );\n svg.push(`<text x=\"${x.toFixed(0)}\" y=\"${bottom.toFixed(0)}\" textLength=\"${width.toFixed(0)}\">${text}</text>`);\n};\n\nexport const createBadgeSvg = (options: BadgeSvgOptions) => {\n const { label, message, labelColor, messageColor, rounded } = options;\n const labelWidth = getWidthVerdana110(label);\n const messageWidth = message ? getWidthVerdana110(message) : 0;\n const width = labelWidth + messageWidth + (messageWidth ? 4 : 2) * margin;\n const height = 200;\n const ariaLabel = `${label}${message ? ' ' : ''}${message ?? ''}`;\n\n // svg header and title\n const svg = [\n '<svg xmlns=\"http://www.w3.org/2000/svg\" role=\"img\" ',\n `width=\"${(width * 0.1).toFixed(1)}\" height=\"${(height * 0.1).toFixed(0)}\" `,\n `viewBox=\"0 0 ${width} ${height}\" aria-label=\"${ariaLabel}\">`,\n `<title>${ariaLabel}</title>`,\n ];\n\n // clip path to round the corners\n if (rounded) {\n svg.push(\n `<g><clipPath id=\"r\"><rect width=\"${width.toFixed(0)}\" height=\"${\n height.toFixed(0)\n }\" rx=\"30\" fill=\"#fff\"/></clipPath></g>`,\n );\n }\n\n // backgrounds\n svg.push(`<g clip-path=\"url(#r)\">`);\n svg.push(\n `<rect fill=\"${labelColor}\" width=\"${(labelWidth + 2 * margin).toFixed(0)}\" height=\"${height.toFixed(0)}\"/>`,\n );\n if (message) {\n svg.push(\n `<rect fill=\"${messageColor}\" x=\"${(labelWidth + 2 * margin).toFixed(0)}\" width=\"${\n (messageWidth + 2 * margin).toFixed(0)\n }\" height=\"${height.toFixed(0)}\"/>`,\n );\n }\n svg.push('</g>');\n\n // text\n svg.push(`<g aria-hidden=\"true\" fill=\"#fff\" font-family=\"Verdana,DejaVu Sans,sans-serif\" font-size=\"110\">`);\n emitText(svg, label, labelWidth, margin);\n if (message) emitText(svg, message, messageWidth, 3 * margin - shift * 0.5 + labelWidth);\n svg.push('</g>');\n\n // footer & return svg string\n svg.push('</svg>');\n return svg.join('');\n};\n", "import type { CoverageBadgeConfig, TestBadgeConfig } from './testReportConfig.ts';\nimport type { Manifest } from './testReportToManifest.ts';\nimport { createBadgeSvg } from './utilities/createBadgeSvg.ts';\n\nexport function createTestBadge(config: TestBadgeConfig, manifest: Manifest): string {\n const messageColor = {\n 'no tests': config.color_none,\n failed: config.color_failed,\n skipped: config.color_disabled,\n passed: config.color_ok,\n }[manifest.test_status];\n\n const message = {\n 'no tests': `${manifest.test_status}`,\n failed: `${manifest.test_failed}/${manifest.test_total} ${manifest.test_status}`,\n skipped: `${manifest.test_skipped}/${manifest.test_total} ${manifest.test_status}`,\n passed: `${manifest.test_passed}/${manifest.test_total} ${manifest.test_status}`,\n }[manifest.test_status];\n\n return createBadgeSvg({\n label: config.label,\n message,\n labelColor: config.color_label,\n messageColor,\n rounded: config.style === 'flat',\n });\n}\n\nexport const createCoverageBadge = (config: CoverageBadgeConfig, manifest: Manifest): string =>\n // Derive color\n createBadgeSvg({\n label: config.label,\n message: manifest.coverage_percentage,\n labelColor: config.color_label,\n messageColor: manifest.coverage_color,\n rounded: config.style === 'flat',\n });\n", "import { encodeBase64 } from '@std/encoding/base64';\nimport type { TestCaseState } from './utilities/junit_parser.ts';\nimport type { Manifest } from './testReportToManifest.ts';\nimport {\n buildMarkdownTable,\n markdownCollapsibleEnd,\n markdownCollapsibleTitle,\n markdownTitle,\n} from './utilities/markdownUtils.ts';\nimport { percentage, percentageNoZero } from './utilities/miscUtils.ts';\nimport { createCoverageBadge, createTestBadge } from './testReportToBadges.ts';\nimport type { TestReportConfig } from './testReportConfig.ts';\n\nconst testState = (state: TestCaseState) => state === 'PASSED' ? '\u2705' : state === 'FAILED' ? '\u274C' : '\u26A0\uFE0F';\n\nconst getTestResultSummary = (manifest: Manifest) =>\n buildMarkdownTable(\n [\n '\u2611 Tests',\n `${testState('PASSED')} Success`,\n `${testState('FAILED')} Failures/Errors`,\n `${testState('SKIPPED')} Skipped`,\n ],\n ['right', 'right', 'right', 'right'],\n [[\n manifest.test_total.toLocaleString(),\n manifest.test_passed.toLocaleString(),\n manifest.test_failed.toLocaleString(),\n manifest.test_skipped.toLocaleString(),\n ], ['', percentage(manifest.test_passed, manifest.test_total), '', '']],\n );\n\nconst getCodeCoverageSummary = (manifest: Manifest) =>\n buildMarkdownTable(\n ['\u2630 Lines', '\u16D8 Branches'],\n ['right', 'right'],\n [[\n percentageNoZero(manifest.coverage_lines_hit, manifest.coverage_lines_total),\n percentageNoZero(manifest.coverage_branches_hit, manifest.coverage_branches_total),\n ]],\n );\n\nconst getTestDetails = (manifest: Manifest) =>\n buildMarkdownTable(\n ['\u2713\u2713 Test Suite', '\u2611 Test', 'State'],\n ['default', 'default', 'default'],\n manifest.test_details.map((row) => [`\\`${row.suite}\\``, row.test, testState(row.state)]),\n );\n\nconst getCodeCoverageDetails = (manifest: Manifest) =>\n buildMarkdownTable(\n ['\uD83D\uDDCE File', '\u2630 Lines', '\u16D8 Branches'],\n ['left', 'right', 'right'],\n manifest.coverage_details.map((file) => [\n `\\`${file.name}\\``,\n percentageNoZero(file.lines_hit, file.lines_total),\n percentageNoZero(file.branches_hit, file.branches_total),\n ]),\n );\n\nconst testResulsHeaderLine = (manifest: Manifest) => [\n `Results from \\`${manifest.source}\\` contains ${manifest.testsuites_total} testsuites with ${manifest.test_total} tests:`,\n '',\n];\n\nconst encodeBadge = (name: string, badge: string) => `})`;\n\nconst badges = (config: TestReportConfig, manifest: Manifest) => {\n if (!config.markdown?.badges) return [];\n const badges = [];\n if (config.testBadge) {\n badges.push(encodeBadge('tests', createTestBadge(config.testBadge, manifest)));\n }\n if (config.coverageBadge) {\n badges.push(encodeBadge('coverage', createCoverageBadge(config.coverageBadge, manifest)));\n }\n return badges.length > 0 ? [...badges, ''] : [];\n};\n\nexport const convertTestresultsToMarkdown = (config: TestReportConfig, manifest: Manifest) =>\n [\n markdownTitle('Test Results', 1),\n badges(config, manifest),\n testResulsHeaderLine(manifest),\n markdownTitle('Summary', 2),\n markdownTitle('Test Results', 3),\n getTestResultSummary(manifest),\n markdownTitle('Code Coverage', 3),\n getCodeCoverageSummary(manifest),\n markdownCollapsibleTitle('Detailed Test Results', 2, config.markdown!.collapseDetails),\n getTestDetails(manifest),\n markdownCollapsibleEnd(config.markdown!.collapseDetails),\n markdownCollapsibleTitle('Detailed Code Coverage Results', 2, config.markdown!.collapseDetails),\n getCodeCoverageDetails(manifest),\n markdownCollapsibleEnd(config.markdown!.collapseDetails),\n ].flat().join('\\n');\n", "import type { BaseIssue, Config } from '../../types/index.ts';\n\n/**\n * The global config type.\n */\nexport type GlobalConfig = Omit<Config<never>, 'message'>;\n\n// Create global configuration store\nlet store: GlobalConfig | undefined;\n\n/**\n * Sets the global configuration.\n *\n * @param config The configuration.\n */\nexport function setGlobalConfig(config: GlobalConfig): void {\n store = { ...store, ...config };\n}\n\n/**\n * Returns the global configuration.\n *\n * @param config The config to merge.\n *\n * @returns The configuration.\n */\nexport function getGlobalConfig<const TIssue extends BaseIssue<unknown>>(\n config?: Config<TIssue>\n): Config<TIssue> {\n // Hint: The configuration is deliberately not constructed with the spread\n // operator for performance reasons\n return {\n lang: config?.lang ?? store?.lang,\n message: config?.message,\n abortEarly: config?.abortEarly ?? store?.abortEarly,\n abortPipeEarly: config?.abortPipeEarly ?? store?.abortPipeEarly,\n };\n}\n\n/**\n * Deletes the global configuration.\n */\nexport function deleteGlobalConfig(): void {\n store = undefined;\n}\n", "import type { BaseIssue, ErrorMessage } from '../../types/index.ts';\n\n// Create global message store\nlet store:\n | Map<string | undefined, ErrorMessage<BaseIssue<unknown>>>\n | undefined;\n\n/**\n * Sets a global error message.\n *\n * @param message The error message.\n * @param lang The language of the message.\n */\nexport function setGlobalMessage(\n message: ErrorMessage<BaseIssue<unknown>>,\n lang?: string\n): void {\n if (!store) store = new Map();\n store.set(lang, message);\n}\n\n/**\n * Returns a global error message.\n *\n * @param lang The language of the message.\n *\n * @returns The error message.\n */\nexport function getGlobalMessage(\n lang?: string\n): ErrorMessage<BaseIssue<unknown>> | undefined {\n return store?.get(lang);\n}\n\n/**\n * Deletes a global error message.\n *\n * @param lang The language of the message.\n */\nexport function deleteGlobalMessage(lang?: string): void {\n store?.delete(lang);\n}\n", "import type { BaseIssue, ErrorMessage } from '../../types/index.ts';\n\n// Create schema message store\nlet store:\n | Map<string | undefined, ErrorMessage<BaseIssue<unknown>>>\n | undefined;\n\n/**\n * Sets a schema error message.\n *\n * @param message The error message.\n * @param lang The language of the message.\n */\nexport function setSchemaMessage(\n message: ErrorMessage<BaseIssue<unknown>>,\n lang?: string\n): void {\n if (!store) store = new Map();\n store.set(lang, message);\n}\n\n/**\n * Returns a schema error message.\n *\n * @param lang The language of the message.\n *\n * @returns The error message.\n */\nexport function getSchemaMessage(\n lang?: string\n): ErrorMessage<BaseIssue<unknown>> | undefined {\n return store?.get(lang);\n}\n\n/**\n * Deletes a schema error message.\n *\n * @param lang The language of the message.\n */\nexport function deleteSchemaMessage(lang?: string): void {\n store?.delete(lang);\n}\n", "import type {\n BaseIssue,\n BaseSchema,\n BaseSchemaAsync,\n BaseTransformation,\n BaseTransformationAsync,\n BaseValidation,\n BaseValidationAsync,\n ErrorMessage,\n InferIssue,\n} from '../../types/index.ts';\n\n/**\n * Reference type.\n */\ntype Reference = (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ...args: any[]\n) =>\n | BaseSchema<unknown, unknown, BaseIssue<unknown>>\n | BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>\n | BaseValidation<unknown, unknown, BaseIssue<unknown>>\n | BaseValidationAsync<unknown, unknown, BaseIssue<unknown>>\n | BaseTransformation<unknown, unknown, BaseIssue<unknown>>\n | BaseTransformationAsync<unknown, unknown, BaseIssue<unknown>>;\n\n// Create specific message store\nlet store:\n | Map<Reference, Map<string | undefined, ErrorMessage<BaseIssue<unknown>>>>\n | undefined;\n\n/**\n * Sets a specific error message.\n *\n * @param reference The identifier reference.\n * @param message The error message.\n * @param lang The language of the message.\n */\nexport function setSpecificMessage<const TReference extends Reference>(\n reference: TReference,\n message: ErrorMessage<InferIssue<ReturnType<TReference>>>,\n lang?: string\n): void {\n if (!store) store = new Map();\n if (!store.get(reference)) store.set(reference, new Map());\n store.get(reference)!.set(lang, message);\n}\n\n/**\n * Returns a specific error message.\n *\n * @param reference The identifier reference.\n * @param lang The language of the message.\n *\n * @returns The error message.\n */\nexport function getSpecificMessage<const TReference extends Reference>(\n reference: TReference,\n lang?: string\n): ErrorMessage<InferIssue<ReturnType<TReference>>> | undefined {\n return store?.get(reference)?.get(lang);\n}\n\n/**\n * Deletes a specific error message.\n *\n * @param reference The identifier reference.\n * @param lang The language of the message.\n */\nexport function deleteSpecificMessage(\n reference: Reference,\n lang?: string\n): void {\n store?.get(reference)?.delete(lang);\n}\n", "/**\n * Stringifies an unknown input to a literal or type string.\n *\n * @param input The unknown input.\n *\n * @returns A literal or type string.\n *\n * @internal\n */\nexport function _stringify(input: unknown): string {\n const type = typeof input;\n if (type === 'string') {\n return `\"${input}\"`;\n }\n if (type === 'number' || type === 'bigint' || type === 'boolean') {\n return `${input}`;\n }\n if (type === 'object' || type === 'function') {\n return (input && Object.getPrototypeOf(input)?.constructor?.name) ?? 'null';\n }\n return type;\n}\n", "import {\n getGlobalMessage,\n getSchemaMessage,\n getSpecificMessage,\n} from '../../storages/index.ts';\nimport type {\n BaseIssue,\n BaseSchema,\n BaseSchemaAsync,\n BaseTransformation,\n BaseTransformationAsync,\n BaseValidation,\n BaseValidationAsync,\n Config,\n Dataset,\n ErrorMessage,\n InferInput,\n InferIssue,\n IssuePathItem,\n} from '../../types/index.ts';\nimport { _stringify } from '../_stringify/index.ts';\n\n/**\n * Context type.\n */\ntype Context =\n | BaseSchema<unknown, unknown, BaseIssue<unknown>>\n | BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n | BaseValidation<any, unknown, BaseIssue<unknown>>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n | BaseValidationAsync<any, unknown, BaseIssue<unknown>>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n | BaseTransformation<any, unknown, BaseIssue<unknown>>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n | BaseTransformationAsync<any, unknown, BaseIssue<unknown>>;\n\n/**\n * Other type.\n */\ninterface Other<TContext extends Context> {\n input?: unknown | undefined;\n expected?: string | undefined;\n received?: string | undefined;\n message?: ErrorMessage<InferIssue<TContext>> | undefined;\n path?: [IssuePathItem, ...IssuePathItem[]] | undefined;\n issues?:\n | [BaseIssue<InferInput<TContext>>, ...BaseIssue<InferInput<TContext>>[]]\n | undefined;\n}\n\n/**\n * Adds an issue to the dataset.\n *\n * @param context The issue context.\n * @param label The issue label.\n * @param dataset The input dataset.\n * @param config The configuration.\n * @param other The optional props.\n *\n * @internal\n */\nexport function _addIssue<const TContext extends Context>(\n context: TContext & {\n expects?: string | null;\n requirement?: unknown;\n message?:\n | ErrorMessage<Extract<InferIssue<TContext>, { type: TContext['type'] }>>\n | undefined;\n },\n label: string,\n dataset: Dataset<unknown, BaseIssue<unknown>>,\n config: Config<InferIssue<TContext>>,\n other?: Other<TContext>\n): void {\n // Get expected and received string\n const input = other && 'input' in other ? other.input : dataset.value;\n const expected = other?.expected ?? context.expects ?? null;\n const received = other?.received ?? _stringify(input);\n\n // Create issue object\n // Hint: The issue is deliberately not constructed with the spread operator\n // for performance reasons\n const issue: BaseIssue<unknown> = {\n kind: context.kind,\n type: context.type,\n input,\n expected,\n received,\n message: `Invalid ${label}: ${\n expected ? `Expected ${expected} but r` : 'R'\n }eceived ${received}`,\n requirement: context.requirement,\n path: other?.path,\n issues: other?.issues,\n lang: config.lang,\n abortEarly: config.abortEarly,\n abortPipeEarly: config.abortPipeEarly,\n };\n\n // Check if context is a schema\n const isSchema = context.kind === 'schema';\n\n // Get custom issue message\n const message =\n other?.message ??\n context.message ??\n getSpecificMessage(context.reference, issue.lang) ??\n (isSchema ? getSchemaMessage(issue.lang) : null) ??\n config.message ??\n getGlobalMessage(issue.lang);\n\n // If custom message if specified, override default message\n if (message) {\n // @ts-expect-error\n issue.message =\n typeof message === 'function'\n ? // @ts-expect-error\n message(issue)\n : message;\n }\n\n // If context is a schema, set typed to `false`\n if (isSchema) {\n dataset.typed = false;\n }\n\n // Add issue to dataset\n if (dataset.issues) {\n dataset.issues.push(issue);\n } else {\n dataset.issues = [issue];\n }\n}\n", "/**\n * Joins multiple `expects` values with the given separator.\n *\n * @param values The `expects` values.\n * @param separator The separator.\n *\n * @returns The joined `expects` property.\n *\n * @internal\n */\nexport function _joinExpects(values: string[], separator: '&' | '|'): string {\n // Create list without duplicates\n const list = [...new Set(values)];\n\n // If list has more than one item, join them\n if (list.length > 1) {\n return `(${list.join(` ${separator} `)})`;\n }\n\n // Otherwise, return first item or \"never\"\n return list[0] ?? 'never';\n}\n", "import type {\n BaseIssue,\n BaseSchema,\n BaseSchemaAsync,\n InferIssue,\n} from '../../types/index.ts';\n\n/**\n * A Valibot error with useful information.\n */\nexport class ValiError<\n TSchema extends\n | BaseSchema<unknown, unknown, BaseIssue<unknown>>\n | BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>,\n> extends Error {\n /**\n * The error issues.\n */\n public readonly issues: [InferIssue<TSchema>, ...InferIssue<TSchema>[]];\n\n /**\n * Creates a Valibot error with useful information.\n *\n * @param issues The error issues.\n */\n constructor(issues: [InferIssue<TSchema>, ...InferIssue<TSchema>[]]) {\n super(issues[0].message);\n this.name = 'ValiError';\n this.issues = issues;\n }\n}\n", "import type {\n NullableSchema,\n NullableSchemaAsync,\n NullishSchema,\n NullishSchemaAsync,\n OptionalSchema,\n OptionalSchemaAsync,\n UndefinedableSchema,\n UndefinedableSchemaAsync,\n} from '../../schemas/index.ts';\nimport type {\n BaseIssue,\n BaseSchema,\n BaseSchemaAsync,\n Config,\n Dataset,\n InferInput,\n InferIssue,\n MaybePromise,\n} from '../../types/index.ts';\n\n/**\n * Infer default type.\n */\nexport type InferDefault<\n TSchema extends\n | BaseSchema<unknown, unknown, BaseIssue<unknown>>\n | BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>\n | NullableSchema<BaseSchema<unknown, unknown, BaseIssue<unknown>>, unknown>\n | NullableSchemaAsync<\n | BaseSchema<unknown, unknown, BaseIssue<unknown>>\n | BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>,\n unknown\n >\n | NullishSchema<BaseSchema<unknown, unknown, BaseIssue<unknown>>, unknown>\n | NullishSchemaAsync<\n | BaseSchema<unknown, unknown, BaseIssue<unknown>>\n | BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>,\n unknown\n >\n | OptionalSchema<BaseSchema<unknown, unknown, BaseIssue<unknown>>, unknown>\n | OptionalSchemaAsync<\n | BaseSchema<unknown, unknown, BaseIssue<unknown>>\n | BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>,\n unknown\n >\n | UndefinedableSchema<\n BaseSchema<unknown, unknown, BaseIssue<unknown>>,\n unknown\n >\n | UndefinedableSchemaAsync<\n | BaseSchema<unknown, unknown, BaseIssue<unknown>>\n | BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>,\n unknown\n >,\n> = TSchema extends\n | NullableSchema<\n BaseSchema<unknown, unknown, BaseIssue<unknown>>,\n infer TDefault\n >\n | NullableSchemaAsync<\n | BaseSchema<unknown, unknown, BaseIssue<unknown>>\n | BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>,\n infer TDefault\n >\n | NullishSchema<\n BaseSchema<unknown, unknown, BaseIssue<unknown>>,\n infer TDefault\n >\n | NullishSchemaAsync<\n | BaseSchema<unknown, unknown, BaseIssue<unknown>>\n | BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>,\n infer TDefault\n >\n | OptionalSchema<\n BaseSchema<unknown, unknown, BaseIssue<unknown>>,\n infer TDefault\n >\n | OptionalSchemaAsync<\n | BaseSchema<unknown, unknown, BaseIssue<unknown>>\n | BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>,\n infer TDefault\n >\n | UndefinedableSchema<\n BaseSchema<unknown, unknown, BaseIssue<unknown>>,\n infer TDefault\n >\n | UndefinedableSchemaAsync<\n | BaseSchema<unknown, unknown, BaseIssue<unknown>>\n | BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>,\n infer TDefault\n >\n ? [TDefault] extends [never]\n ? undefined\n : TDefault extends () => MaybePromise<InferInput<TSchema>>\n ? ReturnType<TDefault>\n : TDefault\n : undefined;\n\n/**\n * Returns the default value of the schema.\n *\n * @param schema The schema to get it from.\n * @param dataset The input dataset if available.\n * @param config The config if available.\n *\n * @returns The default value.\n */\nexport function getDefault<\n const TSchema extends\n | BaseSchema<unknown, unknown, BaseIssue<unknown>>\n | BaseSchemaAsync<unknown, unknown, BaseIssue<unknown>>,\n>(\n schema: TSchema,\n dataset?: Dataset<null | undefined, never>,\n config?: Config<InferIssue<TSchema>>\n): InferDefault<TSchema> {\n // @ts-expect-error\n return typeof schema.default === 'function'\n ? // @ts-expect-error\n schema.default(dataset, config)\n : // @ts-expect-error\n schema.default;\n}\n", "import type {\n ArrayPathItem,\n BaseIssue,\n BaseSchema,\n Dataset,\n ErrorMessage,\n InferInput,\n InferIssue,\n InferOutput,\n} from '../../types/index.ts';\nimport { _addIssue } from '../../utils/index.ts';\nimport type { ArrayIssue } from './types.ts';\n\n/**\n * Array schema type.\n */\nexport interface ArraySchema<\n TItem extends BaseSchema<unknown, unknown, BaseIssue<unknown>>,\n TMessage extends ErrorMessage<ArrayIssue> | undefined,\n> extends BaseSchema<\n InferInput<TItem>[],\n InferOutput<TItem>[],\n ArrayIssue | InferIssue<TItem>\n > {\n /**\n * The schema type.\n */\n readonly type: 'array';\n /**\n * The schema reference.\n */\n readonly reference: typeof array;\n /**\n * The expected property.\n */\n readonly expects: 'Array';\n /**\n * The array item schema.\n */\n readonly item: TItem;\n /**\n * The error message.\n */\n readonly message: TMessage;\n}\n\n/**\n * Creates an array schema.\n *\n * @param item The item schema.\n *\n * @returns An array schema.\n */\nexport function array<\n const TItem extends BaseSchema<unknown, unknown, BaseIssue<unknown>>,\n>(item: TItem): ArraySchema<TItem, undefined>;\n\n/**\n * Creates an array schema.\n *\n * @param item The item schema.\n * @param message The error message.\n *\n * @returns An array schema.\n */\nexport function array<\n const TItem extends BaseSchema<unknown, unknown, BaseIssue<unknown>>,\n const TMessage extends ErrorMessage<ArrayIssue> | undefined,\n>(item: TItem, message: TMessage): ArraySchema<TItem, TMessage>;\n\nexport function array(\n item: BaseSchema<unknown, unknown, BaseIssue<unknown>>,\n message?: ErrorMessage<ArrayIssue>\n): ArraySchema<\n BaseSchema<unknown, unknown, BaseIssue<unknown>>,\n ErrorMessage<ArrayIssue> | undefined\n> {\n return {\n kind: 'schema',\n type: 'array',\n reference: array,\n expects: 'Array',\n async: false,\n item,\n message,\n _run(dataset, config) {\n // Get input value from dataset\n const input = dataset.value;\n\n // If root type is valid, check nested types\n if (Array.isArray(input)) {\n // Set typed to `true` and value to empty array\n dataset.typed = true;\n dataset.value = [];\n\n // Parse schema of each array item\n for (let key = 0; key < input.length; key++) {\n const value = input[key];\n const itemDataset = this.item._run({ typed: false, value }, config);\n\n // If there are issues, capture them\n if (itemDataset.issues) {\n // Create array path item\n const pathItem: ArrayPathItem = {\n type: 'array',\n origin: 'value',\n input,\n key,\n value,\n };\n\n // Add modified item dataset issues to issues\n for (const issue of itemDataset.issues) {\n if (issue.path) {\n issue.path.unshift(pathItem);\n } else {\n // @ts-expect-error\n issue.path = [pathItem];\n }\n // @ts-expect-error\n dataset.issues?.push(issue);\n }\n if (!dataset.issues) {\n // @ts-expect-error\n dataset.issues = i