diff --git a/README.md b/README.md index 39fd988..15b9721 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,31 @@ export default defineUniPages({ 现在所有的 page 都会被自动发现! -### SFC 自定义块用于路由数据 +### 页面调用方式(1): `definePage` 宏定义路由数据 +```html + + + + + +``` + +### 页面调用方式(2):SFC 自定义块用于路由数据 通过添加一个 `` 块到 SFC 中来添加路由元数据。这将会在路由生成后直接添加到路由中,并且会覆盖。 diff --git a/packages/core/README.md b/packages/core/README.md index 5a66ce3..56f0153 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -44,7 +44,31 @@ export default defineUniPages({ Now all pages will be found automatically! -### SFC custom block for Route Data +### Page usage (1): `definePage` macro define page options +```html + + + + + +``` + +### Page usage (2): SFC custom block for Route Data Add route meta to the route by adding a `` block to the SFC. This will be directly added to the route after it is generated, and will override it. diff --git a/packages/core/client.d.ts b/packages/core/client.d.ts index 9af7099..0ae9dc2 100644 --- a/packages/core/client.d.ts +++ b/packages/core/client.d.ts @@ -5,3 +5,7 @@ declare module 'virtual:uni-pages' { export const pages: PageMetaDatum[] export const subPackages: SubPackage[] } + +declare module globalThis { + export const definePage: import('./src/types').DefinePage +} diff --git a/packages/core/package.json b/packages/core/package.json index bed53e1..153a1d3 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -40,8 +40,11 @@ "stub": "unbuild --stub" }, "dependencies": { + "@babel/generator": "^7.24.1", + "@babel/types": "^7.24.0", "@uni-helper/uni-env": "^0.1.1", "@vue/compiler-sfc": "^3.4.21", + "ast-kit": "^0.12.1", "chokidar": "^3.6.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", @@ -53,6 +56,8 @@ }, "devDependencies": { "@antfu/utils": "^0.7.7", + "@babel/parser": "^7.24.1", + "@types/babel__generator": "^7.6.8", "@types/debug": "^4.1.12", "@types/node": "^20.11.24" } diff --git a/packages/core/src/constant.ts b/packages/core/src/constant.ts index e3eafdb..ee13441 100644 --- a/packages/core/src/constant.ts +++ b/packages/core/src/constant.ts @@ -4,3 +4,5 @@ export const RESOLVED_MODULE_ID_VIRTUAL = `\0${MODULE_ID_VIRTUAL}` export const OUTPUT_NAME = 'pages.json' export const FILE_EXTENSIONS = ['vue', 'nvue', 'uvue'] + +export const DEFINE_PAGE = 'definePage' diff --git a/packages/core/src/context.ts b/packages/core/src/context.ts index f5cc0e2..a6c56b6 100644 --- a/packages/core/src/context.ts +++ b/packages/core/src/context.ts @@ -2,7 +2,6 @@ import path from 'node:path' import process from 'node:process' import type { FSWatcher } from 'chokidar' import type { Logger, ViteDevServer } from 'vite' -import { normalizePath } from 'vite' import { loadConfig } from 'unconfig' import { slash } from '@antfu/utils' import dbg from 'debug' @@ -10,30 +9,25 @@ import { platform } from '@uni-helper/uni-env' import type { PagesConfig } from './config/types' import type { PageMetaDatum, PagePath, ResolvedOptions, SubPageMetaDatum, UserOptions } from './types' import { writeDeclaration } from './declaration' - import { debug, invalidatePagesModule, isTargetFile, mergePageMetaDataArray, - useCachedPages, } from './utils' import { resolveOptions } from './options' import { checkPagesJsonFile, getPageFiles, writeFileSync } from './files' -import { getRouteBlock, getRouteSfcBlock } from './customBlock' import { OUTPUT_NAME } from './constant' +import { Page } from './page' let lsatPagesJson = '' -const { setCache, hasChanged } = useCachedPages() export class PageContext { private _server: ViteDevServer | undefined pagesGlobConfig: PagesConfig | undefined pagesConfigSourcePaths: string[] = [] - pagesPath: PagePath[] = [] - subPagesPath: Record = {} pageMetaData: PageMetaDatum[] = [] subPageMetaData: SubPageMetaDatum[] = [] @@ -46,6 +40,9 @@ export class PageContext { withUniPlatform = false + pages: Page[] = [] + subPages: Record = {} + constructor(userOptions: UserOptions, viteRoot: string = process.cwd()) { this.rawOptions = userOptions this.root = slash(viteRoot) @@ -79,18 +76,24 @@ export class PageContext { return { dir, files: getPagePaths(dir, this.options) } }) - this.pagesPath = pageDirFiles.map(page => page.files).flat() - debug.pages(this.pagesPath) + const paths = pageDirFiles.map(page => page.files).flat() + debug.pages(paths) + + this.pages = paths.map(path => new Page(this, path)) } async scanSubPages() { - const subPagesPath: Record = {} + const paths: Record = {} + const subPages: Record = {} for (const dir of this.options.subPackages) { const pagePaths = getPagePaths(dir, this.options) - subPagesPath[dir] = pagePaths + paths[dir] = pagePaths + + subPages[dir] = pagePaths.map(path => new Page(this, path)) } - this.subPagesPath = subPagesPath - debug.subPages(this.subPagesPath) + debug.subPages(JSON.stringify(paths, null, 2)) + + this.subPages = subPages } setupViteServer(server: ViteDevServer) { @@ -167,23 +170,6 @@ export class PageContext { }) } - async parsePage(page: PagePath): Promise { - const { relativePath, absolutePath } = page - const routeSfcBlock = await getRouteSfcBlock(absolutePath) - const routeBlock = await getRouteBlock(absolutePath, routeSfcBlock, this.options) - setCache(absolutePath, routeSfcBlock) - const relativePathWithFileName = relativePath.replace(path.extname(relativePath), '') - const pageMetaDatum: PageMetaDatum = { - path: normalizePath(relativePathWithFileName), - type: routeBlock?.attr.type ?? 'page', - } - - if (routeBlock) - Object.assign(pageMetaDatum, routeBlock.content) - - return pageMetaDatum - } - /** * parse pages rules && set page type * @param pages page path array @@ -191,8 +177,8 @@ export class PageContext { * @param overrides custom page config * @returns pages rules */ - async parsePages(pages: PagePath[], type: 'main' | 'sub', overrides?: PageMetaDatum[]) { - const generatedPageMetaData = await Promise.all(pages.map(async page => await this.parsePage(page))) + async parsePages(pages: Page[], type: 'main' | 'sub', overrides?: PageMetaDatum[]) { + const generatedPageMetaData = await Promise.all(pages.map(async page => await page.getOptions())) const customPageMetaData = overrides || [] const result = customPageMetaData.length @@ -231,7 +217,7 @@ export class PageContext { } async mergePageMetaData() { - const pageMetaData = await this.parsePages(this.pagesPath, 'main', this.pagesGlobConfig?.pages) + const pageMetaData = await this.parsePages(this.pages, 'main', this.pagesGlobConfig?.pages) this.pageMetaData = pageMetaData debug.pages(this.pageMetaData) } @@ -240,7 +226,7 @@ export class PageContext { const subPageMaps: Record = {} const subPackages = this.pagesGlobConfig?.subPackages || [] - for (const [dir, pages] of Object.entries(this.subPagesPath)) { + for (const [dir, pages] of Object.entries(this.subPages)) { const root = path.basename(dir) const globPackage = subPackages?.find(v => v.root === root) @@ -260,9 +246,24 @@ export class PageContext { debug.subPages(this.subPageMetaData) } + private getPageByPath(absolutePath: string) { + const page = this.pages.find(page => page.file.absolutePath === absolutePath) + if (page) + return page + + for (const pages of Object.values(this.subPages)) { + const subPage = pages.find(page => page.file.absolutePath === absolutePath) + if (subPage) + return subPage + } + + return undefined + } + async updatePagesJSON(filepath?: string) { if (filepath) { - if (!await hasChanged(filepath)) { + const page = this.getPageByPath(filepath) + if (page && !await page.hasChanged()) { debug.cache(`The route block on page ${filepath} did not send any changes, skipping`) return false } diff --git a/packages/core/src/customBlock.ts b/packages/core/src/customBlock.ts deleted file mode 100644 index 8df8fb9..0000000 --- a/packages/core/src/customBlock.ts +++ /dev/null @@ -1,88 +0,0 @@ -import fs from 'node:fs' -import JSON5 from 'json5' -import { parse as YAMLParser } from 'yaml' -import { parse as VueParser } from '@vue/compiler-sfc' -import type { SFCBlock, SFCDescriptor } from '@vue/compiler-sfc' -import { debug } from './utils' -import type { CustomBlock, ResolvedOptions } from './types' - -export async function parseSFC(code: string): Promise { - try { - return ( - VueParser(code, { - pad: 'space', - }).descriptor - // for @vue/compiler-sfc ^2.7 - || (VueParser as any)({ - source: code, - }) - ) - } - catch (error) { - throw new Error(`[vite-plugin-uni-pages] Vue3's "@vue/compiler-sfc" is required. \nOriginal error: \n${error}`) - } -} - -export function parseCustomBlock( - block: SFCBlock, - filePath: string, - options: ResolvedOptions, -): CustomBlock | undefined { - const lang = block.lang ?? options.routeBlockLang - const attr = { - type: 'page', - ...block.attrs, - } - let content: Record | undefined - debug.routeBlock(`use ${lang} parser`) - - if (lang === 'json5' || lang === 'jsonc') { - try { - content = JSON5.parse(block.content) - } - catch (err: any) { - throw new Error( - `Invalid JSON5 format of <${block.type}> content in ${filePath}\n${err.message}`, - ) - } - } - else if (lang === 'json') { - try { - content = JSON.parse(block.content) - } - catch (err: any) { - throw new Error( - `Invalid JSON format of <${block.type}> content in ${filePath}\n${err.message}`, - ) - } - } - else if (lang === 'yaml' || lang === 'yml') { - try { - content = YAMLParser(block.content) - } - catch (err: any) { - throw new Error( - `Invalid YAML format of <${block.type}> content in ${filePath}\n${err.message}`, - ) - } - } - return { - attr, - content: content ?? {}, - } -} - -export async function getRouteSfcBlock(path: string): Promise { - const content = fs.readFileSync(path, 'utf8') - - const parsedSFC = await parseSFC(content) - const blockStr = parsedSFC?.customBlocks.find(b => b.type === 'route') - - return blockStr -} - -export async function getRouteBlock(path: string, blockStr: SFCBlock | undefined, options: ResolvedOptions): Promise { - if (!blockStr) - return - return parseCustomBlock(blockStr, path, options) -} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 3f2a07d..b3cf30c 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -5,14 +5,18 @@ import type { Plugin } from 'vite' import { createLogger } from 'vite' import MagicString from 'magic-string' import chokidar from 'chokidar' +import { parse as parseSFC } from '@vue/compiler-sfc' import type { UserOptions } from './types' import { PageContext } from './context' import { + DEFINE_PAGE, MODULE_ID_VIRTUAL, OUTPUT_NAME, RESOLVED_MODULE_ID_VIRTUAL, } from './constant' import { checkPagesJsonFile } from './files' +import { findMacro } from './page' +import { isTargetFile } from './utils' export * from './config' export * from './types' @@ -21,7 +25,7 @@ export * from './context' export * from './utils' export * from './files' export * from './options' -export * from './customBlock' +export * from './page' async function restart() { return new Promise((resolve) => { @@ -78,19 +82,33 @@ export function VitePluginUniPages(userOptions: UserOptions = {}): Plugin { }, // Applet do not support custom route block, so we need to remove the route block here async transform(code: string, id: string) { - if (!/\.n?vue$/.test(id) && !code.includes('')) + if (!isTargetFile(id)) return null + + const { descriptor: sfc, errors } = parseSFC(code, { filename: id }) + + if (errors.length) + throw new Error(errors[0].message) + + const macro = findMacro(sfc.scriptSetup) + const routeBlock = sfc.customBlocks.find(block => block.type === 'route') + + if (!macro && !routeBlock) + return null + + if (macro && routeBlock) + throw new Error(`mixed ${DEFINE_PAGE}() and is not allowed`) + const s = new MagicString(code) - const routeBlockMatches = s.original.matchAll( - /]*>([\s\S]*?)<\/route>/g, - ) - - for (const match of routeBlockMatches) { - const index = match.index! - const length = match[0].length - s.remove(index, index + length) + + if (macro) { + const setupOffset = sfc.scriptSetup!.loc.start.offset + s.remove(setupOffset + macro.start!, setupOffset + macro.end!) } + if (routeBlock) + s.remove(routeBlock.loc.start.offset, routeBlock.loc.end.offset) + if (s.hasChanged()) { return { code: s.toString(), diff --git a/packages/core/src/page.ts b/packages/core/src/page.ts new file mode 100644 index 0000000..2c29c18 --- /dev/null +++ b/packages/core/src/page.ts @@ -0,0 +1,189 @@ +import { readFileSync } from 'node:fs' +import { extname } from 'node:path' +import type { SFCDescriptor, SFCScriptBlock } from '@vue/compiler-sfc' +import { parse as VueParser } from '@vue/compiler-sfc' +import { babelParse, isCallOf } from 'ast-kit' +import * as t from '@babel/types' +import generate from '@babel/generator' +import JSON5 from 'json5' +import { parse as YAMLParser } from 'yaml' +import { normalizePath } from 'vite' +import type { PageContext } from './context' +import { debug } from './utils' +import type { DefinePageOptions, PageMetaDatum, PagePath, RouteBlockLang } from './types' +import { DEFINE_PAGE } from './constant' + +export class Page { + ctx: PageContext + + file: PagePath + + private rawOptions: string = '' + private options: PageMetaDatum | undefined + + constructor(ctx: PageContext, file: PagePath) { + this.ctx = ctx + this.file = file + } + + async getOptions(forceUpdate = false) { + if (forceUpdate || !this.options) + await this.readOptions() + + return this.options! + } + + async hasChanged() { + const { hasChanged } = await this.readOptions() + return hasChanged + } + + async readOptions() { + try { + const { relativePath, absolutePath } = this.file + + // eslint-disable-next-line unused-imports/no-unused-vars + const { path, ...others } = await readPageOptionsFromFile(absolutePath, this.ctx.options.routeBlockLang) + this.options = { + path: normalizePath(relativePath.replace(extname(relativePath), '')), + ...others, + } + + const raw = (this.options ? JSON.stringify(this.options) : '') + const hasChanged = this.rawOptions !== raw + this.rawOptions = raw + return { + options: this.options, + hasChanged, + } + } + catch (err: any) { + throw new Error(`Read page options fail in ${this.file.relativePath}\n${err.message}`) + } + } +} + +async function readPageOptionsFromFile(path: string, routeBlockLang: RouteBlockLang) { + const content = readFileSync(path, 'utf-8') + const sfc = VueParser(content).descriptor + + const macroOptions = await readPageOptionsFromMacro(path, sfc) + if (macroOptions) + return macroOptions + + const blockOptions = readPageOptionsFromBlock(path, routeBlockLang, sfc) + if (blockOptions) + return blockOptions + + return {} as DefinePageOptions +} + +async function readPageOptionsFromMacro(path: string, sfc?: SFCDescriptor) { + if (!sfc) { + const content = readFileSync(path, 'utf-8') + sfc = VueParser(content).descriptor + } + + const { macro } = findMacroWithImports(sfc.scriptSetup) + + if (!macro) + return + + if (sfc?.customBlocks.find(b => b.type === 'route')) + throw new Error(`mixed ${DEFINE_PAGE}() and is not allowed`) + + const [arg] = macro.arguments + + if (!arg) + return + + const code = generate(arg).code + + const script = t.isFunctionExpression(arg) || t.isArrowFunctionExpression(arg) + ? `return await Promise.resolve((${code})())` + : `return ${code}` + + const AsyncFunction = Object.getPrototypeOf(async () => { }).constructor + + const fn = new AsyncFunction(script) + + const options = await fn() as DefinePageOptions + + return options +} + +function readPageOptionsFromBlock(path: string, routeBlockLang: RouteBlockLang, sfc?: SFCDescriptor) { + if (!sfc) { + const content = readFileSync(path, 'utf-8') + sfc = VueParser(content).descriptor + } + + const block = sfc.customBlocks.find(b => b.type === 'route') + + if (!block) + return + + const lang = (block.lang ?? routeBlockLang) as RouteBlockLang + + debug.routeBlock(`use ${lang} parser`) + + let options = {} as PageMetaDatum + + if (['json5', 'jsonc', 'json'].includes(lang)) + options = JSON5.parse(block.content) as PageMetaDatum + else if (['yaml', 'yml'].includes(lang)) + options = YAMLParser(block.content) as PageMetaDatum + + if (!options.type) + options.type = (typeof block.attrs.type === 'string') && block.attrs.type.length ? block.attrs.type : 'page' + + return options +} + +function findMacroWithImports(scriptSetup: SFCScriptBlock | null) { + const empty = { imports: [], macro: undefined } + + if (!scriptSetup) + return empty + + const parsed = babelParse(scriptSetup.content, scriptSetup.lang || 'js', { + plugins: [['importAttributes', { deprecatedAssertSyntax: true }]], + }) + + const stmts = parsed.body + + const nodes = stmts + .map((raw: t.Node) => { + let node = raw + if (raw.type === 'ExpressionStatement') + node = raw.expression + return isCallOf(node, DEFINE_PAGE) ? node : undefined + }) + .filter((node): node is t.CallExpression => !!node) + + if (!nodes.length) + return empty + + if (nodes.length > 1) + throw new Error(`duplicate ${DEFINE_PAGE}() call`) + + const macro = nodes[0] + + const [arg] = macro.arguments + + if (arg && !t.isFunctionExpression(arg) && !t.isArrowFunctionExpression(arg) && !t.isObjectExpression(arg)) + throw new Error(`${DEFINE_PAGE}() only accept argument in function or object`) + + const imports = stmts + .map((node: t.Node) => (node.type === 'ImportDeclaration') ? node : undefined) + .filter((node): node is t.ImportDeclaration => !!node) + + return { + imports, + macro, + } +} + +export function findMacro(scriptSetup: SFCScriptBlock | null) { + return findMacroWithImports(scriptSetup).macro +} diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index f727612..3271803 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -12,6 +12,8 @@ export type debugType = keyof typeof debug export type ConfigSource = string | LoadConfigSource | LoadConfigSource[] +export type RouteBlockLang = 'json5' | 'jsonc' | 'json' | 'yaml' | 'yml' + export interface Options { /** @@ -68,7 +70,7 @@ export interface Options { * Set the default route block parser, or use `` in SFC route block * @default 'json5' */ - routeBlockLang: 'json5' | 'json' | 'yaml' | 'yml' + routeBlockLang: RouteBlockLang /** * minify the `pages.json` @@ -140,3 +142,13 @@ export interface SubPageMetaDatum { root: string pages: PageMetaDatum[] } + +export interface DefinePageOptions extends Partial { + /** + * 配置页面路径 + * @deprecated 无效,将会根据文件路径自动生成 + */ + path?: string +} + +export type DefinePage = (options: DefinePageOptions | (() => DefinePageOptions) | (() => Promise)) => void diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts index 3a5173d..11160b5 100644 --- a/packages/core/src/utils.ts +++ b/packages/core/src/utils.ts @@ -1,10 +1,8 @@ import Debug from 'debug' -import { type ModuleNode, type ViteDevServer, normalizePath } from 'vite' +import type { ModuleNode, ViteDevServer } from 'vite' import { groupBy } from 'lodash-unified' -import type { SFCBlock } from '@vue/compiler-sfc' import { FILE_EXTENSIONS, RESOLVED_MODULE_ID_VIRTUAL } from './constant' import type { PageMetaDatum } from './types' -import { getRouteSfcBlock } from './customBlock' export function invalidatePagesModule(server: ViteDevServer) { const { moduleGraph } = server @@ -56,30 +54,3 @@ export function mergePageMetaDataArray(pageMetaData: PageMetaDatum[]) { } return result } - -export function useCachedPages() { - const pages = new Map() - - function parseData(block?: SFCBlock) { - return { - content: block?.loc.source.trim() ?? '', - attr: block?.attrs ?? '', - } - } - - function setCache(filePath: string, routeBlock?: SFCBlock) { - pages.set(filePath, JSON.stringify(parseData(routeBlock))) - } - - async function hasChanged(filePath: string, routeBlock?: SFCBlock) { - if (!routeBlock) - routeBlock = await getRouteSfcBlock(normalizePath(filePath)) - - return !pages.has(filePath) || JSON.stringify(parseData(routeBlock)) !== pages.get(filePath) - } - - return { - setCache, - hasChanged, - } -} diff --git a/packages/playground/src/pages/macros/async-function.vue b/packages/playground/src/pages/macros/async-function.vue new file mode 100644 index 0000000..b645698 --- /dev/null +++ b/packages/playground/src/pages/macros/async-function.vue @@ -0,0 +1,22 @@ + + + diff --git a/packages/playground/src/pages/macros/function.vue b/packages/playground/src/pages/macros/function.vue new file mode 100644 index 0000000..b701ed7 --- /dev/null +++ b/packages/playground/src/pages/macros/function.vue @@ -0,0 +1,21 @@ + + + diff --git a/packages/playground/src/pages/macros/object.vue b/packages/playground/src/pages/macros/object.vue new file mode 100644 index 0000000..4b4dab4 --- /dev/null +++ b/packages/playground/src/pages/macros/object.vue @@ -0,0 +1,14 @@ + + + diff --git a/packages/playground/src/uni-pages.d.ts b/packages/playground/src/uni-pages.d.ts index 32a1f53..328608a 100644 --- a/packages/playground/src/uni-pages.d.ts +++ b/packages/playground/src/uni-pages.d.ts @@ -3,7 +3,7 @@ // @ts-nocheck // Generated by vite-plugin-uni-pages -export interface NavigateToOptions { +interface NavigateToOptions { url: "/pages/index" | "/pages/A-top" | "/pages/i18n" | @@ -12,13 +12,16 @@ export interface NavigateToOptions { "/pages/test" | "/pages/blog/index" | "/pages/blog/post" | + "/pages/macros/async-function" | + "/pages/macros/function" | + "/pages/macros/object" | "/pages-sub/index" | "/pages-sub/about/index" | "/pages-sub/about/your"; } interface RedirectToOptions extends NavigateToOptions {} -export interface SwitchTabOptions { +interface SwitchTabOptions { } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9ec156b..459c7a0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,12 +41,21 @@ importers: packages/core: dependencies: + '@babel/generator': + specifier: ^7.24.1 + version: 7.24.1 + '@babel/types': + specifier: ^7.24.0 + version: 7.24.0 '@uni-helper/uni-env': specifier: ^0.1.1 version: 0.1.1(typescript@5.3.3)(vitest@1.3.1) '@vue/compiler-sfc': specifier: ^3.4.21 version: 3.4.21 + ast-kit: + specifier: ^0.12.1 + version: 0.12.1 chokidar: specifier: ^3.6.0 version: 3.6.0 @@ -75,6 +84,12 @@ importers: '@antfu/utils': specifier: ^0.7.7 version: 0.7.7 + '@babel/parser': + specifier: ^7.24.1 + version: 7.24.1 + '@types/babel__generator': + specifier: ^7.6.8 + version: 7.6.8 '@types/debug': specifier: ^4.1.12 version: 4.1.12 @@ -324,11 +339,11 @@ packages: dependencies: '@ampproject/remapping': 2.3.0 '@babel/code-frame': 7.23.5 - '@babel/generator': 7.23.6 + '@babel/generator': 7.24.1 '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0) '@babel/helpers': 7.24.0 - '@babel/parser': 7.24.0 + '@babel/parser': 7.24.1 '@babel/template': 7.24.0 '@babel/traverse': 7.24.0 '@babel/types': 7.24.0 @@ -340,8 +355,8 @@ packages: transitivePeerDependencies: - supports-color - /@babel/generator@7.23.6: - resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==} + /@babel/generator@7.24.1: + resolution: {integrity: sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.0 @@ -555,8 +570,8 @@ packages: chalk: 2.4.2 js-tokens: 4.0.0 - /@babel/parser@7.24.0: - resolution: {integrity: sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==} + /@babel/parser@7.24.1: + resolution: {integrity: sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==} engines: {node: '>=6.0.0'} hasBin: true dependencies: @@ -1469,7 +1484,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.23.5 - '@babel/parser': 7.24.0 + '@babel/parser': 7.24.1 '@babel/types': 7.24.0 /@babel/traverse@7.24.0: @@ -1477,12 +1492,12 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.23.5 - '@babel/generator': 7.23.6 + '@babel/generator': 7.24.1 '@babel/helper-environment-visitor': 7.22.20 '@babel/helper-function-name': 7.23.0 '@babel/helper-hoist-variables': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 - '@babel/parser': 7.24.0 + '@babel/parser': 7.24.1 '@babel/types': 7.24.0 debug: 4.3.4 globals: 11.12.0 @@ -1566,7 +1581,7 @@ packages: '@ampproject/remapping': 2.3.0 '@babel/code-frame': 7.23.5 '@babel/core': 7.24.0 - '@babel/parser': 7.24.0 + '@babel/parser': 7.24.1 '@babel/types': 7.24.0 '@dcloudio/uni-i18n': 3.0.0-alpha-4000220240302002 '@dcloudio/uni-shared': 3.0.0-alpha-4000220240302002 @@ -1713,8 +1728,8 @@ packages: /@dcloudio/uni-mp-compiler@3.0.0-alpha-4000220240302002(postcss@8.4.35)(rollup@3.29.4)(vue@3.4.21): resolution: {integrity: sha512-kQ02IVWozEdA4gi0txiN0GgzBslG1f+hDeq8cehjXFb+Cpanj8l3yjaR5y2lao7iynsYc7TTMeplpxZ6DmlY6A==} dependencies: - '@babel/generator': 7.23.6 - '@babel/parser': 7.24.0 + '@babel/generator': 7.24.1 + '@babel/parser': 7.24.1 '@babel/types': 7.24.0 '@dcloudio/uni-cli-shared': 3.0.0-alpha-4000220240302002(postcss@8.4.35)(rollup@3.29.4)(vue@3.4.21) '@dcloudio/uni-shared': 3.0.0-alpha-4000220240302002 @@ -3615,7 +3630,7 @@ packages: /@types/babel__core@7.20.5: resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} dependencies: - '@babel/parser': 7.24.0 + '@babel/parser': 7.24.1 '@babel/types': 7.24.0 '@types/babel__generator': 7.6.8 '@types/babel__template': 7.4.4 @@ -3631,7 +3646,7 @@ packages: /@types/babel__template@7.4.4: resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} dependencies: - '@babel/parser': 7.24.0 + '@babel/parser': 7.24.1 '@babel/types': 7.24.0 dev: true @@ -4157,14 +4172,14 @@ packages: '@babel/core': 7.24.0 '@babel/helper-module-imports': 7.22.15 '@babel/helper-plugin-utils': 7.24.0 - '@babel/parser': 7.24.0 + '@babel/parser': 7.24.1 '@vue/compiler-sfc': 3.4.21 dev: true /@vue/compiler-core@3.3.11: resolution: {integrity: sha512-h97/TGWBilnLuRaj58sxNrsUU66fwdRKLOLQ9N/5iNDfp+DZhYH9Obhe0bXxhedl8fjAgpRANpiZfbgWyruQ0w==} dependencies: - '@babel/parser': 7.24.0 + '@babel/parser': 7.24.1 '@vue/shared': 3.3.11 estree-walker: 2.0.2 source-map-js: 1.0.2 @@ -4172,7 +4187,7 @@ packages: /@vue/compiler-core@3.4.21: resolution: {integrity: sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==} dependencies: - '@babel/parser': 7.24.0 + '@babel/parser': 7.24.1 '@vue/shared': 3.4.21 entities: 4.5.0 estree-walker: 2.0.2 @@ -4193,7 +4208,7 @@ packages: /@vue/compiler-sfc@3.3.11: resolution: {integrity: sha512-U4iqPlHO0KQeK1mrsxCN0vZzw43/lL8POxgpzcJweopmqtoYy9nljJzWDIQS3EfjiYhfdtdk9Gtgz7MRXnz3GA==} dependencies: - '@babel/parser': 7.24.0 + '@babel/parser': 7.24.1 '@vue/compiler-core': 3.3.11 '@vue/compiler-dom': 3.3.11 '@vue/compiler-ssr': 3.3.11 @@ -4207,7 +4222,7 @@ packages: /@vue/compiler-sfc@3.4.21: resolution: {integrity: sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ==} dependencies: - '@babel/parser': 7.24.0 + '@babel/parser': 7.24.1 '@vue/compiler-core': 3.4.21 '@vue/compiler-dom': 3.4.21 '@vue/compiler-ssr': 3.4.21 @@ -4236,7 +4251,7 @@ packages: /@vue/reactivity-transform@3.3.11: resolution: {integrity: sha512-fPGjH0wqJo68A0wQ1k158utDq/cRyZNlFoxGwNScE28aUFOKFEnCBsvyD8jHn+0kd0UKVpuGuaZEQ6r9FJRqCg==} dependencies: - '@babel/parser': 7.24.0 + '@babel/parser': 7.24.1 '@vue/compiler-core': 3.3.11 '@vue/shared': 3.3.11 estree-walker: 2.0.2 @@ -4477,6 +4492,14 @@ packages: /assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + /ast-kit@0.12.1: + resolution: {integrity: sha512-O+33g7x6irsESUcd47KdfWUrS2F6aGp9KeVJFGj0YjIznfXpBxVGjA0w+y/1OKqX4mFOfmZ9Xpf1ixPT4n9xxw==} + engines: {node: '>=16.14.0'} + dependencies: + '@babel/parser': 7.24.1 + pathe: 1.1.2 + dev: false + /asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} dev: true @@ -7018,7 +7041,7 @@ packages: engines: {node: '>=8'} dependencies: '@babel/core': 7.24.0 - '@babel/parser': 7.24.0 + '@babel/parser': 7.24.1 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 @@ -7437,7 +7460,7 @@ packages: engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@babel/core': 7.24.0 - '@babel/generator': 7.23.6 + '@babel/generator': 7.24.1 '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.24.0) '@babel/traverse': 7.24.0 '@babel/types': 7.24.0