diff --git a/packages/frontend/routes/README.md b/packages/frontend/routes/README.md new file mode 100644 index 0000000000..96e1b8bfa6 --- /dev/null +++ b/packages/frontend/routes/README.md @@ -0,0 +1,36 @@ +# Routes + +## Usage + +### Path Factories + +```ts +import { FACTORIES } from '@affine/routes'; + +const path = FACTORIES.workspace.doc({ workspaceId: '123', docId: '456' }); +// ^^^^ with typecheck +``` + +### Register router + +```tsx +import { ROUTES } from '@affine/routes'; + +function Routes() { + return ; +} +``` + +### Path Parameter + +```ts +import { RouteParamsTypes } from '@affine/routes'; + +function Doc() { + const { workspaceId, docId } = useParams(); +} + +function Attachment() { + const { workspaceId, docId, attachmentId } = useParams(); +} +``` diff --git a/packages/frontend/routes/build.ts b/packages/frontend/routes/build.ts new file mode 100644 index 0000000000..13ddc911c3 --- /dev/null +++ b/packages/frontend/routes/build.ts @@ -0,0 +1,260 @@ +import fs from 'node:fs'; +import { join } from 'node:path/posix'; + +import { Path, prettier } from '@affine-tools/utils'; +import { parse } from 'path-to-regexp'; + +const curdir = Path.dir(import.meta.url); + +const inputFile = curdir.join('routes.json').value; +const routerOutputFile = curdir.join('src', 'routes.ts').value; + +interface RawRoutesSchema { + route: string; + children: { + [key: string]: string | RawRoutesSchema; + }; +} + +interface RouteSchema { + name: string; + fromParent: string; + fromRoot: string; + children: Array; +} + +function loadRoutesSchema(): RouteSchema { + const rawSchema = JSON.parse( + fs.readFileSync(inputFile, 'utf-8') + ) as RawRoutesSchema; + + const build = ( + name: string, + schema: RawRoutesSchema | string, + fromRoot: string = '' + ): RouteSchema => { + if (typeof schema === 'string') { + return { + name, + fromParent: schema, + fromRoot: join(fromRoot, schema), + children: [], + }; + } + + const absolute = join(fromRoot, schema.route); + return { + name, + fromParent: schema.route, + fromRoot: absolute, + children: Object.entries(schema.children).map(([key, value]) => { + return build(key, value, absolute); + }), + }; + }; + + return build('home', rawSchema); +} + +interface BuiltRouteSchema { + name: string; + type?: string; + factory: string; + fromRoot: string; + fromParent: string; + children: BuiltRouteSchema[]; + parent: BuiltRouteSchema | null; +} + +function buildRoutes( + schema: RouteSchema, + parent: BuiltRouteSchema | null = null +): BuiltRouteSchema { + const { tokens } = parse(schema.fromRoot); + + const types: string[] = []; + const factories: string[] = []; + + for (const token of tokens) { + switch (token.type) { + case 'param': + case 'wildcard': + types.push(token.name); + factories.push(`\${params.${token.name}}`); + break; + case 'text': { + factories.push(token.value); + break; + } + } + } + + // [a, b, c] -> '{ a: string; b: string; c: string }' + const type = types.length + ? `{ ${types.map(type => `${type}: string`).join('; ')} }` + : undefined; + + const builtResult: BuiltRouteSchema = { + name: schema.name, + type, + factory: factories.join(''), + fromRoot: schema.fromRoot, + fromParent: schema.fromParent, + parent: parent, + children: [], + }; + + builtResult.children = schema.children.map(child => + buildRoutes(child, builtResult) + ); + + return builtResult; +} + +function printSchemaTypes(schema: BuiltRouteSchema, level: number = 1): string { + const types: string[] = []; + + if (schema.type) { + if (schema.children.length) { + types.push(`index: ${schema.type};`); + } else { + return schema.type; + } + } + + for (const child of schema.children) { + const childType = printSchemaTypes(child, level + 1); + if (childType) { + types.push(`${child.name}: ${childType};`); + } + } + + if (types.length > 0) { + const output = `{ ${types.join('\n')} }`; + return level === 1 ? `export interface RouteParamsTypes ${output}` : output; + } + + return ''; +} + +function printAbsolutePaths(schema: BuiltRouteSchema, level = 1): string { + const absolutes: string[] = []; + + if (schema.children.length) { + absolutes.push(`index: '${schema.fromRoot}'`); + } else { + return `'${schema.fromRoot}'`; + } + + for (const child of schema.children) { + const childRoute = printAbsolutePaths(child, level + 1); + absolutes.push(`${child.name}: ${childRoute}`); + } + + const output = `{ ${absolutes.join('\n,')} }`; + + return level === 1 ? `export const ROUTES = ${output}` : output; +} + +function printRelativePaths(schema: BuiltRouteSchema, level = 1): string { + const relatives: string[] = []; + + if (schema.children.length) { + relatives.push(`index: '${schema.fromParent}'`); + } else { + return `'${schema.fromParent}'`; + } + + for (const child of schema.children) { + const childRoute = printRelativePaths(child, level + 1); + relatives.push(`${child.name}: ${childRoute}`); + } + + const output = `{ ${relatives.join('\n,')} }`; + + return level === 1 ? `export const RELATIVE_ROUTES = ${output}` : output; +} + +function printFactories(schema: BuiltRouteSchema): string { + const factories: string[] = []; + + const factory = schema.type + ? `(params: ${schema.type}) => \`${schema.factory}\`` + : `() => '${schema.factory}'`; + + let parent: BuiltRouteSchema | null = schema.parent; + let nameFromRoot: string[] = [schema.name]; + while (parent) { + // ignore home + if (parent.parent) { + nameFromRoot = [parent.name, ...nameFromRoot]; + } + parent = parent.parent; + } + + if (schema.children.length) { + // with children, we do + const visitor = nameFromRoot.join('_'); + // 1. const workspace_doc = () => 'workspace/doc' + factories.push(`const ${visitor} = ${factory}`); + for (const child of schema.children) { + // 2. generate children for workspace_doc + factories.push(printFactories(child)); + } + // 3. workspace.doc = workspace_doc + const parentNameFromRoot = nameFromRoot.slice(0, -1).join('_'); + if (parentNameFromRoot) { + factories.push(`${parentNameFromRoot}.${schema.name} = ${visitor}`); + } + } else { + // without children, we directly + const parentNameFromRoot = nameFromRoot.slice(0, -1).join('_'); + if (parentNameFromRoot) { + // parent.child = () => 'child' + factories.push(`${parentNameFromRoot}.${schema.name} = ${factory}`); + } else { + // const route = () => 'route' + factories.push(`const ${schema.name} = ${factory}`); + } + } + + const output = factories.join('\n'); + + if (!schema.parent) { + const firstLevelNames = schema.children.map(child => child.name); + firstLevelNames.push(schema.name); + return `${output}\nexport const FACTORIES = { ${firstLevelNames.join( + ', ' + )} };`; + } + + return output; +} + +async function printRoutes(schema: BuiltRouteSchema) { + const parts = { + ['Path Parameter Types']: printSchemaTypes, + ['Absolute Paths']: printAbsolutePaths, + ['Relative Paths']: printRelativePaths, + ['Path Factories']: printFactories, + }; + const content = await prettier( + Object.entries(parts) + .map(([key, print]) => { + return `// #region ${key}\n${print(schema)}\n// #endregion`; + }) + .join('\n\n'), + 'typescript' + ); + + fs.writeFileSync(routerOutputFile, content, 'utf-8'); +} + +async function build() { + const schema = loadRoutesSchema(); + const builtSchema = buildRoutes(schema); + + await printRoutes(builtSchema); +} + +await build(); diff --git a/packages/frontend/routes/package.json b/packages/frontend/routes/package.json new file mode 100644 index 0000000000..e70b33168c --- /dev/null +++ b/packages/frontend/routes/package.json @@ -0,0 +1,22 @@ +{ + "name": "@affine/routes", + "version": "0.0.1", + "private": true, + "type": "module", + "exports": { + ".": "./src/routes.ts" + }, + "scripts": { + "build": "r build.ts" + }, + "devDependencies": { + "@affine-tools/cli": "workspace:*", + "@affine-tools/utils": "workspace:*", + "path-to-regexp": "^8.2.0", + "query-string": "^9.1.1", + "vitest": "^3.0.6" + }, + "optionalDependencies": { + "react-router-dom": "^6.28.0" + } +} diff --git a/packages/frontend/routes/routes.json b/packages/frontend/routes/routes.json new file mode 100644 index 0000000000..14a8e00001 --- /dev/null +++ b/packages/frontend/routes/routes.json @@ -0,0 +1,21 @@ +{ + "$schema": "./schema.json", + "route": "/", + "children": { + "admin": { + "route": "admin", + "children": { + "accounts": "accounts", + "ai": "ai", + "settings": { + "route": "settings", + "children": { + "module": ":module" + } + }, + "about": "about", + "notFound": "404" + } + } + } +} diff --git a/packages/frontend/routes/schema.json b/packages/frontend/routes/schema.json new file mode 100644 index 0000000000..18039ed9db --- /dev/null +++ b/packages/frontend/routes/schema.json @@ -0,0 +1,32 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "AFFiNE Routes Schema", + "definitions": { + "route": { + "type": "string", + "description": "route path" + }, + "children": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "object", + "required": ["route", "children"], + "properties": { + "route": { "$ref": "#/definitions/route" }, + "children": { "$ref": "#/definitions/children" } + } + } + ] + } + } + }, + "properties": { + "route": { "$ref": "#/definitions/route" }, + "children": { "$ref": "#/definitions/children" } + } +} diff --git a/packages/frontend/routes/src/__tests__/routes.spec.ts b/packages/frontend/routes/src/__tests__/routes.spec.ts new file mode 100644 index 0000000000..77ba3e133c --- /dev/null +++ b/packages/frontend/routes/src/__tests__/routes.spec.ts @@ -0,0 +1,13 @@ +import { describe, expect, it } from 'vitest'; + +import { FACTORIES } from '../routes'; + +describe('PATH_FACTORIES', () => { + it('should generate correct paths', () => { + expect( + FACTORIES.admin.settings.module({ + module: 'auth', + }) + ).toBe('/admin/settings/auth'); + }); +}); diff --git a/packages/frontend/routes/src/routes.ts b/packages/frontend/routes/src/routes.ts new file mode 100644 index 0000000000..a55b862eb5 --- /dev/null +++ b/packages/frontend/routes/src/routes.ts @@ -0,0 +1,44 @@ +// #region Path Parameter Types +export interface RouteParamsTypes { + admin: { settings: { module: { module: string } } }; +} +// #endregion + +// #region Absolute Paths +export const ROUTES = { + index: '/', + admin: { + index: '/admin', + accounts: '/admin/accounts', + ai: '/admin/ai', + settings: { index: '/admin/settings', module: '/admin/settings/:module' }, + about: '/admin/about', + }, +}; +// #endregion + +// #region Relative Paths +export const RELATIVE_ROUTES = { + index: '/', + admin: { + index: 'admin', + accounts: 'accounts', + ai: 'ai', + settings: { index: 'settings', module: ':module' }, + about: 'about', + }, +}; +// #endregion + +// #region Path Factories +const home = () => '/'; +const admin = () => '/admin'; +admin.accounts = () => '/admin/accounts'; +admin.ai = () => '/admin/ai'; +const admin_settings = () => '/admin/settings'; +admin_settings.module = (params: { module: string }) => + `/admin/settings/${params.module}`; +admin.settings = admin_settings; +admin.about = () => '/admin/about'; +export const FACTORIES = { admin, home }; +// #endregion diff --git a/packages/frontend/routes/tsconfig.json b/packages/frontend/routes/tsconfig.json new file mode 100644 index 0000000000..6433071963 --- /dev/null +++ b/packages/frontend/routes/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../../tsconfig.web.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist", + "tsBuildInfoFile": "./dist/tsconfig.tsbuildinfo" + }, + "include": ["./src"], + "references": [ + { "path": "../../../tools/cli" }, + { "path": "../../../tools/utils" } + ] +} diff --git a/tools/utils/package.json b/tools/utils/package.json index a6eaf562e7..dfb217df63 100644 --- a/tools/utils/package.json +++ b/tools/utils/package.json @@ -4,6 +4,7 @@ "type": "module", "private": true, "exports": { + ".": "./src/index.ts", "./path": "./src/path.ts", "./workspace": "./src/workspace.ts", "./process": "./src/process.ts", @@ -16,6 +17,7 @@ "@types/node": "^22.0.0", "chalk": "^5.3.0", "lodash-es": "^4.17.21", + "prettier": "^3.3.3", "typescript": "^5.5.4" } } diff --git a/tools/utils/src/format.ts b/tools/utils/src/format.ts new file mode 100644 index 0000000000..975d3ec9cc --- /dev/null +++ b/tools/utils/src/format.ts @@ -0,0 +1,17 @@ +import { readFileSync } from 'node:fs'; + +import { once } from 'lodash-es'; +import { type BuiltInParserName, format } from 'prettier'; + +import { ProjectRoot } from './path'; + +const readConfig = once(() => { + const path = ProjectRoot.join('.prettierrc').value; + const config = JSON.parse(readFileSync(path, 'utf-8')); + return config; +}); + +export function prettier(content: string, parser: BuiltInParserName) { + const config = readConfig(); + return format(content, { parser, ...config }); +} diff --git a/tools/utils/src/index.ts b/tools/utils/src/index.ts new file mode 100644 index 0000000000..1df3f5afd3 --- /dev/null +++ b/tools/utils/src/index.ts @@ -0,0 +1,2 @@ +export * from './format'; +export * from './path'; diff --git a/tools/utils/src/workspace.gen.ts b/tools/utils/src/workspace.gen.ts index e957afe87e..fc2924e8f4 100644 --- a/tools/utils/src/workspace.gen.ts +++ b/tools/utils/src/workspace.gen.ts @@ -1165,6 +1165,11 @@ export const PackageList = [ name: '@affine/native', workspaceDependencies: [], }, + { + location: 'packages/frontend/routes', + name: '@affine/routes', + workspaceDependencies: ['tools/cli', 'tools/utils'], + }, { location: 'packages/frontend/templates', name: '@affine/templates', @@ -1349,6 +1354,7 @@ export type PackageName = | '@affine/i18n' | '@affine/media-capture-playground' | '@affine/native' + | '@affine/routes' | '@affine/templates' | '@affine/track' | '@affine-test/affine-cloud' diff --git a/tsconfig.json b/tsconfig.json index 2102f04a6b..30726ef91d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -133,6 +133,7 @@ { "path": "./packages/frontend/i18n" }, { "path": "./packages/frontend/media-capture-playground" }, { "path": "./packages/frontend/native" }, + { "path": "./packages/frontend/routes" }, { "path": "./packages/frontend/track" }, { "path": "./tests/affine-cloud" }, { "path": "./tests/affine-cloud-copilot" }, diff --git a/yarn.lock b/yarn.lock index d016f774d2..d0032b3ad7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -167,6 +167,7 @@ __metadata: "@types/node": "npm:^22.0.0" chalk: "npm:^5.3.0" lodash-es: "npm:^4.17.21" + prettier: "npm:^3.3.3" typescript: "npm:^5.5.4" languageName: unknown linkType: soft @@ -851,6 +852,22 @@ __metadata: languageName: unknown linkType: soft +"@affine/routes@workspace:packages/frontend/routes": + version: 0.0.0-use.local + resolution: "@affine/routes@workspace:packages/frontend/routes" + dependencies: + "@affine-tools/cli": "workspace:*" + "@affine-tools/utils": "workspace:*" + path-to-regexp: "npm:^8.2.0" + query-string: "npm:^9.1.1" + react-router-dom: "npm:^6.28.0" + vitest: "npm:^3.0.6" + dependenciesMeta: + react-router-dom: + optional: true + languageName: unknown + linkType: soft + "@affine/server-native@workspace:*, @affine/server-native@workspace:packages/backend/native": version: 0.0.0-use.local resolution: "@affine/server-native@workspace:packages/backend/native" @@ -15958,6 +15975,18 @@ __metadata: languageName: node linkType: hard +"@vitest/expect@npm:3.1.2": + version: 3.1.2 + resolution: "@vitest/expect@npm:3.1.2" + dependencies: + "@vitest/spy": "npm:3.1.2" + "@vitest/utils": "npm:3.1.2" + chai: "npm:^5.2.0" + tinyrainbow: "npm:^2.0.0" + checksum: 10/3c414e376154c8095f40efe409bb5f2c9380ba05a15b20552ee2e29f73197ab73068177e3da298ac135ef72673d1ea92090c466c78443ee69a7438bc8ab65f4f + languageName: node + linkType: hard + "@vitest/mocker@npm:3.1.1": version: 3.1.1 resolution: "@vitest/mocker@npm:3.1.1" @@ -15977,6 +16006,25 @@ __metadata: languageName: node linkType: hard +"@vitest/mocker@npm:3.1.2": + version: 3.1.2 + resolution: "@vitest/mocker@npm:3.1.2" + dependencies: + "@vitest/spy": "npm:3.1.2" + estree-walker: "npm:^3.0.3" + magic-string: "npm:^0.30.17" + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + checksum: 10/e6d730400daa7a97fb277159733df1366a932b5b06ac83d72e094e5383191c2597b4a5ae3538b28de6112b9e5d314cb50b44e031e79522f43f3dfc8ab022a584 + languageName: node + linkType: hard + "@vitest/pretty-format@npm:2.0.5": version: 2.0.5 resolution: "@vitest/pretty-format@npm:2.0.5" @@ -15995,7 +16043,7 @@ __metadata: languageName: node linkType: hard -"@vitest/pretty-format@npm:3.1.1, @vitest/pretty-format@npm:^3.1.1": +"@vitest/pretty-format@npm:3.1.1": version: 3.1.1 resolution: "@vitest/pretty-format@npm:3.1.1" dependencies: @@ -16004,6 +16052,15 @@ __metadata: languageName: node linkType: hard +"@vitest/pretty-format@npm:3.1.2, @vitest/pretty-format@npm:^3.1.1, @vitest/pretty-format@npm:^3.1.2": + version: 3.1.2 + resolution: "@vitest/pretty-format@npm:3.1.2" + dependencies: + tinyrainbow: "npm:^2.0.0" + checksum: 10/454d0a8c250dbe52f7ec9dab4968e7c769fa10c8318eb5c54cb4b6d5b524772c04856e1990279f2c6e76705ffa107fddcbc1973560ed3b88167c231ccfeada16 + languageName: node + linkType: hard + "@vitest/runner@npm:3.1.1": version: 3.1.1 resolution: "@vitest/runner@npm:3.1.1" @@ -16014,6 +16071,16 @@ __metadata: languageName: node linkType: hard +"@vitest/runner@npm:3.1.2": + version: 3.1.2 + resolution: "@vitest/runner@npm:3.1.2" + dependencies: + "@vitest/utils": "npm:3.1.2" + pathe: "npm:^2.0.3" + checksum: 10/b09c1ff3a556f318585307e6bb8954d219d0d35d1e17708fdd5d5ae1a230e6f29eba4f37a86faa71192f72406bb96b576c1b620d49d686def87bc5dcb8bf5737 + languageName: node + linkType: hard + "@vitest/snapshot@npm:3.1.1": version: 3.1.1 resolution: "@vitest/snapshot@npm:3.1.1" @@ -16025,6 +16092,17 @@ __metadata: languageName: node linkType: hard +"@vitest/snapshot@npm:3.1.2": + version: 3.1.2 + resolution: "@vitest/snapshot@npm:3.1.2" + dependencies: + "@vitest/pretty-format": "npm:3.1.2" + magic-string: "npm:^0.30.17" + pathe: "npm:^2.0.3" + checksum: 10/dda969b697bdcd8616f17e98c74ad5e95a5f3c2284140aa72390ce668db34e70936ee0b8ebe89adb2e0dea332500689d54c8ff03f8adf1e00be70639ec9032bf + languageName: node + linkType: hard + "@vitest/spy@npm:2.0.5": version: 2.0.5 resolution: "@vitest/spy@npm:2.0.5" @@ -16043,6 +16121,15 @@ __metadata: languageName: node linkType: hard +"@vitest/spy@npm:3.1.2": + version: 3.1.2 + resolution: "@vitest/spy@npm:3.1.2" + dependencies: + tinyspy: "npm:^3.0.2" + checksum: 10/c2c638368fa4130f903901fdf4e86da6f90d5d6a8cf7ce880cdd24768a1f8e6b726ea3428501c97e00c34ac2e8e39ac09b3a03606dffd8081559e0a35c892ddc + languageName: node + linkType: hard + "@vitest/ui@npm:3.1.1": version: 3.1.1 resolution: "@vitest/ui@npm:3.1.1" @@ -16083,6 +16170,17 @@ __metadata: languageName: node linkType: hard +"@vitest/utils@npm:3.1.2": + version: 3.1.2 + resolution: "@vitest/utils@npm:3.1.2" + dependencies: + "@vitest/pretty-format": "npm:3.1.2" + loupe: "npm:^3.1.3" + tinyrainbow: "npm:^2.0.0" + checksum: 10/221faaaf6c69ef24eacdcf68581c833cb99bf3e5125945b5dec928af7ef1af4359aa520b90c42413a128b308037bf3217d8c41a41f44ca4aee3ac44e3f0d56b5 + languageName: node + linkType: hard + "@vitest/utils@npm:^2.1.1": version: 2.1.9 resolution: "@vitest/utils@npm:2.1.9" @@ -21142,7 +21240,7 @@ __metadata: languageName: node linkType: hard -"expect-type@npm:^1.2.0": +"expect-type@npm:^1.2.0, expect-type@npm:^1.2.1": version: 1.2.1 resolution: "expect-type@npm:1.2.1" checksum: 10/d121d90f4f3f705ca0b656e36f28c0ba91483d0cddf2876e64e23c3dea2f2d5853e9c0c9a4e90eb4b3e4663bf09c2c02e9729c339dcd308c70b2107188e6b286 @@ -21448,15 +21546,15 @@ __metadata: languageName: node linkType: hard -"fdir@npm:^6.4.3": - version: 6.4.3 - resolution: "fdir@npm:6.4.3" +"fdir@npm:^6.4.4": + version: 6.4.4 + resolution: "fdir@npm:6.4.4" peerDependencies: picomatch: ^3 || ^4 peerDependenciesMeta: picomatch: optional: true - checksum: 10/8e6d20f4590dc168de1374a9cadaa37e20ca6e0b822aa247c230e7ea1d9e9674a68cd816146435e4ecc98f9285091462ab7e5e56eebc9510931a1794e4db68b2 + checksum: 10/d0000d6b790059b35f4ed19acc8847a66452e0bc68b28766c929ffd523e5ec2083811fc8a545e4a1d4945ce70e887b3a610c145c681073b506143ae3076342ed languageName: node linkType: hard @@ -26881,8 +26979,8 @@ __metadata: linkType: hard "msw@npm:^2.6.8": - version: 2.7.4 - resolution: "msw@npm:2.7.4" + version: 2.7.3 + resolution: "msw@npm:2.7.3" dependencies: "@bundled-es-modules/cookie": "npm:^2.0.1" "@bundled-es-modules/statuses": "npm:^1.0.1" @@ -26909,7 +27007,7 @@ __metadata: optional: true bin: msw: cli/index.js - checksum: 10/3ce3cb190b1a036536a047c018fc4f52d23371765c97595127411695c11e73bc7c737fea8fb4a6b46b3cd36223031ffc23a8bbaff10d1daebdda3bb4a817dd34 + checksum: 10/f193329a68fc22e477a6f8504aa44a92bd12847f2eeac1dfbd8ec1cc43ff293112ec067de1c7fe312ba02beecb313fb00aeeebf5817432b57af2d796b2dff2fa languageName: node linkType: hard @@ -28261,7 +28359,7 @@ __metadata: languageName: node linkType: hard -"path-to-regexp@npm:8.2.0, path-to-regexp@npm:^8.0.0": +"path-to-regexp@npm:8.2.0, path-to-regexp@npm:^8.0.0, path-to-regexp@npm:^8.2.0": version: 8.2.0 resolution: "path-to-regexp@npm:8.2.0" checksum: 10/23378276a172b8ba5f5fb824475d1818ca5ccee7bbdb4674701616470f23a14e536c1db11da9c9e6d82b82c556a817bbf4eee6e41b9ed20090ef9427cbb38e13 @@ -29079,7 +29177,7 @@ __metadata: languageName: node linkType: hard -"prettier@npm:3.5.3, prettier@npm:^3.2.5, prettier@npm:^3.4.2": +"prettier@npm:3.5.3, prettier@npm:^3.2.5, prettier@npm:^3.3.3, prettier@npm:^3.4.2": version: 3.5.3 resolution: "prettier@npm:3.5.3" bin: @@ -31683,7 +31781,7 @@ __metadata: languageName: node linkType: hard -"std-env@npm:^3.7.0, std-env@npm:^3.8.1": +"std-env@npm:^3.7.0, std-env@npm:^3.8.1, std-env@npm:^3.9.0": version: 3.9.0 resolution: "std-env@npm:3.9.0" checksum: 10/3044b2c54a74be4f460db56725571241ab3ac89a91f39c7709519bc90fa37148784bc4cd7d3a301aa735f43bd174496f263563f76703ce3e81370466ab7c235b @@ -32480,13 +32578,13 @@ __metadata: languageName: node linkType: hard -"tinyglobby@npm:^0.2.12": - version: 0.2.12 - resolution: "tinyglobby@npm:0.2.12" +"tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.13": + version: 0.2.13 + resolution: "tinyglobby@npm:0.2.13" dependencies: - fdir: "npm:^6.4.3" + fdir: "npm:^6.4.4" picomatch: "npm:^4.0.2" - checksum: 10/4ad28701fa9118b32ef0e27f409e0a6c5741e8b02286d50425c1f6f71e6d6c6ded9dd5bbbbb714784b08623c4ec4d150151f1d3d996cfabe0495f908ab4f7002 + checksum: 10/b04557ee58ad2be5f2d2cbb4b441476436c92bb45ba2e1fc464d686b793392b305ed0bcb8b877429e9b5036bdd46770c161a08384c0720b6682b7cd6ac80e403 languageName: node linkType: hard @@ -33651,7 +33749,7 @@ __metadata: languageName: node linkType: hard -"vite-node@npm:3.1.1, vite-node@npm:^3.0.4": +"vite-node@npm:3.1.1": version: 3.1.1 resolution: "vite-node@npm:3.1.1" dependencies: @@ -33666,6 +33764,21 @@ __metadata: languageName: node linkType: hard +"vite-node@npm:3.1.2, vite-node@npm:^3.0.4": + version: 3.1.2 + resolution: "vite-node@npm:3.1.2" + dependencies: + cac: "npm:^6.7.14" + debug: "npm:^4.4.0" + es-module-lexer: "npm:^1.6.0" + pathe: "npm:^2.0.3" + vite: "npm:^5.0.0 || ^6.0.0" + bin: + vite-node: vite-node.mjs + checksum: 10/8af0465810c6f27200dc899792002320995f3d85c432aaa411bf7ff15580c0b93c4a5153d8a93c7af89b496a6e1a7979a7777984e37ebd7311851ea7572eaac7 + languageName: node + linkType: hard + "vite-plugin-istanbul@npm:^7.0.0": version: 7.0.0 resolution: "vite-plugin-istanbul@npm:7.0.0" @@ -33811,6 +33924,60 @@ __metadata: languageName: node linkType: hard +"vitest@npm:^3.0.6": + version: 3.1.2 + resolution: "vitest@npm:3.1.2" + dependencies: + "@vitest/expect": "npm:3.1.2" + "@vitest/mocker": "npm:3.1.2" + "@vitest/pretty-format": "npm:^3.1.2" + "@vitest/runner": "npm:3.1.2" + "@vitest/snapshot": "npm:3.1.2" + "@vitest/spy": "npm:3.1.2" + "@vitest/utils": "npm:3.1.2" + chai: "npm:^5.2.0" + debug: "npm:^4.4.0" + expect-type: "npm:^1.2.1" + magic-string: "npm:^0.30.17" + pathe: "npm:^2.0.3" + std-env: "npm:^3.9.0" + tinybench: "npm:^2.9.0" + tinyexec: "npm:^0.3.2" + tinyglobby: "npm:^0.2.13" + tinypool: "npm:^1.0.2" + tinyrainbow: "npm:^2.0.0" + vite: "npm:^5.0.0 || ^6.0.0" + vite-node: "npm:3.1.2" + why-is-node-running: "npm:^2.3.0" + peerDependencies: + "@edge-runtime/vm": "*" + "@types/debug": ^4.1.12 + "@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0 + "@vitest/browser": 3.1.2 + "@vitest/ui": 3.1.2 + happy-dom: "*" + jsdom: "*" + peerDependenciesMeta: + "@edge-runtime/vm": + optional: true + "@types/debug": + optional: true + "@types/node": + optional: true + "@vitest/browser": + optional: true + "@vitest/ui": + optional: true + happy-dom: + optional: true + jsdom: + optional: true + bin: + vitest: vitest.mjs + checksum: 10/aa5638bf37b2811b01ad8ff0563cdec09202f7a28d9dbcb8eabb2e51cadefc57309cba4f5ff2bac4a72edda44055a844236fc4a09eb72127ef1bd34eb25d0808 + languageName: node + linkType: hard + "void-elements@npm:3.1.0": version: 3.1.0 resolution: "void-elements@npm:3.1.0"