@madojs/mado 0.11.1 → 0.13.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.
Files changed (298) hide show
  1. package/AGENTS.md +116 -32
  2. package/CHANGELOG.md +216 -1
  3. package/README.md +158 -173
  4. package/dist/src/component.d.ts +6 -3
  5. package/dist/src/component.d.ts.map +1 -0
  6. package/dist/src/component.js +163 -36
  7. package/dist/src/component.js.map +1 -1
  8. package/dist/src/context.d.ts +13 -32
  9. package/dist/src/context.d.ts.map +1 -0
  10. package/dist/src/context.js +73 -48
  11. package/dist/src/context.js.map +1 -1
  12. package/dist/src/css.d.ts +1 -0
  13. package/dist/src/css.d.ts.map +1 -0
  14. package/dist/src/css.js +34 -5
  15. package/dist/src/css.js.map +1 -1
  16. package/dist/src/devtools-hook.d.ts +14 -0
  17. package/dist/src/devtools-hook.d.ts.map +1 -0
  18. package/dist/src/devtools-hook.js +27 -0
  19. package/dist/src/devtools-hook.js.map +1 -0
  20. package/dist/src/devtools.d.ts +24 -22
  21. package/dist/src/devtools.d.ts.map +1 -0
  22. package/dist/src/devtools.js +230 -58
  23. package/dist/src/devtools.js.map +1 -1
  24. package/dist/src/diagnostics.d.ts +12 -0
  25. package/dist/src/diagnostics.d.ts.map +1 -0
  26. package/dist/src/diagnostics.js +68 -8
  27. package/dist/src/diagnostics.js.map +1 -1
  28. package/dist/src/each.d.ts +1 -5
  29. package/dist/src/each.d.ts.map +1 -0
  30. package/dist/src/each.js +0 -8
  31. package/dist/src/each.js.map +1 -1
  32. package/dist/src/forms.d.ts +27 -96
  33. package/dist/src/forms.d.ts.map +1 -0
  34. package/dist/src/forms.js +184 -394
  35. package/dist/src/forms.js.map +1 -1
  36. package/dist/src/head.d.ts +7 -6
  37. package/dist/src/head.d.ts.map +1 -0
  38. package/dist/src/head.js +8 -7
  39. package/dist/src/head.js.map +1 -1
  40. package/dist/src/html/bindings.d.ts +1 -0
  41. package/dist/src/html/bindings.d.ts.map +1 -0
  42. package/dist/src/html/bindings.js.map +1 -1
  43. package/dist/src/html/parser.d.ts +4 -5
  44. package/dist/src/html/parser.d.ts.map +1 -0
  45. package/dist/src/html/parser.js +64 -15
  46. package/dist/src/html/parser.js.map +1 -1
  47. package/dist/src/html/template-types.d.ts +1 -0
  48. package/dist/src/html/template-types.d.ts.map +1 -0
  49. package/dist/src/html/template-types.js.map +1 -1
  50. package/dist/src/html/template.d.ts +5 -1
  51. package/dist/src/html/template.d.ts.map +1 -0
  52. package/dist/src/html/template.js +102 -13
  53. package/dist/src/html/template.js.map +1 -1
  54. package/dist/src/index.d.ts +15 -12
  55. package/dist/src/index.d.ts.map +1 -0
  56. package/dist/src/index.js +18 -10
  57. package/dist/src/index.js.map +1 -1
  58. package/dist/src/json.d.ts +3 -0
  59. package/dist/src/json.d.ts.map +1 -0
  60. package/dist/src/json.js +14 -0
  61. package/dist/src/json.js.map +1 -0
  62. package/dist/src/lifecycle.d.ts +1 -0
  63. package/dist/src/lifecycle.d.ts.map +1 -0
  64. package/dist/src/lifecycle.js +3 -2
  65. package/dist/src/lifecycle.js.map +1 -1
  66. package/dist/src/page.d.ts +63 -28
  67. package/dist/src/page.d.ts.map +1 -0
  68. package/dist/src/page.js +5 -0
  69. package/dist/src/page.js.map +1 -1
  70. package/dist/src/persisted.d.ts +6 -1
  71. package/dist/src/persisted.d.ts.map +1 -0
  72. package/dist/src/persisted.js +17 -11
  73. package/dist/src/persisted.js.map +1 -1
  74. package/dist/src/resource.d.ts +2 -1
  75. package/dist/src/resource.d.ts.map +1 -0
  76. package/dist/src/resource.js +128 -50
  77. package/dist/src/resource.js.map +1 -1
  78. package/dist/src/router/base.d.ts +66 -0
  79. package/dist/src/router/base.d.ts.map +1 -0
  80. package/dist/src/router/base.js +168 -0
  81. package/dist/src/router/base.js.map +1 -0
  82. package/dist/src/router/manifest.d.ts +1 -0
  83. package/dist/src/router/manifest.d.ts.map +1 -0
  84. package/dist/src/router/manifest.js +156 -171
  85. package/dist/src/router/manifest.js.map +1 -1
  86. package/dist/src/router/match.d.ts +17 -2
  87. package/dist/src/router/match.d.ts.map +1 -0
  88. package/dist/src/router/match.js +60 -6
  89. package/dist/src/router/match.js.map +1 -1
  90. package/dist/src/router/navigation.d.ts +1 -0
  91. package/dist/src/router/navigation.d.ts.map +1 -0
  92. package/dist/src/router/navigation.js +58 -9
  93. package/dist/src/router/navigation.js.map +1 -1
  94. package/dist/src/signal.d.ts +1 -0
  95. package/dist/src/signal.d.ts.map +1 -0
  96. package/dist/src/signal.js +46 -17
  97. package/dist/src/signal.js.map +1 -1
  98. package/dist/src/static-runtime.d.ts +82 -0
  99. package/dist/src/static-runtime.d.ts.map +1 -0
  100. package/dist/src/static-runtime.js +209 -0
  101. package/dist/src/static-runtime.js.map +1 -0
  102. package/dist/src/vite/index.d.ts +32 -3
  103. package/dist/src/vite/index.d.ts.map +1 -0
  104. package/dist/src/vite/index.js +49 -17
  105. package/dist/src/vite/index.js.map +1 -1
  106. package/docs/README.md +5 -8
  107. package/docs/architecture/adr/0001-browser-static-snapshots.md +132 -0
  108. package/docs/architecture/v1-roadmap.md +19 -0
  109. package/docs/en/00-the-mado-way.md +1 -1
  110. package/docs/en/01-quickstart.md +183 -0
  111. package/docs/en/10-pages-and-components.md +279 -0
  112. package/docs/en/11-templates-and-signals.md +211 -0
  113. package/docs/en/12-routing.md +229 -0
  114. package/docs/en/13-data.md +227 -0
  115. package/docs/en/14-forms.md +91 -0
  116. package/docs/en/15-static-snapshots.md +181 -0
  117. package/docs/en/{10-app-architecture.md → 16-app-architecture.md} +56 -4
  118. package/docs/en/{13-deployment.md → 20-deployment.md} +79 -17
  119. package/docs/en/{15-error-handling.md → 21-error-handling.md} +9 -6
  120. package/docs/en/{14-testing.md → 22-testing.md} +6 -5
  121. package/docs/en/23-cookbook.md +292 -0
  122. package/docs/en/24-devtools-and-diagnostics.md +45 -0
  123. package/docs/en/{18-api-freeze-map.md → 30-api-freeze-map.md} +17 -9
  124. package/docs/en/{20-v1-stability.md → 32-v1-stability.md} +5 -5
  125. package/docs/en/33-migration-0.12-0.13.md +56 -0
  126. package/docs/en/40-llm-guide.md +774 -0
  127. package/docs/en/{06-for-backenders.md → 41-for-backenders.md} +28 -25
  128. package/docs/en/{05-why-mado.md → 42-why-mado.md} +3 -3
  129. package/docs/en/README.md +99 -27
  130. package/docs/recipes/nginx/Containerfile +26 -0
  131. package/docs/recipes/nginx/nginx.conf +42 -0
  132. package/llms.txt +263 -210
  133. package/package.json +51 -23
  134. package/scripts/clean.mjs +8 -0
  135. package/scripts/cli/generate.mjs +57 -10
  136. package/scripts/cli/help.mjs +13 -5
  137. package/scripts/cli/index.mjs +31 -7
  138. package/scripts/cli/init.mjs +19 -19
  139. package/scripts/cli/release.mjs +38 -83
  140. package/scripts/cli/run.mjs +5 -3
  141. package/scripts/logger.mjs +117 -0
  142. package/scripts/output-guard.mjs +128 -0
  143. package/scripts/preview.mjs +105 -24
  144. package/scripts/static/browser.mjs +695 -0
  145. package/scripts/static/discover.mjs +284 -0
  146. package/scripts/static/output.mjs +141 -0
  147. package/scripts/static/serialize.mjs +212 -0
  148. package/scripts/static/server.mjs +167 -0
  149. package/scripts/static.mjs +205 -0
  150. package/starters/default/README.md +57 -55
  151. package/starters/default/package.json +6 -12
  152. package/starters/default/src/app.routes.ts +20 -33
  153. package/starters/default/src/components/feature-card.component.ts +40 -0
  154. package/starters/default/src/components/live-counter.component.ts +57 -0
  155. package/starters/default/src/content/guides.ts +55 -0
  156. package/starters/default/src/main.ts +9 -13
  157. package/starters/default/src/pages/app.page.ts +41 -0
  158. package/starters/default/src/pages/guide.page.ts +40 -0
  159. package/starters/default/src/pages/home.page.ts +49 -0
  160. package/starters/default/src/pages/not-found.page.ts +18 -0
  161. package/starters/default/src/styles/document.css +39 -0
  162. package/starters/default/src/styles/reset.css +37 -0
  163. package/starters/default/src/styles/tokens.css +30 -0
  164. package/starters/default/src/styles.d.ts +3 -1
  165. package/starters/default/src/vite-env.d.ts +1 -1
  166. package/starters/default/tsconfig.node.json +13 -0
  167. package/starters/default/vite.config.ts +14 -4
  168. package/starters/modular/README.md +142 -0
  169. package/starters/modular/index.html +13 -0
  170. package/starters/modular/package.json +30 -0
  171. package/starters/modular/src/app.routes.ts +39 -0
  172. package/starters/{default → modular}/src/layouts/app-shell.layout.ts +9 -7
  173. package/starters/{default → modular}/src/layouts/auth-shell.layout.ts +3 -3
  174. package/starters/modular/src/main.ts +16 -0
  175. package/starters/{default → modular}/src/modules/auth/login.page.ts +5 -12
  176. package/starters/{default → modular}/src/modules/billing/pages/invoice-detail.page.ts +3 -4
  177. package/starters/{default → modular}/src/modules/billing/pages/invoices-list.page.ts +4 -4
  178. package/starters/{default → modular}/src/modules/home/home.page.ts +5 -7
  179. package/starters/modular/src/modules/home/not-found.page.ts +14 -0
  180. package/starters/{default → modular}/src/shared/styles/reset.css +21 -1
  181. package/starters/modular/src/styles.d.ts +1 -0
  182. package/starters/modular/src/vite-env.d.ts +1 -0
  183. package/starters/modular/tsconfig.json +33 -0
  184. package/starters/modular/tsconfig.node.json +13 -0
  185. package/starters/modular/vite.config.ts +132 -0
  186. package/TODO.md +0 -79
  187. package/dist/src/lazy.d.ts +0 -38
  188. package/dist/src/lazy.js +0 -73
  189. package/dist/src/lazy.js.map +0 -1
  190. package/docs/en/01-routing.md +0 -152
  191. package/docs/en/02-project-layout.md +0 -124
  192. package/docs/en/03-static-bake.md +0 -249
  193. package/docs/en/04-ide-setup.md +0 -162
  194. package/docs/en/07-llm-pitfalls.md +0 -724
  195. package/docs/en/08-llm-zero-history-test.md +0 -56
  196. package/docs/en/09-shadow-vs-light-dom.md +0 -174
  197. package/docs/en/11-layouts.md +0 -113
  198. package/docs/en/12-auth-and-api.md +0 -124
  199. package/docs/en/16-bake-cookbook.md +0 -100
  200. package/docs/en/17-shadow-dom-forms.md +0 -192
  201. package/docs/fr/00-the-mado-way.md +0 -85
  202. package/docs/fr/01-routing.md +0 -120
  203. package/docs/fr/02-project-layout.md +0 -84
  204. package/docs/fr/03-static-bake.md +0 -289
  205. package/docs/fr/04-ide-setup.md +0 -162
  206. package/docs/fr/05-why-mado.md +0 -193
  207. package/docs/fr/06-for-backenders.md +0 -438
  208. package/docs/fr/07-llm-pitfalls.md +0 -625
  209. package/docs/fr/08-llm-zero-history-test.md +0 -38
  210. package/docs/fr/09-shadow-vs-light-dom.md +0 -65
  211. package/docs/fr/10-app-architecture.md +0 -138
  212. package/docs/fr/11-layouts.md +0 -47
  213. package/docs/fr/12-auth-and-api.md +0 -76
  214. package/docs/fr/13-deployment.md +0 -57
  215. package/docs/fr/14-testing.md +0 -41
  216. package/docs/fr/15-error-handling.md +0 -50
  217. package/docs/fr/16-bake-cookbook.md +0 -88
  218. package/docs/fr/17-shadow-dom-forms.md +0 -196
  219. package/docs/fr/18-api-freeze-map.md +0 -63
  220. package/docs/fr/19-reactivity-ordering.md +0 -97
  221. package/docs/fr/20-v1-stability.md +0 -88
  222. package/docs/fr/README.md +0 -27
  223. package/docs/ru/00-the-mado-way.md +0 -84
  224. package/docs/ru/01-routing.md +0 -119
  225. package/docs/ru/02-project-layout.md +0 -84
  226. package/docs/ru/03-static-bake.md +0 -250
  227. package/docs/ru/04-ide-setup.md +0 -144
  228. package/docs/ru/05-why-mado.md +0 -193
  229. package/docs/ru/06-for-backenders.md +0 -428
  230. package/docs/ru/07-llm-pitfalls.md +0 -624
  231. package/docs/ru/08-llm-zero-history-test.md +0 -57
  232. package/docs/ru/09-shadow-vs-light-dom.md +0 -63
  233. package/docs/ru/10-app-architecture.md +0 -152
  234. package/docs/ru/11-layouts.md +0 -47
  235. package/docs/ru/12-auth-and-api.md +0 -75
  236. package/docs/ru/13-deployment.md +0 -66
  237. package/docs/ru/14-testing.md +0 -50
  238. package/docs/ru/15-error-handling.md +0 -56
  239. package/docs/ru/16-bake-cookbook.md +0 -95
  240. package/docs/ru/17-shadow-dom-forms.md +0 -193
  241. package/docs/ru/18-api-freeze-map.md +0 -64
  242. package/docs/ru/19-reactivity-ordering.md +0 -95
  243. package/docs/ru/20-v1-stability.md +0 -82
  244. package/docs/ru/README.md +0 -25
  245. package/docs/uk/00-the-mado-way.md +0 -82
  246. package/docs/uk/01-routing.md +0 -76
  247. package/docs/uk/02-project-layout.md +0 -73
  248. package/docs/uk/03-static-bake.md +0 -48
  249. package/docs/uk/04-ide-setup.md +0 -26
  250. package/docs/uk/05-why-mado.md +0 -34
  251. package/docs/uk/06-for-backenders.md +0 -55
  252. package/docs/uk/07-llm-pitfalls.md +0 -145
  253. package/docs/uk/08-llm-zero-history-test.md +0 -34
  254. package/docs/uk/09-shadow-vs-light-dom.md +0 -58
  255. package/docs/uk/10-app-architecture.md +0 -97
  256. package/docs/uk/11-layouts.md +0 -47
  257. package/docs/uk/12-auth-and-api.md +0 -70
  258. package/docs/uk/13-deployment.md +0 -40
  259. package/docs/uk/14-testing.md +0 -34
  260. package/docs/uk/15-error-handling.md +0 -32
  261. package/docs/uk/16-bake-cookbook.md +0 -36
  262. package/docs/uk/17-shadow-dom-forms.md +0 -193
  263. package/docs/uk/18-api-freeze-map.md +0 -61
  264. package/docs/uk/19-reactivity-ordering.md +0 -95
  265. package/docs/uk/20-v1-stability.md +0 -83
  266. package/docs/uk/README.md +0 -27
  267. package/scripts/bake.mjs +0 -570
  268. package/scripts/package-smoke.mjs +0 -77
  269. package/scripts/release-notes.mjs +0 -66
  270. package/scripts/size-budget.mjs +0 -91
  271. package/starters/default/src/modules/home/not-found.page.ts +0 -11
  272. package/starters/default/src/shared/ui/x-button.component.ts +0 -49
  273. /package/docs/en/{19-reactivity-ordering.md → 31-reactivity-ordering.md} +0 -0
  274. /package/starters/{default → modular}/.editorconfig +0 -0
  275. /package/starters/{default → modular}/eslint.config.mjs +0 -0
  276. /package/starters/{default → modular}/public/favicon.svg +0 -0
  277. /package/starters/{default → modular}/src/modules/auth/_contracts/auth-api.types.ts +0 -0
  278. /package/starters/{default → modular}/src/modules/auth/auth.connector.ts +0 -0
  279. /package/starters/{default → modular}/src/modules/auth/auth.guard.ts +0 -0
  280. /package/starters/{default → modular}/src/modules/auth/auth.public.ts +0 -0
  281. /package/starters/{default → modular}/src/modules/auth/auth.routes.ts +0 -0
  282. /package/starters/{default → modular}/src/modules/auth/auth.service.ts +0 -0
  283. /package/starters/{default → modular}/src/modules/auth/auth.types.ts +0 -0
  284. /package/starters/{default → modular}/src/modules/billing/_contracts/stripe.types.ts +0 -0
  285. /package/starters/{default → modular}/src/modules/billing/api/stripe.connector.ts +0 -0
  286. /package/starters/{default → modular}/src/modules/billing/billing.public.ts +0 -0
  287. /package/starters/{default → modular}/src/modules/billing/billing.routes.ts +0 -0
  288. /package/starters/{default → modular}/src/modules/billing/billing.types.ts +0 -0
  289. /package/starters/{default → modular}/src/modules/billing/components/invoice-status-badge.component.ts +0 -0
  290. /package/starters/{default → modular}/src/modules/billing/data/invoices.resource.ts +0 -0
  291. /package/starters/{default → modular}/src/shared/http/http-client.ts +0 -0
  292. /package/starters/{default → modular}/src/shared/http/http-error.ts +0 -0
  293. /package/starters/{default → modular}/src/shared/http/interceptors.ts +0 -0
  294. /package/starters/{default → modular}/src/shared/lib/format-date.ts +0 -0
  295. /package/starters/{default → modular}/src/shared/styles/content.css +0 -0
  296. /package/starters/{default → modular}/src/shared/styles/shell.css +0 -0
  297. /package/starters/{default → modular}/src/shared/styles/tokens.css +0 -0
  298. /package/starters/{default → modular}/src/shared/ui/x-spinner.component.ts +0 -0
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Single source of truth for the Vite `base` URL prefix at runtime.
3
+ *
4
+ * Mado reads `import.meta.env.BASE_URL` once at module init and exposes
5
+ * three pure helpers used by the router, navigation, head and any user
6
+ * code that constructs internal links.
7
+ *
8
+ * vite.config.ts → base
9
+ * ├── runtime: import.meta.env.BASE_URL (this module)
10
+ * └── CLI: resolved config → _mado/build.json
11
+ *
12
+ * There is intentionally NO `<meta name="mado:base">`, no
13
+ * `routes({}, { base })`, no second runtime config. Tools that load Mado
14
+ * outside Vite (native ESM tests, partial SSR probes) fall back to "/".
15
+ */
16
+ function readEnvBase() {
17
+ // Direct access to the well-known constant so Vite's static
18
+ // `define`-replacement (and Vite-only `import.meta.env.BASE_URL`
19
+ // injection) sees the expression verbatim. Optional chaining or
20
+ // intermediate variables would defeat the rewriter. In non-Vite
21
+ // environments the property is undefined and we fall back to "/".
22
+ try {
23
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
24
+ const value = import.meta.env?.BASE_URL;
25
+ if (typeof value === "string")
26
+ return value;
27
+ }
28
+ catch {
29
+ /* fall through */
30
+ }
31
+ return "/";
32
+ }
33
+ /**
34
+ * Normalise an arbitrary base value into the canonical Mado form:
35
+ * starts with "/", ends with "/", collapses repeated slashes. The root
36
+ * base is the literal "/".
37
+ *
38
+ * normalizeBase("") === "/"
39
+ * normalizeBase("/") === "/"
40
+ * normalizeBase("mado") === "/mado/"
41
+ * normalizeBase("/mado") === "/mado/"
42
+ * normalizeBase("/mado/") === "/mado/"
43
+ * normalizeBase("//x//y/") === "/x/y/"
44
+ */
45
+ export function normalizeBase(raw) {
46
+ if (!raw)
47
+ return "/";
48
+ let s = String(raw).trim();
49
+ if (!s || s === "/")
50
+ return "/";
51
+ if (!s.startsWith("/"))
52
+ s = "/" + s;
53
+ if (!s.endsWith("/"))
54
+ s = s + "/";
55
+ s = s.replace(/\/+/g, "/");
56
+ return s;
57
+ }
58
+ /**
59
+ * The active base prefix for the running app. Computed once from
60
+ * `import.meta.env.BASE_URL` and normalised. Use it inside Mado runtime;
61
+ * application code should call `routeUrl()` instead.
62
+ */
63
+ export const appBase = normalizeBase(readEnvBase());
64
+ /**
65
+ * Strip the base prefix off a browser pathname so it becomes a route
66
+ * pathname the matcher understands.
67
+ *
68
+ * base = "/mado/"
69
+ * stripBase("/mado/") === "/"
70
+ * stripBase("/mado/docs") === "/docs"
71
+ * stripBase("/mado/docs/") === "/docs"
72
+ * stripBase("/other") === "/other" (no base → unchanged)
73
+ * stripBase("") === "/"
74
+ *
75
+ * base = "/"
76
+ * stripBase("/docs") === "/docs"
77
+ */
78
+ export function stripBase(pathname, base = appBase) {
79
+ const b = normalizeBase(base);
80
+ if (!pathname)
81
+ return "/";
82
+ if (b === "/")
83
+ return pathname.startsWith("/") ? pathname : "/" + pathname;
84
+ // Exact match of base without trailing slash → root.
85
+ const bNoTrail = b.slice(0, -1);
86
+ if (pathname === bNoTrail)
87
+ return "/";
88
+ if (pathname === b)
89
+ return "/";
90
+ if (pathname.startsWith(b)) {
91
+ const rest = pathname.slice(b.length - 1); // keep leading slash
92
+ return rest || "/";
93
+ }
94
+ // Pathname is outside our base (foreign link clicked, etc.); return it
95
+ // unchanged so the caller can detect the mismatch and fall back to a
96
+ // native navigation.
97
+ return pathname;
98
+ }
99
+ /**
100
+ * Prefix a route pathname with the active base so it becomes a real
101
+ * browser URL suitable for `history.pushState` and `<a href>`.
102
+ *
103
+ * base = "/mado/"
104
+ * withBase("/") === "/mado/"
105
+ * withBase("/docs") === "/mado/docs"
106
+ * withBase("/docs/", b) === "/mado/docs/"
107
+ * withBase("docs") === "/mado/docs"
108
+ *
109
+ * base = "/"
110
+ * withBase("/docs") === "/docs"
111
+ */
112
+ export function withBase(pathname, base = appBase) {
113
+ const b = normalizeBase(base);
114
+ const p = pathname || "/";
115
+ const abs = p.startsWith("/") ? p : "/" + p;
116
+ if (b === "/")
117
+ return abs;
118
+ // Root route under a non-trivial base must keep the trailing slash so
119
+ // that `<a href>` agrees with the canonical deployment URL shape.
120
+ // routeUrl("/") with base "/mado/" === "/mado/" (not "/mado")
121
+ if (abs === "/")
122
+ return b;
123
+ // Strip leading slash from abs so we can concatenate with base ("/mado/").
124
+ // If abs already starts with the base prefix, return it unchanged so we
125
+ // do not double-prefix on accident.
126
+ if (abs === b || abs.startsWith(b))
127
+ return abs;
128
+ if (abs === b.slice(0, -1))
129
+ return abs;
130
+ return b + abs.slice(1);
131
+ }
132
+ /**
133
+ * Build an internal link URL: prefix the given route pathname with the
134
+ * active Vite base, preserving query and hash. This is the canonical way
135
+ * to emit `<a href>` values in Mado views.
136
+ *
137
+ * import { routeUrl } from "@madojs/mado";
138
+ * html`<a data-link href=${routeUrl("/docs")}>Docs</a>`
139
+ *
140
+ * base = "/mado/"
141
+ * routeUrl("/docs") === "/mado/docs"
142
+ * routeUrl("/docs?q=1#h") === "/mado/docs?q=1#h"
143
+ * routeUrl("/") === "/mado/"
144
+ *
145
+ * base = "/"
146
+ * routeUrl("/docs") === "/docs"
147
+ */
148
+ export function routeUrl(pathname, base = appBase) {
149
+ if (!pathname)
150
+ return withBase("/", base);
151
+ // Split off ?query and #hash so we only run withBase on the pathname.
152
+ let path = pathname;
153
+ let suffix = "";
154
+ const hashAt = path.indexOf("#");
155
+ if (hashAt >= 0) {
156
+ suffix = path.slice(hashAt) + suffix;
157
+ path = path.slice(0, hashAt);
158
+ }
159
+ const queryAt = path.indexOf("?");
160
+ if (queryAt >= 0) {
161
+ suffix = path.slice(queryAt) + suffix;
162
+ path = path.slice(0, queryAt);
163
+ }
164
+ if (path === "")
165
+ path = "/";
166
+ return withBase(path, base) + suffix;
167
+ }
168
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../../src/router/base.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Single source of truth for the Vite `base` URL prefix at runtime.\n *\n * Mado reads `import.meta.env.BASE_URL` once at module init and exposes\n * three pure helpers used by the router, navigation, head and any user\n * code that constructs internal links.\n *\n * vite.config.ts → base\n * ├── runtime: import.meta.env.BASE_URL (this module)\n * └── CLI: resolved config → _mado/build.json\n *\n * There is intentionally NO `<meta name=\"mado:base\">`, no\n * `routes({}, { base })`, no second runtime config. Tools that load Mado\n * outside Vite (native ESM tests, partial SSR probes) fall back to \"/\".\n */\nfunction readEnvBase(): string {\n // Direct access to the well-known constant so Vite's static\n // `define`-replacement (and Vite-only `import.meta.env.BASE_URL`\n // injection) sees the expression verbatim. Optional chaining or\n // intermediate variables would defeat the rewriter. In non-Vite\n // environments the property is undefined and we fall back to \"/\".\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const value = (import.meta as any).env?.BASE_URL;\n if (typeof value === \"string\") return value;\n } catch {\n /* fall through */\n }\n return \"/\";\n}\n\n/**\n * Normalise an arbitrary base value into the canonical Mado form:\n * starts with \"/\", ends with \"/\", collapses repeated slashes. The root\n * base is the literal \"/\".\n *\n * normalizeBase(\"\") === \"/\"\n * normalizeBase(\"/\") === \"/\"\n * normalizeBase(\"mado\") === \"/mado/\"\n * normalizeBase(\"/mado\") === \"/mado/\"\n * normalizeBase(\"/mado/\") === \"/mado/\"\n * normalizeBase(\"//x//y/\") === \"/x/y/\"\n */\nexport function normalizeBase(raw: string | null | undefined): string {\n if (!raw) return \"/\";\n let s = String(raw).trim();\n if (!s || s === \"/\") return \"/\";\n if (!s.startsWith(\"/\")) s = \"/\" + s;\n if (!s.endsWith(\"/\")) s = s + \"/\";\n s = s.replace(/\\/+/g, \"/\");\n return s;\n}\n\n/**\n * The active base prefix for the running app. Computed once from\n * `import.meta.env.BASE_URL` and normalised. Use it inside Mado runtime;\n * application code should call `routeUrl()` instead.\n */\nexport const appBase: string = normalizeBase(readEnvBase());\n\n/**\n * Strip the base prefix off a browser pathname so it becomes a route\n * pathname the matcher understands.\n *\n * base = \"/mado/\"\n * stripBase(\"/mado/\") === \"/\"\n * stripBase(\"/mado/docs\") === \"/docs\"\n * stripBase(\"/mado/docs/\") === \"/docs\"\n * stripBase(\"/other\") === \"/other\" (no base → unchanged)\n * stripBase(\"\") === \"/\"\n *\n * base = \"/\"\n * stripBase(\"/docs\") === \"/docs\"\n */\nexport function stripBase(pathname: string, base: string = appBase): string {\n const b = normalizeBase(base);\n if (!pathname) return \"/\";\n if (b === \"/\") return pathname.startsWith(\"/\") ? pathname : \"/\" + pathname;\n // Exact match of base without trailing slash → root.\n const bNoTrail = b.slice(0, -1);\n if (pathname === bNoTrail) return \"/\";\n if (pathname === b) return \"/\";\n if (pathname.startsWith(b)) {\n const rest = pathname.slice(b.length - 1); // keep leading slash\n return rest || \"/\";\n }\n // Pathname is outside our base (foreign link clicked, etc.); return it\n // unchanged so the caller can detect the mismatch and fall back to a\n // native navigation.\n return pathname;\n}\n\n/**\n * Prefix a route pathname with the active base so it becomes a real\n * browser URL suitable for `history.pushState` and `<a href>`.\n *\n * base = \"/mado/\"\n * withBase(\"/\") === \"/mado/\"\n * withBase(\"/docs\") === \"/mado/docs\"\n * withBase(\"/docs/\", b) === \"/mado/docs/\"\n * withBase(\"docs\") === \"/mado/docs\"\n *\n * base = \"/\"\n * withBase(\"/docs\") === \"/docs\"\n */\nexport function withBase(pathname: string, base: string = appBase): string {\n const b = normalizeBase(base);\n const p = pathname || \"/\";\n const abs = p.startsWith(\"/\") ? p : \"/\" + p;\n if (b === \"/\") return abs;\n // Root route under a non-trivial base must keep the trailing slash so\n // that `<a href>` agrees with the canonical deployment URL shape.\n // routeUrl(\"/\") with base \"/mado/\" === \"/mado/\" (not \"/mado\")\n if (abs === \"/\") return b;\n // Strip leading slash from abs so we can concatenate with base (\"/mado/\").\n // If abs already starts with the base prefix, return it unchanged so we\n // do not double-prefix on accident.\n if (abs === b || abs.startsWith(b)) return abs;\n if (abs === b.slice(0, -1)) return abs;\n return b + abs.slice(1);\n}\n\n/**\n * Build an internal link URL: prefix the given route pathname with the\n * active Vite base, preserving query and hash. This is the canonical way\n * to emit `<a href>` values in Mado views.\n *\n * import { routeUrl } from \"@madojs/mado\";\n * html`<a data-link href=${routeUrl(\"/docs\")}>Docs</a>`\n *\n * base = \"/mado/\"\n * routeUrl(\"/docs\") === \"/mado/docs\"\n * routeUrl(\"/docs?q=1#h\") === \"/mado/docs?q=1#h\"\n * routeUrl(\"/\") === \"/mado/\"\n *\n * base = \"/\"\n * routeUrl(\"/docs\") === \"/docs\"\n */\nexport function routeUrl(pathname: string, base: string = appBase): string {\n if (!pathname) return withBase(\"/\", base);\n // Split off ?query and #hash so we only run withBase on the pathname.\n let path = pathname;\n let suffix = \"\";\n const hashAt = path.indexOf(\"#\");\n if (hashAt >= 0) {\n suffix = path.slice(hashAt) + suffix;\n path = path.slice(0, hashAt);\n }\n const queryAt = path.indexOf(\"?\");\n if (queryAt >= 0) {\n suffix = path.slice(queryAt) + suffix;\n path = path.slice(0, queryAt);\n }\n if (path === \"\") path = \"/\";\n return withBase(path, base) + suffix;\n}\n\n"]}
@@ -66,3 +66,4 @@ export declare function routes(manifest: RoutesMap, options?: RoutesOptions): Ro
66
66
  * If there is no active routes() — no-op.
67
67
  */
68
68
  export declare function prefetchPath(pathname: string): void;
69
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/router/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAShE,OAAO,EAIL,KAAK,WAAW,EAEhB,KAAK,SAAS,EACf,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAWnE,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,cAAc,CAAC;IAC/B,0CAA0C;IAC1C,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,cAAc,CAAC;IACvC;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,KAAK,cAAc,CAAC;IAChE,mDAAmD;IACnD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AA2CD;;GAEG;AACH,wBAAgB,MAAM,CACpB,QAAQ,EAAE,SAAS,EACnB,OAAO,GAAE,aAAkB,GAC1B,SAAS,CA4DX;AAiCD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAInD"}