@marko/run 0.1.16 → 0.2.1

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.
@@ -1,3 +1,28 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => {
4
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
+ return value;
6
+ };
7
+ var __accessCheck = (obj, member, msg) => {
8
+ if (!member.has(obj))
9
+ throw TypeError("Cannot " + msg);
10
+ };
11
+ var __privateGet = (obj, member, getter) => {
12
+ __accessCheck(obj, member, "read from private field");
13
+ return getter ? getter.call(obj) : member.get(obj);
14
+ };
15
+ var __privateAdd = (obj, member, value) => {
16
+ if (member.has(obj))
17
+ throw TypeError("Cannot add the same private member more than once");
18
+ member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
19
+ };
20
+ var __privateSet = (obj, member, value, setter) => {
21
+ __accessCheck(obj, member, "write to private field");
22
+ setter ? setter.call(obj, value) : member.set(obj, value);
23
+ return value;
24
+ };
25
+
1
26
  // src/vite/plugin.ts
2
27
  import path2 from "path";
3
28
  import crypto from "crypto";
@@ -23,236 +48,509 @@ var RoutableFileTypes = {
23
48
  Error: "500"
24
49
  };
25
50
 
51
+ // src/vite/routes/vdir.ts
52
+ var _dirs, _pathlessDirs;
53
+ var _VDir = class {
54
+ constructor(parent, segment, source) {
55
+ __privateAdd(this, _dirs, void 0);
56
+ __privateAdd(this, _pathlessDirs, void 0);
57
+ __publicField(this, "parent");
58
+ __publicField(this, "source");
59
+ __publicField(this, "path");
60
+ __publicField(this, "fullPath");
61
+ __publicField(this, "segment");
62
+ __publicField(this, "files");
63
+ if (!parent || !segment) {
64
+ this.parent = null;
65
+ this.source = null;
66
+ this.path = "/";
67
+ this.fullPath = "/";
68
+ this.segment = {
69
+ raw: "",
70
+ name: ""
71
+ };
72
+ } else {
73
+ this.parent = parent;
74
+ this.source = source;
75
+ this.path = parent.path + (parent.path === "/" ? segment.name : `/${segment.name}`);
76
+ this.fullPath = parent.fullPath + (parent.fullPath === "/" ? segment.name : `/${segment.name}`);
77
+ if (segment.param) {
78
+ this.fullPath += segment.param;
79
+ }
80
+ this.segment = segment;
81
+ }
82
+ }
83
+ get pathInfo() {
84
+ const value = {
85
+ id: "/",
86
+ path: "/",
87
+ segments: []
88
+ };
89
+ let sep = "";
90
+ for (const { segment } of this) {
91
+ const { type, name, param } = segment;
92
+ if (name && type !== "_") {
93
+ value.id += sep + (type || name);
94
+ value.path += sep + name;
95
+ value.isEnd = type === "$$";
96
+ if (param) {
97
+ value.path += param;
98
+ let index = type === "$$" ? null : value.segments.length;
99
+ if (!value.params) {
100
+ value.params = { [param]: index };
101
+ } else if (!(param in value.params)) {
102
+ value.params[param] = index;
103
+ }
104
+ }
105
+ value.segments.push(name);
106
+ sep = "/";
107
+ }
108
+ }
109
+ Object.defineProperty(this, "pathInfo", {
110
+ value,
111
+ enumerable: true
112
+ });
113
+ return value;
114
+ }
115
+ addDir(path3, segment) {
116
+ const map = segment.type === "_" ? __privateGet(this, _pathlessDirs) ?? __privateSet(this, _pathlessDirs, /* @__PURE__ */ new Map()) : __privateGet(this, _dirs) ?? __privateSet(this, _dirs, /* @__PURE__ */ new Map());
117
+ if (!map.has(segment.name)) {
118
+ const dir = new _VDir(this, segment, path3);
119
+ map.set(segment.name, dir);
120
+ return dir;
121
+ }
122
+ return map.get(segment.name);
123
+ }
124
+ addFile(file) {
125
+ if (!this.files) {
126
+ this.files = /* @__PURE__ */ new Map();
127
+ this.files.set(file.type, file);
128
+ } else if (!this.files.has(file.type)) {
129
+ this.files.set(file.type, file);
130
+ } else {
131
+ const existing = this.files.get(file.type);
132
+ if (existing !== file) {
133
+ throw new Error(
134
+ `Duplicate file type '${file.type}' added at path '${this.path}'. File '${file.filePath}' collides with '${existing.filePath}'.`
135
+ );
136
+ } else if (file.type === RoutableFileTypes.Page || file.type === RoutableFileTypes.Handler) {
137
+ throw new Error(
138
+ `Ambiguous path definition: route '${this.path}' is defined multiple times by ${file.filePath}`
139
+ );
140
+ }
141
+ throw new Error(
142
+ `Ambiguous path definition: file '${this.path}' is included multiple times by ${file.filePath}`
143
+ );
144
+ }
145
+ }
146
+ *dirs() {
147
+ if (__privateGet(this, _pathlessDirs)) {
148
+ yield* __privateGet(this, _pathlessDirs).values();
149
+ }
150
+ if (__privateGet(this, _dirs)) {
151
+ yield* __privateGet(this, _dirs).values();
152
+ }
153
+ }
154
+ *[Symbol.iterator]() {
155
+ if (this.parent) {
156
+ yield* this.parent;
157
+ }
158
+ yield this;
159
+ }
160
+ static addPaths(roots, paths) {
161
+ const dirs = [];
162
+ const unique = /* @__PURE__ */ new Set();
163
+ for (const root of roots) {
164
+ for (const path3 of paths) {
165
+ let dir = root;
166
+ for (const segment of path3.segments) {
167
+ dir = dir.addDir(path3, segment);
168
+ }
169
+ if (unique.has(dir.path)) {
170
+ const sources = /* @__PURE__ */ new Set();
171
+ let sourcePath = "";
172
+ for (const { source } of dir) {
173
+ if (source && !sources.has(source.source)) {
174
+ sources.add(source.source);
175
+ sourcePath += source.source + "/";
176
+ }
177
+ }
178
+ throw new Error(
179
+ `Ambiguous directory structure: '${sourcePath}${path3.source}' defines '${dir.path}' multiple times.`
180
+ );
181
+ } else {
182
+ unique.add(dir.path);
183
+ dirs.push(dir);
184
+ }
185
+ }
186
+ }
187
+ return dirs;
188
+ }
189
+ };
190
+ var VDir = _VDir;
191
+ _dirs = new WeakMap();
192
+ _pathlessDirs = new WeakMap();
193
+
194
+ // src/vite/routes/parse.ts
195
+ function parseFlatRoute(pattern) {
196
+ if (!pattern)
197
+ throw new Error("Empty pattern");
198
+ const len = pattern.length;
199
+ let i = 0;
200
+ return parse2([
201
+ {
202
+ id: "/",
203
+ segments: [],
204
+ source: pattern
205
+ }
206
+ ]);
207
+ function parse2(basePaths, group) {
208
+ const pathMap = /* @__PURE__ */ new Map();
209
+ const delimiters = group ? ").," : ".,";
210
+ let charCode;
211
+ let segmentStart = i;
212
+ let type;
213
+ let current;
214
+ do {
215
+ charCode = pattern.charCodeAt(i);
216
+ if (charCode === 41 && group) {
217
+ break;
218
+ } else if (charCode === 44) {
219
+ if (!current) {
220
+ segmentEnd(
221
+ basePaths.map((path3) => ({
222
+ ...path3,
223
+ segments: path3.segments.slice()
224
+ })),
225
+ "",
226
+ "_",
227
+ pathMap
228
+ );
229
+ } else {
230
+ segmentEnd(current, pattern.slice(segmentStart, i), type, pathMap);
231
+ }
232
+ current = void 0;
233
+ type = void 0;
234
+ segmentStart = ++i;
235
+ } else if (charCode === 46) {
236
+ if (current) {
237
+ segmentEnd(current, pattern.slice(segmentStart, i), type);
238
+ }
239
+ type = void 0;
240
+ segmentStart = ++i;
241
+ } else if (charCode === 40) {
242
+ const groupPaths = parse2(current || basePaths, ++i);
243
+ if (groupPaths.length) {
244
+ current = groupPaths;
245
+ }
246
+ segmentStart = ++i;
247
+ } else {
248
+ if (charCode === 95) {
249
+ type = "_";
250
+ } else if (charCode === 36) {
251
+ type = pattern.charCodeAt(i + 1) === 36 ? "$$" : "$";
252
+ }
253
+ current ?? (current = basePaths.map((path3) => ({
254
+ ...path3,
255
+ segments: path3.segments.slice()
256
+ })));
257
+ i = len;
258
+ for (const char of delimiters) {
259
+ const index = pattern.indexOf(char, segmentStart);
260
+ if (index >= 0 && index < i) {
261
+ i = index;
262
+ }
263
+ }
264
+ }
265
+ } while (i < len);
266
+ if (group && charCode !== 41) {
267
+ throw new Error(
268
+ `Invalid route pattern: group was not closed '${pattern.slice(
269
+ group
270
+ )}' in '${pattern}'`
271
+ );
272
+ }
273
+ if (!current) {
274
+ segmentEnd(
275
+ basePaths.map((path3) => ({
276
+ ...path3,
277
+ segments: path3.segments.slice()
278
+ })),
279
+ "",
280
+ "_",
281
+ pathMap
282
+ );
283
+ } else {
284
+ segmentEnd(current, pattern.slice(segmentStart, i), type, pathMap);
285
+ }
286
+ return [...pathMap.values()];
287
+ }
288
+ function segmentEnd(paths, raw, type, map) {
289
+ let segment;
290
+ if (raw) {
291
+ segment = {
292
+ raw,
293
+ name: raw,
294
+ type
295
+ };
296
+ if (type === "$" || type === "$$") {
297
+ segment.name = type;
298
+ segment.param = raw.slice(type.length);
299
+ }
300
+ }
301
+ for (const path3 of paths) {
302
+ if (segment) {
303
+ if (path3.isCatchall) {
304
+ throw new Error(
305
+ `Invalid route pattern: nested segments are not allowed after a catch-all parameter. Found '.' following '${pattern.slice(
306
+ 0,
307
+ i
308
+ )}' in '${pattern}'.`
309
+ );
310
+ }
311
+ path3.segments.push(segment);
312
+ path3.id += path3.id === "/" ? segment.name : `/${segment.name}`;
313
+ if (type === "$$") {
314
+ path3.isCatchall = true;
315
+ }
316
+ }
317
+ if (map) {
318
+ if (map.has(path3.id)) {
319
+ const existing = map.get(path3.id);
320
+ const existingExpansion = existing.segments.map((s) => s.raw).join(".");
321
+ const currentExpansion = path3.segments.map((s) => s.raw).join(".");
322
+ throw new Error(
323
+ `Invalid route pattern: route '${path3.id}' is ambiguous. Expansion '${currentExpansion}' collides with '${existingExpansion}' in '${pattern}'.`
324
+ );
325
+ }
326
+ map.set(path3.id, path3);
327
+ }
328
+ }
329
+ }
330
+ }
331
+
26
332
  // src/vite/routes/builder.ts
