@marko/run 0.1.15 → 0.2.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.
@@ -5,6 +5,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
9
  var __export = (target, all) => {
9
10
  for (var name in all)
10
11
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -22,6 +23,28 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
22
23
  mod
23
24
  ));
24
25
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
26
+ var __publicField = (obj, key, value) => {
27
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
28
+ return value;
29
+ };
30
+ var __accessCheck = (obj, member, msg) => {
31
+ if (!member.has(obj))
32
+ throw TypeError("Cannot " + msg);
33
+ };
34
+ var __privateGet = (obj, member, getter) => {
35
+ __accessCheck(obj, member, "read from private field");
36
+ return getter ? getter.call(obj) : member.get(obj);
37
+ };
38
+ var __privateAdd = (obj, member, value) => {
39
+ if (member.has(obj))
40
+ throw TypeError("Cannot add the same private member more than once");
41
+ member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
42
+ };
43
+ var __privateSet = (obj, member, value, setter) => {
44
+ __accessCheck(obj, member, "write to private field");
45
+ setter ? setter.call(obj, value) : member.set(obj, value);
46
+ return value;
47
+ };
25
48
 
26
49
  // src/vite/index.ts
27
50
  var vite_exports = {};
@@ -65,236 +88,509 @@ var RoutableFileTypes = {
65
88
  Error: "500"
66
89
  };
67
90
 
