@gracile/engine 0.0.2

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 (68) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +9 -0
  3. package/ambient.d.ts +1 -0
  4. package/dist/assertions.d.ts +12 -0
  5. package/dist/assertions.d.ts.map +1 -0
  6. package/dist/assertions.js +27 -0
  7. package/dist/build/build.d.ts +2 -0
  8. package/dist/build/build.d.ts.map +1 -0
  9. package/dist/build/build.js +7 -0
  10. package/dist/build/static.d.ts +8 -0
  11. package/dist/build/static.d.ts.map +1 -0
  12. package/dist/build/static.js +82 -0
  13. package/dist/dev/dev.d.ts +6 -0
  14. package/dist/dev/dev.d.ts.map +1 -0
  15. package/dist/dev/dev.js +14 -0
  16. package/dist/dev/request.d.ts +4 -0
  17. package/dist/dev/request.d.ts.map +1 -0
  18. package/dist/dev/request.js +151 -0
  19. package/dist/dev/server.d.ts +10 -0
  20. package/dist/dev/server.d.ts.map +1 -0
  21. package/dist/dev/server.js +54 -0
  22. package/dist/errors/templates.d.ts +3 -0
  23. package/dist/errors/templates.d.ts.map +1 -0
  24. package/dist/errors/templates.js +69 -0
  25. package/dist/preview.d.ts +6 -0
  26. package/dist/preview.d.ts.map +1 -0
  27. package/dist/preview.js +9 -0
  28. package/dist/render/route-template.d.ts +15 -0
  29. package/dist/render/route-template.d.ts.map +1 -0
  30. package/dist/render/route-template.js +83 -0
  31. package/dist/routes/collect.d.ts +4 -0
  32. package/dist/routes/collect.d.ts.map +1 -0
  33. package/dist/routes/collect.js +111 -0
  34. package/dist/routes/comparator.d.ts +35 -0
  35. package/dist/routes/comparator.d.ts.map +1 -0
  36. package/dist/routes/comparator.js +132 -0
  37. package/dist/routes/load-module.d.ts +11 -0
  38. package/dist/routes/load-module.d.ts.map +1 -0
  39. package/dist/routes/load-module.js +23 -0
  40. package/dist/routes/match.d.ts +16 -0
  41. package/dist/routes/match.d.ts.map +1 -0
  42. package/dist/routes/match.js +63 -0
  43. package/dist/routes/route.d.ts +63 -0
  44. package/dist/routes/route.d.ts.map +1 -0
  45. package/dist/routes/route.js +32 -0
  46. package/dist/tsconfig.tsbuildinfo +1 -0
  47. package/dist/user-config.d.ts +8 -0
  48. package/dist/user-config.d.ts.map +1 -0
  49. package/dist/user-config.js +10 -0
  50. package/dist/vite/build.d.ts +2 -0
  51. package/dist/vite/build.d.ts.map +1 -0
  52. package/dist/vite/build.js +39 -0
  53. package/dist/vite/config.d.ts +26 -0
  54. package/dist/vite/config.d.ts.map +1 -0
  55. package/dist/vite/config.js +64 -0
  56. package/dist/vite/plugins/html-static-pages.d.ts +13 -0
  57. package/dist/vite/plugins/html-static-pages.d.ts.map +1 -0
  58. package/dist/vite/plugins/html-static-pages.js +58 -0
  59. package/dist/vite/plugins/scss.d.ts +3 -0
  60. package/dist/vite/plugins/scss.d.ts.map +1 -0
  61. package/dist/vite/plugins/scss.js +28 -0
  62. package/dist/vite/server.d.ts +3 -0
  63. package/dist/vite/server.d.ts.map +1 -0
  64. package/dist/vite/server.js +18 -0
  65. package/dist/vite/utils.d.ts +3 -0
  66. package/dist/vite/utils.d.ts.map +1 -0
  67. package/dist/vite/utils.js +5 -0
  68. package/package.json +84 -0