27
333
  var markoFiles = `(${RoutableFileTypes.Layout}|${RoutableFileTypes.Page}|${RoutableFileTypes.NotFound}|${RoutableFileTypes.Error})\\.(?:.*\\.)?(marko)`;
28
334
  var nonMarkoFiles = `(${RoutableFileTypes.Middleware}|${RoutableFileTypes.Handler}|${RoutableFileTypes.Meta})\\.(?:.*\\.)?(.+)`;
29
335
  var routeableFileRegex = new RegExp(
30
- `^[+](?:${markoFiles}|${nonMarkoFiles})$`,
336
+ `[+](?:${markoFiles}|${nonMarkoFiles})$`,
31
337
  "i"
32
338
  );
33
339
  function matchRoutableFile(filename) {
34
340
  const match = filename.match(routeableFileRegex);
35
341
  return match && (match[1] || match[3]).toLowerCase();
36
342
  }
37
- function scorePath(path3, index) {
38
- const [pattern, splat] = path3.split("/$$", 2);
39
- const segments = pattern.split("/").filter(Boolean);
40
- return segments.reduce(
41
- (score, segment) => score + (segment.startsWith("$") ? 3 : 4),
42
- segments.length + (splat === void 0 ? 1 : 2)
43
- ) * 1e4 - index;
44
- }
45
343
  function isSpecialType(type) {
46
344
  return type === RoutableFileTypes.NotFound || type === RoutableFileTypes.Error;
47
345
  }