91
+ // src/vite/routes/vdir.ts
92
+ var _dirs, _pathlessDirs;
93
+ var _VDir = class {
94
+ constructor(parent, segment, source) {
95
+ __privateAdd(this, _dirs, void 0);
96
+ __privateAdd(this, _pathlessDirs, void 0);
97
+ __publicField(this, "parent");
98
+ __publicField(this, "source");
99
+ __publicField(this, "path");
100
+ __publicField(this, "fullPath");
101
+ __publicField(this, "segment");
102
+ __publicField(this, "files");
103
+ if (!parent || !segment) {
104
+ this.parent = null;
105
+ this.source = null;
106
+ this.path = "/";
107
+ this.fullPath = "/";
108
+ this.segment = {
109
+ raw: "",
110
+ name: ""
111
+ };
112
+ } else {
113
+ this.parent = parent;
114
+ this.source = source;
115
+ this.path = parent.path + (parent.path === "/" ? segment.name : `/${segment.name}`);
116
+ this.fullPath = parent.fullPath + (parent.fullPath === "/" ? segment.name : `/${segment.name}`);
117
+ if (segment.param) {
118
+ this.fullPath += segment.param;
119
+ }
120
+ this.segment = segment;
121
+ }
122
+ }
123
+ get pathInfo() {
124
+ const value = {
125
+ id: "/",
126
+ path: "/",
127
+ segments: []
128
+ };
129
+ let sep = "";
130
+ for (const { segment } of this) {
131
+ const { type, name, param } = segment;
132
+ if (name && type !== "_") {
133
+ value.id += sep + (type || name);
134
+ value.path += sep + name;
135
+ value.isEnd = type === "$$";
136
+ if (param) {
137
+ value.path += param;
138
+ let index = type === "$$" ? null : value.segments.length;
139
+ if (!value.params) {
140
+ value.params = { [param]: index };
141
+ } else if (!(param in value.params)) {
142
+ value.params[param] = index;
143
+ }
144
+ }
145
+ value.segments.push(name);
146
+ sep = "/";
147
+ }
148
+ }
149
+ Object.defineProperty(this, "pathInfo", {
150
+ value,
151
+ enumerable: true
152
+ });
153
+ return value;
154
+ }
155
+ addDir(path3, segment) {
156
+ const map = segment.type === "_" ? __privateGet(this, _pathlessDirs) ?? __privateSet(this, _pathlessDirs, /* @__PURE__ */ new Map()) : __privateGet(this, _dirs) ?? __privateSet(this, _dirs, /* @__PURE__ */ new Map());
157
+ if (!map.has(segment.name)) {
158
+ const dir = new _VDir(this, segment, path3);
159
+ map.set(segment.name, dir);
160
+ return dir;
161
+ }
162
+ return map.get(segment.name);
163
+ }
164
+ addFile(file) {
165
+ if (!this.files) {
166
+ this.files = /* @__PURE__ */ new Map();
167
+ this.files.set(file.type, file);
168
+ } else if (!this.files.has(file.type)) {
169
+ this.files.set(file.type, file);
170
+ } else {
171
+ const existing = this.files.get(file.type);
172
+ if (existing !== file) {
173
+ throw new Error(
174
+ `Duplicate file type '${file.type}' added at path '${this.path}'. File '${file.filePath}' collides with '${existing.filePath}'.`
175
+ );
176
+ } else if (file.type === RoutableFileTypes.Page || file.type === RoutableFileTypes.Handler) {
177
+ throw new Error(
178
+ `Ambiguous path definition: route '${this.path}' is defined multiple times by ${file.filePath}`
179
+ );
180
+ }
181
+ throw new Error(
182
+ `Ambiguous path definition: file '${this.path}' is included multiple times by ${file.filePath}`
183
+ );
184
+ }
185
+ }
186
+ *dirs() {
187
+ if (__privateGet(this, _pathlessDirs)) {
188
+ yield* __privateGet(this, _pathlessDirs).values();
189
+ }
190
+ if (__privateGet(this, _dirs)) {
191
+ yield* __privateGet(this, _dirs).values();
192
+ }
193
+ }
194
+ *[Symbol.iterator]() {
195
+ if (this.parent) {
196
+ yield* this.parent;
197
+ }
198
+ yield this;
199
+ }
200
+ static addPaths(roots, paths) {
201
+ const dirs = [];
202
+ const unique = /* @__PURE__ */ new Set();
203
+ for (const root of roots) {
204
+ for (const path3 of paths) {
205
+ let dir = root;
206
+ for (const segment of path3.segments) {
207
+ dir = dir.addDir(path3, segment);
208
+ }
209
+ if (unique.has(dir.path)) {
210
+ const sources = /* @__PURE__ */ new Set();
211
+ let sourcePath = "";
212
+ for (const { source } of dir) {
213
+ if (source && !sources.has(source.source)) {
214
+ sources.add(source.source);
215
+ sourcePath += source.source + "/";
216
+ }
217
+ }
218
+ throw new Error(
219
+ `Ambiguous directory structure: '${sourcePath}${path3.source}' defines '${dir.path}' multiple times.`
220
+ );
221
+ } else {
222
+ unique.add(dir.path);
223
+ dirs.push(dir);
224
+ }
225
+ }
226
+ }
227
+ return dirs;
228
+ }
229
+ };
230
+ var VDir = _VDir;
231
+ _dirs = new WeakMap();
232
+ _pathlessDirs = new WeakMap();
233
+
234
+ // src/vite/routes/parse.ts
235
+ function parseFlatRoute(pattern) {
236
+ if (!pattern)
237
+ throw new Error("Empty pattern");
238
+ const len = pattern.length;
239
+ let i = 0;
240
+ return parse2([
241
+ {
242
+ id: "/",
243
+ segments: [],
244
+ source: pattern
245
+ }
246
+ ]);
247
+ function parse2(basePaths, group) {
248
+ const pathMap = /* @__PURE__ */ new Map();
249
+ const delimiters = group ? ").," : ".,";
250
+ let charCode;
251
+ let segmentStart = i;
252
+ let type;
253
+ let current;
254
+ do {
255
+ charCode = pattern.charCodeAt(i);
256
+ if (charCode === 41 && group) {
257
+ break;
258
+ } else if (charCode === 44) {
259
+ if (!current) {
260
+ segmentEnd(
261
+ basePaths.map((path3) => ({
262
+ ...path3,
263
+ segments: path3.segments.slice()
264
+ })),
265
+ "",
266
+ "_",
267
+ pathMap
268
+ );
269
+ } else {
270
+ segmentEnd(current, pattern.slice(segmentStart, i), type, pathMap);
271
+ }
272
+ current = void 0;
273
+ type = void 0;
274
+ segmentStart = ++i;
275
+ } else if (charCode === 46) {
276
+ if (current) {
277
+ segmentEnd(current, pattern.slice(segmentStart, i), type);
278
+ }
279
+ type = void 0;
280
+ segmentStart = ++i;
281
+ } else if (charCode === 40) {
282
+ const groupPaths = parse2(current || basePaths, ++i);
283
+ if (groupPaths.length) {
284
+ current = groupPaths;
285
+ }
286
+ segmentStart = ++i;
287
+ } else {
288
+ if (charCode === 95) {
289
+ type = "_";
290
+ } else if (charCode === 36) {
291
+ type = pattern.charCodeAt(i + 1) === 36 ? "$$" : "$";
292
+ }
293
+ current ?? (current = basePaths.map((path3) => ({
294
+ ...path3,
295
+ segments: path3.segments.slice()
296
+ })));
297
+ i = len;
298
+ for (const char of delimiters) {
299
+ const index = pattern.indexOf(char, segmentStart);
300
+ if (index >= 0 && index < i) {
301
+ i = index;
302
+ }
303
+ }
304
+ }
305
+ } while (i < len);
306
+ if (group && charCode !== 41) {
307
+ throw new Error(
308
+ `Invalid route pattern: group was not closed '${pattern.slice(
309
+ group
310
+ )}' in '${pattern}'`
311
+ );
312
+ }
313
+ if (!current) {
314
+ segmentEnd(
315
+ basePaths.map((path3) => ({
316
+ ...path3,
317
+ segments: path3.segments.slice()
318
+ })),
319
+ "",
320
+ "_",
321
+ pathMap
322
+ );
323
+ } else {
324
+ segmentEnd(current, pattern.slice(segmentStart, i), type, pathMap);
325
+ }
326
+ return [...pathMap.values()];
327
+ }
328
+ function segmentEnd(paths, raw, type, map) {
329
+ let segment;
330
+ if (raw) {
331
+ segment = {
332
+ raw,
333
+ name: raw,
334
+ type
335
+ };
336
+ if (type === "$" || type === "$$") {
337
+ segment.name = type;
338
+ segment.param = raw.slice(type.length);
339
+ }
340
+ }
341
+ for (const path3 of paths) {
342
+ if (segment) {
343
+ if (path3.isCatchall) {
344
+ throw new Error(
345
+ `Invalid route pattern: nested segments are not allowed after a catch-all parameter. Found '.' following '${pattern.slice(
346
+ 0,
347
+ i
348
+ )}' in '${pattern}'.`
349
+ );
350
+ }
351
+ path3.segments.push(segment);
352
+ path3.id += path3.id === "/" ? segment.name : `/${segment.name}`;
353
+ if (type === "$$") {
354
+ path3.isCatchall = true;
355
+ }
356
+ }
357
+ if (map) {
358
+ if (map.has(path3.id)) {
359
+ const existing = map.get(path3.id);
360
+ const existingExpansion = existing.segments.map((s) => s.raw).join(".");
361
+ const currentExpansion = path3.segments.map((s) => s.raw).join(".");
362
+ throw new Error(
363
+ `Invalid route pattern: route '${path3.id}' is ambiguous. Expansion '${currentExpansion}' collides with '${existingExpansion}' in '${pattern}'.`
364
+ );
365
+ }
366
+ map.set(path3.id, path3);
367
+ }
368
+ }
369
+ }
370
+ }
371
+
68
372
  // src/vite/routes/builder.ts
69
373
  var markoFiles = `(${RoutableFileTypes.Layout}|${RoutableFileTypes.Page}|${RoutableFileTypes.NotFound}|${RoutableFileTypes.Error})\\.(?:.*\\.)?(marko)`;
70
374
  var nonMarkoFiles = `(${RoutableFileTypes.Middleware}|${RoutableFileTypes.Handler}|${RoutableFileTypes.Meta})\\.(?:.*\\.)?(.+)`;
