diff --git a/.changeset/lazy-pandas-repeat.md b/.changeset/lazy-pandas-repeat.md
new file mode 100644
index 00000000000..bc623b022a7
--- /dev/null
+++ b/.changeset/lazy-pandas-repeat.md
@@ -0,0 +1,5 @@
+---
+'@qwik.dev/router': patch
+---
+
+chore: trim dependencies by inlining small single-use helpers
diff --git a/.changeset/warm-crabs-smile.md b/.changeset/warm-crabs-smile.md
new file mode 100644
index 00000000000..01a58f6fc1b
--- /dev/null
+++ b/.changeset/warm-crabs-smile.md
@@ -0,0 +1,5 @@
+---
+'@qwik.dev/core': patch
+---
+
+chore: update magic-string to v1
diff --git a/packages/docs/package.json b/packages/docs/package.json
index f4356604c91..fe4e52754a8 100644
--- a/packages/docs/package.json
+++ b/packages/docs/package.json
@@ -40,7 +40,7 @@
"fflate": "0.8.2",
"gray-matter": "4.0.3",
"leaflet": "1.9.4",
- "magic-string": "0.30.21",
+ "magic-string": "1.2.3",
"pagefind": "1.4.0",
"playwright": "1.61.1",
"prettier": "3.7.4",
diff --git a/packages/docs/src/routes/api/qwik-router-middleware-azure-swa/api.json b/packages/docs/src/routes/api/qwik-router-middleware-azure-swa/api.json
index 9d86e4d4a4b..1c3964ad7fa 100644
--- a/packages/docs/src/routes/api/qwik-router-middleware-azure-swa/api.json
+++ b/packages/docs/src/routes/api/qwik-router-middleware-azure-swa/api.json
@@ -2,6 +2,48 @@
"id": "qwik-router-middleware-azure-swa",
"package": "@qwik.dev/qwik-router/middleware/azure-swa",
"members": [
+ {
+ "name": "AzureContext",
+ "id": "azurecontext",
+ "hierarchy": [
+ {
+ "name": "AzureContext",
+ "id": "azurecontext"
+ }
+ ],
+ "kind": "Interface",
+ "content": "```typescript\nexport interface AzureContext \n```\n\n\n
| \n\nProperty\n\n\n | \n\nModifiers\n\n\n | \n\nType\n\n\n | \n\nDescription\n\n\n |
\n| \n\nbindingData\n\n\n | \n\n\n | \n\n{ \\[key: string\\]: any; }\n\n\n | \n\n\n |
\n| \n\nbindingDefinitions\n\n\n | \n\n\n | \n\n{ name: string; type: string; direction: 'in' \\| 'out' \\| 'inout'; }\\[\\]\n\n\n | \n\n\n |
\n| \n\nbindings\n\n\n | \n\n\n | \n\n{ \\[key: string\\]: any; }\n\n\n | \n\n\n |
\n| \n\nexecutionContext\n\n\n | \n\n\n | \n\n{ invocationId: string; functionName: string; functionDirectory: string; }\n\n\n | \n\n\n |
\n| \n\ninvocationId\n\n\n | \n\n\n | \n\nstring\n\n\n | \n\n\n |
\n| \n\nlog\n\n\n | \n\n\n | \n\n((...args: any\\[\\]) => void) & { error(...args: any\\[\\]): void; warn(...args: any\\[\\]): void; info(...args: any\\[\\]): void; verbose(...args: any\\[\\]): void; }\n\n\n | \n\n\n |
\n| \n\nreq?\n\n\n | \n\n\n | \n\n[AzureHttpRequest](#azurehttprequest)\n\n\n | \n\n_(Optional)_\n\n\n |
\n| \n\nres?\n\n\n | \n\n\n | \n\n{ \\[key: string\\]: any; }\n\n\n | \n\n_(Optional)_\n\n\n |
\n| \n\ntraceContext\n\n\n | \n\n\n | \n\n{ traceparent?: string \\| null; tracestate?: string \\| null; attributes?: { \\[key: string\\]: string; } \\| null; }\n\n\n | \n\n\n |
\n
\n\n\n| \n\nMethod\n\n\n | \n\nDescription\n\n\n |
\n| \n\n[done(err, result)](#azurecontext-done)\n\n\n | \n\n\n |
\n
",
+ "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/middleware/azure-swa/index.ts",
+ "mdFile": "router.azurecontext.md"
+ },
+ {
+ "name": "AzureFunction",
+ "id": "azurefunction",
+ "hierarchy": [
+ {
+ "name": "AzureFunction",
+ "id": "azurefunction"
+ }
+ ],
+ "kind": "TypeAlias",
+ "content": "```typescript\nexport type AzureFunction = (context: AzureContext, ...args: any[]) => Promise | void;\n```\n**References:** [AzureContext](#azurecontext)",
+ "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/middleware/azure-swa/index.ts",
+ "mdFile": "router.azurefunction.md"
+ },
+ {
+ "name": "AzureHttpRequest",
+ "id": "azurehttprequest",
+ "hierarchy": [
+ {
+ "name": "AzureHttpRequest",
+ "id": "azurehttprequest"
+ }
+ ],
+ "kind": "Interface",
+ "content": "```typescript\nexport interface AzureHttpRequest \n```\n\n\n| \n\nProperty\n\n\n | \n\nModifiers\n\n\n | \n\nType\n\n\n | \n\nDescription\n\n\n |
\n| \n\nbody?\n\n\n | \n\n\n | \n\nany\n\n\n | \n\n_(Optional)_\n\n\n |
\n| \n\nbufferBody?\n\n\n | \n\n\n | \n\nUint8Array\n\n\n | \n\n_(Optional)_\n\n\n |
\n| \n\nheaders\n\n\n | \n\n\n | \n\n{ \\[name: string\\]: string; }\n\n\n | \n\n\n |
\n| \n\nmethod\n\n\n | \n\n\n | \n\nstring \\| null\n\n\n | \n\n\n |
\n| \n\nparams\n\n\n | \n\n\n | \n\n{ \\[name: string\\]: string; }\n\n\n | \n\n\n |
\n| \n\nquery\n\n\n | \n\n\n | \n\n{ \\[name: string\\]: string; }\n\n\n | \n\n\n |
\n| \n\nrawBody?\n\n\n | \n\n\n | \n\nany\n\n\n | \n\n_(Optional)_\n\n\n |
\n| \n\nurl\n\n\n | \n\n\n | \n\nstring\n\n\n | \n\n\n |
\n
",
+ "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/middleware/azure-swa/index.ts",
+ "mdFile": "router.azurehttprequest.md"
+ },
{
"name": "createQwikCity",
"id": "createqwikcity",
@@ -26,10 +68,27 @@
}
],
"kind": "Function",
- "content": "```typescript\nexport declare function createQwikRouter(opts: QwikRouterAzureOptions): AzureFunction;\n```\n\n\n| \n\nParameter\n\n\n | \n\nType\n\n\n | \n\nDescription\n\n\n |
\n| \n\nopts\n\n\n | \n\n[QwikRouterAzureOptions](#qwikrouterazureoptions)\n\n\n | \n\n\n |
\n
\n\n**Returns:**\n\nAzureFunction",
+ "content": "```typescript\nexport declare function createQwikRouter(opts: QwikRouterAzureOptions): AzureFunction;\n```\n\n\n| \n\nParameter\n\n\n | \n\nType\n\n\n | \n\nDescription\n\n\n |
\n| \n\nopts\n\n\n | \n\n[QwikRouterAzureOptions](#qwikrouterazureoptions)\n\n\n | \n\n\n |
\n
\n\n**Returns:**\n\n[AzureFunction](#azurefunction)",
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/middleware/azure-swa/index.ts",
"mdFile": "router.createqwikrouter.md"
},
+ {
+ "name": "done",
+ "id": "azurecontext-done",
+ "hierarchy": [
+ {
+ "name": "AzureContext",
+ "id": "azurecontext-done"
+ },
+ {
+ "name": "done",
+ "id": "azurecontext-done"
+ }
+ ],
+ "kind": "MethodSignature",
+ "content": "```typescript\ndone(err?: Error | string | null, result?: any): void;\n```\n\n\n| \n\nParameter\n\n\n | \n\nType\n\n\n | \n\nDescription\n\n\n |
\n| \n\nerr\n\n\n | \n\nError \\| string \\| null\n\n\n | \n\n_(Optional)_\n\n\n |
\n| \n\nresult\n\n\n | \n\nany\n\n\n | \n\n_(Optional)_\n\n\n |
\n
\n\n**Returns:**\n\nvoid",
+ "mdFile": "router.azurecontext.done.md"
+ },
{
"name": "PlatformAzure",
"id": "platformazure",
@@ -40,7 +99,7 @@
}
],
"kind": "Interface",
- "content": "```typescript\nexport interface PlatformAzure extends Partial \n```\n**Extends:** Partial<Context>",
+ "content": "```typescript\nexport interface PlatformAzure extends Partial \n```\n**Extends:** Partial<[AzureContext](#azurecontext)>",
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/middleware/azure-swa/index.ts",
"mdFile": "router.platformazure.md"
},
diff --git a/packages/docs/src/routes/api/qwik-router-middleware-azure-swa/index.mdx b/packages/docs/src/routes/api/qwik-router-middleware-azure-swa/index.mdx
index 7c9c43112d7..51705437760 100644
--- a/packages/docs/src/routes/api/qwik-router-middleware-azure-swa/index.mdx
+++ b/packages/docs/src/routes/api/qwik-router-middleware-azure-swa/index.mdx
@@ -4,6 +4,322 @@ title: \@qwik.dev/qwik-router/middleware/azure-swa API Reference
# [API](/api) › @qwik.dev/qwik-router/middleware/azure-swa
+AzureContext
+
+```typescript
+export interface AzureContext
+```
+
+|
+
+Property
+
+ |
+
+Modifiers
+
+ |
+
+Type
+
+ |
+
+Description
+
+ |
+|
+
+bindingData
+
+ |
+
+ |
+
+\{ [key: string]: any; }
+
+ |
+
+ |
+|
+
+bindingDefinitions
+
+ |
+
+ |
+
+\{ name: string; type: string; direction: 'in' \| 'out' \| 'inout'; }[]
+
+ |
+
+ |
+|
+
+bindings
+
+ |
+
+ |
+
+\{ [key: string]: any; }
+
+ |
+
+ |
+|
+
+executionContext
+
+ |
+
+ |
+
+\{ invocationId: string; functionName: string; functionDirectory: string; }
+
+ |
+
+ |
+|
+
+invocationId
+
+ |
+
+ |
+
+string
+
+ |
+
+ |
+|
+
+log
+
+ |
+
+ |
+
+((...args: any[]) => void) & \{ error(...args: any[]): void; warn(...args: any[]): void; info(...args: any[]): void; verbose(...args: any[]): void; }
+
+ |
+
+ |
+|
+
+req?
+
+ |
+
+ |
+
+[AzureHttpRequest](#azurehttprequest)
+
+ |
+
+_(Optional)_
+
+ |
+|
+
+res?
+
+ |
+
+ |
+
+\{ [key: string]: any; }
+
+ |
+
+_(Optional)_
+
+ |
+|
+
+traceContext
+
+ |
+
+ |
+
+\{ traceparent?: string \| null; tracestate?: string \| null; attributes?: \{ [key: string]: string; } \| null; }
+
+ |
+
+ |
+
+
+|
+
+Method
+
+ |
+
+Description
+
+ |
+|
+
+[done(err, result)](#azurecontext-done)
+
+ |
+
+ |
+
+
+[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/middleware/azure-swa/index.ts)
+
+AzureFunction
+
+```typescript
+export type AzureFunction = (
+ context: AzureContext,
+ ...args: any[]
+) => Promise | void;
+```
+
+**References:** [AzureContext](#azurecontext)
+
+[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/middleware/azure-swa/index.ts)
+
+AzureHttpRequest
+
+```typescript
+export interface AzureHttpRequest
+```
+
+|
+
+Property
+
+ |
+
+Modifiers
+
+ |
+
+Type
+
+ |
+
+Description
+
+ |
+|
+
+body?
+
+ |
+
+ |
+
+any
+
+ |
+
+_(Optional)_
+
+ |
+|
+
+bufferBody?
+
+ |
+
+ |
+
+Uint8Array
+
+ |
+
+_(Optional)_
+
+ |
+|
+
+headers
+
+ |
+
+ |
+
+\{ [name: string]: string; }
+
+ |
+
+ |
+|
+
+method
+
+ |
+
+ |
+
+string \| null
+
+ |
+
+ |
+|
+
+params
+
+ |
+
+ |
+
+\{ [name: string]: string; }
+
+ |
+
+ |
+|
+
+query
+
+ |
+
+ |
+
+\{ [name: string]: string; }
+
+ |
+
+ |
+|
+
+rawBody?
+
+ |
+
+ |
+
+any
+
+ |
+
+_(Optional)_
+
+ |
+|
+
+url
+
+ |
+
+ |
+
+string
+
+ |
+
+ |
+
+
+[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/middleware/azure-swa/index.ts)
+
createQwikCity
> Warning: This API is now obsolete.
@@ -52,17 +368,68 @@ opts
**Returns:**
-AzureFunction
+[AzureFunction](#azurefunction)
[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/middleware/azure-swa/index.ts)
+done
+
+```typescript
+done(err?: Error | string | null, result?: any): void;
+```
+
+|
+
+Parameter
+
+ |
+
+Type
+
+ |
+
+Description
+
+ |
+|
+
+err
+
+ |
+
+Error \| string \| null
+
+ |
+
+_(Optional)_
+
+ |
+|
+
+result
+
+ |
+
+any
+
+ |
+
+_(Optional)_
+
+ |
+
+
+**Returns:**
+
+void
+
```typescript
-export interface PlatformAzure extends Partial
+export interface PlatformAzure extends Partial
```
-**Extends:** Partial<Context>
+**Extends:** Partial<[AzureContext](#azurecontext)>
[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/middleware/azure-swa/index.ts)
diff --git a/packages/qwik-router/package.json b/packages/qwik-router/package.json
index fe3313bb9ef..e3d00707760 100644
--- a/packages/qwik-router/package.json
+++ b/packages/qwik-router/package.json
@@ -4,23 +4,14 @@
"version": "2.0.0-beta.42",
"bugs": "https://github.com/QwikDev/qwik/issues",
"dependencies": {
- "@azure/functions": "3.5.1",
"@mdx-js/mdx": "^3.1.1",
"@netlify/edge-functions": "^3.0.6",
- "@types/mdx": "^2.0.13",
- "estree-util-value-to-estree": "^3.5.0",
- "github-slugger": "^2.0.0",
- "hast-util-heading-rank": "^2.1.1",
- "hast-util-to-string": "^2.0.0",
- "kleur": "^4.1.5",
- "marked": "^12.0.2",
- "mdast-util-mdx": "^3.0.0",
"mlly": "^1.8.2",
"refractor": "^4.8.1",
"rehype-autolink-headings": "^7.1.0",
"remark-frontmatter": "^5.0.0",
"remark-gfm": "^4.0.1",
- "set-cookie-parser": "^2.7.2",
+ "remark-parse": "^11.0.0",
"source-map": "^0.7.6",
"svgo": "^3.3.4",
"unified": "^11.0.5",
@@ -34,13 +25,11 @@
"devDependencies": {
"@microsoft/api-extractor": "7.57.6",
"@qwik.dev/core": "workspace:*",
+ "@types/estree": "1.0.8",
"@types/mdast": "4.0.4",
"@types/node": "24.10.0",
- "@types/refractor": "4.0.0",
- "@types/set-cookie-parser": "2.4.10",
- "tsm": "2.3.0",
+ "mdast-util-mdx": "3.0.0",
"typescript": "5.9.3",
- "uvu": "0.5.6",
"vite": "8.2.1"
},
"engines": {
diff --git a/packages/qwik-router/src/buildtime/build-endpoints.unit.ts b/packages/qwik-router/src/buildtime/build-endpoints.unit.ts
index 1128b4ee038..613922cabc8 100644
--- a/packages/qwik-router/src/buildtime/build-endpoints.unit.ts
+++ b/packages/qwik-router/src/buildtime/build-endpoints.unit.ts
@@ -1,20 +1,20 @@
-import { equal } from 'uvu/assert';
+import { assert } from 'vitest';
import { testAppSuite } from '../utils/test-suite';
const test = testAppSuite('Build Endpoints');
test('endpoint', ({ assertRoute }) => {
const r = assertRoute('/api/data.json');
- equal(r.id, 'CommonApiDataRoute');
- equal(r.pattern, /^\/api\/data\.json\/?$/);
- equal(r.paramNames.length, 0);
+ assert.deepEqual(r.id, 'CommonApiDataRoute');
+ assert.deepEqual(r.pattern, /^\/api\/data\.json\/?$/);
+ assert.deepEqual(r.paramNames.length, 0);
});
test('endpoint w/ params', ({ assertRoute }) => {
const r = assertRoute('/api/[org]/[user].json');
- equal(r.id, 'CommonApiOrgUserRoute');
- equal(r.pattern, /^\/api\/([^/]+?)\/([^/]+?)\.json\/?$/);
- equal(r.paramNames.length, 2);
- equal(r.paramNames[0], 'org');
- equal(r.paramNames[1], 'user');
+ assert.deepEqual(r.id, 'CommonApiOrgUserRoute');
+ assert.deepEqual(r.pattern, /^\/api\/([^/]+?)\/([^/]+?)\.json\/?$/);
+ assert.deepEqual(r.paramNames.length, 2);
+ assert.deepEqual(r.paramNames[0], 'org');
+ assert.deepEqual(r.paramNames[1], 'user');
});
diff --git a/packages/qwik-router/src/buildtime/build-menus.unit.ts b/packages/qwik-router/src/buildtime/build-menus.unit.ts
index 5b27470dc85..baf4064a834 100644
--- a/packages/qwik-router/src/buildtime/build-menus.unit.ts
+++ b/packages/qwik-router/src/buildtime/build-menus.unit.ts
@@ -1,14 +1,14 @@
-import { equal, ok } from 'uvu/assert';
+import { assert } from 'vitest';
import { testAppSuite } from '../utils/test-suite';
const test = testAppSuite('Build Menu');
test('menus found', ({ ctx: { menus } }) => {
- equal(menus.length, 1);
+ assert.deepEqual(menus.length, 1);
});
test('docs menu', ({ ctx: { menus } }) => {
const docsMenu = menus.find((r) => r.pathname === '/docs/')!;
- ok(docsMenu, 'found docs menu');
- equal(docsMenu.pathname, '/docs/');
+ assert.ok(docsMenu, 'found docs menu');
+ assert.deepEqual(docsMenu.pathname, '/docs/');
});
diff --git a/packages/qwik-router/src/buildtime/build-pages-rewrited.unit.ts b/packages/qwik-router/src/buildtime/build-pages-rewrited.unit.ts
index 3af18235189..e6e535125c1 100644
--- a/packages/qwik-router/src/buildtime/build-pages-rewrited.unit.ts
+++ b/packages/qwik-router/src/buildtime/build-pages-rewrited.unit.ts
@@ -1,4 +1,4 @@
-import * as assert from 'uvu/assert';
+import { assert } from 'vitest';
import { testAppSuite } from '../utils/test-suite';
const test = testAppSuite('Build Pages Rewrited', {
@@ -25,13 +25,13 @@ const test = testAppSuite('Build Pages Rewrited', {
test('translated pathname / with prefix', ({ assertRoute }) => {
const r = assertRoute('/it/');
- assert.equal(r.id, 'CommonRouteIT');
- assert.equal(r.pathname, '/it/');
- assert.equal(r.routeName, 'it/');
- assert.equal(r.pattern, /^\/it\/$/);
- assert.equal(r.paramNames.length, 0);
- assert.equal(r.segments[0][0].content, 'it');
- assert.equal(r.layouts.length, 2);
+ assert.deepEqual(r.id, 'CommonRouteIT');
+ assert.deepEqual(r.pathname, '/it/');
+ assert.deepEqual(r.routeName, 'it/');
+ assert.deepEqual(r.pattern, /^\/it\/$/);
+ assert.deepEqual(r.paramNames.length, 0);
+ assert.deepEqual(r.segments[0][0].content, 'it');
+ assert.deepEqual(r.layouts.length, 2);
assert.ok(
r.layouts[0].filePath.endsWith('e2e/qwik-e2e/apps/qwikrouter-test/src/routes/layout.tsx')
);
@@ -45,15 +45,15 @@ test('translated pathname / with prefix', ({ assertRoute }) => {
test('translated pathname /docs/getting-started with prefix', ({ assertRoute }) => {
const r = assertRoute('/it/documentazione/per-iniziare/');
- assert.equal(r.id, 'DocsGettingstartedRouteIT');
- assert.equal(r.pathname, '/it/documentazione/per-iniziare/');
- assert.equal(r.routeName, 'it/documentazione/per-iniziare/');
- assert.equal(r.pattern, /^\/it\/documentazione\/per-iniziare\/?/);
- assert.equal(r.paramNames.length, 0);
- assert.equal(r.segments[0][0].content, 'it');
- assert.equal(r.segments[1][0].content, 'documentazione');
- assert.equal(r.segments[2][0].content, 'per-iniziare');
- assert.equal(r.layouts.length, 2);
+ assert.deepEqual(r.id, 'DocsGettingstartedRouteIT');
+ assert.deepEqual(r.pathname, '/it/documentazione/per-iniziare/');
+ assert.deepEqual(r.routeName, 'it/documentazione/per-iniziare/');
+ assert.deepEqual(r.pattern, /^\/it\/documentazione\/per-iniziare\/?/);
+ assert.deepEqual(r.paramNames.length, 0);
+ assert.deepEqual(r.segments[0][0].content, 'it');
+ assert.deepEqual(r.segments[1][0].content, 'documentazione');
+ assert.deepEqual(r.segments[2][0].content, 'per-iniziare');
+ assert.deepEqual(r.layouts.length, 2);
assert.ok(
r.layouts[0].filePath.endsWith('e2e/qwik-e2e/apps/qwikrouter-test/src/routes/layout.tsx')
);
@@ -69,17 +69,17 @@ test('translated pathname /docs/getting-started with prefix', ({ assertRoute })
test('translated pathname /docs/[category]/[id] with prefix', ({ assertRoute }) => {
const r = assertRoute('/it/documentazione/[category]/[id]/');
- assert.equal(r.id, 'DocsCategoryIdRouteIT');
- assert.equal(r.pathname, '/it/documentazione/[category]/[id]/');
- assert.equal(r.routeName, 'it/documentazione/[category]/[id]/');
- assert.equal(r.pattern, /^\/it\/documentazione\/([^/]+?)\/([^/]+?)\/?/);
- assert.equal(r.paramNames[0], 'category');
- assert.equal(r.paramNames[1], 'id');
- assert.equal(r.segments[0][0].content, 'it');
- assert.equal(r.segments[1][0].content, 'documentazione');
- assert.equal(r.segments[2][0].content, 'category');
- assert.equal(r.segments[3][0].content, 'id');
- assert.equal(r.layouts.length, 2);
+ assert.deepEqual(r.id, 'DocsCategoryIdRouteIT');
+ assert.deepEqual(r.pathname, '/it/documentazione/[category]/[id]/');
+ assert.deepEqual(r.routeName, 'it/documentazione/[category]/[id]/');
+ assert.deepEqual(r.pattern, /^\/it\/documentazione\/([^/]+?)\/([^/]+?)\/?/);
+ assert.deepEqual(r.paramNames[0], 'category');
+ assert.deepEqual(r.paramNames[1], 'id');
+ assert.deepEqual(r.segments[0][0].content, 'it');
+ assert.deepEqual(r.segments[1][0].content, 'documentazione');
+ assert.deepEqual(r.segments[2][0].content, 'category');
+ assert.deepEqual(r.segments[3][0].content, 'id');
+ assert.deepEqual(r.layouts.length, 2);
assert.ok(
r.layouts[0].filePath.endsWith('e2e/qwik-e2e/apps/qwikrouter-test/src/routes/layout.tsx')
);
@@ -95,14 +95,14 @@ test('translated pathname /docs/[category]/[id] with prefix', ({ assertRoute })
test('translated pathname /about-us with prefix', ({ assertRoute }) => {
const r = assertRoute('/it/informazioni/');
- assert.equal(r.id, 'CommonAboutusRouteIT');
- assert.equal(r.pathname, '/it/informazioni/');
- assert.equal(r.routeName, 'it/informazioni/');
- assert.equal(r.pattern, /^\/it\/informazioni\/?/);
- assert.equal(r.paramNames.length, 0);
- assert.equal(r.segments[0][0].content, 'it');
- assert.equal(r.segments[1][0].content, 'informazioni');
- assert.equal(r.layouts.length, 2);
+ assert.deepEqual(r.id, 'CommonAboutusRouteIT');
+ assert.deepEqual(r.pathname, '/it/informazioni/');
+ assert.deepEqual(r.routeName, 'it/informazioni/');
+ assert.deepEqual(r.pattern, /^\/it\/informazioni\/?/);
+ assert.deepEqual(r.paramNames.length, 0);
+ assert.deepEqual(r.segments[0][0].content, 'it');
+ assert.deepEqual(r.segments[1][0].content, 'informazioni');
+ assert.deepEqual(r.layouts.length, 2);
assert.ok(
r.layouts[0].filePath.endsWith('e2e/qwik-e2e/apps/qwikrouter-test/src/routes/layout.tsx')
);
@@ -118,15 +118,15 @@ test('translated pathname /about-us with prefix', ({ assertRoute }) => {
test('translated pathname /products/[id] with prefix', ({ assertRoute }) => {
const r = assertRoute('/it/prodotti/[id]/');
- assert.equal(r.id, 'CommonProductsIdRouteIT');
- assert.equal(r.pathname, '/it/prodotti/[id]/');
- assert.equal(r.routeName, 'it/prodotti/[id]/');
- assert.equal(r.pattern, /^\/it\/prodotti\/([^/]+?)\/?/);
- assert.equal(r.paramNames[0], 'id');
- assert.equal(r.segments[0][0].content, 'it');
- assert.equal(r.segments[1][0].content, 'prodotti');
- assert.equal(r.segments[2][0].content, 'id');
- assert.equal(r.layouts.length, 2);
+ assert.deepEqual(r.id, 'CommonProductsIdRouteIT');
+ assert.deepEqual(r.pathname, '/it/prodotti/[id]/');
+ assert.deepEqual(r.routeName, 'it/prodotti/[id]/');
+ assert.deepEqual(r.pattern, /^\/it\/prodotti\/([^/]+?)\/?/);
+ assert.deepEqual(r.paramNames[0], 'id');
+ assert.deepEqual(r.segments[0][0].content, 'it');
+ assert.deepEqual(r.segments[1][0].content, 'prodotti');
+ assert.deepEqual(r.segments[2][0].content, 'id');
+ assert.deepEqual(r.layouts.length, 2);
assert.ok(
r.layouts[0].filePath.endsWith('e2e/qwik-e2e/apps/qwikrouter-test/src/routes/layout.tsx')
);
@@ -144,14 +144,14 @@ test('translated pathname /products/[id] with prefix', ({ assertRoute }) => {
test('translated pathname /docs/getting-started', ({ assertRoute }) => {
const r = assertRoute('/documentazione/per-iniziare/');
- assert.equal(r.id, 'DocsGettingstartedRoute0');
- assert.equal(r.pathname, '/documentazione/per-iniziare/');
- assert.equal(r.routeName, 'documentazione/per-iniziare/');
- assert.equal(r.pattern, /^\/documentazione\/per-iniziare\/?/);
- assert.equal(r.paramNames.length, 0);
- assert.equal(r.segments[0][0].content, 'documentazione');
- assert.equal(r.segments[1][0].content, 'per-iniziare');
- assert.equal(r.layouts.length, 2);
+ assert.deepEqual(r.id, 'DocsGettingstartedRoute0');
+ assert.deepEqual(r.pathname, '/documentazione/per-iniziare/');
+ assert.deepEqual(r.routeName, 'documentazione/per-iniziare/');
+ assert.deepEqual(r.pattern, /^\/documentazione\/per-iniziare\/?/);
+ assert.deepEqual(r.paramNames.length, 0);
+ assert.deepEqual(r.segments[0][0].content, 'documentazione');
+ assert.deepEqual(r.segments[1][0].content, 'per-iniziare');
+ assert.deepEqual(r.layouts.length, 2);
assert.ok(
r.layouts[0].filePath.endsWith('e2e/qwik-e2e/apps/qwikrouter-test/src/routes/layout.tsx')
);
@@ -167,16 +167,16 @@ test('translated pathname /docs/getting-started', ({ assertRoute }) => {
test('translated pathname /docs/[category]/[id]', ({ assertRoute }) => {
const r = assertRoute('/documentazione/[category]/[id]/');
- assert.equal(r.id, 'DocsCategoryIdRoute0');
- assert.equal(r.pathname, '/documentazione/[category]/[id]/');
- assert.equal(r.routeName, 'documentazione/[category]/[id]/');
- assert.equal(r.pattern, /^\/documentazione\/([^/]+?)\/([^/]+?)\/?/);
- assert.equal(r.paramNames[0], 'category');
- assert.equal(r.paramNames[1], 'id');
- assert.equal(r.segments[0][0].content, 'documentazione');
- assert.equal(r.segments[1][0].content, 'category');
- assert.equal(r.segments[2][0].content, 'id');
- assert.equal(r.layouts.length, 2);
+ assert.deepEqual(r.id, 'DocsCategoryIdRoute0');
+ assert.deepEqual(r.pathname, '/documentazione/[category]/[id]/');
+ assert.deepEqual(r.routeName, 'documentazione/[category]/[id]/');
+ assert.deepEqual(r.pattern, /^\/documentazione\/([^/]+?)\/([^/]+?)\/?/);
+ assert.deepEqual(r.paramNames[0], 'category');
+ assert.deepEqual(r.paramNames[1], 'id');
+ assert.deepEqual(r.segments[0][0].content, 'documentazione');
+ assert.deepEqual(r.segments[1][0].content, 'category');
+ assert.deepEqual(r.segments[2][0].content, 'id');
+ assert.deepEqual(r.layouts.length, 2);
assert.ok(
r.layouts[0].filePath.endsWith('e2e/qwik-e2e/apps/qwikrouter-test/src/routes/layout.tsx')
);
@@ -192,13 +192,13 @@ test('translated pathname /docs/[category]/[id]', ({ assertRoute }) => {
test('translated pathname /about-us', ({ assertRoute }) => {
const r = assertRoute('/informazioni/');
- assert.equal(r.id, 'CommonAboutusRoute0');
- assert.equal(r.pathname, '/informazioni/');
- assert.equal(r.routeName, 'informazioni/');
- assert.equal(r.pattern, /^\/informazioni\/?/);
- assert.equal(r.paramNames.length, 0);
- assert.equal(r.segments[0][0].content, 'informazioni');
- assert.equal(r.layouts.length, 2);
+ assert.deepEqual(r.id, 'CommonAboutusRoute0');
+ assert.deepEqual(r.pathname, '/informazioni/');
+ assert.deepEqual(r.routeName, 'informazioni/');
+ assert.deepEqual(r.pattern, /^\/informazioni\/?/);
+ assert.deepEqual(r.paramNames.length, 0);
+ assert.deepEqual(r.segments[0][0].content, 'informazioni');
+ assert.deepEqual(r.layouts.length, 2);
assert.ok(
r.layouts[0].filePath.endsWith('e2e/qwik-e2e/apps/qwikrouter-test/src/routes/layout.tsx')
);
@@ -214,14 +214,14 @@ test('translated pathname /about-us', ({ assertRoute }) => {
test('translated pathname /products/[id]', ({ assertRoute }) => {
const r = assertRoute('/prodotti/[id]/');
- assert.equal(r.id, 'CommonProductsIdRoute0');
- assert.equal(r.pathname, '/prodotti/[id]/');
- assert.equal(r.routeName, 'prodotti/[id]/');
- assert.equal(r.pattern, /^\/prodotti\/([^/]+?)\/?/);
- assert.equal(r.paramNames[0], 'id');
- assert.equal(r.segments[0][0].content, 'prodotti');
- assert.equal(r.segments[1][0].content, 'id');
- assert.equal(r.layouts.length, 2);
+ assert.deepEqual(r.id, 'CommonProductsIdRoute0');
+ assert.deepEqual(r.pathname, '/prodotti/[id]/');
+ assert.deepEqual(r.routeName, 'prodotti/[id]/');
+ assert.deepEqual(r.pattern, /^\/prodotti\/([^/]+?)\/?/);
+ assert.deepEqual(r.paramNames[0], 'id');
+ assert.deepEqual(r.segments[0][0].content, 'prodotti');
+ assert.deepEqual(r.segments[1][0].content, 'id');
+ assert.deepEqual(r.layouts.length, 2);
assert.ok(
r.layouts[0].filePath.endsWith('e2e/qwik-e2e/apps/qwikrouter-test/src/routes/layout.tsx')
);
@@ -245,32 +245,32 @@ test('trie has _G nodes for translated routes', ({ ctx }) => {
assert.ok(documentazione, 'trie should have "documentazione" child');
const perIniziare = documentazione!.children.get('per-iniziare');
assert.ok(perIniziare, 'trie should have "per-iniziare" under "documentazione"');
- assert.equal(perIniziare!._G, 'docs/getting-started');
+ assert.deepEqual(perIniziare!._G, 'docs/getting-started');
// Without prefix: 'informazioni' should point to about-us
const informazioni = trie.children.get('informazioni');
assert.ok(informazioni, 'trie should have "informazioni" child');
- assert.equal(informazioni!._G, 'about-us');
+ assert.deepEqual(informazioni!._G, 'about-us');
// Without prefix: 'prodotti' should have _W child with _G pointing to products/_W
const prodotti = trie.children.get('prodotti');
assert.ok(prodotti, 'trie should have "prodotti" child');
const prodottiW = prodotti!.children.get('_W');
assert.ok(prodottiW, 'trie should have "_W" under "prodotti"');
- assert.equal(prodottiW!._G, 'products/_W');
- assert.equal(prodottiW!._P, 'id');
+ assert.deepEqual(prodottiW!._G, 'products/_W');
+ assert.deepEqual(prodottiW!._P, 'id');
// With prefix: 'it' should contain translated children
const it = trie.children.get('it');
assert.ok(it, 'trie should have "it" child');
// 'it' root index rewrite
- assert.equal(it!._G, '');
+ assert.deepEqual(it!._G, '');
// 'it/documentazione/per-iniziare'
const itDoc = it!.children.get('documentazione');
assert.ok(itDoc, 'trie should have "documentazione" under "it"');
const itDocGs = itDoc!.children.get('per-iniziare');
assert.ok(itDocGs, 'trie should have "per-iniziare" under "it/documentazione"');
- assert.equal(itDocGs!._G, 'docs/getting-started');
+ assert.deepEqual(itDocGs!._G, 'docs/getting-started');
});
const testWithDuplicatedRoutes = testAppSuite('Duplicated segments with multiple prefixes', {
@@ -301,7 +301,7 @@ testWithDuplicatedRoutes(
({ assertRoute }) => {
const r = assertRoute('/produkt/');
- assert.equal(r.pathname, '/produkt/');
+ assert.deepEqual(r.pathname, '/produkt/');
}
);
@@ -330,7 +330,7 @@ testSameRoutes(
'Issue #6799: Bug while using rewrite routes pointing to the same file',
({ assertRoute }) => {
const r = assertRoute('/produkt/');
- assert.equal(r.pathname, '/produkt/');
+ assert.deepEqual(r.pathname, '/produkt/');
}
);
@@ -342,5 +342,9 @@ testExclude('exclude skips localized mirrors for matched routes', ({ ctx }) => {
const it = ctx.routeTrie.children.get('it');
assert.ok(it, 'prefix mirror "it" should exist for non-excluded routes');
assert.ok(it!.children.get('about-us'), 'non-excluded route is mirrored under "it"');
- assert.is(it!.children.get('docs'), undefined, '"/docs/*" is excluded from the "it" mirror');
+ assert.strictEqual(
+ it!.children.get('docs'),
+ undefined,
+ '"/docs/*" is excluded from the "it" mirror'
+ );
});
diff --git a/packages/qwik-router/src/buildtime/markdown/hast-utils.ts b/packages/qwik-router/src/buildtime/markdown/hast-utils.ts
new file mode 100644
index 00000000000..9ff27139d3e
--- /dev/null
+++ b/packages/qwik-router/src/buildtime/markdown/hast-utils.ts
@@ -0,0 +1,23 @@
+// Minimal inlined replacement for `hast-util-to-string` and `hast-util-heading-rank`.
+
+/** Concatenated text content of a hast node's text descendants. */
+export function hastToString(node: any): string {
+ if (node && Array.isArray(node.children)) {
+ return node.children.map(textContent).join('');
+ }
+ return typeof node?.value === 'string' ? node.value : '';
+}
+
+function textContent(node: any): string {
+ if (node.type === 'text') {
+ return node.value || '';
+ }
+ return Array.isArray(node.children) ? node.children.map(textContent).join('') : '';
+}
+
+/** Heading level (1-6) of a hast element, or undefined for non-headings. */
+export function headingRank(node: any): number | undefined {
+ const tagName = node?.type === 'element' && typeof node.tagName === 'string' ? node.tagName : '';
+ const rank = tagName.length === 2 && tagName[0] === 'h' ? Number(tagName[1]) : NaN;
+ return rank >= 1 && rank <= 6 ? rank : undefined;
+}
diff --git a/packages/qwik-router/src/buildtime/markdown/menu.ts b/packages/qwik-router/src/buildtime/markdown/menu.ts
index 0fb6760444b..0e5ce313af9 100644
--- a/packages/qwik-router/src/buildtime/markdown/menu.ts
+++ b/packages/qwik-router/src/buildtime/markdown/menu.ts
@@ -1,5 +1,7 @@
import type { NormalizedPluginOptions, BuiltMenu, ParsedMenuItem, RouteSourceFile } from '../types';
-import { marked } from 'marked';
+import type { List, PhrasingContent, RootContent } from 'mdast';
+import remarkParse from 'remark-parse';
+import { unified } from 'unified';
import { createFileId, getMenuPathname } from '../../utils/fs';
import { getMarkdownRelativeUrl } from './markdown-url';
@@ -32,12 +34,12 @@ export function parseMenu(
content: string,
checkFileExists = true
) {
- const tokens = marked.lexer(content, {});
+ const tree = unified().use(remarkParse).parse(content);
let currentDepth = 0;
const stack: ParsedMenuItem[] = [];
- for (const t of tokens) {
- if (t.type === 'heading') {
- const diff = currentDepth - t.depth;
+ for (const node of tree.children) {
+ if (node.type === 'heading') {
+ const diff = currentDepth - node.depth;
if (diff >= 0) {
stack.length -= diff + 1;
}
@@ -45,23 +47,26 @@ export function parseMenu(
throw new Error(
`Menu hierarchy skipped a level, went from to , in menu: ${filePath}`
+ )}> to , in menu: ${filePath}`
);
}
- currentDepth = t.depth;
+ currentDepth = node.depth;
const parentNode = stack[stack.length - 1];
- for (const h2Token of t.tokens || []) {
+ for (const inline of node.children) {
const lastNode: ParsedMenuItem = {
text: '',
};
- if (h2Token.type === 'text') {
- lastNode.text = h2Token.text;
- } else if (h2Token.type === 'link') {
- lastNode.text = h2Token.text;
- lastNode.href = getMarkdownRelativeUrl(opts, filePath, h2Token.href, checkFileExists);
+ if (inline.type === 'text') {
+ lastNode.text = inline.value;
+ } else if (inline.type === 'link') {
+ lastNode.text = inlineText(inline.children);
+ lastNode.href = getMarkdownRelativeUrl(opts, filePath, inline.url, checkFileExists);
} else {
throw new Error(
- `Headings can only be a text or link. Received "${h2Token.type}", value "${h2Token.raw}", in menu: ${filePath}`
+ `Headings can only be a text or link. Received "${inline.type}", value "${rawSource(
+ content,
+ inline
+ )}", in menu: ${filePath}`
);
}
if (parentNode) {
@@ -70,50 +75,19 @@ export function parseMenu(
}
stack.push(lastNode);
}
- } else if (t.type === 'list') {
+ } else if (node.type === 'list') {
const parentNode = stack[stack.length - 1];
-
- parentNode.items = parentNode.items || [];
- for (const li of t.items) {
- if (li.type === 'list_item') {
- for (const liToken of li.tokens) {
- if (liToken.type === 'text') {
- for (const liItem of (liToken as any).tokens) {
- if (liItem.type === 'text') {
- parentNode.items.push({ text: liItem.text });
- } else if (liItem.type === 'link') {
- parentNode.items.push({
- text: liItem.text,
- href: getMarkdownRelativeUrl(opts, filePath, liItem.href, checkFileExists),
- });
- } else {
- throw new Error(
- `List items can only be a text or link. Received "${liItem.type}", value "${liItem.raw}", in menu: ${filePath}`
- );
- }
- }
- } else if (liToken.type === 'link') {
- parentNode.items.push({
- text: liToken.text,
- href: getMarkdownRelativeUrl(opts, filePath, liToken.href, checkFileExists),
- });
- } else {
- throw new Error(
- `List items can only be a text or link. Received "${liToken.type}", value "${liToken.raw}", in menu: ${filePath}`
- );
- }
- }
- } else {
- throw new Error(
- `Only list items can be used in lists. Received "${li.type}", value "${li.raw}", in menu: ${filePath}`
- );
- }
+ if (!parentNode) {
+ throw new Error(`Menu must start with an h1 in the index: ${filePath}`);
}
- } else if (t.type === 'space') {
- continue;
+ parentNode.items = parentNode.items || [];
+ parseListItems(opts, filePath, content, node, parentNode, checkFileExists);
} else {
throw new Error(
- `Menu has a "${t.type}" with the value "${t.raw}". However, only headings and lists can be used in the menu: ${filePath}`
+ `Menu has a "${node.type}" with the value "${rawSource(
+ content,
+ node
+ )}". However, only headings and lists can be used in the menu: ${filePath}`
);
}
}
@@ -123,3 +97,52 @@ export function parseMenu(
}
return stack[0];
}
+
+function parseListItems(
+ opts: NormalizedPluginOptions,
+ filePath: string,
+ content: string,
+ list: List,
+ parentNode: ParsedMenuItem,
+ checkFileExists: boolean
+) {
+ for (const listItem of list.children) {
+ for (const block of listItem.children) {
+ if (block.type !== 'paragraph') {
+ throw new Error(
+ `List items can only be a text or link. Received "${block.type}", value "${rawSource(
+ content,
+ block
+ )}", in menu: ${filePath}`
+ );
+ }
+ for (const inline of block.children) {
+ if (inline.type === 'text') {
+ parentNode.items!.push({ text: inline.value });
+ } else if (inline.type === 'link') {
+ parentNode.items!.push({
+ text: inlineText(inline.children),
+ href: getMarkdownRelativeUrl(opts, filePath, inline.url, checkFileExists),
+ });
+ } else {
+ throw new Error(
+ `List items can only be a text or link. Received "${inline.type}", value "${rawSource(
+ content,
+ inline
+ )}", in menu: ${filePath}`
+ );
+ }
+ }
+ }
+ }
+}
+
+function inlineText(children: PhrasingContent[]): string {
+ return children.map((child) => ('value' in child ? child.value : '')).join('');
+}
+
+function rawSource(content: string, node: RootContent | PhrasingContent) {
+ const start = node.position?.start.offset;
+ const end = node.position?.end.offset;
+ return start != null && end != null ? content.slice(start, end) : node.type;
+}
diff --git a/packages/qwik-router/src/buildtime/markdown/rehype.ts b/packages/qwik-router/src/buildtime/markdown/rehype.ts
index a7577e50dd1..4707340dd3d 100644
--- a/packages/qwik-router/src/buildtime/markdown/rehype.ts
+++ b/packages/qwik-router/src/buildtime/markdown/rehype.ts
@@ -1,10 +1,9 @@
import type { Transformer } from 'unified';
-import Slugger from 'github-slugger';
import type { Root } from 'mdast';
import type { MdxjsEsm } from 'mdast-util-mdx';
-import { valueToEstree } from 'estree-util-value-to-estree';
-import { headingRank } from 'hast-util-heading-rank';
-import { toString } from 'hast-util-to-string';
+import { valueToEstree } from './value-to-estree';
+import { hastToString, headingRank } from './hast-utils';
+import { Slugger } from './slugger';
import { visit } from 'unist-util-visit';
import type { ContentHeading } from '../../runtime/src';
import type { RoutingContext, NormalizedPluginOptions } from '../types';
@@ -21,7 +20,7 @@ export function rehypeSlug(): Transformer {
visit(mdast, 'element', (node: any) => {
const level = headingRank(node);
if (level && node.properties) {
- const text = toString(node);
+ const text = hastToString(node);
if (!hasProperty(node, 'id')) {
node.properties.id = slugs.slug(text);
@@ -116,7 +115,7 @@ function exportContentHeadings(mdast: Root) {
const level = headingRank(node);
if (level && node.properties) {
if (hasProperty(node, 'id')) {
- const text = toString(node);
+ const text = hastToString(node);
headings.push({
text,
id: node.properties.id,
diff --git a/packages/qwik-router/src/buildtime/markdown/slugger.ts b/packages/qwik-router/src/buildtime/markdown/slugger.ts
new file mode 100644
index 00000000000..3a2e7b42a37
--- /dev/null
+++ b/packages/qwik-router/src/buildtime/markdown/slugger.ts
@@ -0,0 +1,21 @@
+// Minimal inlined replacement for `github-slugger`.
+// Characters GitHub strips from heading anchors: everything except letters,
+// marks, numbers, connector punctuation, emoji (incl. ZWJ), spaces, and hyphens.
+const INVALID_SLUG_CHARS = /[^\p{L}\p{M}\p{N}\p{Pc}\p{Extended_Pictographic}\- ]/gu;
+
+/** GitHub-style heading slugger with per-instance duplicate tracking. */
+export class Slugger {
+ private occurrences = new Map();
+
+ slug(value: string): string {
+ const base = value.trim().toLowerCase().replace(INVALID_SLUG_CHARS, '').replace(/ /g, '-');
+ let result = base;
+ while (this.occurrences.has(result)) {
+ const count = this.occurrences.get(base)! + 1;
+ this.occurrences.set(base, count);
+ result = `${base}-${count}`;
+ }
+ this.occurrences.set(result, 0);
+ return result;
+ }
+}
diff --git a/packages/qwik-router/src/buildtime/markdown/slugger.unit.ts b/packages/qwik-router/src/buildtime/markdown/slugger.unit.ts
new file mode 100644
index 00000000000..3d438b0cb2a
--- /dev/null
+++ b/packages/qwik-router/src/buildtime/markdown/slugger.unit.ts
@@ -0,0 +1,48 @@
+import { assert, test } from 'vitest';
+import { Slugger } from './slugger';
+
+test('basic text is lowercased and spaces become dashes', () => {
+ const slugger = new Slugger();
+ assert.equal(slugger.slug('Getting Started'), 'getting-started');
+});
+
+test('punctuation is stripped', () => {
+ const slugger = new Slugger();
+ assert.equal(slugger.slug(`What's new? (v2.0)`), 'whats-new-v20');
+});
+
+test('underscores and hyphens are kept', () => {
+ const slugger = new Slugger();
+ assert.equal(slugger.slug('use_task - api'), 'use_task---api');
+});
+
+test('leading and trailing whitespace is trimmed', () => {
+ const slugger = new Slugger();
+ assert.equal(slugger.slug(' Hello World '), 'hello-world');
+});
+
+test('unicode letters are preserved', () => {
+ const slugger = new Slugger();
+ assert.equal(slugger.slug('Héllo Wörld'), 'héllo-wörld');
+});
+
+test('duplicate slugs get numeric suffixes', () => {
+ const slugger = new Slugger();
+ assert.equal(slugger.slug('Intro'), 'intro');
+ assert.equal(slugger.slug('Intro'), 'intro-1');
+ assert.equal(slugger.slug('Intro'), 'intro-2');
+});
+
+test('suffixed duplicates do not collide with explicit headings', () => {
+ const slugger = new Slugger();
+ assert.equal(slugger.slug('foo'), 'foo');
+ assert.equal(slugger.slug('foo 1'), 'foo-1');
+ assert.equal(slugger.slug('foo'), 'foo-2');
+});
+
+test('each instance tracks its own occurrences', () => {
+ const a = new Slugger();
+ const b = new Slugger();
+ assert.equal(a.slug('same'), 'same');
+ assert.equal(b.slug('same'), 'same');
+});
diff --git a/packages/qwik-router/src/buildtime/markdown/syntax-highlight.ts b/packages/qwik-router/src/buildtime/markdown/syntax-highlight.ts
index ac9b65331e7..51380cc3152 100644
--- a/packages/qwik-router/src/buildtime/markdown/syntax-highlight.ts
+++ b/packages/qwik-router/src/buildtime/markdown/syntax-highlight.ts
@@ -1,5 +1,5 @@
import type { Transformer } from 'unified';
-import { toString } from 'hast-util-to-string';
+import { hastToString } from './hast-utils';
import { visit } from 'unist-util-visit';
import { refractor } from 'refractor';
import tsxLang from 'refractor/lang/tsx.js';
@@ -32,7 +32,7 @@ export function rehypeSyntaxHighlight(): Transformer {
}
function syntaxHighlight(node: any, lang: string) {
- const code = toString(node);
+ const code = hastToString(node);
const result = refractor.highlight(code, lang);
if (result && Array.isArray(node.children)) {
node.children = result.children;
diff --git a/packages/qwik-router/src/buildtime/markdown/value-to-estree.ts b/packages/qwik-router/src/buildtime/markdown/value-to-estree.ts
new file mode 100644
index 00000000000..07e3030db7a
--- /dev/null
+++ b/packages/qwik-router/src/buildtime/markdown/value-to-estree.ts
@@ -0,0 +1,55 @@
+// Minimal inlined replacement for `estree-util-value-to-estree` (JSON values plus Date).
+
+import type { Expression } from 'estree';
+
+/** Convert a JSON-serializable value (plus Date) to an ESTree expression. */
+export function valueToEstree(value: unknown): Expression {
+ if (value === undefined) {
+ return { type: 'Identifier', name: 'undefined' };
+ }
+ if (value === null || typeof value === 'string' || typeof value === 'boolean') {
+ return { type: 'Literal', value };
+ }
+ if (typeof value === 'number') {
+ if (Number.isNaN(value)) {
+ return { type: 'Identifier', name: 'NaN' };
+ }
+ if (value < 0 || Object.is(value, -0)) {
+ return {
+ type: 'UnaryExpression',
+ operator: '-',
+ prefix: true,
+ argument: valueToEstree(-value),
+ };
+ }
+ if (!Number.isFinite(value)) {
+ return { type: 'Identifier', name: 'Infinity' };
+ }
+ return { type: 'Literal', value };
+ }
+ if (Array.isArray(value)) {
+ return { type: 'ArrayExpression', elements: value.map(valueToEstree) };
+ }
+ if (value instanceof Date) {
+ return {
+ type: 'NewExpression',
+ callee: { type: 'Identifier', name: 'Date' },
+ arguments: [{ type: 'Literal', value: value.getTime() }],
+ };
+ }
+ if (typeof value === 'object') {
+ return {
+ type: 'ObjectExpression',
+ properties: Object.entries(value).map(([key, propValue]) => ({
+ type: 'Property',
+ method: false,
+ shorthand: false,
+ computed: false,
+ kind: 'init',
+ key: { type: 'Literal', value: key },
+ value: valueToEstree(propValue),
+ })),
+ };
+ }
+ throw new TypeError(`Unsupported value in markdown export: ${typeof value}`);
+}
diff --git a/packages/qwik-router/src/buildtime/markdown/value-to-estree.unit.ts b/packages/qwik-router/src/buildtime/markdown/value-to-estree.unit.ts
new file mode 100644
index 00000000000..be30addc3f9
--- /dev/null
+++ b/packages/qwik-router/src/buildtime/markdown/value-to-estree.unit.ts
@@ -0,0 +1,53 @@
+import { assert, test } from 'vitest';
+import { valueToEstree } from './value-to-estree';
+
+test('primitives', () => {
+ assert.deepEqual(valueToEstree(null), { type: 'Literal', value: null });
+ assert.deepEqual(valueToEstree(true), { type: 'Literal', value: true });
+ assert.deepEqual(valueToEstree('hi'), { type: 'Literal', value: 'hi' });
+ assert.deepEqual(valueToEstree(42), { type: 'Literal', value: 42 });
+});
+
+test('undefined becomes an identifier', () => {
+ assert.deepEqual(valueToEstree(undefined), { type: 'Identifier', name: 'undefined' });
+});
+
+test('negative and non-finite numbers', () => {
+ assert.deepEqual(valueToEstree(-3), {
+ type: 'UnaryExpression',
+ operator: '-',
+ prefix: true,
+ argument: { type: 'Literal', value: 3 },
+ });
+ assert.deepEqual(valueToEstree(Infinity), { type: 'Identifier', name: 'Infinity' });
+ assert.deepEqual(valueToEstree(NaN), { type: 'Identifier', name: 'NaN' });
+});
+
+test('arrays and nested objects', () => {
+ assert.deepEqual(valueToEstree([1, 'a']), {
+ type: 'ArrayExpression',
+ elements: [
+ { type: 'Literal', value: 1 },
+ { type: 'Literal', value: 'a' },
+ ],
+ });
+ const estree = valueToEstree({ title: 'Docs', meta: { level: 2 } }) as any;
+ assert.equal(estree.type, 'ObjectExpression');
+ assert.equal(estree.properties[0].key.value, 'title');
+ assert.equal(estree.properties[0].value.value, 'Docs');
+ assert.equal(estree.properties[1].value.properties[0].value.value, 2);
+});
+
+test('dates become new Date() expressions', () => {
+ const date = new Date('2026-01-01T00:00:00Z');
+ assert.deepEqual(valueToEstree(date), {
+ type: 'NewExpression',
+ callee: { type: 'Identifier', name: 'Date' },
+ arguments: [{ type: 'Literal', value: date.getTime() }],
+ });
+});
+
+test('unsupported values throw', () => {
+ assert.throws(() => valueToEstree(() => 0));
+ assert.throws(() => valueToEstree(Symbol('nope')));
+});
diff --git a/packages/qwik-router/src/middleware/azure-swa/index.ts b/packages/qwik-router/src/middleware/azure-swa/index.ts
index d1a92a19325..53d27587e88 100644
--- a/packages/qwik-router/src/middleware/azure-swa/index.ts
+++ b/packages/qwik-router/src/middleware/azure-swa/index.ts
@@ -1,4 +1,3 @@
-import type { AzureFunction, Context, HttpRequest } from '@azure/functions';
import { setServerPlatform } from '@qwik.dev/core/server';
import type {
ServerRenderOptions,
@@ -9,10 +8,55 @@ import {
isStaticPath,
requestHandler,
} from '@qwik.dev/router/middleware/request-handler';
-import { parseString } from 'set-cookie-parser';
+import { parseSetCookieString } from './parse-set-cookie';
// @qwik.dev/router/middleware/azure-swa
+// Minimal structural types for the Azure Functions v3 programming model,
+// matching what `@azure/functions@3` declares for the fields this middleware touches.
+
+/** @public */
+export interface AzureHttpRequest {
+ method: string | null;
+ url: string;
+ headers: { [name: string]: string };
+ query: { [name: string]: string };
+ params: { [name: string]: string };
+ body?: any;
+ rawBody?: any;
+ bufferBody?: Uint8Array;
+}
+
+/** @public */
+export interface AzureContext {
+ invocationId: string;
+ executionContext: {
+ invocationId: string;
+ functionName: string;
+ functionDirectory: string;
+ };
+ bindings: { [key: string]: any };
+ bindingData: { [key: string]: any };
+ bindingDefinitions: { name: string; type: string; direction: 'in' | 'out' | 'inout' }[];
+ traceContext: {
+ traceparent?: string | null;
+ tracestate?: string | null;
+ attributes?: { [key: string]: string } | null;
+ };
+ log: ((...args: any[]) => void) & {
+ error(...args: any[]): void;
+ warn(...args: any[]): void;
+ info(...args: any[]): void;
+ verbose(...args: any[]): void;
+ };
+ done(err?: Error | string | null, result?: any): void;
+ req?: AzureHttpRequest;
+ res?: { [key: string]: any };
+}
+
+/** @public */
+export type AzureFunction = (context: AzureContext, ...args: any[]) => Promise | void;
+
interface AzureResponse {
status: number;
headers: { [key: string]: any };
@@ -53,7 +97,10 @@ export function createQwikRouter(opts: QwikRouterAzureOptions): AzureFunction {
if (opts.manifest) {
setServerPlatform(opts.manifest);
}
- async function onAzureSwaRequest(context: Context, req: HttpRequest): Promise {
+ async function onAzureSwaRequest(
+ context: AzureContext,
+ req: AzureHttpRequest
+ ): Promise {
try {
const url = new URL(req.headers['x-ms-original-url']!);
const options: RequestInit = {
@@ -79,7 +126,7 @@ export function createQwikRouter(opts: QwikRouterAzureOptions): AzureFunction {
const response: AzureResponse = {
status,
headers: {},
- cookies: cookies.headers().map((header) => parseString(header)),
+ cookies: cookies.headers().map((header) => parseSetCookieString(header)),
};
headers.forEach((value, key) => (response.headers[key] = value));
return new WritableStream({
@@ -160,4 +207,4 @@ export interface QwikRouterAzureOptions extends ServerRenderOptions {}
export type QwikCityAzureOptions = QwikRouterAzureOptions;
/** @public */
-export interface PlatformAzure extends Partial {}
+export interface PlatformAzure extends Partial {}
diff --git a/packages/qwik-router/src/middleware/azure-swa/middleware.azure-swa.api.md b/packages/qwik-router/src/middleware/azure-swa/middleware.azure-swa.api.md
index cf1728f8a3b..7cecb70e33e 100644
--- a/packages/qwik-router/src/middleware/azure-swa/middleware.azure-swa.api.md
+++ b/packages/qwik-router/src/middleware/azure-swa/middleware.azure-swa.api.md
@@ -4,10 +4,86 @@
```ts
-import type { AzureFunction } from '@azure/functions';
-import type { Context } from '@azure/functions';
import type { ServerRenderOptions } from '@qwik.dev/router/middleware/request-handler';
+// @public (undocumented)
+export interface AzureContext {
+ // (undocumented)
+ bindingData: {
+ [key: string]: any;
+ };
+ // (undocumented)
+ bindingDefinitions: {
+ name: string;
+ type: string;
+ direction: 'in' | 'out' | 'inout';
+ }[];
+ // (undocumented)
+ bindings: {
+ [key: string]: any;
+ };
+ // (undocumented)
+ done(err?: Error | string | null, result?: any): void;
+ // (undocumented)
+ executionContext: {
+ invocationId: string;
+ functionName: string;
+ functionDirectory: string;
+ };
+ // (undocumented)
+ invocationId: string;
+ // (undocumented)
+ log: ((...args: any[]) => void) & {
+ error(...args: any[]): void;
+ warn(...args: any[]): void;
+ info(...args: any[]): void;
+ verbose(...args: any[]): void;
+ };
+ // (undocumented)
+ req?: AzureHttpRequest;
+ // (undocumented)
+ res?: {
+ [key: string]: any;
+ };
+ // (undocumented)
+ traceContext: {
+ traceparent?: string | null;
+ tracestate?: string | null;
+ attributes?: {
+ [key: string]: string;
+ } | null;
+ };
+}
+
+// @public (undocumented)
+export type AzureFunction = (context: AzureContext, ...args: any[]) => Promise | void;
+
+// @public (undocumented)
+export interface AzureHttpRequest {
+ // (undocumented)
+ body?: any;
+ // (undocumented)
+ bufferBody?: Uint8Array;
+ // (undocumented)
+ headers: {
+ [name: string]: string;
+ };
+ // (undocumented)
+ method: string | null;
+ // (undocumented)
+ params: {
+ [name: string]: string;
+ };
+ // (undocumented)
+ query: {
+ [name: string]: string;
+ };
+ // (undocumented)
+ rawBody?: any;
+ // (undocumented)
+ url: string;
+}
+
// @public @deprecated (undocumented)
export const createQwikCity: typeof createQwikRouter;
@@ -15,7 +91,7 @@ export const createQwikCity: typeof createQwikRouter;
export function createQwikRouter(opts: QwikRouterAzureOptions): AzureFunction;
// @public (undocumented)
-export interface PlatformAzure extends Partial {
+export interface PlatformAzure extends Partial {
}
// @public @deprecated (undocumented)
diff --git a/packages/qwik-router/src/middleware/azure-swa/parse-set-cookie.ts b/packages/qwik-router/src/middleware/azure-swa/parse-set-cookie.ts
new file mode 100644
index 00000000000..b7a5d57c34a
--- /dev/null
+++ b/packages/qwik-router/src/middleware/azure-swa/parse-set-cookie.ts
@@ -0,0 +1,54 @@
+// Minimal inlined replacement for `set-cookie-parser`'s parseString.
+
+export interface ParsedSetCookie {
+ name: string;
+ value: string;
+ domain?: string;
+ path?: string;
+ expires?: Date;
+ maxAge?: number;
+ secure?: boolean;
+ httpOnly?: boolean;
+ sameSite?: string;
+}
+
+/** Parse a single Set-Cookie header string into the Azure cookie shape. */
+export function parseSetCookieString(setCookieHeader: string): ParsedSetCookie {
+ const [nameValuePair, ...attributeParts] = setCookieHeader.split(';');
+ const equalsIndex = nameValuePair.indexOf('=');
+ const cookie: ParsedSetCookie = {
+ name: nameValuePair.slice(0, equalsIndex).trim(),
+ value: tryDecode(nameValuePair.slice(equalsIndex + 1).trim()),
+ };
+ for (const part of attributeParts) {
+ const attrEqualsIndex = part.indexOf('=');
+ const key = (attrEqualsIndex === -1 ? part : part.slice(0, attrEqualsIndex))
+ .trim()
+ .toLowerCase();
+ const value = attrEqualsIndex === -1 ? '' : part.slice(attrEqualsIndex + 1).trim();
+ if (key === 'domain') {
+ cookie.domain = value;
+ } else if (key === 'path') {
+ cookie.path = value;
+ } else if (key === 'expires') {
+ cookie.expires = new Date(value);
+ } else if (key === 'max-age') {
+ cookie.maxAge = parseInt(value, 10);
+ } else if (key === 'secure') {
+ cookie.secure = true;
+ } else if (key === 'httponly') {
+ cookie.httpOnly = true;
+ } else if (key === 'samesite') {
+ cookie.sameSite = value;
+ }
+ }
+ return cookie;
+}
+
+function tryDecode(value: string): string {
+ try {
+ return decodeURIComponent(value);
+ } catch {
+ return value;
+ }
+}
diff --git a/packages/qwik-router/src/middleware/azure-swa/parse-set-cookie.unit.ts b/packages/qwik-router/src/middleware/azure-swa/parse-set-cookie.unit.ts
new file mode 100644
index 00000000000..4620547fe45
--- /dev/null
+++ b/packages/qwik-router/src/middleware/azure-swa/parse-set-cookie.unit.ts
@@ -0,0 +1,45 @@
+import { assert, test } from 'vitest';
+import { parseSetCookieString } from './parse-set-cookie';
+
+test('parses name and value', () => {
+ assert.deepEqual(parseSetCookieString('foo=bar'), { name: 'foo', value: 'bar' });
+});
+
+test('decodes percent-encoded values', () => {
+ assert.deepEqual(parseSetCookieString('foo=hello%20world'), {
+ name: 'foo',
+ value: 'hello world',
+ });
+});
+
+test('keeps values that are not valid percent-encoding', () => {
+ assert.deepEqual(parseSetCookieString('foo=100%'), { name: 'foo', value: '100%' });
+});
+
+test('keeps = inside the value', () => {
+ assert.deepEqual(parseSetCookieString('foo=a=b'), { name: 'foo', value: 'a=b' });
+});
+
+test('parses all supported attributes', () => {
+ const cookie = parseSetCookieString(
+ 'session=abc123; Domain=example.com; Path=/app; Expires=Wed, 21 Oct 2026 07:28:00 GMT; Max-Age=3600; Secure; HttpOnly; SameSite=Lax'
+ );
+ assert.deepEqual(cookie, {
+ name: 'session',
+ value: 'abc123',
+ domain: 'example.com',
+ path: '/app',
+ expires: new Date('Wed, 21 Oct 2026 07:28:00 GMT'),
+ maxAge: 3600,
+ secure: true,
+ httpOnly: true,
+ sameSite: 'Lax',
+ });
+});
+
+test('ignores unknown attributes', () => {
+ assert.deepEqual(parseSetCookieString('foo=bar; Partitioned; Priority=High'), {
+ name: 'foo',
+ value: 'bar',
+ });
+});
diff --git a/packages/qwik-router/src/ssg/ansi-colors.ts b/packages/qwik-router/src/ssg/ansi-colors.ts
new file mode 100644
index 00000000000..add393a31b1
--- /dev/null
+++ b/packages/qwik-router/src/ssg/ansi-colors.ts
@@ -0,0 +1,24 @@
+// Minimal inlined replacement for `kleur/colors` — same color-support detection.
+const isColorEnabled = () => {
+ const env = typeof process !== 'undefined' ? process.env : undefined;
+ if (!env || env.NODE_DISABLE_COLORS != null || env.NO_COLOR != null || env.TERM === 'dumb') {
+ return false;
+ }
+ if (env.FORCE_COLOR != null) {
+ return env.FORCE_COLOR !== '0';
+ }
+ return !!process.stdout?.isTTY;
+};
+
+const enabled = /*#__PURE__*/ isColorEnabled();
+
+const style =
+ (open: number, close: number) =>
+ (text: string | number): string =>
+ enabled ? `\x1b[${open}m${text}\x1b[${close}m` : String(text);
+
+export const bold = /*#__PURE__*/ style(1, 22);
+export const dim = /*#__PURE__*/ style(2, 22);
+export const red = /*#__PURE__*/ style(31, 39);
+export const green = /*#__PURE__*/ style(32, 39);
+export const magenta = /*#__PURE__*/ style(35, 39);
diff --git a/packages/qwik-router/src/ssg/orchestrator.ts b/packages/qwik-router/src/ssg/orchestrator.ts
index 439a984ad71..941992d808d 100644
--- a/packages/qwik-router/src/ssg/orchestrator.ts
+++ b/packages/qwik-router/src/ssg/orchestrator.ts
@@ -1,5 +1,5 @@
import type { PageModule, PathParams, RouteData } from '@qwik.dev/router';
-import { bold, dim, green, magenta, red } from 'kleur/colors';
+import { bold, dim, green, magenta, red } from './ansi-colors';
import { relative } from 'node:path';
import { msToString } from '../utils/format';
import { ensureSlash, getPathnameForDynamicRoute } from '../utils/pathname';
diff --git a/packages/qwik-vite/package.json b/packages/qwik-vite/package.json
index 8b3bc454b62..cb47ad3044e 100644
--- a/packages/qwik-vite/package.json
+++ b/packages/qwik-vite/package.json
@@ -2,7 +2,7 @@
"name": "@qwik.dev/qwik-vite",
"devDependencies": {
"image-size": "2.0.2",
- "magic-string": "0.30.21",
+ "magic-string": "1.2.3",
"rolldown": "1.2.4",
"vite": "8.2.1"
},
diff --git a/packages/qwik/package.json b/packages/qwik/package.json
index b3b15cd678f..fc39a8182d6 100644
--- a/packages/qwik/package.json
+++ b/packages/qwik/package.json
@@ -11,7 +11,7 @@
"@qwik.dev/optimizer": "workspace:*",
"csstype": "^3.2.3",
"launch-editor": "^2.14.1",
- "magic-string": "0.30.21"
+ "magic-string": "1.2.3"
},
"devDependencies": {
"@croct/json5-parser": "0.2.2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 40720840248..52c25d560fb 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -595,8 +595,8 @@ importers:
specifier: 1.9.4
version: 1.9.4
magic-string:
- specifier: 0.30.21
- version: 0.30.21
+ specifier: 1.2.3
+ version: 1.2.3
pagefind:
specifier: 1.4.0
version: 1.4.0
@@ -791,8 +791,8 @@ importers:
specifier: ^2.14.1
version: 2.14.1
magic-string:
- specifier: 0.30.21
- version: 0.30.21
+ specifier: 1.2.3
+ version: 1.2.3
devDependencies:
'@croct/json5-parser':
specifier: 0.2.2
@@ -853,39 +853,12 @@ importers:
packages/qwik-router:
dependencies:
- '@azure/functions':
- specifier: 3.5.1
- version: 3.5.1
'@mdx-js/mdx':
specifier: ^3.1.1
version: 3.1.1(supports-color@10.2.2)
'@netlify/edge-functions':
specifier: ^3.0.6
version: 3.0.6
- '@types/mdx':
- specifier: ^2.0.13
- version: 2.0.13
- estree-util-value-to-estree:
- specifier: ^3.5.0
- version: 3.5.0
- github-slugger:
- specifier: ^2.0.0
- version: 2.0.0
- hast-util-heading-rank:
- specifier: ^2.1.1
- version: 2.1.1
- hast-util-to-string:
- specifier: ^2.0.0
- version: 2.0.0
- kleur:
- specifier: ^4.1.5
- version: 4.1.5
- marked:
- specifier: ^12.0.2
- version: 12.0.2
- mdast-util-mdx:
- specifier: ^3.0.0
- version: 3.0.0(supports-color@10.2.2)
mlly:
specifier: ^1.8.2
version: 1.8.2
@@ -901,9 +874,9 @@ importers:
remark-gfm:
specifier: ^4.0.1
version: 4.0.1(supports-color@10.2.2)
- set-cookie-parser:
- specifier: ^2.7.2
- version: 2.7.2
+ remark-parse:
+ specifier: ^11.0.0
+ version: 11.0.0(supports-color@10.2.2)
source-map:
specifier: ^0.7.6
version: 0.7.6
@@ -938,27 +911,21 @@ importers:
'@qwik.dev/core':
specifier: workspace:*
version: link:../qwik
+ '@types/estree':
+ specifier: 1.0.8
+ version: 1.0.8
'@types/mdast':
specifier: 4.0.4
version: 4.0.4
'@types/node':
specifier: 24.10.0
version: 24.10.0
- '@types/refractor':
- specifier: 4.0.0
- version: 4.0.0
- '@types/set-cookie-parser':
- specifier: 2.4.10
- version: 2.4.10
- tsm:
- specifier: 2.3.0
- version: 2.3.0
+ mdast-util-mdx:
+ specifier: 3.0.0
+ version: 3.0.0(supports-color@10.2.2)
typescript:
specifier: 5.9.3
version: 5.9.3
- uvu:
- specifier: 0.5.6
- version: 0.5.6
vite:
specifier: 8.2.1
version: 8.2.1(@types/node@24.10.0)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.3)
@@ -981,8 +948,8 @@ importers:
specifier: 2.0.2
version: 2.0.2(patch_hash=528a7f0bab7d6d539a7b50aba6b45cb5e94dd506574151b0a5adc3a84721800c)
magic-string:
- specifier: 0.30.21
- version: 0.30.21
+ specifier: 1.2.3
+ version: 1.2.3
rolldown:
specifier: 1.2.4
version: 1.2.4
@@ -1087,9 +1054,6 @@ packages:
resolution: {integrity: sha512-DBQXuds7Inna78djvURx6oCfBZ11hyYM56sEfU03Z4iKpYa4QPSN4UGajGGP1oiYOeJXvnRypKnwzRUqDa2uyQ==}
engines: {node: '>=18.17'}
- '@azure/functions@3.5.1':
- resolution: {integrity: sha512-6UltvJiuVpvHSwLcK/Zc6NfUwlkDLOFFx97BHCJzlWNsfiWwzwmTsxJXg4kE/LemKTHxPpfoPE+kOJ8hAdiKFQ==}
-
'@babel/code-frame@7.29.0':
resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==}
engines: {node: '>=6.9.0'}
@@ -4434,10 +4398,6 @@ packages:
'@types/react@19.2.14':
resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==}
- '@types/refractor@4.0.0':
- resolution: {integrity: sha512-qba+Qpzch8TqKwHPw3TIR8VaCK3o7spwnlQd51cbYgrZyBOc9K9kFSdH3zxlAmcD0RN6vWBwFZBe6FwJSfM/LA==}
- deprecated: This is a stub types definition. refractor provides its own type definitions, so you do not need this installed.
-
'@types/retry@0.12.2':
resolution: {integrity: sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==}
@@ -4450,9 +4410,6 @@ packages:
'@types/serve-static@2.2.0':
resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==}
- '@types/set-cookie-parser@2.4.10':
- resolution: {integrity: sha512-GGmQVGpQWUe5qglJozEjZV/5dyxbOOZ0LHe/lqyWssB88Y4svNfst0uqBVscdDeIKl5Jy5+aPSvy7mI9tYRguw==}
-
'@types/tmp@0.2.6':
resolution: {integrity: sha512-chhaNf2oKHlRkDGt+tiKE2Z5aJ6qalm7Z9rlLdBwmOiAAf09YQvvoLXjWK4HWPF1xU/fqvMgfNfpVoBscA/tKA==}
@@ -5945,10 +5902,6 @@ packages:
resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==}
engines: {node: '>=0.3.1'}
- diff@5.2.2:
- resolution: {integrity: sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==}
- engines: {node: '>=0.3.1'}
-
diff@8.0.4:
resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==}
engines: {node: '>=0.3.1'}
@@ -6401,9 +6354,6 @@ packages:
estree-util-to-js@2.0.0:
resolution: {integrity: sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==}
- estree-util-value-to-estree@3.5.0:
- resolution: {integrity: sha512-aMV56R27Gv3QmfmF1MY12GWkGzzeAezAX+UplqHVASfjc9wNzI/X6hC0S9oxq61WT4aQesLGslWP9tKk6ghRZQ==}
-
estree-util-visit@2.0.0:
resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==}
@@ -6844,9 +6794,6 @@ packages:
gitconfiglocal@2.1.0:
resolution: {integrity: sha512-qoerOEliJn3z+Zyn1HW2F6eoYJqKwS6MgC9cztTLUB/xLWX8gD/6T60pKn4+t/d6tP7JlybI7Z3z+I572CR/Vg==}
- github-slugger@2.0.0:
- resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==}
-
github-url-from-git@1.5.0:
resolution: {integrity: sha512-WWOec4aRI7YAykQ9+BHmzjyNlkfJFG8QLXnDTsLz/kZefq7qkzdfo4p6fkYYMIq1aj+gZcQs/1HQhQh3DPPxlQ==}
@@ -6980,9 +6927,6 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
- hast-util-heading-rank@2.1.1:
- resolution: {integrity: sha512-iAuRp+ESgJoRFJbSyaqsfvJDY6zzmFoEnL1gtz1+U8gKtGGj1p0CVlysuUAUjq95qlZESHINLThwJzNGmgGZxA==}
-
hast-util-heading-rank@3.0.0:
resolution: {integrity: sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==}
@@ -7001,9 +6945,6 @@ packages:
hast-util-to-jsx-runtime@2.3.6:
resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==}
- hast-util-to-string@2.0.0:
- resolution: {integrity: sha512-02AQ3vLhuH3FisaMM+i/9sm4OXGSq1UhOOCpTLLQtHdL3tZt7qil69r8M8iDkZYyC0HCFylcYoP+8IO7ddta1A==}
-
hast-util-to-string@3.0.1:
resolution: {integrity: sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==}
@@ -7103,10 +7044,6 @@ packages:
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
engines: {node: '>=0.10.0'}
- iconv-lite@0.6.3:
- resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
- engines: {node: '>=0.10.0'}
-
iconv-lite@0.7.2:
resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==}
engines: {node: '>=0.10.0'}
@@ -8111,9 +8048,6 @@ packages:
resolution: {integrity: sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==}
engines: {node: '>= 12.0.0'}
- long@4.0.0:
- resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==}
-
longest-streak@3.1.0:
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
@@ -8150,6 +8084,9 @@ packages:
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
+ magic-string@1.2.3:
+ resolution: {integrity: sha512-Bpb0W2TbLKOZ7vJnOUnVRGq3WL2p+ISV29M6hYPL1AFCpyKZpdr5ytiXoTSSxRVhg8YW7f65+6gbG8WG6PCa/g==}
+
magicast@0.5.2:
resolution: {integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==}
@@ -8175,11 +8112,6 @@ packages:
markdown-table@3.0.4:
resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
- marked@12.0.2:
- resolution: {integrity: sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q==}
- engines: {node: '>= 18'}
- hasBin: true
-
marked@14.0.0:
resolution: {integrity: sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==}
engines: {node: '>= 18'}
@@ -9755,10 +9687,6 @@ packages:
rxjs@7.8.2:
resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==}
- sade@1.8.1:
- resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
- engines: {node: '>=6'}
-
safe-array-concat@1.1.3:
resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==}
engines: {node: '>=0.4'}
@@ -10870,11 +10798,6 @@ packages:
resolution: {integrity: sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==}
hasBin: true
- uvu@0.5.6:
- resolution: {integrity: sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==}
- engines: {node: '>=8'}
- hasBin: true
-
v8-compile-cache-lib@3.0.1:
resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
@@ -11438,12 +11361,6 @@ snapshots:
- '@simplewebauthn/server'
- nodemailer
- '@azure/functions@3.5.1':
- dependencies:
- iconv-lite: 0.6.3
- long: 4.0.0
- uuid: 11.1.1
-
'@babel/code-frame@7.29.0':
dependencies:
'@babel/helper-validator-identifier': 7.28.5
@@ -14663,10 +14580,6 @@ snapshots:
dependencies:
csstype: 3.2.3
- '@types/refractor@4.0.0':
- dependencies:
- refractor: 4.9.0
-
'@types/retry@0.12.2': {}
'@types/semver@7.7.1': {}
@@ -14680,10 +14593,6 @@ snapshots:
'@types/http-errors': 2.0.5
'@types/node': 24.10.0
- '@types/set-cookie-parser@2.4.10':
- dependencies:
- '@types/node': 24.10.0
-
'@types/tmp@0.2.6': {}
'@types/triple-beam@1.3.5': {}
@@ -16342,8 +16251,6 @@ snapshots:
diff@4.0.4: {}
- diff@5.2.2: {}
-
diff@8.0.4: {}
dir-glob@3.0.1:
@@ -16854,10 +16761,6 @@ snapshots:
astring: 1.9.0
source-map: 0.7.6
- estree-util-value-to-estree@3.5.0:
- dependencies:
- '@types/estree': 1.0.8
-
estree-util-visit@2.0.0:
dependencies:
'@types/estree-jsx': 1.0.5
@@ -17395,8 +17298,6 @@ snapshots:
dependencies:
ini: 1.3.8
- github-slugger@2.0.0: {}
-
github-url-from-git@1.5.0: {}
glob-parent@5.1.2:
@@ -17538,10 +17439,6 @@ snapshots:
dependencies:
function-bind: 1.1.2
- hast-util-heading-rank@2.1.1:
- dependencies:
- '@types/hast': 2.3.10
-
hast-util-heading-rank@3.0.0:
dependencies:
'@types/hast': 3.0.4
@@ -17609,10 +17506,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- hast-util-to-string@2.0.0:
- dependencies:
- '@types/hast': 2.3.10
-
hast-util-to-string@3.0.1:
dependencies:
'@types/hast': 3.0.4
@@ -17729,10 +17622,6 @@ snapshots:
dependencies:
safer-buffer: 2.1.2
- iconv-lite@0.6.3:
- dependencies:
- safer-buffer: 2.1.2
-
iconv-lite@0.7.2:
dependencies:
safer-buffer: 2.1.2
@@ -18725,8 +18614,6 @@ snapshots:
safe-stable-stringify: 2.5.0
triple-beam: 1.4.1
- long@4.0.0: {}
-
longest-streak@3.1.0: {}
loose-envify@1.4.0:
@@ -18763,6 +18650,10 @@ snapshots:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
+ magic-string@1.2.3:
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+
magicast@0.5.2:
dependencies:
'@babel/parser': 7.29.2
@@ -18783,8 +18674,6 @@ snapshots:
markdown-table@3.0.4: {}
- marked@12.0.2: {}
-
marked@14.0.0: {}
marky@1.3.0: {}
@@ -20996,10 +20885,6 @@ snapshots:
dependencies:
tslib: 2.8.1
- sade@1.8.1:
- dependencies:
- mri: 1.2.0
-
safe-array-concat@1.1.3:
dependencies:
call-bind: 1.0.9
@@ -22127,13 +22012,6 @@ snapshots:
uuid@11.1.1: {}
- uvu@0.5.6:
- dependencies:
- dequal: 2.0.3
- diff: 5.2.2
- kleur: 4.1.5
- sade: 1.8.1
-
v8-compile-cache-lib@3.0.1: {}
valibot@1.4.2(typescript@5.9.3):