what-router 0.10.0 → 0.11.0

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/dist/match.js ADDED
@@ -0,0 +1,72 @@
1
+ // packages/router/src/match.js
2
+ function compilePath(path) {
3
+ const normalized = path.replace(/\([\w-]+\)\//g, "").replace(/\[\.\.\.(\w+)\]/g, (_, name) => `*:${name}`).replace(/\[(\w+)\]/g, ":$1");
4
+ const paramNames = [];
5
+ let catchAll = null;
6
+ const regexStr = normalized.split("/").map((segment) => {
7
+ if (segment.startsWith("*:")) {
8
+ catchAll = segment.slice(2);
9
+ paramNames.push(catchAll);
10
+ return "(.+)";
11
+ }
12
+ if (segment === "*") {
13
+ catchAll = "rest";
14
+ paramNames.push("rest");
15
+ return "(.+)";
16
+ }
17
+ if (segment.startsWith(":")) {
18
+ paramNames.push(segment.slice(1));
19
+ return "([^/]+)";
20
+ }
21
+ return segment.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
22
+ }).join("/");
23
+ const regex = new RegExp(`^${regexStr}$`);
24
+ return { regex, paramNames, catchAll };
25
+ }
26
+ function matchRoute(path, routes) {
27
+ const routable = routes.filter((r) => r.path);
28
+ const sorted = routable.sort((a, b) => {
29
+ const aSpecific = (a.path.match(/:/g) || []).length + (a.path.includes("*") ? 100 : 0);
30
+ const bSpecific = (b.path.match(/:/g) || []).length + (b.path.includes("*") ? 100 : 0);
31
+ return aSpecific - bSpecific;
32
+ });
33
+ for (const route of sorted) {
34
+ const { regex, paramNames } = compilePath(route.path);
35
+ const match = path.match(regex);
36
+ if (match) {
37
+ const params = {};
38
+ paramNames.forEach((name, i) => {
39
+ params[name] = decodeURIComponent(match[i + 1]);
40
+ });
41
+ return { route, params };
42
+ }
43
+ }
44
+ return null;
45
+ }
46
+ function parseQuery(search) {
47
+ const params = {};
48
+ if (!search) return params;
49
+ const qs = search.startsWith("?") ? search.slice(1) : search;
50
+ for (const pair of qs.split("&")) {
51
+ const [key, val] = pair.split("=");
52
+ if (!key) continue;
53
+ const decodedKey = decodeURIComponent(key);
54
+ const decodedVal = val ? decodeURIComponent(val) : "";
55
+ if (decodedKey in params) {
56
+ if (Array.isArray(params[decodedKey])) {
57
+ params[decodedKey].push(decodedVal);
58
+ } else {
59
+ params[decodedKey] = [params[decodedKey], decodedVal];
60
+ }
61
+ } else {
62
+ params[decodedKey] = decodedVal;
63
+ }
64
+ }
65
+ return params;
66
+ }
67
+ export {
68
+ compilePath,
69
+ matchRoute,
70
+ parseQuery
71
+ };
72
+ //# sourceMappingURL=match.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/match.js"],
4
+ "sourcesContent": ["// Isomorphic route matching \u2014 pure functions with no window/location/document\n// dependencies, so they are safe to import on the server (deploy adapter) as\n// well as in the client Router/FileRouter. Moved verbatim from index.js.\n\nexport function compilePath(path) {\n // /users/:id -> regex + param names\n // /posts/* -> catch-all\n // /[slug] -> dynamic (file-based syntax)\n // (group) -> route group (ignored in URL)\n\n // Remove route groups from path (they don't affect URL matching)\n const normalized = path\n .replace(/\\([\\w-]+\\)\\//g, '') // Remove (group)/ prefixes\n .replace(/\\[\\.\\.\\.(\\w+)\\]/g, (_, name) => `*:${name}`) // Preserve catch-all name\n .replace(/\\[(\\w+)\\]/g, ':$1'); // File-based [param] to :param\n\n const paramNames = [];\n let catchAll = null;\n\n const regexStr = normalized\n .split('/')\n .map(segment => {\n if (segment.startsWith('*:')) {\n catchAll = segment.slice(2);\n paramNames.push(catchAll);\n return '(.+)';\n }\n if (segment === '*') {\n catchAll = 'rest';\n paramNames.push('rest');\n return '(.+)';\n }\n if (segment.startsWith(':')) {\n paramNames.push(segment.slice(1));\n return '([^/]+)';\n }\n return segment.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n })\n .join('/');\n\n const regex = new RegExp(`^${regexStr}$`);\n return { regex, paramNames, catchAll };\n}\n\nexport function matchRoute(path, routes) {\n // Filter out routes without a path (layout-only routes, etc.)\n const routable = routes.filter(r => r.path);\n\n // Sort routes by specificity (more specific first)\n const sorted = routable.sort((a, b) => {\n const aSpecific = (a.path.match(/:/g) || []).length + (a.path.includes('*') ? 100 : 0);\n const bSpecific = (b.path.match(/:/g) || []).length + (b.path.includes('*') ? 100 : 0);\n return aSpecific - bSpecific;\n });\n\n for (const route of sorted) {\n const { regex, paramNames } = compilePath(route.path);\n const match = path.match(regex);\n if (match) {\n const params = {};\n paramNames.forEach((name, i) => {\n params[name] = decodeURIComponent(match[i + 1]);\n });\n return { route, params };\n }\n }\n return null;\n}\n\nexport function parseQuery(search) {\n const params = {};\n if (!search) return params;\n const qs = search.startsWith('?') ? search.slice(1) : search;\n for (const pair of qs.split('&')) {\n const [key, val] = pair.split('=');\n if (!key) continue;\n const decodedKey = decodeURIComponent(key);\n const decodedVal = val ? decodeURIComponent(val) : '';\n if (decodedKey in params) {\n // Collect repeated keys into arrays\n if (Array.isArray(params[decodedKey])) {\n params[decodedKey].push(decodedVal);\n } else {\n params[decodedKey] = [params[decodedKey], decodedVal];\n }\n } else {\n params[decodedKey] = decodedVal;\n }\n }\n return params;\n}\n"],
5
+ "mappings": ";AAIO,SAAS,YAAY,MAAM;AAOhC,QAAM,aAAa,KAChB,QAAQ,iBAAiB,EAAE,EAC3B,QAAQ,oBAAoB,CAAC,GAAG,SAAS,KAAK,IAAI,EAAE,EACpD,QAAQ,cAAc,KAAK;AAE9B,QAAM,aAAa,CAAC;AACpB,MAAI,WAAW;AAEf,QAAM,WAAW,WACd,MAAM,GAAG,EACT,IAAI,aAAW;AACd,QAAI,QAAQ,WAAW,IAAI,GAAG;AAC5B,iBAAW,QAAQ,MAAM,CAAC;AAC1B,iBAAW,KAAK,QAAQ;AACxB,aAAO;AAAA,IACT;AACA,QAAI,YAAY,KAAK;AACnB,iBAAW;AACX,iBAAW,KAAK,MAAM;AACtB,aAAO;AAAA,IACT;AACA,QAAI,QAAQ,WAAW,GAAG,GAAG;AAC3B,iBAAW,KAAK,QAAQ,MAAM,CAAC,CAAC;AAChC,aAAO;AAAA,IACT;AACA,WAAO,QAAQ,QAAQ,uBAAuB,MAAM;AAAA,EACtD,CAAC,EACA,KAAK,GAAG;AAEX,QAAM,QAAQ,IAAI,OAAO,IAAI,QAAQ,GAAG;AACxC,SAAO,EAAE,OAAO,YAAY,SAAS;AACvC;AAEO,SAAS,WAAW,MAAM,QAAQ;AAEvC,QAAM,WAAW,OAAO,OAAO,OAAK,EAAE,IAAI;AAG1C,QAAM,SAAS,SAAS,KAAK,CAAC,GAAG,MAAM;AACrC,UAAM,aAAa,EAAE,KAAK,MAAM,IAAI,KAAK,CAAC,GAAG,UAAU,EAAE,KAAK,SAAS,GAAG,IAAI,MAAM;AACpF,UAAM,aAAa,EAAE,KAAK,MAAM,IAAI,KAAK,CAAC,GAAG,UAAU,EAAE,KAAK,SAAS,GAAG,IAAI,MAAM;AACpF,WAAO,YAAY;AAAA,EACrB,CAAC;AAED,aAAW,SAAS,QAAQ;AAC1B,UAAM,EAAE,OAAO,WAAW,IAAI,YAAY,MAAM,IAAI;AACpD,UAAM,QAAQ,KAAK,MAAM,KAAK;AAC9B,QAAI,OAAO;AACT,YAAM,SAAS,CAAC;AAChB,iBAAW,QAAQ,CAAC,MAAM,MAAM;AAC9B,eAAO,IAAI,IAAI,mBAAmB,MAAM,IAAI,CAAC,CAAC;AAAA,MAChD,CAAC;AACD,aAAO,EAAE,OAAO,OAAO;AAAA,IACzB;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,WAAW,QAAQ;AACjC,QAAM,SAAS,CAAC;AAChB,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,KAAK,OAAO,WAAW,GAAG,IAAI,OAAO,MAAM,CAAC,IAAI;AACtD,aAAW,QAAQ,GAAG,MAAM,GAAG,GAAG;AAChC,UAAM,CAAC,KAAK,GAAG,IAAI,KAAK,MAAM,GAAG;AACjC,QAAI,CAAC,IAAK;AACV,UAAM,aAAa,mBAAmB,GAAG;AACzC,UAAM,aAAa,MAAM,mBAAmB,GAAG,IAAI;AACnD,QAAI,cAAc,QAAQ;AAExB,UAAI,MAAM,QAAQ,OAAO,UAAU,CAAC,GAAG;AACrC,eAAO,UAAU,EAAE,KAAK,UAAU;AAAA,MACpC,OAAO;AACL,eAAO,UAAU,IAAI,CAAC,OAAO,UAAU,GAAG,UAAU;AAAA,MACtD;AAAA,IACF,OAAO;AACL,aAAO,UAAU,IAAI;AAAA,IACvB;AAAA,EACF;AACA,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1,2 @@
1
+ function u(n){let e=n.replace(/\([\w-]+\)\//g,"").replace(/\[\.\.\.(\w+)\]/g,(t,o)=>`*:${o}`).replace(/\[(\w+)\]/g,":$1"),a=[],c=null,r=e.split("/").map(t=>t.startsWith("*:")?(c=t.slice(2),a.push(c),"(.+)"):t==="*"?(c="rest",a.push("rest"),"(.+)"):t.startsWith(":")?(a.push(t.slice(1)),"([^/]+)"):t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join("/");return{regex:new RegExp(`^${r}$`),paramNames:a,catchAll:c}}function h(n,e){let c=e.filter(r=>r.path).sort((r,s)=>{let t=(r.path.match(/:/g)||[]).length+(r.path.includes("*")?100:0),o=(s.path.match(/:/g)||[]).length+(s.path.includes("*")?100:0);return t-o});for(let r of c){let{regex:s,paramNames:t}=u(r.path),o=n.match(s);if(o){let i={};return t.forEach((p,l)=>{i[p]=decodeURIComponent(o[l+1])}),{route:r,params:i}}}return null}function f(n){let e={};if(!n)return e;let a=n.startsWith("?")?n.slice(1):n;for(let c of a.split("&")){let[r,s]=c.split("=");if(!r)continue;let t=decodeURIComponent(r),o=s?decodeURIComponent(s):"";t in e?Array.isArray(e[t])?e[t].push(o):e[t]=[e[t],o]:e[t]=o}return e}export{u as compilePath,h as matchRoute,f as parseQuery};
2
+ //# sourceMappingURL=match.min.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/match.js"],
4
+ "sourcesContent": ["// Isomorphic route matching \u2014 pure functions with no window/location/document\n// dependencies, so they are safe to import on the server (deploy adapter) as\n// well as in the client Router/FileRouter. Moved verbatim from index.js.\n\nexport function compilePath(path) {\n // /users/:id -> regex + param names\n // /posts/* -> catch-all\n // /[slug] -> dynamic (file-based syntax)\n // (group) -> route group (ignored in URL)\n\n // Remove route groups from path (they don't affect URL matching)\n const normalized = path\n .replace(/\\([\\w-]+\\)\\//g, '') // Remove (group)/ prefixes\n .replace(/\\[\\.\\.\\.(\\w+)\\]/g, (_, name) => `*:${name}`) // Preserve catch-all name\n .replace(/\\[(\\w+)\\]/g, ':$1'); // File-based [param] to :param\n\n const paramNames = [];\n let catchAll = null;\n\n const regexStr = normalized\n .split('/')\n .map(segment => {\n if (segment.startsWith('*:')) {\n catchAll = segment.slice(2);\n paramNames.push(catchAll);\n return '(.+)';\n }\n if (segment === '*') {\n catchAll = 'rest';\n paramNames.push('rest');\n return '(.+)';\n }\n if (segment.startsWith(':')) {\n paramNames.push(segment.slice(1));\n return '([^/]+)';\n }\n return segment.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n })\n .join('/');\n\n const regex = new RegExp(`^${regexStr}$`);\n return { regex, paramNames, catchAll };\n}\n\nexport function matchRoute(path, routes) {\n // Filter out routes without a path (layout-only routes, etc.)\n const routable = routes.filter(r => r.path);\n\n // Sort routes by specificity (more specific first)\n const sorted = routable.sort((a, b) => {\n const aSpecific = (a.path.match(/:/g) || []).length + (a.path.includes('*') ? 100 : 0);\n const bSpecific = (b.path.match(/:/g) || []).length + (b.path.includes('*') ? 100 : 0);\n return aSpecific - bSpecific;\n });\n\n for (const route of sorted) {\n const { regex, paramNames } = compilePath(route.path);\n const match = path.match(regex);\n if (match) {\n const params = {};\n paramNames.forEach((name, i) => {\n params[name] = decodeURIComponent(match[i + 1]);\n });\n return { route, params };\n }\n }\n return null;\n}\n\nexport function parseQuery(search) {\n const params = {};\n if (!search) return params;\n const qs = search.startsWith('?') ? search.slice(1) : search;\n for (const pair of qs.split('&')) {\n const [key, val] = pair.split('=');\n if (!key) continue;\n const decodedKey = decodeURIComponent(key);\n const decodedVal = val ? decodeURIComponent(val) : '';\n if (decodedKey in params) {\n // Collect repeated keys into arrays\n if (Array.isArray(params[decodedKey])) {\n params[decodedKey].push(decodedVal);\n } else {\n params[decodedKey] = [params[decodedKey], decodedVal];\n }\n } else {\n params[decodedKey] = decodedVal;\n }\n }\n return params;\n}\n"],
5
+ "mappings": "AAIO,SAASA,EAAYC,EAAM,CAOhC,IAAMC,EAAaD,EAChB,QAAQ,gBAAiB,EAAE,EAC3B,QAAQ,mBAAoB,CAACE,EAAGC,IAAS,KAAKA,CAAI,EAAE,EACpD,QAAQ,aAAc,KAAK,EAExBC,EAAa,CAAC,EAChBC,EAAW,KAETC,EAAWL,EACd,MAAM,GAAG,EACT,IAAIM,GACCA,EAAQ,WAAW,IAAI,GACzBF,EAAWE,EAAQ,MAAM,CAAC,EAC1BH,EAAW,KAAKC,CAAQ,EACjB,QAELE,IAAY,KACdF,EAAW,OACXD,EAAW,KAAK,MAAM,EACf,QAELG,EAAQ,WAAW,GAAG,GACxBH,EAAW,KAAKG,EAAQ,MAAM,CAAC,CAAC,EACzB,WAEFA,EAAQ,QAAQ,sBAAuB,MAAM,CACrD,EACA,KAAK,GAAG,EAGX,MAAO,CAAE,MADK,IAAI,OAAO,IAAID,CAAQ,GAAG,EACxB,WAAAF,EAAY,SAAAC,CAAS,CACvC,CAEO,SAASG,EAAWR,EAAMS,EAAQ,CAKvC,IAAMC,EAHWD,EAAO,OAAO,GAAK,EAAE,IAAI,EAGlB,KAAK,CAACE,EAAGC,IAAM,CACrC,IAAMC,GAAaF,EAAE,KAAK,MAAM,IAAI,GAAK,CAAC,GAAG,QAAUA,EAAE,KAAK,SAAS,GAAG,EAAI,IAAM,GAC9EG,GAAaF,EAAE,KAAK,MAAM,IAAI,GAAK,CAAC,GAAG,QAAUA,EAAE,KAAK,SAAS,GAAG,EAAI,IAAM,GACpF,OAAOC,EAAYC,CACrB,CAAC,EAED,QAAWC,KAASL,EAAQ,CAC1B,GAAM,CAAE,MAAAM,EAAO,WAAAZ,CAAW,EAAIL,EAAYgB,EAAM,IAAI,EAC9CE,EAAQjB,EAAK,MAAMgB,CAAK,EAC9B,GAAIC,EAAO,CACT,IAAMC,EAAS,CAAC,EAChB,OAAAd,EAAW,QAAQ,CAACD,EAAMgB,IAAM,CAC9BD,EAAOf,CAAI,EAAI,mBAAmBc,EAAME,EAAI,CAAC,CAAC,CAChD,CAAC,EACM,CAAE,MAAAJ,EAAO,OAAAG,CAAO,CACzB,CACF,CACA,OAAO,IACT,CAEO,SAASE,EAAWC,EAAQ,CACjC,IAAMH,EAAS,CAAC,EAChB,GAAI,CAACG,EAAQ,OAAOH,EACpB,IAAMI,EAAKD,EAAO,WAAW,GAAG,EAAIA,EAAO,MAAM,CAAC,EAAIA,EACtD,QAAWE,KAAQD,EAAG,MAAM,GAAG,EAAG,CAChC,GAAM,CAACE,EAAKC,CAAG,EAAIF,EAAK,MAAM,GAAG,EACjC,GAAI,CAACC,EAAK,SACV,IAAME,EAAa,mBAAmBF,CAAG,EACnCG,EAAaF,EAAM,mBAAmBA,CAAG,EAAI,GAC/CC,KAAcR,EAEZ,MAAM,QAAQA,EAAOQ,CAAU,CAAC,EAClCR,EAAOQ,CAAU,EAAE,KAAKC,CAAU,EAElCT,EAAOQ,CAAU,EAAI,CAACR,EAAOQ,CAAU,EAAGC,CAAU,EAGtDT,EAAOQ,CAAU,EAAIC,CAEzB,CACA,OAAOT,CACT",
6
+ "names": ["compilePath", "path", "normalized", "_", "name", "paramNames", "catchAll", "regexStr", "segment", "matchRoute", "routes", "sorted", "a", "b", "aSpecific", "bSpecific", "route", "regex", "match", "params", "i", "parseQuery", "search", "qs", "pair", "key", "val", "decodedKey", "decodedVal"]
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "what-router",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "What Framework - File-based & programmatic router with View Transitions",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -32,7 +32,7 @@
32
32
  "author": "ZVN DEV (https://zvndev.com)",
33
33
  "license": "MIT",
34
34
  "peerDependencies": {
35
- "what-core": "^0.10.0"
35
+ "what-core": "^0.11.0"
36
36
  },
37
37
  "repository": {
38
38
  "type": "git",