71
375
  var routeableFileRegex = new RegExp(
72
- `^[+](?:${markoFiles}|${nonMarkoFiles})$`,
376
+ `[+](?:${markoFiles}|${nonMarkoFiles})$`,
73
377
  "i"
74
378
  );
75
379
  function matchRoutableFile(filename) {
76
380
  const match = filename.match(routeableFileRegex);
77
381
  return match && (match[1] || match[3]).toLowerCase();
78
382
  }
79
- function scorePath(path3, index) {
80
- const [pattern, splat] = path3.split("/$$", 2);
81
- const segments = pattern.split("/").filter(Boolean);
82
- return segments.reduce(
83
- (score, segment) => score + (segment.startsWith("$") ? 3 : 4),
84
- segments.length + (splat === void 0 ? 1 : 2)
85
- ) * 1e4 - index;
86
- }
87
383
  function isSpecialType(type) {
88
384
  return type === RoutableFileTypes.NotFound || type === RoutableFileTypes.Error;
89
385
  }
90
- async function buildRoutes(walk, basePath) {
386
+ async function buildRoutes(walk, basePath = "") {
91
387
  if (basePath) {
92
388
  basePath = basePath.replace(/^\/+|\/+$/g, "");
93
389
  }
94
- const dirStack = [];
95
- const pathStack = [];
96
- const paramStack = [];
97
- const layoutsStack = [];
98
- const middlewareStack = [];
99
- const routes = /* @__PURE__ */ new Map();
390
+ const uniqueRoutes = /* @__PURE__ */ new Map();
391
+ const routes = [];
100
392
  const special = {};
101
- const middleware = /* @__PURE__ */ new Set();
102
- let isRoot = true;
393
+ const middlewares = /* @__PURE__ */ new Set();
394
+ const unusedFiles = /* @__PURE__ */ new Set();
395
+ const currentLayouts = /* @__PURE__ */ new Set();
396
+ const currentMiddleware = /* @__PURE__ */ new Set();
397
+ const root = new VDir();
398
+ const dirStack = [];
399
+ let activeDirs = [root];
103
400
  let nextFileId = 1;
104
401
  let nextRouteIndex = 1;
105
- let current;
106
- let children = [];
402
+ let isBaseDir = true;
107
403
  await walk({
108
- onFile(entry) {
109
- const type = matchRoutableFile(entry.name);
110
- if (!type) {
404
+ onEnter({ name }) {
405
+ if (!name || isBaseDir) {
406
+ isBaseDir = false;
407
+ return;
408
+ }
409
+ dirStack.push(name);
410
+ const previousDirs = activeDirs;
411
+ const paths = parseFlatRoute(name);
412
+ activeDirs = VDir.addPaths(previousDirs, paths);
413
+ return () => {
414
+ activeDirs = previousDirs;
415
+ dirStack.pop();
416
+ };
417
+ },
418
+ onFile({ name, path: path3 }) {
419
+ const match = name.match(routeableFileRegex);
420
+ if (!match) {
111
421
  return;
112
422
  }
113
- if (!isRoot && isSpecialType(type)) {
423
+ const type = (match[1] || match[3]).toLowerCase();
424
+ if (dirStack.length && isSpecialType(type)) {
114
425
  console.warn(
115
- `Special pages '${RoutableFileTypes.NotFound}' and '${RoutableFileTypes.Error}' are only considered in the root directory - ignoring ${entry.path}`
426
+ `Special pages '${RoutableFileTypes.NotFound}' and '${RoutableFileTypes.Error}' are only considered in the root directory - ignoring ${path3}`
116
427
  );
117
428
  return;
118
429
  }
119
- if (!current) {
120
- current = {
121
- path: "/" + pathStack.join("/"),
122
- originalPath: dirStack.join("/"),
123
- children: [],
124
- files: /* @__PURE__ */ new Map()
125
- };
126
- children.push(current);
430
+ let dirs = activeDirs;
431
+ if (match.index) {
432
+ const paths = parseFlatRoute(name.slice(0, match.index));
433
+ dirs = VDir.addPaths(activeDirs, paths);
127
434
  }
128
- let entries = current.files.get(type);
129
- if (!entries) {
130
- current.files.set(type, entries = []);
131
- }
132
- const relativePath = current.originalPath ? `${current.originalPath}/${entry.name}` : entry.name;
133
- entries.push({
435
+ const dirPath = dirStack.join("/");
436
+ const relativePath = dirPath ? `${dirPath}/${name}` : name;
437
+ const file = {
134
438
  id: String(nextFileId++),
439
+ name,
135
440
  type,
136
- filePath: entry.path,
441
+ filePath: path3,
137
442
  relativePath,
138
443
  importPath: `${basePath}/${relativePath}`,
139
- name: entry.name,
140
444
  verbs: type === RoutableFileTypes.Page ? ["get"] : void 0
141
- });
142
- },
143
- onDir(dir) {
144
- var _a, _b, _c, _d, _e;
145
- if (!current) {
146
- return;
445
+ };
446
+ for (const dir of dirs) {
447
+ dir.addFile(file);
147
448
  }
148
- const { path: path3, files } = current;
149
- const localMiddleware = (_a = files.get(RoutableFileTypes.Middleware)) == null ? void 0 : _a[0];
150
- const localLayout = (_b = files.get(RoutableFileTypes.Layout)) == null ? void 0 : _b[0];
151
- const handler = (_c = files.get(RoutableFileTypes.Handler)) == null ? void 0 : _c[0];
152
- const page = (_d = files.get(RoutableFileTypes.Page)) == null ? void 0 : _d[0];
153
- const middlewareStackLength = middlewareStack.length;
154
- const layoutsStackLength = layoutsStack.length;
155
- if (localMiddleware) {
156
- middlewareStack.push(localMiddleware);
449
+ }
450
+ });
451
+ traverse(root);
452
+ return {
453
+ list: routes,
454
+ middleware: [...middlewares],
455
+ special
456
+ };
457
+ function traverse(dir) {
458
+ let middleware;
459
+ let layout;
460
+ if (dir.files) {
461
+ middleware = dir.files.get(RoutableFileTypes.Middleware);
462
+ layout = dir.files.get(RoutableFileTypes.Layout);
463
+ const handler = dir.files.get(RoutableFileTypes.Handler);
464
+ const page = dir.files.get(RoutableFileTypes.Page);
465
+ let hasSpecial = false;
466
+ if (middleware) {
467
+ if (currentMiddleware.has(middleware)) {
468
+ middleware = void 0;
469
+ } else {
470
+ currentMiddleware.add(middleware);
471
+ unusedFiles.add(middleware);
472
+ }
157
473
  }
158
- if (localLayout) {
159
- layoutsStack.push(localLayout);
474
+ if (layout) {
475
+ if (currentLayouts.has(layout)) {
476
+ layout = void 0;
477
+ } else {
478
+ currentLayouts.add(layout);
479
+ unusedFiles.add(layout);
480
+ }
160
481
  }
161
- if (handler || page) {
162
- const key = path3.replace(/(\$\$?)[^\/]*/g, "$1").replace(/^\/+/, "").replace(/[^a-z0-9_$\/]+/gi, "").replace(/\//g, "__") || "index";
163
- if (routes.has(key)) {
164
- const existing = routes.get(key);
165
- const existingFiles = [existing.handler, existing.page].filter(Boolean).map((f) => f.filePath);
482
+ if (page || handler) {
483
+ const path3 = dir.pathInfo;
484
+ if (uniqueRoutes.has(path3.id)) {
485
+ const existing = uniqueRoutes.get(path3.id);
486
+ const route = routes[existing.index];
487
+ const existingFiles = [route.handler, route.page].filter(Boolean).map((f) => f.filePath);
166
488
  const currentFiles = [handler, page].filter(Boolean).map((f) => f.filePath);
167
- throw new Error(`Duplicate routes for path ${path3} were defined. A route established by:
168
- ${existingFiles}
169
- collides with
170
- ${currentFiles.join(" and ")}
171
- `);
172
- } else {
173
- const index = nextRouteIndex++;
174
- routes.set(key, {
175
- index,
176
- key,
177
- path: path3,
178
- params: [...paramStack],
179
- middleware: [...middlewareStack],
180
- layouts: page ? [...layoutsStack] : [],
181
- meta: (_e = files.get(RoutableFileTypes.Meta)) == null ? void 0 : _e[0],
182
- page,
183
- handler,
184
- entryName: `${markoRunFilePrefix}route__${key}`,
185
- score: scorePath(path3, index)
186
- });
187
- for (const mw of middlewareStack) {
188
- middleware.add(mw);
189
- }
489
+ throw new Error(`Duplicate routes for path '${path3.path}' were defined. A route established by:
490
+ ${existingFiles.join(" and ")} via '${existing.dir.path}'
491
+ collides with
492
+ ${currentFiles.join(" and ")} via '${dir.path}'
493
+ `);
190
494
  }
495
+ uniqueRoutes.set(path3.id, { dir, index: routes.length });
496
+ routes.push({
497
+ index: nextRouteIndex++,
498
+ key: dir.fullPath,
499
+ paths: [path3],
500
+ middleware: [...currentMiddleware],
501
+ layouts: page ? [...currentLayouts] : [],
502
+ meta: dir.files.get(RoutableFileTypes.Meta),
503
+ page,
504
+ handler,
505
+ entryName: `${markoRunFilePrefix}route` + (dir.path !== "/" ? dir.fullPath.replace(/\//g, ".").replace(/(%[A-Fa-f0-9]{2})+/g, "_") : "")
506
+ });
191
507
  }
192
- if (isRoot) {
193
- for (const [type, entries] of files) {
508
+ if (dir === root) {
509
+ for (const [type, file] of dir.files) {
194
510
  if (isSpecialType(type)) {
511
+ hasSpecial = true;
195
512
  special[type] = {
196
513
  index: 0,
197
514
  key: type,
198
- path: path3,
515
+ paths: [],
199
516
  middleware: [],
200
- layouts: [...layoutsStack],
201
- page: entries[0],
202
- entryName: `${markoRunFilePrefix}special__${type}`,
203
- score: 0
517
+ layouts: [...currentLayouts],
518
+ page: file,
519
+ entryName: `${markoRunFilePrefix}special.${type}`
204
520
  };
205
521
  }
206
522
  }
207
- } else if (dir.startsWith("$$")) {
208
- return false;
209
523
  }
210
- return () => {
211
- middlewareStack.length = middlewareStackLength;
212
- layoutsStack.length = layoutsStackLength;
213
- };
214
- },
215
- onEnter({ name }) {
216
- const pathStackLength = pathStack.length;
217
- const paramStackLength = paramStack.length;
218
- const prevChildren = children;
219
- const prevCurrent = current;
220
- const prevIsRoot = isRoot;
221
- if (name.charCodeAt(0) === 95) {
222
- } else {
223
- if (name.charCodeAt(0) === 36) {
224
- if (name.charCodeAt(1) === 36) {
225
- if (name.length > 2) {
226
- paramStack.push({
227
- name: name.slice(2),
228
- index: -1
229
- });
230
- }
231
- } else if (name.length > 1) {
232
- paramStack.push({
233
- name: name.slice(1),
234
- index: pathStackLength
235
- });
236
- }
524
+ if (handler || page) {
525
+ for (const middleware2 of currentMiddleware) {
526
+ middlewares.add(middleware2);
527
+ unusedFiles.delete(middleware2);
237
528
  }
238
- pathStack.push(name);
239
529
  }
240
- dirStack.push(name);
241
- isRoot = false;
242
- if (current) {
243
- children = current.children;
244
- current = void 0;
530
+ if (page || hasSpecial) {
531
+ for (const layout2 of currentLayouts) {
532
+ unusedFiles.delete(layout2);
533
+ }
245
534
  }
246
- return () => {
247
- dirStack.pop();
248
- pathStack.length = pathStackLength;
249
- paramStack.length = paramStackLength;
250
- children = prevChildren;
251
- current = prevCurrent;
252
- isRoot = prevIsRoot;
253
- };
254
535
  }
255
- });
256
- return {
257
- list: [...routes.values()],
258
- special,
259
- middleware: [...middleware]
260
- };
536
+ if (dir.dirs) {
537
+ for (const child of dir.dirs()) {
538
+ traverse(child);
539
+ }
540
+ }
541
+ if (middleware) {
542
+ currentMiddleware.delete(middleware);
543
+ }
544
+ if (layout) {
545
+ currentLayouts.delete(layout);
546
+ }
547
+ }
261
548
  }
262
549
 
263
550
  // src/vite/routes/walk.ts
264
551
  var import_fs = __toESM(require("fs"), 1);
265
552
  var import_path = __toESM(require("path"), 1);
266
553
  function createFSWalker(dir) {
267
- return async function walkFS({ onFile, onEnter, onDir, maxDepth = 50 }) {
554
+ return async function walkFS({
555
+ onEnter,
556
+ onFile,
557
+ onDir,
558
+ maxDepth = 50
559
+ }) {
268
560
  async function walk(dir2, depth) {
269
- const dirs = [];
270
- const entries = await import_fs.default.promises.readdir(dir2, { withFileTypes: true });
271
- const prefix = dir2 + import_path.default.sep;
272
- for (const dirEntry of entries) {
273
- const entry = {
274
- name: dirEntry.name,
275
- path: prefix + dirEntry.name
276
- };
277
- if (dirEntry.isDirectory()) {
278
- dirs.push(entry);
279
- } else {
280
- onFile == null ? void 0 : onFile(entry);
561
+ const onExit = onEnter == null ? void 0 : onEnter(dir2);
562
+ if (onExit !== false) {
563
+ const dirs = [];
564
+ const entries = await import_fs.default.promises.readdir(dir2.path, {
565
+ withFileTypes: true
566
+ });
567
+ const prefix = dir2.path + import_path.default.sep;
568
+ for (const entry of entries) {
569
+ const walkEntry = {
570
+ name: entry.name,
571
+ path: prefix + entry.name
572
+ };
573
+ if (entry.isDirectory()) {
574
+ dirs.push(walkEntry);
575
+ } else {
576
+ onFile == null ? void 0 : onFile(walkEntry);
577
+ }
281
578
  }
282
- }
283
- const onAfter = onDir == null ? void 0 : onDir(dir2);
284
- if (onAfter !== false) {
285
- if (--depth > 0) {
579
+ if ((onDir == null ? void 0 : onDir()) !== false && --depth > 0) {
286
580
  for (const entry of dirs) {
287
- const onExit = onEnter == null ? void 0 : onEnter(entry);
288
- if (onExit !== false) {
289
- await walk(entry.path, depth);
290
- onExit == null ? void 0 : onExit();
291
- }
581
+ await walk(entry, depth);
292
582
  }
293
583
  }
294
- onAfter == null ? void 0 : onAfter();
584
+ onExit == null ? void 0 : onExit();
295
585
  }
296
586
  }
297
- await walk(dir, maxDepth);
587
+ await walk(
588
+ {
589
+ path: dir,
590
+ name: import_path.default.basename(dir)
591
+ },
592
+ maxDepth
593
+ );
298
594
  };
299
595
  }
300
596
 
@@ -386,6 +682,10 @@ function createWriter(sink, options) {
386
682
  branches[i] = null;
387
683
  firstOpenIndex++;
388
684
  }
685
+ if (!openWriters.size) {
686
+ sink(buffer);
687
+ buffer = "";
688
+ }
389
689
  }
390
690
  }
391
691
  )
@@ -431,49 +731,6 @@ function createStringWriter(opts) {
431
731
  });
432
732
  }
433
733
 
434
- // src/vite/routes/routeTrie.ts
435
- function createRouteTrie(routes) {
436
- const root = {
437
- key: ""
438
- };
439
- function insert(keys, value) {
440
- let node = root;
441
- for (const key of keys) {
442
- if (key.startsWith("$$")) {
443
- if (!node.catchAll) {
444
- node.catchAll = value;
445
- return true;
446
- }
447
- return false;
448
- } else if (key.startsWith("$")) {
449
- node = node.dynamic ?? (node.dynamic = {
450
- key: ""
451
- });
452
- } else {
453
- node.static ?? (node.static = /* @__PURE__ */ new Map());
454
- let next = node.static.get(key);
455
- if (!next) {
456
- next = {
457
- key
458
- };
459
- node.static.set(key, next);
460
- }
461
- node = next;
462
- }
463
- }
464
- if (node.route === void 0) {
465
- node.route = value;
466
- return true;
467
- }
468
- return false;
469
- }
470
- for (const route of routes) {
471
- const keys = route.path === "/" ? [] : route.path.split("/").slice(1);
472
- insert(keys, route);
473
- }
474
- return root;
475
- }
476
-
477
734
  // src/vite/utils/route.ts
478
735
  function getVerbs(route) {
479
736
  var _a, _b;
@@ -494,9 +751,7 @@ function renderRouteTemplate(route) {
494
751
  throw new Error(`Route ${route.key} has no page to render`);
495
752
  }
496
753
  const writer = createStringWriter();
497
- writer.writeLines(
498
- `// ${virtualFilePrefix}/${route.entryName}.marko`
499
- );
754
+ writer.writeLines(`// ${virtualFilePrefix}/${route.entryName}.marko`);
500
755
  writer.branch("imports");
501
756
  writer.writeLines("");
502
757
  writeRouteTemplateTag(writer, [...route.layouts, route.page]);
@@ -526,9 +781,7 @@ function renderRouteEntry(route) {
526
781
  );
527
782
  }
528
783
  const writer = createStringWriter();
529
- writer.writeLines(
530
- `// ${virtualFilePrefix}/${entryName}.js`
531
- );
784
+ writer.writeLines(`// ${virtualFilePrefix}/${entryName}.js`);
532
785
  const imports = writer.branch("imports");
533
786
  const runtimeImports = [];
534
787
  if (handler) {
@@ -673,9 +926,7 @@ function renderRouter(routes, options = {
673
926
  const names = verbs.map((verb) => `${verb}${route.index}`);
674
927
  route.meta && names.push(`meta${route.index}`);
675
928
  imports.writeLines(
676
- `import { ${names.join(
677
- ", "
678
- )} } from '${virtualFilePrefix}/${route.entryName}.js';`
929
+ `import { ${names.join(", ")} } from '${virtualFilePrefix}/${route.entryName}.js';`
679
930
  );
680
931
  }
681
932
  for (const { key, entryName } of Object.values(routes.special)) {
@@ -746,7 +997,7 @@ const page404ResponseInit = {
746
997
  if (routes.special[RoutableFileTypes.Error]) {
747
998
  imports.writeLines(`
748
999
  const page500ResponseInit = {
749
- status: 404,
1000
+ status: 500,
750
1001
  headers: { "content-type": "text/html;charset=UTF-8" },
751
1002
  };`);
752
1003
  writer.writeBlockStart(
@@ -810,7 +1061,7 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
810
1061
  writer.writeLines(`const len = pathname.length;`);
811
1062
  if (route) {
812
1063
  writer.writeLines(
813
- `if (len === 1) return ${renderMatch(verb, route)}; // ${route.path}`
1064
+ `if (len === 1) return ${renderMatch(verb, route, trie.path)}; // ${trie.path.path}`
814
1065
  );
815
1066
  } else if (trie.static || dynamic) {
816
1067
  writer.writeBlockStart(`if (len > 1) {`);
@@ -847,14 +1098,14 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
847
1098
  if (useSwitch) {
848
1099
  writer.writeBlockStart(`switch (${value}.toLowerCase()) {`);
849
1100
  }
850
- for (const { key, route: route2 } of terminal) {
1101
+ for (const { key, path: path3, route: route2 } of terminal) {
851
1102
  if (useSwitch) {
852
1103
  writer.write(`case '${key}': `, true);
853
1104
  } else {
854
1105
  writer.write(`if (${value}.toLowerCase() === '${key}') `, true);
855
1106
  }
856
1107
  writer.write(
857
- `return ${renderMatch(verb, route2)}; // ${route2.path}
1108
+ `return ${renderMatch(verb, route2, path3)}; // ${path3.path}
858
1109
  `
859
1110
  );
860
1111
  }
@@ -864,7 +1115,11 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
864
1115
  }
865
1116
  if (dynamic == null ? void 0 : dynamic.route) {
866
1117
  writer.writeLines(
867
- `if (${value}) return ${renderMatch(verb, dynamic.route)}; // ${dynamic.route.path}`
1118
+ `if (${value}) return ${renderMatch(
1119
+ verb,
1120
+ dynamic.route,
1121
+ dynamic.path
1122
+ )}; // ${dynamic.path.path}`
868
1123
  );
869
1124
  }
870
1125
  }
@@ -897,7 +1152,11 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
897
1152
  }
898
1153
  const nextOffset = typeof offset === "string" ? index : offset + child.key.length + 1;
899
1154
  writeRouterVerb(writer, child, verb, next, nextOffset);
900
- writer.writeBlockEnd("}");
1155
+ if (useSwitch) {
1156
+ writer.writeBlockEnd("} break;");
1157
+ } else {
1158
+ writer.writeBlockEnd("}");
1159
+ }
901
1160
  }
902
1161
  if (useSwitch) {
903
1162
  writer.writeBlockEnd("}");
@@ -915,7 +1174,7 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
915
1174
  }
916
1175
  if (catchAll) {
917
1176
  writer.writeLines(
918
- `return ${renderMatch(verb, catchAll, String(offset))}; // ${catchAll.path}`
1177
+ `return ${renderMatch(verb, catchAll.route, catchAll.path, String(offset))}; // ${catchAll.path.path}`
919
1178
  );
920
1179
  } else if (level === 0) {
921
1180
  writer.writeLines("return null;");
@@ -925,15 +1184,12 @@ function wrapPropertyName(name) {
925
1184
  name = decodeURIComponent(name);
926
1185
  return /^[^A-Za-z_$]|[^A-Za-z0-9$_]/.test(name) ? `'${name}'` : name;
927
1186
  }
928
- function renderParamsInfo(params, pathIndex) {
929
- if (!params.length) {
930
- return "{}";
931
- }
1187
+ function renderParams(params, pathIndex) {
932
1188
  let result = "";
933
1189
  let catchAll = "";
934
1190
  let sep = "{";
935
- for (const { name, index } of params) {
936
- if (index >= 0) {
1191
+ for (const [name, index] of Object.entries(params)) {
1192
+ if (typeof index === "number") {
937
1193
  result += `${sep} ${wrapPropertyName(name)}: s${index + 1}`;
938
1194
  sep = ",";
939
1195
  } else if (pathIndex) {
@@ -947,13 +1203,12 @@ function renderParamsInfo(params, pathIndex) {
947
1203
  }
948
1204
  return result ? result + " }" : "{}";
949
1205
  }
950
- function renderMatch(verb, route, pathIndex) {
951
- var _a;
1206
+ function renderMatch(verb, route, path3, pathIndex) {
952
1207
  const handler = `${verb}${route.index}`;
953
- const params = ((_a = route.params) == null ? void 0 : _a.length) ? renderParamsInfo(route.params, pathIndex) : "{}";
1208
+ const params = path3.params ? renderParams(path3.params, pathIndex) : "{}";
954
1209
  const meta = route.meta ? `meta${route.index}` : "{}";
955
- const path3 = pathToURLPatternString(route.path);
956
- return `{ handler: ${handler}, params: ${params}, meta: ${meta}, path: '${path3}' }`;
1210
+ const pathPattern = pathToURLPatternString(path3.path);
1211
+ return `{ handler: ${handler}, params: ${params}, meta: ${meta}, path: '${pathPattern}' }`;
957
1212
  }
958
1213
  function renderMiddleware(middleware) {
959
1214
  const writer = createStringWriter();
@@ -1004,37 +1259,20 @@ async function renderRouteTypeInfo(routes, pathPrefix = ".", adapter) {
1004
1259
  `);
1005
1260
  }
1006
1261
  }
1262
+ headWriter.join();
1007
1263
  writer.writeBlockStart(`interface AppData extends Run.DefineApp<{`).writeBlockStart("routes: {");
1008
1264
  const routesWriter = writer.branch("routes");
1009
1265
  writer.writeBlockEnd("}").writeBlockEnd(`}> {}`).writeBlockEnd(`}`);
1010
- headWriter.join();
1011
1266
  const moduleWriter = writer.branch("module");
1012
1267
  const middlewareRouteTypes = /* @__PURE__ */ new Map();
1013
1268
  const layoutRouteTypes = /* @__PURE__ */ new Map();
1014
1269
  for (const route of routes.list) {
1015
- const { meta, handler, middleware, page, layouts } = route;
1016
- const pathType = `${pathToURLPatternString(route.path)}`;
1017
- const routeType = `"${pathType}"`;
1018
- let verbType = "";
1019
- if (page || handler) {
1020
- const verbs = [];
1021
- if (page || ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes("get"))) {
1022
- verbs.push(`"get"`);
1023
- }
1024
- if ((_b = handler == null ? void 0 : handler.verbs) == null ? void 0 : _b.includes("post")) {
1025
- verbs.push(`"post"`);
1026
- }
1027
- verbType = verbs.join(" | ");
1028
- }
1029
- if (meta) {
1030
- const path3 = stripTsExtension(`${pathPrefix}/${meta.relativePath}`);
1031
- let metaType = `typeof import("${path3}")`;
1032
- if (/\.(ts|js|mjs)$/.test(meta.relativePath)) {
1033
- metaType += `["default"]`;
1034
- }
1035
- routesWriter.writeBlockStart(`"${pathType}": {`).writeLines(`verb: ${verbType};`, `meta: ${metaType};`).writeBlockEnd("};");
1036
- } else {
1037
- routesWriter.writeLines(`"${pathType}": { verb: ${verbType} };`);
1270
+ const { handler, middleware, page, layouts } = route;
1271
+ let routeType = "";
1272
+ for (const path3 of route.paths) {
1273
+ const pathType = `"${pathToURLPatternString(path3.path)}"`;
1274
+ routeType += routeType ? " | " + pathType : pathType;
1275
+ routesWriter.writeLines(`${pathType}: Routes["${route.key}"]`);
1038
1276
  }
1039
1277
  if (handler) {
1040
1278
  writeModuleDeclaration(
@@ -1101,7 +1339,7 @@ async function renderRouteTypeInfo(routes, pathPrefix = ".", adapter) {
1101
1339
  }`
1102
1340
  );
1103
1341
  }
1104
- if ((_c = routes.special["404"]) == null ? void 0 : _c.page) {
1342
+ if ((_a = routes.special["404"]) == null ? void 0 : _a.page) {
1105
1343
  writeModuleDeclaration(
1106
1344
  writer,
1107
1345
  `${pathPrefix}/${routes.special["404"].page.relativePath}`,
@@ -1110,7 +1348,7 @@ async function renderRouteTypeInfo(routes, pathPrefix = ".", adapter) {
1110
1348
  export interface Input {}`
1111
1349
  );
1112
1350
  }
1113
- if ((_d = routes.special["500"]) == null ? void 0 : _d.page) {
1351
+ if ((_b = routes.special["500"]) == null ? void 0 : _b.page) {
1114
1352
  writeModuleDeclaration(
1115
1353
  writer,
1116
1354
  `${pathPrefix}/${routes.special["500"].page.relativePath}`,
@@ -1122,6 +1360,31 @@ async function renderRouteTypeInfo(routes, pathPrefix = ".", adapter) {
1122
1360
  );
1123
1361
  }
1124
1362
  moduleWriter.join();
1363
+ writer.writeBlockStart(`
1364
+ type Routes = {`);
1365
+ for (const route of routes.list) {
1366
+ const { meta, handler, page } = route;
1367
+ if (page || handler) {
1368
+ const verbs = [];
1369
+ if (page || ((_c = handler == null ? void 0 : handler.verbs) == null ? void 0 : _c.includes("get"))) {
1370
+ verbs.push(`"get"`);
1371
+ }
1372
+ if ((_d = handler == null ? void 0 : handler.verbs) == null ? void 0 : _d.includes("post")) {
1373
+ verbs.push(`"post"`);
1374
+ }
1375
+ let routeType = `{ verb: ${verbs.join(" | ")};`;
1376
+ if (meta) {
1377
+ const metaPath = stripTsExtension(`${pathPrefix}/${meta.relativePath}`);
1378
+ let metaType = `typeof import("${metaPath}")`;
1379
+ if (/\.(ts|js|mjs)$/.test(meta.relativePath)) {
1380
+ metaType += `["default"]`;
1381
+ }
1382
+ routeType += ` meta: ${metaType};`;
1383
+ }
1384
+ writer.writeLines(`"${route.key}": ${routeType} };`);
1385
+ }
1386
+ }
1387
+ writer.writeBlockEnd("}");
1125
1388
  return writer.end();
1126
1389
  }
1127
1390
  function writeModuleDeclaration(writer, path3, routeType, moduleTypes) {
@@ -1149,6 +1412,42 @@ function pathToURLPatternString(path3) {
1149
1412
  return catchAll ? `/:${name || "rest"}*` : `/:${name}`;
1150
1413
  });
1151
1414
  }
1415
+ function createRouteTrie(routes) {
1416
+ const root = {
1417
+ key: ""
1418
+ };
1419
+ function insert(path3, route) {
1420
+ let node = root;
1421
+ for (const segment of path3.segments) {
1422
+ if (segment === "$$") {
1423
+ node.catchAll ?? (node.catchAll = { route, path: path3 });
1424
+ return;
1425
+ } else if (segment === "$") {
1426
+ node = node.dynamic ?? (node.dynamic = {
1427
+ key: ""
1428
+ });
1429
+ } else {
1430
+ node.static ?? (node.static = /* @__PURE__ */ new Map());
1431
+ let next = node.static.get(segment);
1432
+ if (!next) {
1433
+ next = {
1434
+ key: segment
1435
+ };
1436
+ node.static.set(segment, next);
1437
+ }
1438
+ node = next;
1439
+ }
1440
+ }
1441
+ node.path ?? (node.path = path3);
1442
+ node.route ?? (node.route = route);
1443
+ }
1444
+ for (const route of routes) {
1445
+ for (const path3 of route.paths) {
1446
+ insert(path3, route);
1447
+ }
1448
+ }
1449
+ return root;
1450
+ }
1152
1451
 
1153
1452
  // src/vite/utils/ast.ts
1154
1453
  var t = __toESM(require("@babel/types"), 1);
@@ -1230,31 +1529,33 @@ function logRoutesTable(routes, bundle) {
1230
1529
  colAligns,
1231
1530
  style: { compact: true }
1232
1531
  });
1233
- for (const route of routes.list.sort((a, b) => b.score - a.score)) {
1234
- const verbs = getVerbs(route).sort(
1235
- (a, b) => HttpVerbOrder[a] - HttpVerbOrder[b]
1236
- );
1237
- let firstRow = true;
1238
- for (const verb of verbs) {
1239
- let size = "";
1240
- const entryType = [];
1241
- if (route.handler) {
1242
- entryType.push(import_kleur.default.blue("handler"));
1243
- }
1244
- if (verb === "get" && route.page) {
1245
- entryType.push(import_kleur.default.yellow("page"));
1246
- size = prettySize(computeRouteSize(route, bundle));
1247
- }
1248
- const row = [import_kleur.default.bold(HttpVerbColors[verb](verb.toUpperCase()))];
1249
- if (verbs.length === 1 || firstRow) {
1250
- row.push({ rowSpan: verbs.length, content: prettyPath(route.path) });
1251
- firstRow = false;
1532
+ for (const route of routes.list) {
1533
+ for (const path3 of route.paths) {
1534
+ const verbs = getVerbs(route).sort(
1535
+ (a, b) => HttpVerbOrder[a] - HttpVerbOrder[b]
1536
+ );
1537
+ let firstRow = true;
1538
+ for (const verb of verbs) {
1539
+ let size = "";
1540
+ const entryType = [];
1541
+ if (route.handler) {
1542
+ entryType.push(import_kleur.default.blue("handler"));
1543
+ }
1544
+ if (verb === "get" && route.page) {
1545
+ entryType.push(import_kleur.default.yellow("page"));
1546
+ size = prettySize(computeRouteSize(route, bundle));
1547
+ }
1548
+ const row = [import_kleur.default.bold(HttpVerbColors[verb](verb.toUpperCase()))];
1549
+ if (verbs.length === 1 || firstRow) {
1550
+ row.push({ rowSpan: verbs.length, content: prettyPath(path3.path) });
1551
+ firstRow = false;
1552
+ }
1553
+ row.push(entryType.join(" -> "));
1554
+ hasMiddleware && row.push(route.middleware.length || "");
1555
+ hasMeta && row.push(route.meta ? "\u2713" : "");
1556
+ row.push(size || "");
1557
+ table.push(row);
1252
1558
  }
1253
- row.push(entryType.join(" -> "));
1254
- hasMiddleware && row.push(route.middleware.length || "");
1255
- hasMeta && row.push(route.meta ? "\u2713" : "");
1256
- row.push(size || "");
1257
- table.push(row);
1258
1559
  }
1259
1560
  }
1260
1561
  for (const [key, route] of Object.entries(routes.special).sort()) {
@@ -1396,24 +1697,18 @@ function markoRun(opts = {}) {
1396
1697
  }
1397
1698
  if (route.page) {
1398
1699
  virtualFiles.set(
1399
- import_path2.default.posix.join(
1400
- root,
1401
- `${markoRunFilePrefix}route__${route.key}.marko`
1402
- ),
1700
+ import_path2.default.posix.join(root, `${route.entryName}.marko`),
1403
1701
  render ? renderRouteTemplate(route) : ""
1404
1702
  );
1405
1703
  }
1406
1704
  virtualFiles.set(
1407
- import_path2.default.posix.join(root, `${markoRunFilePrefix}route__${route.key}.js`),
1705
+ import_path2.default.posix.join(root, `${route.entryName}.js`),
1408
1706
  render ? renderRouteEntry(route) : ""
1409
1707
  );
1410
1708
  }
1411
1709
  for (const route of Object.values(routes.special)) {
1412
1710
  virtualFiles.set(
1413
- import_path2.default.posix.join(
1414
- root,
1415
- `${markoRunFilePrefix}special__${route.key}.marko`
1416
- ),
1711
+ import_path2.default.posix.join(root, `${route.entryName}.marko`),
1417
1712
  render ? renderRouteTemplate(route) : ""
1418
1713
  );
1419
1714
  }
@@ -1813,10 +2108,10 @@ async function resolveAdapter(root, options, log) {
1813
2108
  log && console.log("Using default adapter");
1814
2109
  return module2.default();
1815
2110
  }
1816
- var markoEntryFileRegex = /__marko-run__([^_]+)__(.+)\.marko.([^.]+)$/;
2111
+ var markoEntryFileRegex = /__marko-run__([^.]+)\.(.+)\.marko\.([^.]+)$/;
1817
2112
  function getEntryFileName(file) {
1818
2113
  const match = file && markoEntryFileRegex.exec(file);
1819
- return match ? `${match[2].replace(/__/g, "-")}` : void 0;
2114
+ return match ? match[2] : void 0;
1820
2115
  }
1821
2116
 
1822
2117
  // src/vite/utils/server.ts