vitarx-router 1.0.0-beta.4 → 1.0.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,6 +15,7 @@ npm install vitarx-router
15
15
  // main.ts
16
16
  import { createRouter } from 'vitarx-router'
17
17
  import Page1 from './Page/Page1.js'
18
+ import App from './App.js'
18
19
 
19
20
  createRouter({
20
21
  mode: 'path', // 路由模式,可选值:hash、path、memory
@@ -0,0 +1,19 @@
1
+ /**
2
+ * 路由路线配置
3
+ */
4
+ declare interface Route {
5
+ path: string;
6
+ name?: string;
7
+ children?: Route[];
8
+ widget?: any;
9
+ }
10
+ /**
11
+ * 生成路由索引类型声明
12
+ *
13
+ * @param {Route[]} routes - 路由表
14
+ * @param {string[]} dynamic - 动态路由参数列表
15
+ * @param {string} [writePath] - 要写入的路径,完整的路径!例如'/Users/Vitarx/vitarx/route.type.d.ts'
16
+ * @return {void}
17
+ */
18
+ export default function make(routes: Route[], dynamic?: string[], writePath?: string): void;
19
+ export {};
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
36
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
37
+ if (ar || !(i in from)) {
38
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
39
+ ar[i] = from[i];
40
+ }
41
+ }
42
+ return to.concat(ar || Array.prototype.slice.call(from));
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.default = make;
46
+ var fs = __importStar(require("node:fs"));
47
+ /**
48
+ * 格式化path
49
+ *
50
+ * @param {string} path - 路径字符串
51
+ * @return {string} - 格式化后的路径字符串
52
+ */
53
+ function formatPath(path) {
54
+ // 去除所有空格 处理重复//
55
+ path = "/".concat(path).replace(/\s+/g, '').replace(/\/+/g, '/');
56
+ if (!path.length)
57
+ return '/';
58
+ if (path === '/' || path === '/#/')
59
+ return path;
60
+ return path.replace(/\/$/, '');
61
+ }
62
+ /**
63
+ * 根据路由表生成路由索引
64
+ *
65
+ * @param {Route[]} routes - 路由表
66
+ * @return {{ paths: string[], names: string[] }} - 路由索引对象,包含所有路由路径和名称
67
+ */
68
+ function buildRouteIndex(routes) {
69
+ var paths = [];
70
+ var names = [];
71
+ // 递归遍历路由,拼接路径
72
+ function traverse(route, parentPath) {
73
+ if (parentPath === void 0) { parentPath = ''; }
74
+ // 如果是路由组,拼接路径并继续遍历子路由
75
+ var fullPath = formatPath(parentPath ? "".concat(parentPath, "/").concat(route.path) : route.path);
76
+ // 如果有widget,记录路径
77
+ if (route.widget) {
78
+ paths.push(fullPath);
79
+ }
80
+ // 如果有name,记录name
81
+ if (route.name) {
82
+ names.push(route.name);
83
+ }
84
+ // 如果有子路由,递归遍历
85
+ if (route.children && route.children.length > 0) {
86
+ route.children.forEach(function (childRoute) { return traverse(childRoute, fullPath); });
87
+ }
88
+ }
89
+ // 遍历所有的根路由
90
+ routes.forEach(function (route) { return traverse(route); });
91
+ return {
92
+ paths: paths,
93
+ names: names
94
+ };
95
+ }
96
+ /**
97
+ * 生成路由索引类型声明
98
+ *
99
+ * @param {Route[]} routes - 路由表
100
+ * @param {string[]} dynamic - 动态路由参数列表
101
+ * @param {string} [writePath] - 要写入的路径,完整的路径!例如'/Users/Vitarx/vitarx/route.type.d.ts'
102
+ * @return {void}
103
+ */
104
+ function make(routes, dynamic, writePath) {
105
+ if (dynamic === void 0) { dynamic = []; }
106
+ if (writePath === void 0) { writePath = ''; }
107
+ var _a = buildRouteIndex(routes), paths = _a.paths, names = _a.names;
108
+ var all = __spreadArray(__spreadArray(__spreadArray([], paths, true), names, true), dynamic, true);
109
+ // 构造类型声明字符串
110
+ var typeDeclaration = "type VitarxRouterRouteIndexTyped = ".concat(all.map(function (route) { return "'".concat(route, "'"); }).join(' | '), ";");
111
+ if (!writePath)
112
+ writePath = "".concat(process.cwd(), "/route.type.d.ts");
113
+ fs.writeFileSync(writePath, typeDeclaration, { encoding: 'utf-8' });
114
+ }
@@ -0,0 +1 @@
1
+ (function(a,o){typeof exports=="object"&&typeof module<"u"?o(exports,require("vitarx")):typeof define=="function"&&define.amd?define(["exports","vitarx"],o):(a=typeof globalThis<"u"?globalThis:a||self,o(a.VitarxRouter={},a.Vitarx))})(this,function(a,o){"use strict";var pt=Object.defineProperty;var Y=a=>{throw TypeError(a)};var Rt=(a,o,h)=>o in a?pt(a,o,{enumerable:!0,configurable:!0,writable:!0,value:h}):a[o]=h;var d=(a,o,h)=>Rt(a,typeof o!="symbol"?o+"":o,h),U=(a,o,h)=>o.has(a)||Y("Cannot "+h);var R=(a,o,h)=>(U(a,o,"read from private field"),h?h.call(a):o.get(a)),x=(a,o,h)=>o.has(a)?Y("Cannot add the same private member more than once"):o instanceof WeakSet?o.add(a):o.set(a,h),L=(a,o,h,V)=>(U(a,o,"write to private field"),V?V.call(a,h):o.set(a,h),h);var w,E,P,_,b;var h=(e=>(e[e.success=0]="success",e[e.aborted=1]="aborted",e[e.cancelled=2]="cancelled",e[e.duplicated=3]="duplicated",e[e.not_matched=4]="not_matched",e[e.exception=5]="exception",e))(h||{});const V=["path","hash","index","fullPath"];function q(e,t){G(e.matched,t.matched),k(e.params,t.params),k(e.query,t.query),k(e.meta,t.meta);for(const i of V)e[i]!==t[i]&&(e[i]=t[i])}function G(e,t){for(let i=0;i<t.length;i++)e[i]!==t[i]&&(e[i]=t[i]);e.length>t.length&&(e.length=t.length)}function k(e,t){const i=Object.keys(e),n=Object.keys(t);for(const s of n)Object.prototype.hasOwnProperty.call(t,s)&&(e[s]=t[s]);for(const s in i)s in t||delete e[s]}function T(e){return typeof e=="boolean"||typeof e=="function"||typeof e=="object"&&e!==null}function K(e){if(e.widget===void 0)return;if(!("injectProps"in e)){e.injectProps=S(e,!0);return}const t=e.injectProps;if(typeof t=="object")J(t)?Q(e,t):X(e,t);else if(T(t))e.injectProps=S(e,t);else throw new TypeError(`[Vitarx.Router][TYPE_ERROR]:${e.path} 路由线路配置的 injectProps 类型有误,它可以是布尔值、函数,亦或是一个{string:any}类型的对象。`)}function J(e){return Object.keys(e).length===1&&"default"in e}function Q(e,t){if(!T(t.default))throw new TypeError(`[Vitarx.Router][TYPE_ERROR]:${e.path} 路由线路配置的 injectProps.default 类型有误,它可以是布尔值、函数,亦或是一个{string:any}类型的对象。`)}function X(e,t){for(const i of Object.keys(e.widget))if(i in t){if(!T(t[i]))throw new TypeError(`[Vitarx.Router][TYPE_ERROR]:${e.path} 路由线路配置的 injectProps.${i} 类型有误,它可以是布尔值、函数,亦或是一个{string:any}类型的对象。`)}else t[i]=!0}function S(e,t){const i={};for(const n of Object.keys(e.widget))i[n]=t;return i}function Z(e){if(!("widget"in e)){if(e.children.length===0)throw new TypeError(`[Vitarx.Router][TYPE_ERROR]:${e.path} 路由线路配置的 widget 属性缺失,它可以是函数式小部件、类小部件,亦或是一个惰性加载器。`);e.widget=void 0;return}if(typeof e.widget=="function")e.widget={default:e.widget};else if(typeof e.widget=="object"&&e.widget!==null){if(Object.keys(e.widget).length===0)e.widget=void 0;else for(const t in e.widget)if(typeof e.widget[t]!="function")throw new TypeError(`[Vitarx.Router][TYPE_ERROR]:${e.path} 路由线路配置的 widget 命名视图 ${t} 类型有误,它可以是函数式小部件、类小部件,亦或是一个惰性加载器。`)}else throw new TypeError(`[Vitarx.Router][TYPE_ERROR]:${e.path} 路由线路配置的 widget 类型有误,它可以是函数式小部件、类小部件,亦或是一个惰性加载器。`)}const W=Symbol("LazyLoader");function j(e){return/\{[^}]+}/.test(e)}function N(e){const t=e.replace(/\s+/g,""),i=/\{[\w-]+\?}/g,n=t.match(i);return n?n.length:0}function A(e){return"children"in e&&e.children!==void 0&&e.children.length>0}function tt(e,t,i,n){let s=0;const r=(f,u)=>{const O=t[f];if(O?O instanceof RegExp||(console.warn(`[Vitarx.Router][WARN]:${e} 动态路径${f}变量的自定义正则表达式必须是 RegExp 类型`),t[f]=n):t[f]=n,u)return s++,`(?:(${t[f].source}))?`;if(s)throw new Error(`[Vitarx.Router][ERROR]:动态路径 ${e} 中,可选变量 ${f} 后不能存在任何必填变量`);return`(${t[f].source})`},c=e.replace(/{([^}?]+)\?}/g,(f,u)=>r(u,!0)).replace(/{([^}]+)}/g,(f,u)=>r(u,!1)).replace(/\//g,"\\/").replace(/\/?$/,"/?"),p=i?"":"i",l=e.replace(/^\/|\/$/g,"").split("/").length;return{regex:new RegExp(`^${c}$`,p),length:l,optional:s}}function g(e){return e=`/${e}`.replace(/\s+/g,"").replace(/\/+/g,"/"),e.length?e==="/"||e==="/#/"?e:e.replace(/\/$/,""):"/"}function C(e,t){if(!j(e))return e;const i=e;return e=e.replace(/{([^}]+)\?*}/g,(n,s)=>{const r=s.endsWith("?");if(r&&(s=s.slice(0,-1)),t[s]===void 0){if(r)return"";throw new TypeError(`[Vitarx.Router.mergePathParams] 访问路由${i}时缺少参数:${s}`)}return String(t[s]).replace(/\s+/g,"_")}),g(e)}function et(e){return typeof e=="function"&&e[W]}function D(e,t){return typeof e!="string"||!e?"":(e=e.trim(),e.startsWith("#")?e:`#${e}`)}function z(e){e=decodeURIComponent(e);const t=new URLSearchParams(e.startsWith("?")?e.substring(1):e),i={};return t.forEach((n,s)=>i[s]=n),i}function it(e){const t=new URLSearchParams(e).toString();return t?`?${t}`:""}function nt(e,t,i){let n=decodeURIComponent(e.pathname),s=decodeURIComponent(e.hash),r=z(e.search);if(n=g(n.startsWith(i)?n.slice(i.length):n),t==="hash"&&s.includes("#/")){const c=s.slice(1),[p,l]=c.split("#"),[f,u]=p.split("?");n=g(f||""),s=l?`#${l}`:"",r=z(u||"")}return{index:n,hash:s,query:r}}function st(e){const t=M(e);return t&&(e=e.slice(0,-t.length)),{path:e,suffix:t}}function M(e){const t=e.match(/^(.*?)(\.[a-zA-Z0-9]+)$/);return t?t[2]:""}function ot(e){if(typeof e!="object"||e===null)return!1;const t=["index","fullPath","path","hash","params","query","matched","meta"];for(const i of t)if(!Object.prototype.hasOwnProperty.call(e,i))return!1;return!0}function rt(e){if(e.meta=e.meta||{},e.pattern=e.pattern||{},e.children=e.children||[],!Array.isArray(e.children))throw new TypeError(`[Vitarx.Router][TYPE_ERROR]:${e.path} 路由线路配置 children 类型错误,它必须是数组类型。`);if(!e.path.trim())throw new TypeError("[Vitarx.Router][TYPE_ERROR]:路由线路配置 path 不能为空");return e.path=g(e.path),Z(e),K(e),e}const y=class y{constructor(t){d(this,"_options");d(this,"_namedRoutes",new Map);d(this,"_dynamicRoutes",new Map);d(this,"_pathRoutes",new Map);d(this,"_parentRoute",new WeakMap);d(this,"_currentTaskId",null);d(this,"_taskCounter",0);d(this,"_pendingReplace",null);d(this,"_pendingPush",null);d(this,"_scrollBehaviorHandler");d(this,"_currentRouteLocation");d(this,"_isBrowser",typeof window<"u"&&typeof window.document<"u");d(this,"_scrollBehavior","auto");if(R(y,w))throw new Error("[Vitarx.Router.constructor]:路由器实例已存在,不能创建多个实例");this._options={base:"/",strict:!1,mode:"path",scrollBehavior:"smooth",suffix:!1,pattern:/[\w.]+/,...t},this._options.base=`/${this._options.base.replace(/^\/+|\/+$/g,"")}`,this._currentRouteLocation=o.reactive({index:this._options.base,path:this._options.base,hash:"",fullPath:this._options.base,params:{},query:{},matched:o.shallowReactive([]),meta:o.markRaw({})})}static get instance(){if(!R(y,w))throw new Error("[Vitarx.Router.instance]:路由器实例未初始化");return R(y,w)}get isBrowser(){return this._isBrowser}get scrollBehavior(){return this._scrollBehavior}get options(){return this._options}get mode(){return this._options.mode}get pathRoutes(){return this._pathRoutes}get namedRoutes(){return this._namedRoutes}get dynamicRoutes(){return this._dynamicRoutes}get routes(){return this._options.routes}get basePath(){return this._options.base}get initialized(){return R(y,w)!==void 0}get suffix(){return this._options.suffix}get currentRouteLocation(){return this._currentRouteLocation}get isPendingNavigation(){return!!(this._pendingReplace||this._pendingPush)}get pendingReplaceData(){return this._pendingReplace}get pendingPushData(){return this._pendingPush}static routeView(t,i){const n=t.widget;if(!Object.prototype.hasOwnProperty.call(n,i))return;const s=n[i];return et(s)?o.createElement(o.LazyWidget,{children:s,key:t.path}):o.createElement(s)}back(){return this.go(-1)}forward(){return this.go(1)}replace(t){return typeof t=="string"?this.navigate({index:t,isReplace:!0}):(t.isReplace=!0,this.navigate(t))}push(t){return typeof t=="string"?this.navigate({index:t,isReplace:!1}):(t.isReplace=!1,this.navigate(t))}removeRoute(t,i=!0){const n=this.findRoute(t);if(n){if(A(n))for(const s of n.children)this.removeRoute(s.path,!1);this._pathRoutes.delete(n.path),n.name&&this._namedRoutes.delete(n.name),this.removeDynamicRoute(n.path),i&&this.removedFromRoutes(n)}}addRoute(t,i){if(i){const n=this.findRoute(i);if(!n)throw new Error(`[Vitarx.Router.addRoute][ERROR]:父路由${i}不存在`);this.registerRoute(t,n)}else this.registerRoute(t),this._options.routes.push(t)}findRoute(t){const i=typeof t=="object",n=i?t.index:t;if(typeof n!="string")throw new TypeError(`[Vitarx.Router.getRoute][ERROR]:路由索引${t}类型错误,必须给定字符串类型`);if(n.startsWith("/")){const s=this.matchRoute(n);return s?(s.params&&i&&(t.params=Object.assign(t.params||{},s.params)),s.route):void 0}return this.findNamedRoute(n)}findNamedRoute(t){return this._namedRoutes.get(t)}initialize(){return R(y,w)?this:(this.setupRoutes(this._options.routes),typeof this.options.scrollBehavior=="function"?this._scrollBehaviorHandler=this.options.scrollBehavior:this._scrollBehavior=this.options.scrollBehavior,this.initializeRouter(),L(y,w,this),this)}scrollTo(t){if(!(this.isBrowser||!t||typeof t!="object")){if("el"in t){const{el:i,...n}=t,s=typeof i=="string"?document.querySelector(i):i;s&&s instanceof Element?s.scrollIntoView?s.scrollIntoView({behavior:this.scrollBehavior,...n}):window.scrollTo({behavior:this.scrollBehavior,top:s.getBoundingClientRect().top+window.scrollY,left:s.getBoundingClientRect().left+window.scrollX}):console.warn(`[Vitarx.Router.scrollTo][WARN]:元素${i}不存在,无法完成滚动到目标元素操作`);return}window.scrollTo({behavior:this.scrollBehavior,...t})}}findParentRoute(t){return this._parentRoute.get(t)}createRouteLocation(t){if(ot(t))return t;const i=this.findRoute(t),{index:n,query:s={},params:r={},hash:c=""}=t;let p;const l=[];if(i){let I=M(n);this.suffix&&I&&!i.path.endsWith(I)?p=C(i.path+I,r):p=C(i.path,r);let $=this.findParentRoute(i);for(;$;)$.widget&&l.unshift($),$=this.findParentRoute($);l.push(i)}else p=g(n);const f=(i==null?void 0:i.meta)||{},u=D(c),O=this.makeFullPath(p,s,u);return{index:n,path:p,hash:u,fullPath:O,params:r,query:s,matched:l,meta:f}}navigate(t){const i=++this._taskCounter;this._currentTaskId=i;const n=()=>this._currentTaskId===i,s=o.deepClone(this.currentRouteLocation),r=async(c,p)=>{const l=this.createRouteLocation(c),f=(u={})=>({from:s,to:l,status:h.success,message:"导航成功",redirectFrom:p?t:void 0,...u});if(this.isSameNavigate(l,this.currentRouteLocation))return f({status:h.duplicated,message:"导航到相同的路由,被系统阻止!"});try{const u=await this.onBeforeEach(l,this.currentRouteLocation);return u===!1?f({status:h.aborted,message:"导航被前置守卫钩子阻止"}):n()?typeof u=="object"&&u.index!==c.index?(u.isReplace??(u.isReplace=!1),r(u,!0)):l.matched.length?(c.isReplace?(this._pendingReplace=l,this.replaceHistory(l)):(this._pendingPush=l,this.pushHistory(l)),f()):f({status:h.not_matched,message:"未匹配到任何路由规则,被系统阻止!请检测目标索引是否正确。"}):f({status:h.cancelled,message:"已被新的导航请求替代,取消此次导航!"})}catch(u){return console.error("[Vitarx.Router.navigate][ERROR]:导航时捕获到了异常",u),f({status:h.exception,message:"导航时捕获到了异常",error:u})}};return r(t,!1)}_completeViewRender(){}completeNavigation(t,i){const n=this._currentRouteLocation;if(this._completeViewRender=()=>{this.onScrollBehavior(this.currentRouteLocation,n,i).then(),this.onAfterEach(this.currentRouteLocation,n)},t)this.updateRouteLocation(t);else if(this._pendingReplace)this.updateRouteLocation(this._pendingReplace);else if(this._pendingPush)this.updateRouteLocation(this._pendingPush);else throw new Error("[Vitarx.Router.completeNavigation][ERROR]:没有处于等待状态的导航请求。");this._pendingReplace=null,this._pendingPush=null}updateQuery(t){o.isDeepEqual(this._currentRouteLocation.query,t)||(this._currentRouteLocation.query=t,this._currentRouteLocation.fullPath=this.makeFullPath(this._currentRouteLocation.path,t,this._currentRouteLocation.hash))}updateHash(t){typeof t!="string"&&console.warn(`[Vitarx.Router.updateHash][WARN]:hash值只能是字符串类型,给定${t}`);const i=D(t);i!==this._currentRouteLocation.hash&&(this._currentRouteLocation.hash=i,this._currentRouteLocation.fullPath=this.makeFullPath(this._currentRouteLocation.path,this._currentRouteLocation.query,i))}matchRoute(t){if(t=g(t),this._options.strict||(t=t.toLowerCase()),this.suffix){const{path:s,suffix:r}=st(t);if(!this.isAllowedSuffix(r))return;t=s}if(this._pathRoutes.has(t))return{route:this._pathRoutes.get(t),params:void 0};const i=t.split("/").filter(Boolean).length,n=this._dynamicRoutes.get(i);if(n){t=`${t}/`;for(const{regex:s,route:r}of n){const c=s.exec(t);if(c){const p={};return Object.keys(r.pattern).forEach((f,u)=>{p[f]=c[u+1]}),{route:r,params:p}}}}}makeFullPath(t,i,n){return n&&!n.startsWith("#")&&(n=`#${n}`),typeof i=="object"&&(i=it(i)),this.mode==="hash"?g(`${this.basePath}/#${t}${i}${n}`):g(`${this.basePath}${t}${i}${n}`)}isSameNavigate(t,i){return o.isDeepEqual(t,i)}onBeforeEach(t,i){var n;return(n=this._options.beforeEach)==null?void 0:n.call(this,t,i)}onAfterEach(t,i){var n;return(n=this._options.afterEach)==null?void 0:n.call(this,t,i)}updateRouteLocation(t){q(this._currentRouteLocation,t)}isAllowedSuffix(t){return t?this.suffix?this.suffix==="*"?!0:Array.isArray(this.suffix)?this.suffix.includes(t):this.suffix===t:!1:!0}async onScrollBehavior(t,i,n){try{if(this._scrollBehaviorHandler){const s=await this._scrollBehaviorHandler(t,i,n);s&&this.scrollTo(s)}else this.scrollTo(n)}catch(s){console.error("[Vitarx.Router.onScrollBehavior]['ERROR']:处理滚动行为时捕获到了异常",s)}}removedFromRoutes(t){const i=this.findParentRoute(t);if(i!=null&&i.children){const n=i.children.indexOf(t);n!==-1&&i.children.splice(n,1)}else{const n=this._options.routes.indexOf(t);n!==-1&&this._options.routes.splice(n,1)}}removeDynamicRoute(t){if(!j(t))return;const n=t.split("/").filter(Boolean).length,s=c=>{const p=this._dynamicRoutes.get(c);if(p){for(let l=0;l<p.length;l++)if(p[l].route.path===t){p.splice(l,1);break}}};s(n);const r=N(t);if(r>0)for(let c=1;c<=r;c++)s(n-c)}setupRoutes(t){for(const i of t)this.registerRoute(i)}registerRoute(t,i){const n=rt(t);if(i&&(n.path=g(`${i.path}${n.path}`),this._parentRoute.set(n,i)),A(n)){t.widget&&this.recordRoute(n);for(const s of n.children)this.registerRoute(s,n)}else this.recordRoute(n)}strictPath(t){return this._options.strict?t:t.toLowerCase()}recordRoute(t){if(t.name){if(t.name.startsWith("/")&&(t.name=t.name.replace(/^\//,""),console.warn(`[Vitarx.Router][WARN]:命名路由(name)不要以/开头: ${t.name},因为内部需要使用/区分path、name`)),this._namedRoutes.has(t.name))throw new Error(`[Vitarx.Router][ERROR]:检测到重复的路由名称(name): ${t.name}`);this._namedRoutes.set(t.name,t)}const i=this.strictPath(t.path);if(this._pathRoutes.has(i))throw new Error(`[Vitarx.Router][ERROR]:检测到重复的路由路径(path): ${t.path}`);this._pathRoutes.set(i,t),j(t.path)&&this.recordDynamicRoute(t)}recordDynamicRoute(t){const{regex:i,length:n,optional:s}=tt(t.path,t.pattern,this.options.strict,this.options.pattern),r=c=>{this._dynamicRoutes.has(c)||this._dynamicRoutes.set(c,[]),this._dynamicRoutes.get(c).push({regex:i,route:t})};if(r(n),s>0)for(let c=1;c<=s;c++)r(n-c)}};w=new WeakMap,x(y,w);let m=y;class F extends m{constructor(t){super(t),["path","hash"].includes(t.mode)&&(t.mode="path"),t.mode==="hash"&&this.ensureHash()}get currentRouteTarget(){return nt(window.location,this.mode,this.basePath)}get webHistory(){return window.history}go(t){this.webHistory.go(t)}initializeRouter(){window.addEventListener("popstate",this.onPopState.bind(this)),this.replace(this.currentRouteTarget).then()}pushHistory(t){this.saveCurrentScrollPosition(),this.webHistory.pushState(this.createState(t),"",t.fullPath),this.completeNavigation(t)}replaceHistory(t){var n;const i=(n=this.webHistory.state)==null?void 0:n.scrollPosition;this.webHistory.replaceState(this.createState(t),"",t.fullPath),this.completeNavigation(t,i)}saveCurrentScrollPosition(){const t={left:window.scrollX,top:window.scrollY,behavior:this.scrollBehavior};this.webHistory.replaceState({...this.webHistory.state,scrollPosition:t},"",window.location.href)}createState(t,i,n){const{matched:s,...r}=t;return typeof i=="string"&&(r.hash=i),typeof n=="object"&&(r.query=n),JSON.parse(JSON.stringify(r))}onPopState(t){var n;let i;(n=t.state)!=null&&n.index?i={index:t.state.index,hash:t.state.hash,query:t.state.query}:i=this.currentRouteTarget,this.replace(i).then(s=>{if(!s.redirectFrom&&this.mode==="hash"&&s.status!==h.success)if(s.status===h.not_matched){if(s.to.index.startsWith("/")){const r=s.to.index.slice(1),c=window.document.getElementById(r);c&&c.scrollIntoView({behavior:this.scrollBehavior}),this.updateHash(`#${r}`),this.webHistory.replaceState(this.createState(this.currentRouteLocation),"",this.currentRouteLocation.fullPath)}}else s.status===h.duplicated&&this.webHistory.replaceState(this.createState(this.currentRouteLocation),"",this.currentRouteLocation.fullPath)})}ensureHash(){const{pathname:t,search:i,hash:n}=window.location;if(!t.startsWith(this.basePath)){const s=`${this.basePath}/#${t}${i}${n}`;return window.location.replace(s)}}}class B extends m{constructor(i){super(i);d(this,"_history",[]);d(this,"_pendingGo",null);d(this,"_currentIndex",0);i.mode="memory"}get currentIndex(){return this._currentIndex}go(i){if(!i)return;const n=this.currentIndex,s=Math.max(0,Math.min(this._history.length-1,n+i));if(s===n)return;const r=this._history[s];this._pendingGo=s,this.navigate(r).then(c=>{c.status!==h.success&&(this._pendingGo=null)})}initializeRouter(){this._history.push(this.currentRouteLocation)}pushHistory(i){this._updateHistory(i,!1)}replaceHistory(i){this._updateHistory(i,!0)}_updateHistory(i,n){let s;if(this._pendingGo!==null)this._history[this._pendingGo]=i,s=this._pendingGo;else if(n)this._history[this.currentIndex]=i,s=this.currentIndex;else{const r=this.currentIndex+1;r<this._history.length?(this._history[r]=i,this._history.length=r+1,s=r):(this._history.push(i),s=this._history.length-1)}this._currentIndex=s,this.completeNavigation(i),this._pendingGo=null}}function at(...e){return e}function ct(e){return e}function ht(e){let t;return!(window!=null&&window.location)&&e.mode!=="memory"?(console.warn("当前环境非浏览器端,强制使用内存模式路由"),e.mode="memory",new B(e).initialize()):(e.mode==="memory"?t=new B(e):t=new F(e),t.initialize())}function ut(){return m.instance}function lt(){return m.instance.currentRouteLocation}function ft(e){return e[W]=!0,e}const v=class v extends o.Widget{constructor(i){super(i);x(this,P);x(this,_);x(this,b,o.shallowRef());const n=o.inject(R(v,E),-1,this);L(this,P,n+1),o.provide(R(v,E),R(this,P),this),L(this,_,this.matchedRoute),R(this,_)&&(R(this,b).value=m.routeView(R(this,_),this.name)),o.watch(this.location.matched,(s,r)=>{const c=r[this.index];c!==R(this,_)&&(L(this,_,c),R(this,b).value=c?m.routeView(c,this.name):void 0)})}get index(){return R(this,P)}get isLastView(){return this.index===this.location.matched.length-1&&this.name==="default"}get name(){return this.props.name||"default"}get matchedRoute(){return this.location.matched[R(this,P)]}get currentElement(){return R(this,b).value}get location(){return m.instance.currentRouteLocation}onMounted(){this.completeViewRender()}onUpdated(){this.completeViewRender()}build(){return this.currentElement||o.createElement(o.Fragment)}completeViewRender(){this.isLastView&&m.instance._completeViewRender()}};E=new WeakMap,P=new WeakMap,_=new WeakMap,b=new WeakMap,x(v,E,Symbol("RouterViewCounter"));let H=v;class dt extends o.Widget{constructor(i){super(i);d(this,"target");d(this,"location");d(this,"active");d(this,"htmlProps");this.target=new o.Computed(()=>o.markRaw(o.isString(i.to)?{index:i.to}:i.to)),this.location=new o.Computed(()=>{const n=m.instance.createRouteLocation(this.target.value);return n.matched.length||console.trace(`[Vitarx.RouterLink][WARN]:索引:${this.target.value.index},未匹配到任何有效的路由线路,请检查to属性是否配置正确!`),o.markRaw(n)}),this.active=new o.Computed(()=>this.location.value.fullPath===m.instance.currentRouteLocation.fullPath),this.htmlProps=new o.Computed(()=>{const n={href:this.href,onClick:s=>this.navigate(s),children:this.children,style:this.props.style,class:this.props.class};return this.isActive&&(n.active=!0),this.isDisabled&&(n.disabled=!0),n})}get isActive(){return this.active.value&&!this.isDisabled}get isDisabled(){return this.props.disabled??!1}get href(){return this.location.value.fullPath}navigate(i){i.stopPropagation(),i.preventDefault(),!this.isDisabled&&m.instance.navigate(this.location.value).then()}build(){return o.createElement("a",this.htmlProps.value)}}a.MemoryRouter=B,a.NavigateStatus=h,a.Router=m,a.RouterLink=dt,a.RouterView=H,a.WebHistoryRouter=F,a.createRouter=ht,a.defineRoute=ct,a.defineRoutes=at,a.lazy=ft,a.useRoute=lt,a.useRouter=ut,Object.defineProperty(a,Symbol.toStringTag,{value:"Module"})});
package/package.json CHANGED
@@ -1,13 +1,18 @@
1
1
  {
2
2
  "name": "vitarx-router",
3
- "version": "1.0.0-beta.4",
3
+ "version": "1.0.0-beta.6",
4
+ "description": "Vitarx前端框架的配套路由器",
4
5
  "type": "module",
5
- "main": "dist/vitarx-router.js",
6
- "types": "dist/vitarx-router.d.ts",
6
+ "main": "dist/vitarx-router.umd.js",
7
+ "module": "dist/vitarx-router.es.js",
8
+ "types": "dist/vitarx-router.es.d.ts",
7
9
  "scripts": {
8
10
  "dev": "vite --force",
9
- "build:lib": "rimraf dist && tsc --p tsconfig-lib.json && vite --config vite.config.lib.ts build",
10
- "build": "rimraf dist-web && vite build",
11
+ "tsc:lib": "tsc --p tsconfig-lib.json",
12
+ "vite:lib": "vite --config vite.config.lib.ts build",
13
+ "build:script": "tsc scripts/type-make.ts --declaration --outDir ./dist/scripts --esModuleInterop",
14
+ "build:lib": "rimraf dist && npm run tsc:lib && npm run vite:lib && npm run build:script",
15
+ "build:web": "rimraf dist-web && vite build",
11
16
  "preview": "vite preview",
12
17
  "prepublishOnly": "npm run build:lib",
13
18
  "push": "npm publish --access=public"
@@ -25,7 +30,6 @@
25
30
  },
26
31
  "files": [
27
32
  "dist",
28
- "type-make.js",
29
33
  "LICENSE",
30
34
  "README.md"
31
35
  ]
package/type-make.js DELETED
@@ -1,74 +0,0 @@
1
- import * as fs from 'node:fs'
2
-
3
- /**
4
- * 格式化path
5
- *
6
- * @param {string} path - 路径字符串
7
- * @return {string} - 格式化后的路径字符串
8
- */
9
- function formatPath(path) {
10
- // 去除所有空格 处理重复//
11
- path = `/${path}`.replace(/\s+/g, '').replace(/\/+/g, '/')
12
- if (!path.length) return '/'
13
- if (path === '/' || path === '/#/') return path
14
- return path.replace(/\/$/, '')
15
- }
16
-
17
- /**
18
- * 根据路由表生成路由索引
19
- *
20
- * @param {Route[]} routes - 路由表
21
- * @return {{ paths: string[], names: string[] }} - 路由索引对象,包含所有路由路径和名称
22
- */
23
- function buildRouteIndex(routes) {
24
- const paths = []
25
- const names = []
26
-
27
- // 递归遍历路由,拼接路径
28
- function traverse(route, parentPath = '') {
29
- // 如果是路由组,拼接路径并继续遍历子路由
30
- const fullPath = formatPath(parentPath ? `${parentPath}/${route.path}` : route.path)
31
-
32
- // 如果有widget,记录路径
33
- if (route.widget) {
34
- paths.push(fullPath)
35
- }
36
- // 如果有name,记录name
37
- if (route.name) {
38
- names.push(route.name)
39
- }
40
- // 如果有子路由,递归遍历
41
- if (route.children && route.children.length > 0) {
42
- route.children.forEach(childRoute => traverse(childRoute, fullPath))
43
- }
44
- }
45
-
46
- // 遍历所有的根路由
47
- routes.forEach(route => traverse(route))
48
- return {
49
- paths,
50
- names
51
- }
52
- }
53
-
54
- // 这个是你可能用来写文件的工具(根据实际情况实现)
55
- function writeToFile(fileName, content) {
56
- fs.writeFileSync(fileName, content, { encoding: 'utf-8' })
57
- }
58
-
59
- /**
60
- * 生成路由索引类型声明
61
- *
62
- * @param {Route[]} routes - 路由表
63
- * @param {string[]} dynamic - 动态路由参数列表
64
- * @param {string} [writePath] - 要写入的路径,完整的路径!例如'/Users/Vitarx/vitarx/route.type.d.ts'
65
- * @return {void}
66
- */
67
- export default function typeMake(routes, dynamic = [], writePath = '') {
68
- const { paths, names } = buildRouteIndex(routes)
69
- const all = [...paths, ...names, ...dynamic]
70
- // 构造类型声明字符串
71
- const typeDeclaration = `type VitarxRouterRouteIndexTyped = ${all.map(route => `'${route}'`).join(' | ')};`
72
- if (!writePath) writePath = `${process.cwd()}/route.type.d.ts`
73
- writeToFile(writePath, typeDeclaration)
74
- }
File without changes