48
- async function buildRoutes(walk, basePath) {
346
+ async function buildRoutes(walk, basePath = "") {
49
347
  if (basePath) {
50
348
  basePath = basePath.replace(/^\/+|\/+$/g, "");
51
349
  }
52
- const dirStack = [];
53
- const pathStack = [];
54
- const paramStack = [];
55
- const layoutsStack = [];
56
- const middlewareStack = [];
57
- const routes = /* @__PURE__ */ new Map();
350
+ const uniqueRoutes = /* @__PURE__ */ new Map();
351
+ const routes = [];
58
352
  const special = {};
59
- const middleware = /* @__PURE__ */ new Set();
60
- let isRoot = true;
353
+ const middlewares = /* @__PURE__ */ new Set();
354
+ const unusedFiles = /* @__PURE__ */ new Set();
355
+ const currentLayouts = /* @__PURE__ */ new Set();
356
+ const currentMiddleware = /* @__PURE__ */ new Set();
357
+ const root = new VDir();
358
+ const dirStack = [];
359
+ let activeDirs = [root];
61
360
  let nextFileId = 1;
62
361
  let nextRouteIndex = 1;
63
- let current;
64
- let children = [];
362
+ let isBaseDir = true;
65
363
  await walk({
66
- onFile(entry) {
67
- const type = matchRoutableFile(entry.name);
68
- if (!type) {
364
+ onEnter({ name }) {
365
+ if (!name || isBaseDir) {
366
+ isBaseDir = false;
69
367
  return;
70
368
  }
71
- if (!isRoot && isSpecialType(type)) {
369
+ dirStack.push(name);
370
+ const previousDirs = activeDirs;
371
+ const paths = parseFlatRoute(name);
372
+ activeDirs = VDir.addPaths(previousDirs, paths);
373
+ return () => {
374
+ activeDirs = previousDirs;
375
+ dirStack.pop();
376
+ };
377
+ },
378
+ onFile({ name, path: path3 }) {
379
+ const match = name.match(routeableFileRegex);
380
+ if (!match) {
381
+ return;
382
+ }
383
+ const type = (match[1] || match[3]).toLowerCase();
384
+ if (dirStack.length && isSpecialType(type)) {
72
385
  console.warn(
73
- `Special pages '${RoutableFileTypes.NotFound}' and '${RoutableFileTypes.Error}' are only considered in the root directory - ignoring ${entry.path}`
386
+ `Special pages '${RoutableFileTypes.NotFound}' and '${RoutableFileTypes.Error}' are only considered in the root directory - ignoring ${path3}`
74
387
  );
75
388
  return;
76
389
  }
77
- if (!current) {
78
- current = {
79
- path: "/" + pathStack.join("/"),
80
- originalPath: dirStack.join("/"),
81
- children: [],
82
- files: /* @__PURE__ */ new Map()
83
- };
84
- children.push(current);
85
- }
86
- let entries = current.files.get(type);
87
- if (!entries) {
88
- current.files.set(type, entries = []);
390
+ let dirs = activeDirs;
391
+ if (match.index) {
392
+ const paths = parseFlatRoute(name.slice(0, match.index));
393
+ dirs = VDir.addPaths(activeDirs, paths);
89
394
  }
90
- const relativePath = current.originalPath ? `${current.originalPath}/${entry.name}` : entry.name;
91
- entries.push({
395
+ const dirPath = dirStack.join("/");
396
+ const relativePath = dirPath ? `${dirPath}/${name}` : name;
397
+ const file = {
92
398
  id: String(nextFileId++),
399
+ name,
93
400
  type,
94
- filePath: entry.path,
401
+ filePath: path3,
95
402
  relativePath,
96
403
  importPath: `${basePath}/${relativePath}`,
97
- name: entry.name,
98
404
  verbs: type === RoutableFileTypes.Page ? ["get"] : void 0
99
- });
100
- },
101
- onDir(dir) {
102
- var _a, _b, _c, _d, _e;
103
- if (!current) {
104
- return;
405
+ };
406
+ for (const dir of dirs) {
407
+ dir.addFile(file);
105
408
  }
106
- const { path: path3, files } = current;
107
- const localMiddleware = (_a = files.get(RoutableFileTypes.Middleware)) == null ? void 0 : _a[0];
108
- const localLayout = (_b = files.get(RoutableFileTypes.Layout)) == null ? void 0 : _b[0];
109
- const handler = (_c = files.get(RoutableFileTypes.Handler)) == null ? void 0 : _c[0];
110
- const page = (_d = files.get(RoutableFileTypes.Page)) == null ? void 0 : _d[0];
111
- const middlewareStackLength = middlewareStack.length;
112
- const layoutsStackLength = layoutsStack.length;
113
- if (localMiddleware) {
114
- middlewareStack.push(localMiddleware);
409
+ }
410
+ });
411
+ traverse(root);
412
+ return {
413
+ list: routes,
414
+ middleware: [...middlewares],
415
+ special
416
+ };
417
+ function traverse(dir) {
418
+ let middleware;
419
+ let layout;
420
+ if (dir.files) {
421
+ middleware = dir.files.get(RoutableFileTypes.Middleware);
422
+ layout = dir.files.get(RoutableFileTypes.Layout);
423
+ const handler = dir.files.get(RoutableFileTypes.Handler);
424
+ const page = dir.files.get(RoutableFileTypes.Page);
425
+ let hasSpecial = false;
426
+ if (middleware) {
427
+ if (currentMiddleware.has(middleware)) {
428
+ middleware = void 0;
429
+ } else {
430
+ currentMiddleware.add(middleware);
431
+ unusedFiles.add(middleware);
432
+ }
115
433
  }
116
- if (localLayout) {
117
- layoutsStack.push(localLayout);
434
+ if (layout) {
435
+ if (currentLayouts.has(layout)) {
436
+ layout = void 0;
437
+ } else {
438
+ currentLayouts.add(layout);
439
+ unusedFiles.add(layout);
440
+ }
118
441
  }
119
- if (handler || page) {
120
- const key = path3.replace(/(\$\$?)[^\/]*/g, "$1").replace(/^\/+/, "").replace(/[^a-z0-9_$\/]+/gi, "").replace(/\//g, "__") || "index";
121
- if (routes.has(key)) {
122
- const existing = routes.get(key);
123
- const existingFiles = [existing.handler, existing.page].filter(Boolean).map((f) => f.filePath);
442
+ if (page || handler) {
443
+ const path3 = dir.pathInfo;
444
+ if (uniqueRoutes.has(path3.id)) {
445
+ const existing = uniqueRoutes.get(path3.id);
446
+ const route = routes[existing.index];
447
+ const existingFiles = [route.handler, route.page].filter(Boolean).map((f) => f.filePath);
124
448
  const currentFiles = [handler, page].filter(Boolean).map((f) => f.filePath);
125
- throw new Error(`Duplicate routes for path ${path3} were defined. A route established by:
126
- ${existingFiles}
127
- collides with
128
- ${currentFiles.join(" and ")}
129
- `);
130
- } else {
131
- const index = nextRouteIndex++;
132
- routes.set(key, {
133
- index,
134
- key,
135
- path: path3,
136
- params: [...paramStack],
137
- middleware: [...middlewareStack],
138
- layouts: page ? [...layoutsStack] : [],
139
- meta: (_e = files.get(RoutableFileTypes.Meta)) == null ? void 0 : _e[0],
140
- page,
141
- handler,
142
- entryName: `${markoRunFilePrefix}route__${key}`,
143
- score: scorePath(path3, index)
144
- });
145
- for (const mw of middlewareStack) {
146
- middleware.add(mw);
147
- }
449
+ throw new Error(`Duplicate routes for path '${path3.path}' were defined. A route established by:
450
+ ${existingFiles.join(" and ")} via '${existing.dir.path}'
451
+ collides with
452
+ ${currentFiles.join(" and ")} via '${dir.path}'
453
+ `);
148
454
  }
455
+ uniqueRoutes.set(path3.id, { dir, index: routes.length });
456
+ routes.push({
457
+ index: nextRouteIndex++,
458
+ key: dir.fullPath,
459
+ paths: [path3],
460
+ middleware: [...currentMiddleware],
461
+ layouts: page ? [...currentLayouts] : [],
462
+ meta: dir.files.get(RoutableFileTypes.Meta),
463
+ page,
464
+ handler,
465
+ entryName: `${markoRunFilePrefix}route` + (dir.path !== "/" ? dir.fullPath.replace(/\//g, ".").replace(/(%[A-Fa-f0-9]{2})+/g, "_") : "")
466
+ });
149
467
  }
150
- if (isRoot) {
151
- for (const [type, entries] of files) {
468
+ if (dir === root) {
469
+ for (const [type, file] of dir.files) {
152
470
  if (isSpecialType(type)) {
471
+ hasSpecial = true;
153
472
  special[type] = {
154
473
  index: 0,
155
474
  key: type,
156
- path: path3,
475
+ paths: [],
157
476
  middleware: [],
158
- layouts: [...layoutsStack],
159
- page: entries[0],
160
- entryName: `${markoRunFilePrefix}special__${type}`,
161
- score: 0
477
+ layouts: [...currentLayouts],
478
+ page: file,
479
+ entryName: `${markoRunFilePrefix}special.${type}`
162
480
  };
163
481
  }
164
482
  }
165
- } else if (dir.startsWith("$$")) {
166
- return false;
167
483
  }
168
- return () => {
169
- middlewareStack.length = middlewareStackLength;
170
- layoutsStack.length = layoutsStackLength;
171
- };
172
- },
173
- onEnter({ name }) {
174
- const pathStackLength = pathStack.length;
175
- const paramStackLength = paramStack.length;
176
- const prevChildren = children;
177
- const prevCurrent = current;
178
- const prevIsRoot = isRoot;
179
- if (name.charCodeAt(0) === 95) {
180
- } else {
181
- if (name.charCodeAt(0) === 36) {
182
- if (name.charCodeAt(1) === 36) {
183
- if (name.length > 2) {
184
- paramStack.push({
185
- name: name.slice(2),
186
- index: -1
187
- });
188
- }
189
- } else if (name.length > 1) {
190
- paramStack.push({
191
- name: name.slice(1),
192
- index: pathStackLength
193
- });
194
- }
484
+ if (handler || page) {
485
+ for (const middleware2 of currentMiddleware) {
486
+ middlewares.add(middleware2);
487
+ unusedFiles.delete(middleware2);
195
488
  }
196
- pathStack.push(name);
197
489
  }
198
- dirStack.push(name);
199
- isRoot = false;
200
- if (current) {
201
- children = current.children;
202
- current = void 0;
490
+ if (page || hasSpecial) {
491
+ for (const layout2 of currentLayouts) {
492
+ unusedFiles.delete(layout2);
493
+ }
203
494
  }
204
- return () => {
205
- dirStack.pop();
206
- pathStack.length = pathStackLength;
207
- paramStack.length = paramStackLength;
208
- children = prevChildren;
209
- current = prevCurrent;
210
- isRoot = prevIsRoot;
211
- };
212
495
  }
213
- });
214
- return {
215
- list: [...routes.values()],
216
- special,
217
- middleware: [...middleware]
218
- };
496
+ if (dir.dirs) {
497
+ for (const child of dir.dirs()) {
498
+ traverse(child);
499
+ }
500
+ }
501
+ if (middleware) {
502
+ currentMiddleware.delete(middleware);
503
+ }
504
+ if (layout) {
505
+ currentLayouts.delete(layout);
506
+ }
507
+ }
219
508
  }
220
509
 
221
510
  // src/vite/routes/walk.ts
222
511
  import fs from "fs";
223
512
  import path from "path";
224
513
  function createFSWalker(dir) {
225
- return async function walkFS({ onFile, onEnter, onDir, maxDepth = 50 }) {
514
+ return async function walkFS({
515
+ onEnter,
516
+ onFile,
517
+ onDir,
518
+ maxDepth = 50
519
+ }) {
226
520
  async function walk(dir2, depth) {
227
- const dirs = [];
228
- const entries = await fs.promises.readdir(dir2, { withFileTypes: true });
229
- const prefix = dir2 + path.sep;
230
- for (const dirEntry of entries) {
231
- const entry = {
232
- name: dirEntry.name,
233
- path: prefix + dirEntry.name
234
- };
235
- if (dirEntry.isDirectory()) {
236
- dirs.push(entry);
237
- } else {
238
- onFile == null ? void 0 : onFile(entry);
521
+ const onExit = onEnter == null ? void 0 : onEnter(dir2);
522
+ if (onExit !== false) {
523
+ const dirs = [];
524
+ const entries = await fs.promises.readdir(dir2.path, {
525
+ withFileTypes: true
526
+ });
527
+ const prefix = dir2.path + path.sep;
528
+ for (const entry of entries) {
529
+ const walkEntry = {
530
+ name: entry.name,
531
+ path: prefix + entry.name
532
+ };
533
+ if (entry.isDirectory()) {
534
+ dirs.push(walkEntry);
535
+ } else {
536
+ onFile == null ? void 0 : onFile(walkEntry);
537
+ }
239
538
  }
240
- }
241
- const onAfter = onDir == null ? void 0 : onDir(dir2);
242
- if (onAfter !== false) {
243
- if (--depth > 0) {
539
+ if ((onDir == null ? void 0 : onDir()) !== false && --depth > 0) {
244
540
  for (const entry of dirs) {
245
- const onExit = onEnter == null ? void 0 : onEnter(entry);
246
- if (onExit !== false) {
247
- await walk(entry.path, depth);
248
- onExit == null ? void 0 : onExit();
249
- }
541
+ await walk(entry, depth);
250
542
  }
251
543
  }
252
- onAfter == null ? void 0 : onAfter();
544
+ onExit == null ? void 0 : onExit();
253
545
  }
254
546
  }
255
- await walk(dir, maxDepth);
547
+ await walk(
548
+ {
549
+ path: dir,
550
+ name: path.basename(dir)
551
+ },
552
+ maxDepth
553
+ );
256
554
  };
257
555
  }
258
556
 
@@ -344,6 +642,10 @@ function createWriter(sink, options) {
344
642
  branches[i] = null;
345
643
  firstOpenIndex++;
346
644
  }
645
+ if (!openWriters.size) {
646
+ sink(buffer);
647
+ buffer = "";
648
+ }
347
649
  }
348
650
  }
349
651
  )
@@ -389,49 +691,6 @@ function createStringWriter(opts) {
389
691
  });
390
692
  }
391
693
 
392
- // src/vite/routes/routeTrie.ts
393
- function createRouteTrie(routes) {
394
- const root = {
395
- key: ""
396
- };
397
- function insert(keys, value) {
398
- let node = root;
399
- for (const key of keys) {
400
- if (key.startsWith("$$")) {
401
- if (!node.catchAll) {
402
- node.catchAll = value;
403
- return true;
404
- }
405
- return false;
406
- } else if (key.startsWith("$")) {
407
- node = node.dynamic ?? (node.dynamic = {
408
- key: ""
409
- });
410
- } else {
411
- node.static ?? (node.static = /* @__PURE__ */ new Map());
412
- let next = node.static.get(key);
413
- if (!next) {
414
- next = {
415
- key
416
- };
417
- node.static.set(key, next);
418
- }
419
- node = next;
420
- }
421
- }
422
- if (node.route === void 0) {
423
- node.route = value;
424
- return true;
425
- }
426
- return false;
427
- }
428
- for (const route of routes) {
429
- const keys = route.path === "/" ? [] : route.path.split("/").slice(1);
430
- insert(keys, route);
431
- }
432
- return root;
433
- }
434
-
435
694
  // src/vite/utils/route.ts
436
695
  function getVerbs(route) {
437
696
  var _a, _b;
@@ -452,9 +711,7 @@ function renderRouteTemplate(route) {
452
711
  throw new Error(`Route ${route.key} has no page to render`);
453
712
  }
454
713
  const writer = createStringWriter();
455
- writer.writeLines(
456
- `// ${virtualFilePrefix}/${route.entryName}.marko`
457
- );
714
+ writer.writeLines(`// ${virtualFilePrefix}/${route.entryName}.marko`);
458
715
  writer.branch("imports");
459
716
  writer.writeLines("");
460
717
  writeRouteTemplateTag(writer, [...route.layouts, route.page]);
@@ -484,9 +741,7 @@ function renderRouteEntry(route) {
484
741
  );
485
742
  }
486
743
  const writer = createStringWriter();
487
- writer.writeLines(
488
- `// ${virtualFilePrefix}/${entryName}.js`
489
- );
744
+ writer.writeLines(`// ${virtualFilePrefix}/${entryName}.js`);
490
745
  const imports = writer.branch("imports");
491
746
  const runtimeImports = [];
492
747
  if (handler) {
@@ -631,9 +886,7 @@ function renderRouter(routes, options = {
631
886
  const names = verbs.map((verb) => `${verb}${route.index}`);
632
887
  route.meta && names.push(`meta${route.index}`);
633
888
  imports.writeLines(
634
- `import { ${names.join(
635
- ", "
636
- )} } from '${virtualFilePrefix}/${route.entryName}.js';`
889
+ `import { ${names.join(", ")} } from '${virtualFilePrefix}/${route.entryName}.js';`
637
890
  );
638
891
  }
639
892
  for (const { key, entryName } of Object.values(routes.special)) {
@@ -768,7 +1021,7 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
768
1021
  writer.writeLines(`const len = pathname.length;`);
769
1022
  if (route) {
770
1023
  writer.writeLines(
771
- `if (len === 1) return ${renderMatch(verb, route)}; // ${route.path}`
1024
+ `if (len === 1) return ${renderMatch(verb, route, trie.path)}; // ${trie.path.path}`
772
1025
  );
773
1026
  } else if (trie.static || dynamic) {
774
1027
  writer.writeBlockStart(`if (len > 1) {`);
@@ -805,14 +1058,14 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
805
1058
  if (useSwitch) {
806
1059
  writer.writeBlockStart(`switch (${value}.toLowerCase()) {`);
807
1060
  }
808
- for (const { key, route: route2 } of terminal) {
1061
+ for (const { key, path: path3, route: route2 } of terminal) {
809
1062
  if (useSwitch) {
810
1063
  writer.write(`case '${key}': `, true);
811
1064
  } else {
812
1065
  writer.write(`if (${value}.toLowerCase() === '${key}') `, true);
813
1066
  }
814
1067
  writer.write(
815
- `return ${renderMatch(verb, route2)}; // ${route2.path}
1068
+ `return ${renderMatch(verb, route2, path3)}; // ${path3.path}
816
1069
  `
817
1070
  );
818
1071
  }
@@ -822,7 +1075,11 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
822
1075
  }
823
1076
  if (dynamic == null ? void 0 : dynamic.route) {
824
1077
  writer.writeLines(
825
- `if (${value}) return ${renderMatch(verb, dynamic.route)}; // ${dynamic.route.path}`
1078
+ `if (${value}) return ${renderMatch(
1079
+ verb,
1080
+ dynamic.route,
1081
+ dynamic.path
1082
+ )}; // ${dynamic.path.path}`
826
1083
  );
827
1084
  }
828
1085
  }
@@ -855,7 +1112,11 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
855
1112
  }
856
1113
  const nextOffset = typeof offset === "string" ? index : offset + child.key.length + 1;
857
1114
  writeRouterVerb(writer, child, verb, next, nextOffset);
858
- writer.writeBlockEnd("}");
1115
+ if (useSwitch) {
1116
+ writer.writeBlockEnd("} break;");
1117
+ } else {
1118
+ writer.writeBlockEnd("}");
1119
+ }
859
1120
  }
860
1121
  if (useSwitch) {
861
1122
  writer.writeBlockEnd("}");
@@ -873,7 +1134,7 @@ function writeRouterVerb(writer, trie, verb, level = 0, offset = 1) {
873
1134
  }
874
1135
  if (catchAll) {
875
1136
  writer.writeLines(
876
- `return ${renderMatch(verb, catchAll, String(offset))}; // ${catchAll.path}`
1137
+ `return ${renderMatch(verb, catchAll.route, catchAll.path, String(offset))}; // ${catchAll.path.path}`
877
1138
  );
878
1139
  } else if (level === 0) {
879
1140
  writer.writeLines("return null;");
@@ -883,15 +1144,12 @@ function wrapPropertyName(name) {
883
1144
  name = decodeURIComponent(name);
884
1145
  return /^[^A-Za-z_$]|[^A-Za-z0-9$_]/.test(name) ? `'${name}'` : name;
885
1146
  }
886
- function renderParamsInfo(params, pathIndex) {
887
- if (!params.length) {
888
- return "{}";
889
- }
1147
+ function renderParams(params, pathIndex) {
890
1148
  let result = "";
891
1149
  let catchAll = "";
892
1150
  let sep = "{";
893
- for (const { name, index } of params) {
894
- if (index >= 0) {
1151
+ for (const [name, index] of Object.entries(params)) {
1152
+ if (typeof index === "number") {
895
1153
  result += `${sep} ${wrapPropertyName(name)}: s${index + 1}`;
896
1154
  sep = ",";
897
1155
  } else if (pathIndex) {
@@ -905,13 +1163,12 @@ function renderParamsInfo(params, pathIndex) {
905
1163
  }
906
1164
  return result ? result + " }" : "{}";
907
1165
  }
908
- function renderMatch(verb, route, pathIndex) {
909
- var _a;
1166
+ function renderMatch(verb, route, path3, pathIndex) {
910
1167
  const handler = `${verb}${route.index}`;
911
- const params = ((_a = route.params) == null ? void 0 : _a.length) ? renderParamsInfo(route.params, pathIndex) : "{}";
1168
+ const params = path3.params ? renderParams(path3.params, pathIndex) : "{}";
912
1169
  const meta = route.meta ? `meta${route.index}` : "{}";
913
- const path3 = pathToURLPatternString(route.path);
914
- return `{ handler: ${handler}, params: ${params}, meta: ${meta}, path: '${path3}' }`;
1170
+ const pathPattern = pathToURLPatternString(path3.path);
1171
+ return `{ handler: ${handler}, params: ${params}, meta: ${meta}, path: '${pathPattern}' }`;
915
1172
  }
916
1173
  function renderMiddleware(middleware) {
917
1174
  const writer = createStringWriter();
@@ -962,37 +1219,20 @@ async function renderRouteTypeInfo(routes, pathPrefix = ".", adapter) {
962
1219
  `);
963
1220
  }
964
1221
  }
1222
+ headWriter.join();
965
1223
  writer.writeBlockStart(`interface AppData extends Run.DefineApp<{`).writeBlockStart("routes: {");
966
1224
  const routesWriter = writer.branch("routes");
967
1225
  writer.writeBlockEnd("}").writeBlockEnd(`}> {}`).writeBlockEnd(`}`);
968
- headWriter.join();
969
1226
  const moduleWriter = writer.branch("module");
970
1227
  const middlewareRouteTypes = /* @__PURE__ */ new Map();
971
1228
  const layoutRouteTypes = /* @__PURE__ */ new Map();
972
1229
  for (const route of routes.list) {
973
- const { meta, handler, middleware, page, layouts } = route;
974
- const pathType = `${pathToURLPatternString(route.path)}`;
975
- const routeType = `"${pathType}"`;
976
- let verbType = "";
977
- if (page || handler) {
978
- const verbs = [];
979
- if (page || ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes("get"))) {
980
- verbs.push(`"get"`);
981
- }
982
- if ((_b = handler == null ? void 0 : handler.verbs) == null ? void 0 : _b.includes("post")) {
983
- verbs.push(`"post"`);
984
- }
985
- verbType = verbs.join(" | ");
986
- }
987
- if (meta) {
988
- const path3 = stripTsExtension(`${pathPrefix}/${meta.relativePath}`);
989
- let metaType = `typeof import("${path3}")`;
990
- if (/\.(ts|js|mjs)$/.test(meta.relativePath)) {
991
- metaType += `["default"]`;
992
- }
993
- routesWriter.writeBlockStart(`"${pathType}": {`).writeLines(`verb: ${verbType};`, `meta: ${metaType};`).writeBlockEnd("};");
994
- } else {
995
- routesWriter.writeLines(`"${pathType}": { verb: ${verbType} };`);
1230
+ const { handler, middleware, page, layouts } = route;
1231
+ let routeType = "";
1232
+ for (const path3 of route.paths) {
1233
+ const pathType = `"${pathToURLPatternString(path3.path)}"`;
1234
+ routeType += routeType ? " | " + pathType : pathType;
1235
+ routesWriter.writeLines(`${pathType}: Routes["${route.key}"]`);
996
1236
  }
997
1237
  if (handler) {
998
1238
  writeModuleDeclaration(
@@ -1005,11 +1245,7 @@ async function renderRouteTypeInfo(routes, pathPrefix = ".", adapter) {
1005
1245
  writeModuleDeclaration(
1006
1246
  writer,
1007
1247
  `${pathPrefix}/${page.relativePath}`,
1008
- `Run.Routes[${routeType}]`,
1009
- `
1010
- export interface Input {
1011
- renderBody: Marko.Body;
1012
- }`
1248
+ `Run.Routes[${routeType}]`
1013
1249
  );
1014
1250
  }
1015
1251
  if (middleware) {
@@ -1059,16 +1295,14 @@ async function renderRouteTypeInfo(routes, pathPrefix = ".", adapter) {
1059
1295
  }`
1060
1296
  );
1061
1297
  }
1062
- if ((_c = routes.special["404"]) == null ? void 0 : _c.page) {
1298
+ if ((_a = routes.special["404"]) == null ? void 0 : _a.page) {
1063
1299
  writeModuleDeclaration(
1064
1300
  writer,
1065
1301
  `${pathPrefix}/${routes.special["404"].page.relativePath}`,
1066
- "Run.Route",
1067
- `
1068
- export interface Input {}`
1302
+ "Run.Route"
1069
1303
  );
1070
1304
  }
1071
- if ((_d = routes.special["500"]) == null ? void 0 : _d.page) {
1305
+ if ((_b = routes.special["500"]) == null ? void 0 : _b.page) {
1072
1306
  writeModuleDeclaration(
1073
1307
  writer,
1074
1308
  `${pathPrefix}/${routes.special["500"].page.relativePath}`,
@@ -1080,6 +1314,31 @@ async function renderRouteTypeInfo(routes, pathPrefix = ".", adapter) {
1080
1314
  );
1081
1315
  }
1082
1316
  moduleWriter.join();
1317
+ writer.writeBlockStart(`
1318
+ type Routes = {`);
1319
+ for (const route of routes.list) {
1320
+ const { meta, handler, page } = route;
1321
+ if (page || handler) {
1322
+ const verbs = [];
1323
+ if (page || ((_c = handler == null ? void 0 : handler.verbs) == null ? void 0 : _c.includes("get"))) {
1324
+ verbs.push(`"get"`);
1325
+ }
1326
+ if ((_d = handler == null ? void 0 : handler.verbs) == null ? void 0 : _d.includes("post")) {
1327
+ verbs.push(`"post"`);
1328
+ }
1329
+ let routeType = `{ verb: ${verbs.join(" | ")};`;
1330
+ if (meta) {
1331
+ const metaPath = stripTsExtension(`${pathPrefix}/${meta.relativePath}`);
1332
+ let metaType = `typeof import("${metaPath}")`;
1333
+ if (/\.(ts|js|mjs)$/.test(meta.relativePath)) {
1334
+ metaType += `["default"]`;
1335
+ }
1336
+ routeType += ` meta: ${metaType};`;
1337
+ }
1338
+ writer.writeLines(`"${route.key}": ${routeType} };`);
1339
+ }
1340
+ }
1341
+ writer.writeBlockEnd("}");
1083
1342
  return writer.end();
1084
1343
  }
1085
1344
  function writeModuleDeclaration(writer, path3, routeType, moduleTypes) {
@@ -1107,6 +1366,42 @@ function pathToURLPatternString(path3) {
1107
1366
  return catchAll ? `/:${name || "rest"}*` : `/:${name}`;
1108
1367
  });
1109
1368
  }
1369
+ function createRouteTrie(routes) {
1370
+ const root = {
1371
+ key: ""
1372
+ };
1373
+ function insert(path3, route) {
1374
+ let node = root;
1375
+ for (const segment of path3.segments) {
1376
+ if (segment === "$$") {
1377
+ node.catchAll ?? (node.catchAll = { route, path: path3 });
1378
+ return;
1379
+ } else if (segment === "$") {
1380
+ node = node.dynamic ?? (node.dynamic = {
1381
+ key: ""
1382
+ });
1383
+ } else {
1384
+ node.static ?? (node.static = /* @__PURE__ */ new Map());
1385
+ let next = node.static.get(segment);
1386
+ if (!next) {
1387
+ next = {
1388
+ key: segment
1389
+ };
1390
+ node.static.set(segment, next);
1391
+ }
1392
+ node = next;
1393
+ }
1394
+ }
1395
+ node.path ?? (node.path = path3);
1396
+ node.route ?? (node.route = route);
1397
+ }
1398
+ for (const route of routes) {
1399
+ for (const path3 of route.paths) {
1400
+ insert(path3, route);
1401
+ }
1402
+ }
1403
+ return root;
1404
+ }
1110
1405
 
1111
1406
  // src/vite/utils/ast.ts
1112
1407
  import * as t from "@babel/types";
@@ -1188,31 +1483,33 @@ function logRoutesTable(routes, bundle) {
1188
1483
  colAligns,
1189
1484
  style: { compact: true }
1190
1485
  });
1191
- for (const route of routes.list.sort((a, b) => b.score - a.score)) {
1192
- const verbs = getVerbs(route).sort(
1193
- (a, b) => HttpVerbOrder[a] - HttpVerbOrder[b]
1194
- );
1195
- let firstRow = true;
1196
- for (const verb of verbs) {
1197
- let size = "";
1198
- const entryType = [];
1199
- if (route.handler) {
1200
- entryType.push(kleur.blue("handler"));
1201
- }
1202
- if (verb === "get" && route.page) {
1203
- entryType.push(kleur.yellow("page"));
1204
- size = prettySize(computeRouteSize(route, bundle));
1205
- }
1206
- const row = [kleur.bold(HttpVerbColors[verb](verb.toUpperCase()))];
1207
- if (verbs.length === 1 || firstRow) {
1208
- row.push({ rowSpan: verbs.length, content: prettyPath(route.path) });
1209
- firstRow = false;
1486
+ for (const route of routes.list) {
1487
+ for (const path3 of route.paths) {
1488
+ const verbs = getVerbs(route).sort(
1489
+ (a, b) => HttpVerbOrder[a] - HttpVerbOrder[b]
1490
+ );
1491
+ let firstRow = true;
1492
+ for (const verb of verbs) {
1493
+ let size = "";
1494
+ const entryType = [];
1495
+ if (route.handler) {
1496
+ entryType.push(kleur.blue("handler"));
1497
+ }
1498
+ if (verb === "get" && route.page) {
1499
+ entryType.push(kleur.yellow("page"));
1500
+ size = prettySize(computeRouteSize(route, bundle));
1501
+ }
1502
+ const row = [kleur.bold(HttpVerbColors[verb](verb.toUpperCase()))];
1503
+ if (verbs.length === 1 || firstRow) {
1504
+ row.push({ rowSpan: verbs.length, content: prettyPath(path3.path) });
1505
+ firstRow = false;
1506
+ }
1507
+ row.push(entryType.join(" -> "));
1508
+ hasMiddleware && row.push(route.middleware.length || "");
1509
+ hasMeta && row.push(route.meta ? "\u2713" : "");
1510
+ row.push(size || "");
1511
+ table.push(row);
1210
1512
  }
1211
- row.push(entryType.join(" -> "));
1212
- hasMiddleware && row.push(route.middleware.length || "");
1213
- hasMeta && row.push(route.meta ? "\u2713" : "");
1214
- row.push(size || "");
1215
- table.push(row);
1216
1513
  }
1217
1514
  }
1218
1515
  for (const [key, route] of Object.entries(routes.special).sort()) {
@@ -1354,24 +1651,18 @@ function markoRun(opts = {}) {
1354
1651
  }
1355
1652
  if (route.page) {
1356
1653
  virtualFiles.set(
1357
- path2.posix.join(
1358
- root,
1359
- `${markoRunFilePrefix}route__${route.key}.marko`
1360
- ),
1654
+ path2.posix.join(root, `${route.entryName}.marko`),
1361
1655
  render ? renderRouteTemplate(route) : ""
1362
1656
  );
1363
1657
  }
1364
1658
  virtualFiles.set(
1365
- path2.posix.join(root, `${markoRunFilePrefix}route__${route.key}.js`),
1659
+ path2.posix.join(root, `${route.entryName}.js`),
1366
1660
  render ? renderRouteEntry(route) : ""
1367
1661
  );
1368
1662
  }
1369
1663
  for (const route of Object.values(routes.special)) {
1370
1664
  virtualFiles.set(
1371
- path2.posix.join(
1372
- root,
1373
- `${markoRunFilePrefix}special__${route.key}.marko`
1374
- ),
1665
+ path2.posix.join(root, `${route.entryName}.marko`),
1375
1666
  render ? renderRouteTemplate(route) : ""
1376
1667
  );
1377
1668
  }
@@ -1499,7 +1790,17 @@ function markoRun(opts = {}) {
1499
1790
  rollupOptions: {
1500
1791
  output: rollupOutputOptions
1501
1792
  }
1502
- }
1793
+ },
1794
+ resolve: isBuild ? {
1795
+ browserField: isSSRBuild ? false : void 0,
1796
+ conditions: [
1797
+ isSSRBuild ? "node" : "browser",
1798
+ "import",
1799
+ "require",
1800
+ "production",
1801
+ "default"
1802
+ ]
1803
+ } : void 0
1503
1804
  };
1504
1805
  const adapterConfig = await ((_g = adapter == null ? void 0 : adapter.viteConfig) == null ? void 0 : _g.call(adapter, config2));
1505
1806
  if (adapterConfig) {
@@ -1771,10 +2072,10 @@ async function resolveAdapter(root, options, log) {
1771
2072
  log && console.log("Using default adapter");
1772
2073
  return module.default();
1773
2074
  }
1774
- var markoEntryFileRegex = /__marko-run__([^_]+)__(.+)\.marko.([^.]+)$/;
2075
+ var markoEntryFileRegex = /__marko-run__([^.]+)\.(.+)\.marko\.([^.]+)$/;
1775
2076
  function getEntryFileName(file) {
1776
2077
  const match = file && markoEntryFileRegex.exec(file);
1777
- return match ? `${match[2].replace(/__/g, "-")}` : void 0;
2078
+ return match ? match[2] : void 0;
1778
2079
  }
1779
2080
 
1780
2081
  // src/vite/utils/server.ts