]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
feat: expose experimental package
authorEduardo San Martin Morote <posva13@gmail.com>
Wed, 23 Jul 2025 15:25:00 +0000 (17:25 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Wed, 23 Jul 2025 15:25:00 +0000 (17:25 +0200)
17 files changed:
package.json
packages/router/package.json
packages/router/src/experimental/index.ts
packages/router/src/experimental/route-resolver/index.ts [moved from packages/router/src/new-route-resolver/index.ts with 100% similarity]
packages/router/src/experimental/route-resolver/matcher-location.ts [moved from packages/router/src/new-route-resolver/matcher-location.ts with 96% similarity]
packages/router/src/experimental/route-resolver/matcher-pattern.spec.ts [moved from packages/router/src/new-route-resolver/matcher-pattern.spec.ts with 100% similarity]
packages/router/src/experimental/route-resolver/matcher-pattern.ts [moved from packages/router/src/new-route-resolver/matcher-pattern.ts with 100% similarity]
packages/router/src/experimental/route-resolver/matcher-resolve.spec.ts [moved from packages/router/src/new-route-resolver/matcher-resolve.spec.ts with 100% similarity]
packages/router/src/experimental/route-resolver/matchers/errors.ts [moved from packages/router/src/new-route-resolver/matchers/errors.ts with 100% similarity]
packages/router/src/experimental/route-resolver/matchers/test-utils.ts [moved from packages/router/src/new-route-resolver/matchers/test-utils.ts with 100% similarity]
packages/router/src/experimental/route-resolver/resolver-static.spec.ts [moved from packages/router/src/new-route-resolver/resolver-static.spec.ts with 100% similarity]
packages/router/src/experimental/route-resolver/resolver-static.ts [moved from packages/router/src/new-route-resolver/resolver-static.ts with 97% similarity]
packages/router/src/experimental/route-resolver/resolver.spec.ts [moved from packages/router/src/new-route-resolver/resolver.spec.ts with 100% similarity]
packages/router/src/experimental/route-resolver/resolver.test-d.ts [moved from packages/router/src/new-route-resolver/resolver.test-d.ts with 100% similarity]
packages/router/src/experimental/route-resolver/resolver.ts [moved from packages/router/src/new-route-resolver/resolver.ts with 98% similarity]
packages/router/src/experimental/router.ts
packages/router/src/navigationGuards.ts

index ecb70d01c4340d742f492deaa513b9eba1f5986b..f75c8aca74143a89dfa369dc008658555d05136a 100644 (file)
@@ -74,6 +74,7 @@
     },
     "onlyBuiltDependencies": [
       "chromedriver",
+      "esbuild",
       "geckodriver"
     ]
   },
index c136b0025d6e6b891b2cbad61dd3f8bb35171682..40a7e95a20f4aadbf7db7f1d5f7ae2a8cc0adb91 100644 (file)
@@ -27,6 +27,7 @@
     "./dist/*": "./dist/*",
     "./vetur/*": "./vetur/*",
     "./package.json": "./package.json",