@@ -0,0 +1,4 @@
1
+ import type { Route } from './route.js';
2
+ export declare const routes: Map<string, Route>;
3
+ export declare function collectRoutes(root: string): Promise<void>;
4
+ //# sourceMappingURL=collect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collect.d.ts","sourceRoot":"","sources":["../../src/routes/collect.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,eAAO,MAAM,MAAM,oBAA2B,CAAC;AAyD/C,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,iBA8E/C"}
@@ -0,0 +1,111 @@
1
+ import path, { join, relative } from 'node:path';
2
+ import { logger } from '@gracile/internal-utils/logger';
3
+ import * as paths from '@gracile/internal-utils/paths';
4
+ import fastGlob from 'fast-glob';
5
+ import c from 'picocolors';
6
+ import { URLPattern } from 'urlpattern-polyfill/urlpattern';
7
+ // import type { ViteDevServer } from 'vite';
8
+ import { prepareSortableRoutes, routeComparator } from './comparator.js';
9
+ import { REGEXES } from './load-module.js';
10
+ export const routes = new Map();
11
+ function extractRoutePatterns(absoluteFilePath) {
12
+ const routePathname = path
13
+ .relative('src/routes', paths.relativeToProject(absoluteFilePath))
14
+ .replace(/\.[j|t]s$/, '');
15
+ let pathParts = routePathname.split(process.platform === 'win32' ? '\\' : '/');
16
+ const last = pathParts.at(-1);
17
+ if (typeof last === 'undefined')
18
+ throw new Error('Cannot parse file path.');
19
+ if (
20
+ // NOTE: /foo/(foo) => /foo
21
+ /\((.*)\)/.test(last) ||
22
+ // NOTE: /foo/index => /foo
23
+ last === 'index')
24
+ pathParts.pop();
25
+ if (pathParts.length === 1 && pathParts.at(0) === 'index')
26
+ pathParts = [];
27
+ if (pathParts.length === 1 && pathParts.at(0) === '404')
28
+ pathParts = ['__404'];
29
+ let hasParams = false;
30
+ const pathRelNorm = pathParts.map((pathEntry) => {
31
+ let entry = pathEntry;
32
+ if (entry.match(REGEXES.rest)) {
33
+ hasParams = true;
34
+ return pathEntry.replace(REGEXES.rest, (_s, param) => `:${param}*`);
35
+ }
36
+ while (REGEXES.param.test(entry)) {
37
+ hasParams = true;
38
+ entry = entry.replace(REGEXES.param, (_s, param) => {
39
+ return `{:${param}}`;
40
+ });
41
+ }
42
+ return entry;
43
+ });
44
+ const trailingSlash = pathRelNorm.length > 0 ? '/' : '';
45
+ const normalizedUrlPattern = `/${pathRelNorm.join('/')}${trailingSlash}`;
46
+ return {
47
+ patternString: normalizedUrlPattern,
48
+ pattern: new URLPattern(normalizedUrlPattern, 'http://gracile/'),
49
+ hasParams,
50
+ };
51
+ }
52
+ export async function collectRoutes(root /* vite: ViteDevServer */) {
53
+ routes.clear();
54
+ const serverEntrypoints = await fastGlob([
55
+ 'src/routes/**/*.{js,ts}',
56
+ '!**/src/routes/**/*.client.{js,ts}',
57
+ '!**/src/routes/**/*.document.{js,ts}',
58
+ '!**/src/routes/**/_*/**',
59
+ '!**/src/routes/**/_*',
60
+ ], { ignore: [], cwd: root, absolute: true });
61
+ // MARK: Routes priority order
62
+ const serverEntrypointsSorted = prepareSortableRoutes(serverEntrypoints)
63
+ .sort((a, b) => routeComparator(a, b))
64
+ .map((r) => r.route);
65
+ const serverPageClientAssets = await fastGlob([
66
+ //
67
+ 'src/routes/**/*.{css,scss}',
68
+ 'src/routes/**/*.client.{js,ts}',
69
+ ], { ignore: [], cwd: root, absolute: true });
70
+ logger.info(`\n${c.underline(`Found ${c.bold('routes')}`)}:\n` +
71
+ `${c.dim('- ')}${serverEntrypointsSorted
72
+ .map((f) => {
73
+ const pathParts = relative(join(root, 'src/routes'), f).split('/');
74
+ return pathParts
75
+ .map((part, index) => {
76
+ if (part.match(/\[\./))
77
+ return c.cyan(c.italic(part));
78
+ if (part.match(/\[/))
79
+ return c.cyan(part);
80
+ if (part.match(/\(/))
81
+ return c.yellow(part);
82
+ if (index === pathParts.length - 1)
83
+ return c.green(part);
84
+ return part;
85
+ })
86
+ .join(c.gray('/'));
87
+ })
88
+ .join(c.dim('\n- '))}\n`);
89
+ // MARK: Associate
90
+ serverEntrypointsSorted.forEach((filePath) => {
91
+ const routeWithPatterns = extractRoutePatterns(filePath);
92
+ routes.set(routeWithPatterns.patternString, {
93
+ filePath: paths.relativeToProject(filePath),
94
+ pattern: routeWithPatterns.pattern,
95
+ hasParams: routeWithPatterns.hasParams,
96
+ pageAssets: [],
97
+ });
98
+ });
99
+ serverPageClientAssets.forEach((filePath) => {
100
+ // NOTE: Exact extension needed client side by Vite.
101
+ const assetPathWithExt = paths.relativeToProject(filePath);
102
+ const associatedRoutePath = assetPathWithExt.replace(/\.(.*)$/,
103
+ // FIXME: Don't need this anymore?
104
+ (_a, b) => `.${String(b)}`);
105
+ routes.forEach((route) => {
106
+ if (paths.removeAllExt(route.filePath) ===
107
+ paths.removeAllExt(associatedRoutePath))
108
+ route.pageAssets.push(assetPathWithExt);
109
+ });
110
+ });
111
+ }
@@ -0,0 +1,35 @@
1
+ interface RoutePart {
2
+ content: string;
3
+ dynamic: boolean;
4
+ spread: boolean;
5
+ allDynamic: boolean;
6
+ }
7
+ export interface RouteCompareObject {
8
+ route: string;
9
+ segments: RoutePart[];
10
+ }
11
+ /**
12
+ * Comparator for sorting routes in resolution order.
13
+ *
14
+ * The routes are sorted in by the following rules in order, following the first rule that
15
+ * applies:
16
+ * - More specific routes are sorted before less specific routes. Here, "specific" means
17
+ * the number of segments in the route, so a parent route is always sorted after its children.
18
+ * For example, `/foo/bar` is sorted before `/foo`.
19
+ * Index routes, originating from a file named `index.astro`, are considered to have one more
20
+ * segment than the URL they represent.
21
+ * - Static routes are sorted before dynamic routes.
22
+ * For example, `/foo/bar` is sorted before `/foo/[bar]`.
23
+ * - Dynamic routes with single parameters are sorted before dynamic routes with rest parameters.
24
+ * For example, `/foo/[bar]` is sorted before `/foo/[...bar]`.
25
+ * - Prerendered routes are sorted before non-prerendered routes.
26
+ * - Endpoints are sorted before pages.
27
+ * For example, a file `/foo.ts` is sorted before `/bar.astro`.
28
+ * - If both routes are equal regarding all previous conditions, they are sorted alphabetically.
29
+ * For example, `/bar` is sorted before `/foo`.
30
+ * The definition of "alphabetically" is dependent on the default locale of the running system.
31
+ */
32
+ export declare function routeComparator(a: RouteCompareObject, b: RouteCompareObject): number;
33
+ export declare function prepareSortableRoutes(routes: string[]): RouteCompareObject[];
34
+ export {};
35
+ //# sourceMappingURL=comparator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comparator.d.ts","sourceRoot":"","sources":["../../src/routes/comparator.ts"],"names":[],"mappings":"AAIA,UAAU,SAAS;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAEhB,UAAU,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,SAAS,EAAE,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,kBAAkB,EAAE,CAAC,EAAE,kBAAkB,UA2F3E;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,wBAuCrD"}
@@ -0,0 +1,132 @@
1
+ // Sorting algorithm taken and adapted from https://github.com/withastro/astro/blob/f6bddd3a155cd10a9f85c92d43b1af8b74786a42/packages/astro/src/core/routing/priority.ts
2
+ import { REGEXES } from './load-module.js';
3
+ /**
4
+ * Comparator for sorting routes in resolution order.
5
+ *
6
+ * The routes are sorted in by the following rules in order, following the first rule that
7
+ * applies:
8
+ * - More specific routes are sorted before less specific routes. Here, "specific" means
9
+ * the number of segments in the route, so a parent route is always sorted after its children.
10
+ * For example, `/foo/bar` is sorted before `/foo`.
11
+ * Index routes, originating from a file named `index.astro`, are considered to have one more
12
+ * segment than the URL they represent.
13
+ * - Static routes are sorted before dynamic routes.
14
+ * For example, `/foo/bar` is sorted before `/foo/[bar]`.
15
+ * - Dynamic routes with single parameters are sorted before dynamic routes with rest parameters.
16
+ * For example, `/foo/[bar]` is sorted before `/foo/[...bar]`.
17
+ * - Prerendered routes are sorted before non-prerendered routes.
18
+ * - Endpoints are sorted before pages.
19
+ * For example, a file `/foo.ts` is sorted before `/bar.astro`.
20
+ * - If both routes are equal regarding all previous conditions, they are sorted alphabetically.
21
+ * For example, `/bar` is sorted before `/foo`.
22
+ * The definition of "alphabetically" is dependent on the default locale of the running system.
23
+ */
24
+ export function routeComparator(a, b) {
25
+ const commonLength = Math.min(a.segments.length, b.segments.length);
26
+ for (let index = 0; index < commonLength; index += 1) {
27
+ const aSegment = a.segments[index];
28
+ const bSegment = b.segments[index];
29
+ // if (index > commonLength - 3)
30
+ // console.log({
31
+ // // aAllDynamic,
32
+ // // bAllDynamic,
33
+ // aS: aSegment,
34
+ // bS: bSegment,
35
+ // });
36
+ const aIsStatic = !aSegment.dynamic && !aSegment.spread;
37
+ const bIsStatic = !bSegment.dynamic && !bSegment.spread;
38
+ if (aIsStatic && bIsStatic) {
39
+ // Both segments are static, they are sorted alphabetically if they are different
40
+ const aContent = aSegment.content;
41
+ const bContent = bSegment.content;
42
+ if (aContent !== bContent) {
43
+ return aContent.localeCompare(bContent);
44
+ }
45
+ }
46
+ // Sort static routes before dynamic routes
47
+ if (aIsStatic !== bIsStatic) {
48
+ return aIsStatic ? -1 : 1;
49
+ }
50
+ const aAllDynamic = aSegment.allDynamic;
51
+ const bAllDynamic = bSegment.allDynamic;
52
+ // Some route might have partial dynamic segments, e.g. game-[title].astro
53
+ // These routes should have higher priority against route that have **only** dynamic segments, e.g. [title].astro
54
+ if (aAllDynamic !== bAllDynamic) {
55
+ return aAllDynamic ? 1 : -1;
56
+ }
57
+ const aHasSpread = aSegment.spread;
58
+ const bHasSpread = bSegment.spread;
59
+ // Sort dynamic routes with rest parameters after dynamic routes with single parameters
60
+ // (also after static, but that is already covered by the previous condition)
61
+ if (aHasSpread !== bHasSpread) {
62
+ return aHasSpread ? 1 : -1;
63
+ }
64
+ }
65
+ const aLength = a.segments.length;
66
+ const bLength = b.segments.length;
67
+ if (aLength !== bLength) {
68
+ const aEndsInRest = a.segments.at(-1)?.spread;
69
+ const bEndsInRest = b.segments.at(-1)?.spread;
70
+ if (aEndsInRest !== bEndsInRest && Math.abs(aLength - bLength) === 1) {
71
+ // If only one of the routes ends in a rest parameter
72
+ // and the difference in length is exactly 1
73
+ // and the shorter route is the one that ends in a rest parameter
74
+ // the shorter route is considered more specific.
75
+ // I.e. `/foo` is considered more specific than `/foo/[...bar]`
76
+ if (aLength > bLength && aEndsInRest) {
77
+ // b: /foo
78
+ // a: /foo/[...bar]
79
+ return 1;
80
+ }
81
+ if (bLength > aLength && bEndsInRest) {
82
+ // a: /foo
83
+ // b: /foo/[...bar]
84
+ return -1;
85
+ }
86
+ }
87
+ // Sort routes by length
88
+ return aLength > bLength ? -1 : 1;
89
+ }
90
+ // NOTE: Might be used at some point for static endpoints etc.
91
+ // // Sort endpoints before pages
92
+ // if ((a.type === 'endpoint') !== (b.type === 'endpoint')) {
93
+ // return a.type === 'endpoint' ? -1 : 1;
94
+ // }
95
+ // Both routes have segments with the same properties
96
+ return a.route.localeCompare(b.route);
97
+ }
98
+ export function prepareSortableRoutes(routes) {
99
+ const routesParsed = routes.map((route) => {
100
+ const segments = route.split('/').map((part) => {
101
+ const segment = {
102
+ content: part,
103
+ dynamic: false,
104
+ spread: false,
105
+ allDynamic: false,
106
+ };
107
+ if (REGEXES.restWithExt.test(part)) {
108
+ segment.spread = true;
109
+ }
110
+ if (REGEXES.param.test(part)) {
111
+ segment.dynamic = true;
112
+ }
113
+ const params = part
114
+ .replace(/\.(js|ts)$/, '')
115
+ .split(REGEXES.dynamicSplit)
116
+ .filter((e) => e !== '');
117
+ if (params.length > 1) {
118
+ segment.allDynamic = false;
119
+ }
120
+ else if (params.length === 1) {
121
+ segment.allDynamic = true;
122
+ }
123
+ return segment;
124
+ });
125
+ // console.log({ segments });
126
+ return {
127
+ route,
128
+ segments,
129
+ };
130
+ });
131
+ return routesParsed;
132
+ }
@@ -0,0 +1,11 @@
1
+ import type { ViteDevServer } from 'vite';
2
+ import * as R from './route.js';
3
+ export declare const REGEXES: {
4
+ param: RegExp;
5
+ rest: RegExp;
6
+ restWithExt: RegExp;
7
+ dynamicSplit: RegExp;
8
+ index: RegExp;
9
+ };
10
+ export declare function loadForeignRouteObject(vite: ViteDevServer, routePath: string): Promise<R.RouteModule>;
11
+ //# sourceMappingURL=load-module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-module.d.ts","sourceRoot":"","sources":["../../src/routes/load-module.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAE1C,OAAO,KAAK,CAAC,MAAM,YAAY,CAAC;AAGhC,eAAO,MAAM,OAAO;;;;;;CASnB,CAAC;AAEF,wBAAsB,sBAAsB,CAC3C,IAAI,EAAE,aAAa,EACnB,SAAS,EAAE,MAAM,0BAiBjB"}
@@ -0,0 +1,23 @@
1
+ import * as R from './route.js';
2
+ // const ROUTE_SPREAD = /^\.{3}.+$/;
3
+ export const REGEXES = {
4
+ //
5
+ param: /\[(.*?)\]/,
6
+ rest: /^\[\.\.\.(.*)\]$/,
7
+ restWithExt: /^\[\.\.\.(.*)\]\.[j|t]s$/,
8
+ dynamicSplit: /\[(.+?\(.+?\)|.+?)\]/,
9
+ // index: /^(index\.(js|ts)|\((.*)\)\.(js|ts))$/,
10
+ index: /\((.*)\)/,
11
+ };
12
+ export async function loadForeignRouteObject(vite, routePath) {
13
+ // NOTE: Check and assert unknown userland module to correct RouteModule instance (in the engine's realm)
14
+ const rm = await vite.ssrLoadModule(routePath);
15
+ const routeModuleFactory = rm['default'];
16
+ const errorBase = `Incorrect route module ${routePath}!`;
17
+ if (typeof routeModuleFactory !== 'function')
18
+ throw new Error(`${errorBase} Not a function.`);
19
+ const routeModule = routeModuleFactory(R.RouteModule);
20
+ if (routeModule instanceof R.RouteModule === false)
21
+ throw new Error(`${errorBase} Not a RouteModule.`);
22
+ return routeModule;
23
+ }
@@ -0,0 +1,16 @@
1
+ import type { ViteDevServer } from 'vite';
2
+ import * as R from './route.js';
3
+ type Params = Record<string, string | undefined>;
4
+ export type RouteInfos = {
5
+ params: Params;
6
+ props: unknown;
7
+ routeModule: Readonly<R.RouteModule>;
8
+ foundRoute: R.Route;
9
+ pathname: string;
10
+ };
11
+ export declare function getRoute(options: {
12
+ url: string;
13
+ vite: ViteDevServer;
14
+ }): Promise<RouteInfos>;
15
+ export {};
16
+ //# sourceMappingURL=match.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match.d.ts","sourceRoot":"","sources":["../../src/routes/match.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAI1C,OAAO,KAAK,CAAC,MAAM,YAAY,CAAC;AAEhC,KAAK,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AA+EjD,MAAM,MAAM,UAAU,GAAG;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IACrC,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CACjB,CAAC;AACF,wBAAsB,QAAQ,CAAC,OAAO,EAAE;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,aAAa,CAAC;CACpB,GAAG,OAAO,CAAC,UAAU,CAAC,CAqBtB"}
@@ -0,0 +1,63 @@
1
+ import { routes } from './collect.js';
2
+ import { loadForeignRouteObject } from './load-module.js';
3
+ import * as R from './route.js';
4
+ function matchRouteFromUrl(url) {
5
+ let match;
6
+ let foundRoute;
7
+ const pathname = new URL(url).pathname;
8
+ // eslint-disable-next-line no-restricted-syntax
9
+ for (const [, route] of routes) {
10
+ if (match)
11
+ break;
12
+ const matchResult = route.pattern.exec(`http://gracile${pathname}`) || undefined;
13
+ if (matchResult) {
14
+ match = matchResult;
15
+ foundRoute = route;
16
+ }
17
+ }
18
+ if (!match || !foundRoute)
19
+ throw new Error(`No route matching for ${url}`, { cause: 404 });
20
+ const params = match.pathname?.groups;
21
+ return { match, foundRoute, params, pathname };
22
+ }
23
+ function extractStaticPaths(options) {
24
+ if (!options.foundRoute.hasParams)
25
+ return null;
26
+ if (!options.routeModule.staticPaths)
27
+ return null;
28
+ const routeStaticPaths = options.routeModule.staticPaths;
29
+ let props;
30
+ const staticPaths = routeStaticPaths();
31
+ let hasCorrectParams = false;
32
+ staticPaths.forEach((providedRouteOptions) => {
33
+ const routeOptions = providedRouteOptions;
34
+ const matchingKeys = Object.entries(routeOptions.params).filter(([key, val]) => options.params[key] === val);
35
+ if (matchingKeys.length === Object.keys(options.params).length) {
36
+ hasCorrectParams = true;
37
+ if (routeOptions.props)
38
+ props = routeOptions.props;
39
+ }
40
+ });
41
+ if (hasCorrectParams === false)
42
+ throw new Error(`Incorrect route parameters for \`${options.pathname}\`.\n` +
43
+ `Check \`staticPaths\` for \`${options.foundRoute.filePath}\`.`);
44
+ return { staticPaths, props };
45
+ }
46
+ export async function getRoute(options) {
47
+ const { foundRoute, pathname, params } = matchRouteFromUrl(options.url);
48
+ const routePath = foundRoute.filePath;
49
+ const routeModule = await loadForeignRouteObject(options.vite, routePath);
50
+ const staticPaths = extractStaticPaths({
51
+ routeModule,
52
+ foundRoute,
53
+ pathname,
54
+ params,
55
+ });
56
+ return {
57
+ params,
58
+ props: staticPaths?.props,
59
+ routeModule,
60
+ foundRoute,
61
+ pathname,
62
+ };
63
+ }
@@ -0,0 +1,63 @@
1
+ import type { ServerRenderedTemplate } from '@lit-labs/ssr';
2
+ import type { TemplateResult } from 'lit';
3
+ export type MethodHtml = 'GET' | 'POST';
4
+ export type MethodNonHtml = 'QUERY' | 'PUT' | 'PATCH' | 'DELETE';
5
+ export type Method = MethodHtml & MethodNonHtml;
6
+ export type ModuleOptions = {
7
+ staticPaths?: StaticPathsGeneric;
8
+ handler?: HandlerGeneric;
9
+ template?: (context: RouteContextGeneric) => RouteTemplateResult;
10
+ document?: DocumentTemplate<RouteContextGeneric>;
11
+ };
12
+ export declare class RouteModule {
13
+ #private;
14
+ get staticPaths(): StaticPathsGeneric | undefined;
15
+ get handler(): Handler<object | Response | undefined> | Partial<Record<MethodHtml, Handler<object | Response | undefined>> & Record<MethodNonHtml, Handler<Response>>> | undefined;
16
+ get document(): DocumentTemplate<RouteContextGeneric> | undefined;
17
+ get template(): ((context: RouteContextGeneric) => RouteTemplateResult) | undefined;
18
+ constructor(options: ModuleOptions);
19
+ }
20
+ export type Params = Record<string, string | undefined>;
21
+ export type Handler<Data extends HandlerData | HandlerDataHtml = never> = (context: {
22
+ url: URL;
23
+ /**
24
+ * Parameters from dynamic route.
25
+ *
26
+ * E.g. `src/routes/foo/[bar]/[baz].ts` -\> `{ bar: string; baz: string; }`
27
+ */
28
+ params: Params;
29
+ request: Request;
30
+ /**
31
+ * Let you mutate the downstream **page** response.
32
+ *
33
+ * It doesn't take effect if you're returning the
34
+ * response yourself before (within your request handler).
35
+ * */
36
+ response: ResponseInit;
37
+ }) => MaybePromise<Data> | MaybePromise<void>;
38
+ export type HandlerGeneric = Handler<HandlerData | HandlerDataHtml> | Partial<Record<MethodHtml, Handler<HandlerData | HandlerDataHtml>> & Record<MethodNonHtml, Handler<Response>>>;
39
+ export type StaticPathsGeneric = () => StaticPathOptionsGeneric[];
40
+ export type HandlerData = Response | undefined;
41
+ export type HandlerDataHtml = HandlerData | object;
42
+ export type StaticPathOptionsGeneric = {
43
+ params: Params;
44
+ props: unknown;
45
+ };
46
+ export type MaybePromise<T> = Promise<T> | T;
47
+ export type StaticRequest = Pick<Request, 'url'>;
48
+ export type RouteContextGeneric = {
49
+ url: URL;
50
+ params: Params;
51
+ props: unknown;
52
+ };
53
+ export type DocumentResult = MaybePromise<ServerRenderedTemplate>;
54
+ export type RouteTemplateResult = MaybePromise<TemplateResult<1> | ServerRenderedTemplate>;
55
+ export type DocumentTemplate<RouteContext extends RouteContextGeneric = RouteContextGeneric> = (context: RouteContext) => DocumentResult;
56
+ export type BodyTemplate<RouteContext> = (context: RouteContext) => RouteTemplateResult;
57
+ export interface Route {
58
+ filePath: string;
59
+ pattern: URLPattern;
60
+ hasParams: boolean;
61
+ pageAssets: string[];
62
+ }
63
+ //# sourceMappingURL=route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../src/routes/route.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ // TODO: put in engine
2
+ export class RouteModule {
3
+ #staticPaths;
4
+ get staticPaths() {
5
+ return this.#staticPaths;
6
+ }
7
+ #handler;
8
+ get handler() {
9
+ return this.#handler;
10
+ }
11
+ #document;
12
+ get document() {
13
+ return this.#document;
14
+ }
15
+ #template;
16
+ get template() {
17
+ return this.#template;
18
+ }
19
+ constructor(options) {
20
+ if (typeof options.staticPaths === 'function')
21
+ this.#staticPaths = options.staticPaths;
22
+ if ((typeof options.handler === 'object' ||
23
+ typeof options.handler === 'function') &&
24
+ options.handler)
25
+ this.#handler = options.handler;
26
+ // if (options.fragment) this.#fragment = options.fragment;
27
+ if (typeof options.template === 'function')
28
+ this.#template = options.template;
29
+ if (typeof options.document === 'function')
30
+ this.#document = options.document;
31
+ }
32
+ }