From ddfd4c1d824bf7486c9d74784a4bb32844b251ed Mon Sep 17 00:00:00 2001 From: Stackwright Bot Date: Sun, 31 May 2026 10:17:58 -0400 Subject: [PATCH] feat(core,types): add format: markdown to TextBlock via micromark (stackwright-7dv) --- .changeset/feat-markdown-textblock.md | 6 + AGENTS.md | 4 +- examples/stackwright-docs/AGENTS.md | 4 +- packages/core/package.json | 1 + .../core/src/components/base/TextGrid.tsx | 111 +++++---- .../core/test/components/text-block.test.tsx | 103 ++++++++ packages/types/schemas/content-schema.json | 95 ++++---- .../types/schemas/site-config-schema.json | 7 + packages/types/src/types/base.ts | 1 + pnpm-lock.yaml | 220 ++++++++++++++++++ 10 files changed, 463 insertions(+), 89 deletions(-) create mode 100644 .changeset/feat-markdown-textblock.md diff --git a/.changeset/feat-markdown-textblock.md b/.changeset/feat-markdown-textblock.md new file mode 100644 index 00000000..68b57c0a --- /dev/null +++ b/.changeset/feat-markdown-textblock.md @@ -0,0 +1,6 @@ +--- +"@stackwright/core": minor +"@stackwright/types": minor +--- + +feat(core,types): add format: markdown to TextBlock for CommonMark rendering via micromark diff --git a/AGENTS.md b/AGENTS.md index 6260ca4a..e48cdeff 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -167,8 +167,8 @@ The YAML key is the key used inside `content_items` entries. All types inherit ` | Type | Fields | |---|---| -| `TextBlock` | `text` (string), `textSize` (TypographyVariant), `textColor`? (string) | -| `ButtonContent` | `text` (string), `textSize` (TypographyVariant), `textColor`? (string), `variant` (`text` | `outlined` | `contained`), `variantSize`? (`small` | `medium` | `large`), `href`? (string), `action`? (string), `icon`? (MediaItem), `alignment`? (`left` | `center` | `right`), `bgColor`? (string) | +| `TextBlock` | `text` (string), `textSize` (TypographyVariant), `textColor`? (string), `format`? (`plain` | `markdown`) | +| `ButtonContent` | `text` (string), `textSize` (TypographyVariant), `textColor`? (string), `format`? (`plain` | `markdown`), `variant` (`text` | `outlined` | `contained`), `variantSize`? (`small` | `medium` | `large`), `href`? (string), `action`? (string), `icon`? (MediaItem), `alignment`? (`left` | `center` | `right`), `bgColor`? (string) | | `MediaItem` | Discriminated union: `type: "media"` \| `type: "icon"` \| `type: "image"` \| `type: "video"`. `type` field is required and acts as discriminator. | | `ImageContent` | `label` (string), `color`? (string), `background`? (string), `src` (string), `alt`? (string), `height`? (number | string), `width`? (number | string), `style`? (`contained` | `overflow`), `type` ("image"), `aspect_ratio`? (number) | | `IconContent` | `label` (string), `color`? (string), `background`? (string), `src` (string), `alt`? (string), `height`? (number | string), `width`? (number | string), `style`? (`contained` | `overflow`), `type` ("icon"), `size`? (number | TypographyVariant) | diff --git a/examples/stackwright-docs/AGENTS.md b/examples/stackwright-docs/AGENTS.md index 27c691bb..18e8ccfb 100644 --- a/examples/stackwright-docs/AGENTS.md +++ b/examples/stackwright-docs/AGENTS.md @@ -41,8 +41,8 @@ The YAML key is the key used inside `content_items` entries. All types inherit ` | Type | Fields | |---|---| -| `TextBlock` | `text` (string), `textSize` (TypographyVariant), `textColor`? (string) | -| `ButtonContent` | `text` (string), `textSize` (TypographyVariant), `textColor`? (string), `variant` (`text` | `outlined` | `contained`), `variantSize`? (`small` | `medium` | `large`), `href`? (string), `action`? (string), `icon`? (MediaItem), `alignment`? (`left` | `center` | `right`), `bgColor`? (string) | +| `TextBlock` | `text` (string), `textSize` (TypographyVariant), `textColor`? (string), `format`? (`plain` | `markdown`) | +| `ButtonContent` | `text` (string), `textSize` (TypographyVariant), `textColor`? (string), `format`? (`plain` | `markdown`), `variant` (`text` | `outlined` | `contained`), `variantSize`? (`small` | `medium` | `large`), `href`? (string), `action`? (string), `icon`? (MediaItem), `alignment`? (`left` | `center` | `right`), `bgColor`? (string) | | `MediaItem` | Discriminated union: `type: "media"` \| `type: "icon"` \| `type: "image"` \| `type: "video"`. `type` field is required and acts as discriminator. | | `ImageContent` | `label` (string), `color`? (string), `background`? (string), `src` (string), `alt`? (string), `height`? (number | string), `width`? (number | string), `style`? (`contained` | `overflow`), `type` ("image"), `aspect_ratio`? (number) | | `IconContent` | `label` (string), `color`? (string), `background`? (string), `src` (string), `alt`? (string), `height`? (number | string), `width`? (number | string), `style`? (`contained` | `overflow`), `type` ("icon"), `size`? (number | TypographyVariant) | diff --git a/packages/core/package.json b/packages/core/package.json index 2990d514..01406717 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -63,6 +63,7 @@ "@stackwright/themes": "workspace:*", "@stackwright/types": "workspace:*", "js-yaml": "^4.1.0", + "micromark": "^4.0.1", "prismjs": "^1.30.0", "uuid": "^13.0.0", "zod": "^4.4.3" diff --git a/packages/core/src/components/base/TextGrid.tsx b/packages/core/src/components/base/TextGrid.tsx index e818eac0..e2e57c13 100644 --- a/packages/core/src/components/base/TextGrid.tsx +++ b/packages/core/src/components/base/TextGrid.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { micromark } from 'micromark'; import { TextBlock } from '@stackwright/types'; import { v4 as uuidv4 } from 'uuid'; import { useSafeTheme } from '../../hooks/useSafeTheme'; @@ -13,6 +14,16 @@ interface TextGridProps { }; } +/** + * Renders a TextBlock using CommonMark via micromark. + * micromark does NOT pass through raw HTML by default (allowDangerousHtml: false), + * so the output is XSS-safe by construction — no sanitization library needed. + */ +function renderMarkdown(text: string, color?: string): React.ReactNode { + const html = micromark(text); + return
; +} + /** * Renders a string with inline markdown: **bold**, *italic*, `code`. * Returns an array of React nodes safe to embed in JSX. @@ -85,52 +96,64 @@ export function TextGrid({ content, config }: TextGridProps) { return ( <> - {content.map((textItem) => ( -
- {textItem.text - .split('\n') - .filter((line) => line.trim() !== '') - .map((line) => { - const lineBlock: TextBlock = { - ...textItem, - text: line, - }; - return ( -
- {startsWithBullet(line) && listIcon && ( - - {listIcon} - - )} + {content.map((textItem) => { + // Markdown mode: pass the entire text to micromark, skip line-splitting and special chars + if (textItem.format === 'markdown') { + return ( +
+ {renderMarkdown(textItem.text, textItem.textColor ?? theme.colors.text)} +
+ ); + } - {startsWithListNumber(line) && ( - - {listNumber++}. - - )} + // Plain mode (default): existing line-splitting + bullet/list/special char logic + return ( +
+ {textItem.text + .split('\n') + .filter((line) => line.trim() !== '') + .map((line) => { + const lineBlock: TextBlock = { + ...textItem, + text: line, + }; + return ( +
+ {startsWithBullet(line) && listIcon && ( + + {listIcon} + + )} + + {startsWithListNumber(line) && ( + + {listNumber++}. + + )} - {renderText(lineBlock)} -
- ); - })} -
- ))} + {renderText(lineBlock)} +
+ ); + })} +
+ ); + })} ); } diff --git a/packages/core/test/components/text-block.test.tsx b/packages/core/test/components/text-block.test.tsx index bcb8b8eb..b061736a 100644 --- a/packages/core/test/components/text-block.test.tsx +++ b/packages/core/test/components/text-block.test.tsx @@ -345,3 +345,106 @@ describe('TextBlockGrid', () => { expect(screen.getByText('After divider')).toBeInTheDocument(); }); }); + +describe('TextGrid — markdown format', () => { + it('renders bold text when format is markdown', () => { + const { container } = render( + + ); + expect(container.querySelector('strong')).toBeTruthy(); + expect(container.querySelector('strong')?.textContent).toBe('Bold text'); + }); + + it('renders italic text when format is markdown', () => { + const { container } = render( + + ); + expect(container.querySelector('em')).toBeTruthy(); + expect(container.querySelector('em')?.textContent).toBe('Italic text'); + }); + + it('renders a link when format is markdown', () => { + const { container } = render( + + ); + const link = container.querySelector('a'); + expect(link).toBeTruthy(); + expect(link?.getAttribute('href')).toBe('https://example.com'); + expect(link?.textContent).toBe('Visit site'); + }); + + it('does NOT render raw HTML (XSS-safe by construction)', () => { + const { container } = render( + alert("xss") safe text', + textSize: 'body1', + format: 'markdown', + }, + ]} + /> + ); + // micromark strips raw HTML by default — no script tag should appear + expect(container.querySelector('script')).toBeNull(); + expect(container.textContent).toContain('safe text'); + }); + + it('renders a markdown list when format is markdown', () => { + const { container } = render( + + ); + const listItems = container.querySelectorAll('li'); + expect(listItems.length).toBe(3); + expect(listItems[0].textContent).toBe('Item one'); + expect(listItems[1].textContent).toBe('Item two'); + }); + + it('backward compat: plain format (no format field) unchanged behavior', () => { + const { container } = render( + + ); + // Plain mode uses renderInlineMarkdown — **text** is rendered as via React children + // (not via dangerouslySetInnerHTML). Existing behavior is preserved. + expect(container.querySelector('strong')).toBeTruthy(); + expect(container.querySelector('strong')?.textContent).toBe('Not bold'); + }); + + it('backward compat: explicit format: plain unchanged behavior', () => { + render( + + ); + expect(screen.getByText('Regular text')).toBeInTheDocument(); + }); +}); diff --git a/packages/types/schemas/content-schema.json b/packages/types/schemas/content-schema.json index 278bfb33..46f78400 100644 --- a/packages/types/schemas/content-schema.json +++ b/packages/types/schemas/content-schema.json @@ -111,7 +111,7 @@ "content_items": { "type": "array", "items": { - "$ref": "#/definitions/__schema25" + "$ref": "#/definitions/__schema26" } }, "list_icon": { @@ -504,6 +504,9 @@ "textColor": { "$ref": "#/definitions/__schema24" }, + "format": { + "$ref": "#/definitions/__schema25" + }, "variant": { "type": "string", "enum": [ @@ -559,6 +562,13 @@ "type": "string" }, "__schema25": { + "type": "string", + "enum": [ + "plain", + "markdown" + ] + }, + "__schema26": { "anyOf": [ { "type": "object", @@ -640,12 +650,12 @@ "const": "main" }, "heading": { - "$ref": "#/definitions/__schema26" + "$ref": "#/definitions/__schema27" }, "textBlocks": { "type": "array", "items": { - "$ref": "#/definitions/__schema26" + "$ref": "#/definitions/__schema27" } }, "media": { @@ -697,12 +707,12 @@ "const": "tabbed_content" }, "heading": { - "$ref": "#/definitions/__schema26" + "$ref": "#/definitions/__schema27" }, "tabs": { "type": "array", "items": { - "$ref": "#/definitions/__schema25" + "$ref": "#/definitions/__schema26" } } }, @@ -727,19 +737,19 @@ "$ref": "#/definitions/__schema21" }, "src": { - "$ref": "#/definitions/__schema27" + "$ref": "#/definitions/__schema28" }, "alt": { - "$ref": "#/definitions/__schema28" + "$ref": "#/definitions/__schema29" }, "height": { - "$ref": "#/definitions/__schema29" + "$ref": "#/definitions/__schema30" }, "width": { - "$ref": "#/definitions/__schema30" + "$ref": "#/definitions/__schema31" }, "style": { - "$ref": "#/definitions/__schema31" + "$ref": "#/definitions/__schema32" }, "type": { "type": "string", @@ -772,7 +782,7 @@ "heading": { "allOf": [ { - "$ref": "#/definitions/__schema26" + "$ref": "#/definitions/__schema27" } ] }, @@ -838,7 +848,7 @@ "heading": { "allOf": [ { - "$ref": "#/definitions/__schema26" + "$ref": "#/definitions/__schema27" } ] }, @@ -857,19 +867,19 @@ "$ref": "#/definitions/__schema21" }, "src": { - "$ref": "#/definitions/__schema27" + "$ref": "#/definitions/__schema28" }, "alt": { - "$ref": "#/definitions/__schema28" + "$ref": "#/definitions/__schema29" }, "height": { - "$ref": "#/definitions/__schema29" + "$ref": "#/definitions/__schema30" }, "width": { - "$ref": "#/definitions/__schema30" + "$ref": "#/definitions/__schema31" }, "style": { - "$ref": "#/definitions/__schema31" + "$ref": "#/definitions/__schema32" }, "type": { "type": "string", @@ -954,7 +964,7 @@ "heading": { "allOf": [ { - "$ref": "#/definitions/__schema26" + "$ref": "#/definitions/__schema27" } ] }, @@ -1014,7 +1024,7 @@ "heading": { "allOf": [ { - "$ref": "#/definitions/__schema26" + "$ref": "#/definitions/__schema27" } ] }, @@ -1080,7 +1090,7 @@ "heading": { "allOf": [ { - "$ref": "#/definitions/__schema26" + "$ref": "#/definitions/__schema27" } ] }, @@ -1130,7 +1140,7 @@ "heading": { "allOf": [ { - "$ref": "#/definitions/__schema26" + "$ref": "#/definitions/__schema27" } ] }, @@ -1246,7 +1256,7 @@ "heading": { "allOf": [ { - "$ref": "#/definitions/__schema26" + "$ref": "#/definitions/__schema27" } ] }, @@ -1295,7 +1305,7 @@ "heading": { "allOf": [ { - "$ref": "#/definitions/__schema26" + "$ref": "#/definitions/__schema27" } ] }, @@ -1390,14 +1400,14 @@ "heading": { "allOf": [ { - "$ref": "#/definitions/__schema26" + "$ref": "#/definitions/__schema27" } ] }, "textBlocks": { "type": "array", "items": { - "$ref": "#/definitions/__schema26" + "$ref": "#/definitions/__schema27" } }, "buttons": { @@ -1433,7 +1443,7 @@ "heading": { "allOf": [ { - "$ref": "#/definitions/__schema26" + "$ref": "#/definitions/__schema27" } ] }, @@ -1441,7 +1451,7 @@ "minItems": 1, "type": "array", "items": { - "$ref": "#/definitions/__schema32" + "$ref": "#/definitions/__schema33" } }, "gap": { @@ -1513,7 +1523,7 @@ "heading": { "allOf": [ { - "$ref": "#/definitions/__schema26" + "$ref": "#/definitions/__schema27" } ] }, @@ -1546,19 +1556,19 @@ "$ref": "#/definitions/__schema21" }, "src": { - "$ref": "#/definitions/__schema27" + "$ref": "#/definitions/__schema28" }, "alt": { - "$ref": "#/definitions/__schema28" + "$ref": "#/definitions/__schema29" }, "height": { - "$ref": "#/definitions/__schema29" + "$ref": "#/definitions/__schema30" }, "width": { - "$ref": "#/definitions/__schema30" + "$ref": "#/definitions/__schema31" }, "style": { - "$ref": "#/definitions/__schema31" + "$ref": "#/definitions/__schema32" }, "type": { "type": "string", @@ -1752,7 +1762,7 @@ } ] }, - "__schema26": { + "__schema27": { "type": "object", "properties": { "text": { @@ -1763,6 +1773,9 @@ }, "textColor": { "$ref": "#/definitions/__schema24" + }, + "format": { + "$ref": "#/definitions/__schema25" } }, "required": [ @@ -1771,13 +1784,13 @@ ], "additionalProperties": false }, - "__schema27": { - "type": "string" - }, "__schema28": { "type": "string" }, "__schema29": { + "type": "string" + }, + "__schema30": { "anyOf": [ { "type": "number" @@ -1787,7 +1800,7 @@ } ] }, - "__schema30": { + "__schema31": { "anyOf": [ { "type": "number" @@ -1797,14 +1810,14 @@ } ] }, - "__schema31": { + "__schema32": { "allOf": [ { "$ref": "#/definitions/__schema6" } ] }, - "__schema32": { + "__schema33": { "type": "object", "properties": { "width": { @@ -1813,7 +1826,7 @@ "content_items": { "type": "array", "items": { - "$ref": "#/definitions/__schema25" + "$ref": "#/definitions/__schema26" } } }, diff --git a/packages/types/schemas/site-config-schema.json b/packages/types/schemas/site-config-schema.json index ecbaf6de..c2f8f58f 100644 --- a/packages/types/schemas/site-config-schema.json +++ b/packages/types/schemas/site-config-schema.json @@ -317,6 +317,13 @@ "textColor": { "type": "string" }, + "format": { + "type": "string", + "enum": [ + "plain", + "markdown" + ] + }, "variant": { "type": "string", "enum": [ diff --git a/packages/types/src/types/base.ts b/packages/types/src/types/base.ts index 61406f23..62af9c55 100644 --- a/packages/types/src/types/base.ts +++ b/packages/types/src/types/base.ts @@ -12,6 +12,7 @@ export const textBlockSchema = z.object({ text: z.string(), textSize: typographyVariantSchema, textColor: z.string().optional(), + format: z.enum(['plain', 'markdown']).optional(), // default: 'plain' for backward compat }); export const buttonContentSchema = textBlockSchema.extend({ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 31d44698..5568f4c5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -296,6 +296,9 @@ importers: js-yaml: specifier: ^4.1.0 version: 4.1.1 + micromark: + specifier: ^4.0.1 + version: 4.0.2 prismjs: specifier: ^1.30.0 version: 1.30.0 @@ -2955,6 +2958,9 @@ packages: '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} + '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} @@ -2982,6 +2988,9 @@ packages: '@types/jsonfile@6.1.4': resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + '@types/mysql@2.15.26': resolution: {integrity: sha512-DSLCOXhkvfS5WNNPbfn2KdICAmk8lLc+/PNvnPnF7gOdMZCxopXduqv0OQ13y/yA/zXTSikZZqVgybUxOEg6YQ==} @@ -3699,6 +3708,9 @@ packages: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + chardet@2.1.1: resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} @@ -3896,6 +3908,9 @@ packages: decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -3931,6 +3946,9 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + devtools-protocol@0.0.1581282: resolution: {integrity: sha512-nv7iKtNZQshSW2hKzYNr46nM/Cfh5SEvE2oV0/SEGgc9XupIY5ggf84Cz8eJIkBce7S3bmTAauFD6aysMpnqsQ==} @@ -5119,6 +5137,66 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -8737,6 +8815,10 @@ snapshots: dependencies: '@types/node': 24.12.3 + '@types/debug@4.1.13': + dependencies: + '@types/ms': 2.1.0 + '@types/deep-eql@4.0.2': {} '@types/estree@1.0.8': {} @@ -8760,6 +8842,8 @@ snapshots: dependencies: '@types/node': 24.12.3 + '@types/ms@2.1.0': {} + '@types/mysql@2.15.26': dependencies: '@types/node': 24.12.3 @@ -9554,6 +9638,8 @@ snapshots: chalk@5.6.2: {} + character-entities@2.0.2: {} + chardet@2.1.1: {} chokidar@4.0.3: @@ -9737,6 +9823,10 @@ snapshots: decimal.js@10.6.0: {} + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + deep-is@0.1.4: {} define-data-property@1.1.4: @@ -9767,6 +9857,10 @@ snapshots: detect-libc@2.1.2: {} + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + devtools-protocol@0.0.1581282: {} devtools-protocol@0.0.1608973: {} @@ -11159,6 +11253,132 @@ snapshots: merge2@1.4.1: {} + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.13 + debug: 4.4.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + micromatch@4.0.8: dependencies: braces: 3.0.3