@timber-js/app 0.2.0-alpha.112 → 0.2.0-alpha.113
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +67 -2
- package/dist/index.js.map +1 -1
- package/dist/plugins/routing.d.ts.map +1 -1
- package/dist/routing/segment-codegen.d.ts +25 -0
- package/dist/routing/segment-codegen.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/plugins/routing.ts +43 -1
- package/src/routing/segment-codegen.ts +73 -0
package/dist/index.js
CHANGED
|
@@ -1979,6 +1979,52 @@ function timberMdx(ctx) {
|
|
|
1979
1979
|
};
|
|
1980
1980
|
}
|
|
1981
1981
|
//#endregion
|
|
1982
|
+
//#region src/routing/segment-codegen.ts
|
|
1983
|
+
/**
|
|
1984
|
+
* _segment type generation and directory-to-route mapping.
|
|
1985
|
+
*
|
|
1986
|
+
* Generates per-route _segment.d.ts files in .timber/types/ that mirror
|
|
1987
|
+
* the app/ directory structure. TypeScript's rootDirs feature makes these
|
|
1988
|
+
* importable as './_segment' from route files.
|
|
1989
|
+
*
|
|
1990
|
+
* Design doc: design/41-global-params.md §The _segment Module
|
|
1991
|
+
*/
|
|
1992
|
+
/**
|
|
1993
|
+
* Build a map of absolute filesystem directory → route pattern.
|
|
1994
|
+
* Used by resolveId to map a _segment import's importer to the correct route.
|
|
1995
|
+
*
|
|
1996
|
+
* Walks every segment (not just leaves) so layouts and middleware
|
|
1997
|
+
* at any depth can import _segment.
|
|
1998
|
+
*/
|
|
1999
|
+
function buildDirToRouteMap(tree, appDir) {
|
|
2000
|
+
const map = /* @__PURE__ */ new Map();
|
|
2001
|
+
function walk(node, fsPath) {
|
|
2002
|
+
const routePattern = node.urlPath || "/";
|
|
2003
|
+
map.set(fsPath, routePattern);
|
|
2004
|
+
for (const child of node.children) walk(child, join(fsPath, child.segmentName));
|
|
2005
|
+
for (const [slotName, slotNode] of Object.entries(node.slots)) walk(slotNode, join(fsPath, slotName));
|
|
2006
|
+
}
|
|
2007
|
+
walk(tree.root, appDir);
|
|
2008
|
+
return map;
|
|
2009
|
+
}
|
|
2010
|
+
/**
|
|
2011
|
+
* Generate per-route _segment.d.ts files in .timber/types/ mirroring
|
|
2012
|
+
* the app/ directory structure. These files are importable via TypeScript's
|
|
2013
|
+
* rootDirs feature.
|
|
2014
|
+
*/
|
|
2015
|
+
async function writeSegmentTypes(routeTree, appDir, root) {
|
|
2016
|
+
const typesBase = join(root, ".timber", "types", appDir.slice(root.length + 1));
|
|
2017
|
+
const map = buildDirToRouteMap(routeTree, appDir);
|
|
2018
|
+
const writes = [];
|
|
2019
|
+
for (const [fsDir, routePattern] of map) {
|
|
2020
|
+
const segmentDir = join(typesBase, fsDir.slice(appDir.length));
|
|
2021
|
+
const segmentPath = join(segmentDir, "_segment.d.ts");
|
|
2022
|
+
const content = `export const route: '${routePattern}';\n`;
|
|
2023
|
+
writes.push(mkdir(segmentDir, { recursive: true }).then(() => writeFile(segmentPath, content, "utf-8")));
|
|
2024
|
+
}
|
|
2025
|
+
await Promise.all(writes);
|
|
2026
|
+
}
|
|
2027
|
+
//#endregion
|
|
1982
2028
|
//#region src/routing/convention-lint.ts
|
|
1983
2029
|
/**
|
|
1984
2030
|
* Convention linter — validates common misconfigurations in the route tree.
|
|
@@ -2217,6 +2263,7 @@ var SEARCH_PARAMS_REGISTRY_ID = "virtual:timber-search-params-registry";
|
|
|
2217
2263
|
var RESOLVED_SEARCH_PARAMS_REGISTRY_ID = `\0${SEARCH_PARAMS_REGISTRY_ID}`;
|
|
2218
2264
|
var SCHEMA_ID = "virtual:timber-schema";
|
|
2219
2265
|
var RESOLVED_SCHEMA_ID = `\0${SCHEMA_ID}`;
|
|
2266
|
+
var SEGMENT_PREFIX = "\0_segment:";
|
|
2220
2267
|
/**
|
|
2221
2268
|
* File convention names we track for changes that require manifest regeneration.
|
|
2222
2269
|
*/
|
|
@@ -2257,13 +2304,19 @@ function writeCodegen(ctx) {
|
|
|
2257
2304
|
});
|
|
2258
2305
|
const routesPath = join(ctx.root, CODEGEN_OUTPUT);
|
|
2259
2306
|
const envPath = join(ctx.root, "timber-env.d.ts");
|
|
2260
|
-
mkdir(timberDir, { recursive: true }).then(() => Promise.all([
|
|
2307
|
+
mkdir(timberDir, { recursive: true }).then(() => Promise.all([
|
|
2308
|
+
writeFile(routesPath, content, "utf-8"),
|
|
2309
|
+
writeFile(envPath, TIMBER_ENV_DTS, "utf-8"),
|
|
2310
|
+
writeSegmentTypes(ctx.routeTree, ctx.appDir, ctx.root)
|
|
2311
|
+
])).catch((err) => {
|
|
2261
2312
|
console.warn("[timber] Failed to write codegen output:", err);
|
|
2262
2313
|
});
|
|
2263
2314
|
}
|
|
2264
2315
|
function timberRouting(ctx) {
|
|
2265
2316
|
/** Track warned files to avoid repeating warnings on rescan. */
|
|
2266
2317
|
const warnedFiles = /* @__PURE__ */ new Set();
|
|
2318
|
+
/** Maps absolute filesystem directory → route pattern for _segment resolution. */
|
|
2319
|
+
let dirToRoute = /* @__PURE__ */ new Map();
|
|
2267
2320
|
function rescan() {
|
|
2268
2321
|
const appDirWarning = checkAppDirExists(ctx.appDir);
|
|
2269
2322
|
if (appDirWarning) {
|
|
@@ -2281,6 +2334,7 @@ function timberRouting(ctx) {
|
|
|
2281
2334
|
ctx.timer.start("route-scan");
|
|
2282
2335
|
ctx.routeTree = scanRoutes(ctx.appDir, { pageExtensions: ctx.config.pageExtensions });
|
|
2283
2336
|
ctx.timer.end("route-scan");
|
|
2337
|
+
dirToRoute = buildDirToRouteMap(ctx.routeTree, ctx.appDir);
|
|
2284
2338
|
writeCodegen(ctx);
|
|
2285
2339
|
warnUnregisteredSegments(ctx);
|
|
2286
2340
|
const newConventionWarnings = lintConventions(ctx.routeTree, ctx.appDir).filter((w) => !warnedFiles.has(w.id));
|
|
@@ -2292,12 +2346,18 @@ function timberRouting(ctx) {
|
|
|
2292
2346
|
}
|
|
2293
2347
|
return {
|
|
2294
2348
|
name: "timber-routing",
|
|
2295
|
-
resolveId(id) {
|
|
2349
|
+
resolveId(id, importer) {
|
|
2296
2350
|
const cleanId = id.startsWith("\0") ? id.slice(1) : id;
|
|
2297
2351
|
if (cleanId === VIRTUAL_MODULE_ID$1) return RESOLVED_VIRTUAL_ID$1;
|
|
2298
2352
|
if (cleanId.endsWith(`/${VIRTUAL_MODULE_ID$1}`)) return RESOLVED_VIRTUAL_ID$1;
|
|
2299
2353
|
if (cleanId === SEARCH_PARAMS_REGISTRY_ID || cleanId.endsWith(`/${SEARCH_PARAMS_REGISTRY_ID}`)) return RESOLVED_SEARCH_PARAMS_REGISTRY_ID;
|
|
2300
2354
|
if (cleanId === SCHEMA_ID || cleanId.endsWith(`/${SCHEMA_ID}`)) return RESOLVED_SCHEMA_ID;
|
|
2355
|
+
if (importer && (cleanId === "./_segment" || cleanId === "./_segment.js" || cleanId === "./_segment.ts")) {
|
|
2356
|
+
const cleanImporter = importer.startsWith("\0") ? importer.slice(1) : importer;
|
|
2357
|
+
const importerDir = cleanImporter.substring(0, cleanImporter.lastIndexOf("/"));
|
|
2358
|
+
const routePattern = dirToRoute.get(importerDir);
|
|
2359
|
+
if (routePattern !== void 0) return `${SEGMENT_PREFIX}${routePattern}`;
|
|
2360
|
+
}
|
|
2301
2361
|
return null;
|
|
2302
2362
|
},
|
|
2303
2363
|
load(id) {
|
|
@@ -2310,6 +2370,10 @@ function timberRouting(ctx) {
|
|
|
2310
2370
|
return generateSearchParamsRegistryModule(ctx.routeTree);
|
|
2311
2371
|
}
|
|
2312
2372
|
if (id === RESOLVED_SCHEMA_ID) return generateSchemaModule(ctx.appDir);
|
|
2373
|
+
if (id.startsWith(SEGMENT_PREFIX)) {
|
|
2374
|
+
const routePattern = id.slice(10);
|
|
2375
|
+
return `export const route = ${JSON.stringify(routePattern)};\n`;
|
|
2376
|
+
}
|
|
2313
2377
|
return null;
|
|
2314
2378
|
},
|
|
2315
2379
|
buildStart() {
|
|
@@ -2391,6 +2455,7 @@ function invalidateManifest(server) {
|
|
|
2391
2455
|
const mod = env.moduleGraph.getModuleById(virtualId);
|
|
2392
2456
|
if (mod) env.moduleGraph.invalidateModule(mod);
|
|
2393
2457
|
}
|
|
2458
|
+
for (const mod of env.moduleGraph.idToModuleMap.values()) if (mod.id?.startsWith(SEGMENT_PREFIX)) env.moduleGraph.invalidateModule(mod);
|
|
2394
2459
|
}
|
|
2395
2460
|
server.hot.send({ type: "full-reload" });
|
|
2396
2461
|
}
|