+    "./experimental": "./dist/experimental/index.mjs",
     "./auto-routes": {
       "types": "./vue-router-auto-routes.d.ts",
       "node": {
@@ -79,8 +80,8 @@
   "homepage": "https://router.vuejs.org",
   "files": [
     "index.js",
-    "dist/*.{js,cjs,mjs}",
-    "dist/vue-router.d.{ts,mts}",
+    "dist/**/*.{js,cjs,mjs}",
+    "dist/**/*.d.{ts,mts}",
     "vue-router-auto.d.ts",
     "vue-router-auto-routes.d.ts",
     "vetur/tags.json",
index 2f16ccb4f490f345df38f683ff22b815709df857..30ec7c68e7b41791b27836401c0bfa8ab8318c1c 100644 (file)
@@ -1,6 +1,27 @@
-export { experimental_createRouter } from './router'
+export { experimental_createRouter, normalizeRouteRecord } from './router'
 export type {
+  EXPERIMENTAL_Router_Base,
   EXPERIMENTAL_Router,
   EXPERIMENTAL_RouteRecordNormalized,
+  EXPERIMENTAL_RouterOptions_Base,
   EXPERIMENTAL_RouterOptions,
+  EXPERIMENTAL_RouteRecordRaw,
+  EXPERIMENTAL_RouteRecord_Base,
+  EXPERIMENTAL_RouteRecord_Group,
+  EXPERIMENTAL_RouteRecordNormalized_Group,
+  EXPERIMENTAL_RouteRecord_Matchable,
+  EXPERIMENTAL_RouteRecordNormalized_Matchable,
 } from './router'
+
+export { createStaticResolver } from './route-resolver/resolver-static'
+export {
+  MatcherPatternPathDynamic,
+  MatcherPatternPathStatic,
+  MatcherPatternPathStar,
+} from './route-resolver/matcher-pattern'
+export type {
+  MatcherPattern,
+  MatcherPatternHash,
+  MatcherPatternPath,
+  MatcherPatternQuery,
+} from './route-resolver/matcher-pattern'
similarity index 96%
rename from packages/router/src/new-route-resolver/matcher-location.ts
rename to packages/router/src/experimental/route-resolver/matcher-location.ts
index ec1431cf8a807697aa41f81adeca3ad9b1c3a92a..8d955b7bc892eec8f1428fc8c5937beb804169da 100644 (file)
@@ -1,4 +1,4 @@
-import type { LocationQueryRaw } from '../query'
+import type { LocationQueryRaw } from '../../query'
 import type { RecordName } from './resolver'
 
 // FIXME: rename to ResolverLocation... instead of MatcherLocation... since they are returned by a resolver
similarity index 97%
rename from packages/router/src/new-route-resolver/resolver-static.ts
rename to packages/router/src/experimental/route-resolver/resolver-static.ts
index 8c67f6693749642fc1aa8327b263dd66940dc8df..0150aa90d755f1de7fabbb071c8aef00fe84723f 100644 (file)
@@ -1,10 +1,10 @@
-import { normalizeQuery, parseQuery, stringifyQuery } from '../query'
+import { normalizeQuery, parseQuery, stringifyQuery } from '../../query'
 import {
   LocationNormalized,
   NEW_stringifyURL,
   parseURL,
   resolveRelativePath,
-} from '../location'
+} from '../../location'
 import {
   MatcherLocationAsNamed,
   MatcherLocationAsPathAbsolute,
@@ -53,7 +53,7 @@ export interface EXPERIMENTAL_ResolverRecord_Base {
   // TODO: here or in router
   // redirect?: RouteRecordRedirectOption
 
-  parent?: EXPERIMENTAL_ResolverRecord // the parent can be matchable or not
+  parent?: EXPERIMENTAL_ResolverRecord | null // the parent can be matchable or not
   // TODO: implement aliases
   // aliasOf?: this
 }
@@ -79,7 +79,7 @@ export type EXPERIMENTAL_ResolverRecord<T = {}> =
   | (EXPERIMENTAL_ResolverRecord_Matchable & T)
   | (EXPERIMENTAL_ResolverRecord_Group & T)
 
-export type EXPERIMENTAL_ResolverStaticRecord<T> =
+export type EXPERIMENTAL_ResolverStaticRecord<T = {}> =
   EXPERIMENTAL_ResolverRecord<T>
 
 export interface EXPERIMENTAL_ResolverStatic<TRecord>
similarity index 98%
rename from packages/router/src/new-route-resolver/resolver.ts
rename to packages/router/src/experimental/route-resolver/resolver.ts
index fde6f38f7cc2892bd0667a6277ff63b24ca8f187..f6fca8e58c38e8cd36880c8979ce651122237528 100644 (file)
@@ -3,21 +3,24 @@ import {
   normalizeQuery,
   parseQuery,
   stringifyQuery,
-} from '../query'
+} from '../../query'
 import type {
   MatcherPattern,
   MatcherPatternHash,
   MatcherPatternPath,
   MatcherPatternQuery,
 } from './matcher-pattern'
-import { warn } from '../warning'
-import { encodeQueryValue as _encodeQueryValue, encodeParam } from '../encoding'
+import { warn } from '../../warning'
+import {
+  encodeQueryValue as _encodeQueryValue,
+  encodeParam,
+} from '../../encoding'
 import {
   LocationNormalized,
   NEW_stringifyURL,
   parseURL,
   resolveRelativePath,
-} from '../location'
+} from '../../location'
 import type {
   MatcherLocationAsNamed,
   MatcherLocationAsPathAbsolute,
@@ -25,8 +28,8 @@ import type {
   MatcherLocationAsRelative,
   MatcherParamsFormatted,
 } from './matcher-location'
-import { _RouteRecordProps } from '../typed-routes'
-import { comparePathParserScore } from '../matcher/pathParserRanker'
+import { _RouteRecordProps } from '../../typed-routes'
+import { comparePathParserScore } from '../../matcher/pathParserRanker'
 
 /**
  * Allowed types for a matcher name.
index 60a70d5892d229d3cea07f42fb752e153ea10383..2f9cb34216d2fda0d0f2962004b4ce330a4086a3 100644 (file)
@@ -22,7 +22,6 @@ import {
   type RouterHistory,
 } from '../history/common'
 import type { PathParserOptions } from '../matcher'
-import { type NEW_LocationResolved } from '../new-route-resolver/resolver'
 import {
   parseQuery as originalParseQuery,
   stringifyQuery as originalStringifyQuery,
@@ -39,6 +38,7 @@ import {
 } from '../scrollBehavior'
 import type {
   _RouteRecordProps,
+  NavigationGuard,
   NavigationGuardWithThis,
   NavigationHookAfter,
   RouteLocation,
@@ -79,9 +79,11 @@ import {
   routerViewLocationKey,
 } from '../injectionSymbols'
 import {
+  EXPERIMENTAL_ResolverRecord_Base,
+  EXPERIMENTAL_ResolverRecord_Group,
+  EXPERIMENTAL_ResolverRecord_Matchable,
   EXPERIMENTAL_ResolverStatic,
-  EXPERIMENTAL_ResolverStaticRecord,
-} from '../new-route-resolver/resolver-static'
+} from './route-resolver/resolver-static'
 
 /**
  * resolve, reject arguments of Promise constructor
@@ -177,33 +179,183 @@ export interface EXPERIMENTAL_RouterOptions_Base extends PathParserOptions {
   // linkInactiveClass?: string
 }
 
+// TODO: non matchable and parent
+/**
+ * Internal type for common properties among all kind of {@link RouteRecordRaw}.
+ */
+export interface EXPERIMENTAL_RouteRecord_Base
+  extends EXPERIMENTAL_ResolverRecord_Base {
+  // TODO:
+  /**
+   * Where to redirect if the route is directly matched. The redirection happens
+   * before any navigation guard and triggers a new navigation with the new
+   * target location.
+   */
+  // redirect?: RouteRecordRedirectOption;
+
+  // TODO:
+  /**
+   * Aliases for the record. Allows defining extra paths that will behave like a
+   * copy of the record. Allows having paths shorthands like `/users/:id` and
+   * `/u/:id`. All `alias` and `path` values must share the same params.
+   */
+  // alias?: string | string[]
+
+  // TODO:
+  /**
+   * Before Enter guard specific to this record. Note `beforeEnter` has no
+   * effect if the record has a `redirect` property.
+   */
+  // beforeEnter?:
+  //   | NavigationGuardWithThis<undefined>
+  //   | NavigationGuardWithThis<undefined>[]
+
+  /**
+   * Arbitrary data attached to the record.
+   */
+  meta?: RouteMeta
+
+  // TODO:
+  /**
+   * Array of nested routes.
+   */
+  // children?: RouteRecordRaw[]
+
+  /**
+   * Components to display when the URL matches this route. Allow using named views.
+   */
+  components?: Record<string, RawRouteComponent>
+
+  /**
+   * Parent of this component if any
+   */
+  parent?: EXPERIMENTAL_RouteRecordRaw
+
+  // TODO:
+  /**
+   * Allow passing down params as props to the component rendered by `router-view`.
+   */
+  // props?: _RouteRecordProps | Record<string, _RouteRecordProps>
+}
+
+export interface EXPERIMENTAL_RouteRecord_Matchable
+  // preserve the values from the type EXPERIMENTAL_ResolverRecord_Matchable
+  extends Omit<EXPERIMENTAL_RouteRecord_Base, 'name' | 'path' | 'parent'>,
+    EXPERIMENTAL_ResolverRecord_Matchable {
+  components: Record<string, RawRouteComponent>
+
+  parent?: EXPERIMENTAL_RouteRecordNormalized | null
+
+  redirect?: never
+}
+
+export interface EXPERIMENTAL_RouteRecord_Group
+  extends Omit<
+      EXPERIMENTAL_RouteRecord_Base,
+      // preserve the values from the type EXPERIMENTAL_ResolverRecord_Group
+      'name' | 'path' | 'query' | 'hash' | 'parent'
+    >,
+    EXPERIMENTAL_ResolverRecord_Group {
+  components?: Record<string, RawRouteComponent>
+
+  parent?: EXPERIMENTAL_RouteRecordNormalized | null
+
+  // TODO:
+  // redirect?: something
+}
+
+export type EXPERIMENTAL_RouteRecordRaw =
+  | EXPERIMENTAL_RouteRecord_Matchable
+  | EXPERIMENTAL_RouteRecord_Group
+// | RouteRecordSingleViewWithChildren
+// | RouteRecordMultipleViews
+// | RouteRecordMultipleViewsWithChildren
+// | RouteRecordRedirect
+
+export interface EXPERIMENTAL_RouteRecordNoramlized_Base {
+  /**
+   * Contains the original modules for lazy loaded components.
+   *
+   * @internal
+   */
+  mods: Record<string, unknown>
+
+  props: Record<string, _RouteRecordProps>
+
+  /**
+   * Registered leave guards
+   *
+   * @internal
+   */
+  leaveGuards: Set<NavigationGuard>
+
+  /**
+   * Registered update guards
+   *
+   * @internal
+   */
+  updateGuards: Set<NavigationGuard>
+
+  // FIXME: remove the need for these
+  instances: Record<string, unknown>
+}
+
+export interface EXPERIMENTAL_RouteRecordNormalized_Group
+  extends EXPERIMENTAL_RouteRecordNoramlized_Base,
+    EXPERIMENTAL_RouteRecord_Group {
+  meta: RouteMeta
+  parent: EXPERIMENTAL_RouteRecordNormalized | null
+}
+
 // TODO: is it worth to have 2 types for the undefined values?
+export interface EXPERIMENTAL_RouteRecordNormalized_Matchable
+  extends EXPERIMENTAL_RouteRecordNoramlized_Base,
+    EXPERIMENTAL_RouteRecord_Matchable {
+  meta: RouteMeta
+
+  parent: EXPERIMENTAL_RouteRecordNormalized | null
+
+  // TODO:
+  // redirect?: unknown
+
+  // TODO:
+  // props: Record<string, _RouteRecordProps>
+
+  components: Record<string, RawRouteComponent>
+}
+
 export type EXPERIMENTAL_RouteRecordNormalized =
-  EXPERIMENTAL_ResolverStaticRecord<{
-    /**
-     * Arbitrary data attached to the record.
-     */
-    meta: RouteMeta
-
-    // TODO:
-    redirect?: unknown
-
-    /**
-     * Allow passing down params as props to the component rendered by `router-view`.
-     */
-    props: Record<string, _RouteRecordProps>
-
-    /**
-     * {@inheritDoc RouteRecordMultipleViews.components}
-     */
-    components: Record<string, RawRouteComponent>
-
-    /**
-     * Contains the original modules for lazy loaded components.
-     * @internal
-     */
-    mods: Record<string, unknown>
-  }>
+  | EXPERIMENTAL_RouteRecordNormalized_Matchable
+  | EXPERIMENTAL_RouteRecordNormalized_Group
+
+export function normalizeRouteRecord(
+  record: EXPERIMENTAL_RouteRecord_Matchable
+): EXPERIMENTAL_RouteRecordNormalized_Matchable {
+  // we can't define mods if we want to call defineProperty later
+  const normalizedRecord: Omit<
+    EXPERIMENTAL_RouteRecordNormalized_Matchable,
+    'mods'
+  > = {
+    meta: {},
+    // must be defined as non enumerable because it contains modules
+    // mods: {},
+    props: {},
+    parent: null,
+    ...record,
+    // FIXME: to be removed
+    instances: {},
+    leaveGuards: new Set(),
+    updateGuards: new Set(),
+  }
+  // mods contain modules and shouldn't be copied,
+  // logged or anything. It's just used for internal
+  // advanced use cases like data loaders
+  Object.defineProperty(normalizedRecord, 'mods', {
+    value: {},
+  })
+
+  return normalizedRecord as EXPERIMENTAL_RouteRecordNormalized_Matchable
+}
 
 // TODO: probably need some generic types
 // <TResolver extends NEW_RouterResolver_Base>,
@@ -218,7 +370,7 @@ export interface EXPERIMENTAL_RouterOptions
    *
    * @experimental
    */
-  resolver: EXPERIMENTAL_ResolverStatic<EXPERIMENTAL_RouteRecordNormalized>
+  resolver: EXPERIMENTAL_ResolverStatic<EXPERIMENTAL_RouteRecordNormalized_Matchable>
 }
 
 /**
@@ -394,7 +546,7 @@ export interface EXPERIMENTAL_Router
   //   TRouteRecordRaw, // extends NEW_MatcherRecordRaw,
   //   TRouteRecord extends NEW_MatcherRecord,
   // >
-  extends EXPERIMENTAL_Router_Base<EXPERIMENTAL_RouteRecordNormalized> {
+  extends EXPERIMENTAL_Router_Base<EXPERIMENTAL_RouteRecordNormalized_Matchable> {
   /**
    * Original options object passed to create the Router
    */
@@ -1273,7 +1425,7 @@ export function experimental_createRouter(
  * @param matched - array of matched records
  */
 function mergeMetaFields(
-  matched: NEW_LocationResolved<EXPERIMENTAL_RouteRecordNormalized>['matched']
+  matched: EXPERIMENTAL_RouteRecordNormalized[]
 ): RouteMeta {
   return assign({} as RouteMeta, ...matched.map(r => r.meta))
 }
index e0389cd7c6bd0b9216c8617efa4ba9b1061dc24a..4904788ac9bff169b6a66eac00141a361bf475eb 100644 (file)
@@ -289,6 +289,7 @@ export function extractComponentsGuards(
         }
       }
 
+      // TODO: extract the logic relying on instances into an options-api plugin
       // skip update and leave guards if the route component is not mounted
       if (guardType !== 'beforeRouteEnter' && !record.instances[name]) continue