@timber-js/app 0.2.0-alpha.111 → 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/_chunks/cli-schema-sync-BhXdbmgS.js +2 -0
- package/dist/_chunks/cli-schema-sync-DFZmnmqG.js +357 -0
- package/dist/_chunks/cli-schema-sync-DFZmnmqG.js.map +1 -0
- package/dist/cli-schema-sync.d.ts.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/index.js +68 -223
- 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/cli-schema-sync.ts +3 -6
- package/src/plugins/routing.ts +43 -1
- package/src/routing/segment-codegen.ts +73 -0
- package/dist/_chunks/cli-schema-sync-BvvuK8Rp.js +0 -137
- package/dist/_chunks/cli-schema-sync-BvvuK8Rp.js.map +0 -1
- package/dist/_chunks/cli-schema-sync-i2OEL2-p.js +0 -2
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { n as setViteServer } from "./_chunks/warnings-B30wpfaS.js";
|
|
|
2
2
|
import { h as swallow } from "./_chunks/logger-DDmK5skc.js";
|
|
3
3
|
import { t as scanRoutes } from "./_chunks/scanner-DmfoB7iK.js";
|
|
4
4
|
import { n as collectInterceptionRewrites, r as generateRouteMap, t as collectLeafRoutes } from "./_chunks/walkers-DGTmJT0f.js";
|
|
5
|
-
import { n as findSchemaFile, r as parseExistingSchemaKeys, t as collectDynamicSegments } from "./_chunks/cli-schema-sync-
|
|
5
|
+
import { a as DEFAULT_BUILD_DIR, c as mergeFileConfig, d as resolveClientJavascript, f as createNoopTimer, l as resolveAppDir, n as findSchemaFile, o as createPluginContext, r as parseExistingSchemaKeys, s as loadTimberConfigFile, t as collectDynamicSegments, u as resolveBuildDir } from "./_chunks/cli-schema-sync-DFZmnmqG.js";
|
|
6
6
|
import { t as formatSize } from "./_chunks/format-CR6v1pWE.js";
|
|
7
7
|
import { dirname, extname, join, normalize, resolve } from "node:path";
|
|
8
8
|
import { createRequire } from "node:module";
|
|
@@ -14,7 +14,6 @@ import { Readable } from "node:stream";
|
|
|
14
14
|
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
15
15
|
import { createHash, randomUUID } from "node:crypto";
|
|
16
16
|
import { parseAst } from "vite";
|
|
17
|
-
import { performance as performance$1 } from "node:perf_hooks";
|
|
18
17
|
import http from "node:http";
|
|
19
18
|
//#region \0rolldown/runtime.js
|
|
20
19
|
var __defProp = Object.defineProperty;
|
|
@@ -1980,6 +1979,52 @@ function timberMdx(ctx) {
|
|
|
1980
1979
|
};
|
|
1981
1980
|
}
|
|
1982
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
|
|
1983
2028
|
//#region src/routing/convention-lint.ts
|
|
1984
2029
|
/**
|
|
1985
2030
|
* Convention linter — validates common misconfigurations in the route tree.
|
|
@@ -2218,6 +2263,7 @@ var SEARCH_PARAMS_REGISTRY_ID = "virtual:timber-search-params-registry";
|
|
|
2218
2263
|
var RESOLVED_SEARCH_PARAMS_REGISTRY_ID = `\0${SEARCH_PARAMS_REGISTRY_ID}`;
|
|
2219
2264
|
var SCHEMA_ID = "virtual:timber-schema";
|
|
2220
2265
|
var RESOLVED_SCHEMA_ID = `\0${SCHEMA_ID}`;
|
|
2266
|
+
var SEGMENT_PREFIX = "\0_segment:";
|
|
2221
2267
|
/**
|
|
2222
2268
|
* File convention names we track for changes that require manifest regeneration.
|
|
2223
2269
|
*/
|
|
@@ -2258,13 +2304,19 @@ function writeCodegen(ctx) {
|
|
|
2258
2304
|
});
|
|
2259
2305
|
const routesPath = join(ctx.root, CODEGEN_OUTPUT);
|
|
2260
2306
|
const envPath = join(ctx.root, "timber-env.d.ts");
|
|
2261
|
-
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) => {
|
|
2262
2312
|
console.warn("[timber] Failed to write codegen output:", err);
|
|
2263
2313
|
});
|
|
2264
2314
|
}
|
|
2265
2315
|
function timberRouting(ctx) {
|
|
2266
2316
|
/** Track warned files to avoid repeating warnings on rescan. */
|
|
2267
2317
|
const warnedFiles = /* @__PURE__ */ new Set();
|
|
2318
|
+
/** Maps absolute filesystem directory → route pattern for _segment resolution. */
|
|
2319
|
+
let dirToRoute = /* @__PURE__ */ new Map();
|
|
2268
2320
|
function rescan() {
|
|
2269
2321
|
const appDirWarning = checkAppDirExists(ctx.appDir);
|
|
2270
2322
|
if (appDirWarning) {
|
|
@@ -2282,6 +2334,7 @@ function timberRouting(ctx) {
|
|
|
2282
2334
|
ctx.timer.start("route-scan");
|
|
2283
2335
|
ctx.routeTree = scanRoutes(ctx.appDir, { pageExtensions: ctx.config.pageExtensions });
|
|
2284
2336
|
ctx.timer.end("route-scan");
|
|
2337
|
+
dirToRoute = buildDirToRouteMap(ctx.routeTree, ctx.appDir);
|
|
2285
2338
|
writeCodegen(ctx);
|
|
2286
2339
|
warnUnregisteredSegments(ctx);
|
|
2287
2340
|
const newConventionWarnings = lintConventions(ctx.routeTree, ctx.appDir).filter((w) => !warnedFiles.has(w.id));
|
|
@@ -2293,12 +2346,18 @@ function timberRouting(ctx) {
|
|
|
2293
2346
|
}
|
|
2294
2347
|
return {
|
|
2295
2348
|
name: "timber-routing",
|
|
2296
|
-
resolveId(id) {
|
|
2349
|
+
resolveId(id, importer) {
|
|
2297
2350
|
const cleanId = id.startsWith("\0") ? id.slice(1) : id;
|
|
2298
2351
|
if (cleanId === VIRTUAL_MODULE_ID$1) return RESOLVED_VIRTUAL_ID$1;
|
|
2299
2352
|
if (cleanId.endsWith(`/${VIRTUAL_MODULE_ID$1}`)) return RESOLVED_VIRTUAL_ID$1;
|
|
2300
2353
|
if (cleanId === SEARCH_PARAMS_REGISTRY_ID || cleanId.endsWith(`/${SEARCH_PARAMS_REGISTRY_ID}`)) return RESOLVED_SEARCH_PARAMS_REGISTRY_ID;
|
|
2301
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
|
+
}
|
|
2302
2361
|
return null;
|
|
2303
2362
|
},
|
|
2304
2363
|
load(id) {
|
|
@@ -2311,6 +2370,10 @@ function timberRouting(ctx) {
|
|
|
2311
2370
|
return generateSearchParamsRegistryModule(ctx.routeTree);
|
|
2312
2371
|
}
|
|
2313
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
|
+
}
|
|
2314
2377
|
return null;
|
|
2315
2378
|
},
|
|
2316
2379
|
buildStart() {
|
|
@@ -2392,6 +2455,7 @@ function invalidateManifest(server) {
|
|
|
2392
2455
|
const mod = env.moduleGraph.getModuleById(virtualId);
|
|
2393
2456
|
if (mod) env.moduleGraph.invalidateModule(mod);
|
|
2394
2457
|
}
|
|
2458
|
+
for (const mod of env.moduleGraph.idToModuleMap.values()) if (mod.id?.startsWith(SEGMENT_PREFIX)) env.moduleGraph.invalidateModule(mod);
|
|
2395
2459
|
}
|
|
2396
2460
|
server.hot.send({ type: "full-reload" });
|
|
2397
2461
|
}
|
|
@@ -6493,81 +6557,6 @@ function timberBuildReport(ctx) {
|
|
|
6493
6557
|
};
|
|
6494
6558
|
}
|
|
6495
6559
|
//#endregion
|
|
6496
|
-
//#region src/utils/startup-timer.ts
|
|
6497
|
-
/**
|
|
6498
|
-
* Startup timer — records named phases with their durations.
|
|
6499
|
-
*
|
|
6500
|
-
* Used by the plugin system to instrument cold start and report a
|
|
6501
|
-
* timing breakdown in dev mode. Zero overhead in production (disabled).
|
|
6502
|
-
*
|
|
6503
|
-
* See design/18-build-system.md, TIM-155.
|
|
6504
|
-
*/
|
|
6505
|
-
/**
|
|
6506
|
-
* Create a startup timer that records phase durations.
|
|
6507
|
-
*/
|
|
6508
|
-
function createStartupTimer() {
|
|
6509
|
-
const pending = /* @__PURE__ */ new Map();
|
|
6510
|
-
const phases = [];
|
|
6511
|
-
return {
|
|
6512
|
-
start(phase) {
|
|
6513
|
-
pending.set(phase, performance$1.now());
|
|
6514
|
-
},
|
|
6515
|
-
end(phase) {
|
|
6516
|
-
const startMs = pending.get(phase);
|
|
6517
|
-
if (startMs === void 0) return 0;
|
|
6518
|
-
pending.delete(phase);
|
|
6519
|
-
const durationMs = performance$1.now() - startMs;
|
|
6520
|
-
phases.push({
|
|
6521
|
-
name: phase,
|
|
6522
|
-
startMs,
|
|
6523
|
-
durationMs
|
|
6524
|
-
});
|
|
6525
|
-
return durationMs;
|
|
6526
|
-
},
|
|
6527
|
-
getPhases() {
|
|
6528
|
-
return [...phases].sort((a, b) => a.startMs - b.startMs);
|
|
6529
|
-
},
|
|
6530
|
-
totalMs() {
|
|
6531
|
-
if (phases.length === 0) return 0;
|
|
6532
|
-
const sorted = this.getPhases();
|
|
6533
|
-
const first = sorted[0];
|
|
6534
|
-
const last = sorted[sorted.length - 1];
|
|
6535
|
-
return last.startMs + last.durationMs - first.startMs;
|
|
6536
|
-
},
|
|
6537
|
-
formatSummary() {
|
|
6538
|
-
const sorted = this.getPhases();
|
|
6539
|
-
if (sorted.length === 0) return "No phases recorded.";
|
|
6540
|
-
const lines = sorted.map((p) => {
|
|
6541
|
-
const ms = p.durationMs.toFixed(1);
|
|
6542
|
-
return ` ${p.name.padEnd(30)} ${ms.padStart(8)}ms`;
|
|
6543
|
-
});
|
|
6544
|
-
const total = this.totalMs().toFixed(1);
|
|
6545
|
-
lines.push(` ${"total".padEnd(30)} ${total.padStart(8)}ms`);
|
|
6546
|
-
return ["[timber] startup timing:", ...lines].join("\n");
|
|
6547
|
-
}
|
|
6548
|
-
};
|
|
6549
|
-
}
|
|
6550
|
-
/**
|
|
6551
|
-
* No-op timer for production builds — all methods are empty.
|
|
6552
|
-
*/
|
|
6553
|
-
function createNoopTimer() {
|
|
6554
|
-
return {
|
|
6555
|
-
start() {},
|
|
6556
|
-
end() {
|
|
6557
|
-
return 0;
|
|
6558
|
-
},
|
|
6559
|
-
getPhases() {
|
|
6560
|
-
return [];
|
|
6561
|
-
},
|
|
6562
|
-
totalMs() {
|
|
6563
|
-
return 0;
|
|
6564
|
-
},
|
|
6565
|
-
formatSummary() {
|
|
6566
|
-
return "";
|
|
6567
|
-
}
|
|
6568
|
-
};
|
|
6569
|
-
}
|
|
6570
|
-
//#endregion
|
|
6571
6560
|
//#region src/server/action-encryption.ts
|
|
6572
6561
|
/**
|
|
6573
6562
|
* Regex for safe `defineEncryptionKey` expressions.
|
|
@@ -6902,150 +6891,6 @@ async function startDevServerPort(input) {
|
|
|
6902
6891
|
}
|
|
6903
6892
|
}
|
|
6904
6893
|
//#endregion
|
|
6905
|
-
//#region src/plugin-context.ts
|
|
6906
|
-
/**
|
|
6907
|
-
* Plugin context — internal types and helpers for timber sub-plugins.
|
|
6908
|
-
*
|
|
6909
|
-
* These are NOT part of the user-facing API. They are consumed by
|
|
6910
|
-
* sub-plugins (routing, entries, shims, etc.) via relative imports.
|
|
6911
|
-
* The root entry point (index.ts) does not re-export them.
|
|
6912
|
-
*
|
|
6913
|
-
* Design doc: 18-build-system.md §"Shared Plugin Context"
|
|
6914
|
-
*/
|
|
6915
|
-
/**
|
|
6916
|
-
* Resolve `clientJavascript` into a fully resolved config.
|
|
6917
|
-
*/
|
|
6918
|
-
function resolveClientJavascript(config) {
|
|
6919
|
-
if (config.clientJavascript !== void 0) {
|
|
6920
|
-
if (typeof config.clientJavascript === "boolean") return {
|
|
6921
|
-
disabled: !config.clientJavascript,
|
|
6922
|
-
enableHMRInDev: !config.clientJavascript
|
|
6923
|
-
};
|
|
6924
|
-
return {
|
|
6925
|
-
disabled: config.clientJavascript.disabled,
|
|
6926
|
-
enableHMRInDev: config.clientJavascript.enableHMRInDev ?? config.clientJavascript.disabled
|
|
6927
|
-
};
|
|
6928
|
-
}
|
|
6929
|
-
return {
|
|
6930
|
-
disabled: false,
|
|
6931
|
-
enableHMRInDev: false
|
|
6932
|
-
};
|
|
6933
|
-
}
|
|
6934
|
-
/**
|
|
6935
|
-
* Resolve the app directory. Checks (in order):
|
|
6936
|
-
* 1. Explicit `configAppDir` from timber.config.ts
|
|
6937
|
-
* 2. `<root>/app`
|
|
6938
|
-
* 3. `<root>/src/app`
|
|
6939
|
-
*
|
|
6940
|
-
* Throws if none exist.
|
|
6941
|
-
*/
|
|
6942
|
-
function resolveAppDir(root, configAppDir) {
|
|
6943
|
-
if (configAppDir) {
|
|
6944
|
-
const explicit = join(root, configAppDir);
|
|
6945
|
-
if (!existsSync(explicit)) throw new Error(`[timber] Configured appDir "${configAppDir}" does not exist at ${explicit}`);
|
|
6946
|
-
return explicit;
|
|
6947
|
-
}
|
|
6948
|
-
const rootApp = join(root, "app");
|
|
6949
|
-
if (existsSync(rootApp)) return rootApp;
|
|
6950
|
-
const srcApp = join(root, "src", "app");
|
|
6951
|
-
if (existsSync(srcApp)) return srcApp;
|
|
6952
|
-
throw new Error(`[timber] Could not find app directory. Expected "app/" or "src/app/" in ${root}. You can set appDir in timber.config.ts to specify a custom location.`);
|
|
6953
|
-
}
|
|
6954
|
-
function createPluginContext(config, root) {
|
|
6955
|
-
const projectRoot = root ?? process.cwd();
|
|
6956
|
-
const resolvedConfig = { ...config };
|
|
6957
|
-
return {
|
|
6958
|
-
config: resolvedConfig,
|
|
6959
|
-
clientJavascript: resolveClientJavascript(resolvedConfig),
|
|
6960
|
-
routeTree: null,
|
|
6961
|
-
appDir: join(projectRoot, "app"),
|
|
6962
|
-
root: projectRoot,
|
|
6963
|
-
dev: false,
|
|
6964
|
-
buildManifest: null,
|
|
6965
|
-
deploymentId: null,
|
|
6966
|
-
timer: createStartupTimer(),
|
|
6967
|
-
holdingServer: null,
|
|
6968
|
-
buildDir: resolveBuildDir(projectRoot, resolvedConfig.buildDir)
|
|
6969
|
-
};
|
|
6970
|
-
}
|
|
6971
|
-
/** Default build output directory (relative to root). */
|
|
6972
|
-
var DEFAULT_BUILD_DIR = join(".timber", "dist");
|
|
6973
|
-
/**
|
|
6974
|
-
* Resolve the build output directory.
|
|
6975
|
-
*
|
|
6976
|
-
* Priority:
|
|
6977
|
-
* 1. Explicit `timberBuildDir` from timber.config.ts
|
|
6978
|
-
* 2. Explicit `viteBuildOutDir` from Vite's build.outDir (if not the default 'dist')
|
|
6979
|
-
* 3. Default: `.timber/dist`
|
|
6980
|
-
*
|
|
6981
|
-
* Returns an absolute path.
|
|
6982
|
-
*/
|
|
6983
|
-
function resolveBuildDir(root, timberBuildDir, viteBuildOutDir) {
|
|
6984
|
-
if (timberBuildDir) return join(root, timberBuildDir);
|
|
6985
|
-
if (viteBuildOutDir && viteBuildOutDir !== "dist") return join(root, viteBuildOutDir);
|
|
6986
|
-
return join(root, DEFAULT_BUILD_DIR);
|
|
6987
|
-
}
|
|
6988
|
-
/**
|
|
6989
|
-
* Load timber.config.ts (or .js, .mjs) from the project root.
|
|
6990
|
-
* Returns the config object or null if no config file is found.
|
|
6991
|
-
*
|
|
6992
|
-
* Uses require() which works for ESM modules on Node 22.12+.
|
|
6993
|
-
* This keeps timber() synchronous — no async config loading needed.
|
|
6994
|
-
*/
|
|
6995
|
-
function loadTimberConfigFile(root) {
|
|
6996
|
-
const configNames = [
|
|
6997
|
-
"timber.config.ts",
|
|
6998
|
-
"timber.config.js",
|
|
6999
|
-
"timber.config.mjs"
|
|
7000
|
-
];
|
|
7001
|
-
const req = createRequire(join(root, "package.json"));
|
|
7002
|
-
for (const name of configNames) {
|
|
7003
|
-
const configPath = join(root, name);
|
|
7004
|
-
if (existsSync(configPath)) {
|
|
7005
|
-
const mod = req(configPath);
|
|
7006
|
-
return mod.default ?? mod;
|
|
7007
|
-
}
|
|
7008
|
-
}
|
|
7009
|
-
return null;
|
|
7010
|
-
}
|
|
7011
|
-
/**
|
|
7012
|
-
* Detect config keys set in both inline (vite.config.ts) and file (timber.config.ts)
|
|
7013
|
-
* and warn the user. The `output` key is excluded because it defaults to 'server'
|
|
7014
|
-
* in createPluginContext and would always appear as an inline key.
|
|
7015
|
-
*
|
|
7016
|
-
* Returns the list of conflicting key names (for testing).
|
|
7017
|
-
*/
|
|
7018
|
-
function warnConfigConflicts(inline, fileConfig) {
|
|
7019
|
-
const conflicts = [];
|
|
7020
|
-
for (const key of Object.keys(fileConfig)) if (key in inline && inline[key] !== void 0) conflicts.push(key);
|
|
7021
|
-
if (conflicts.length > 0) console.warn(`[timber] Config conflict: ${conflicts.map((k) => `"${k}"`).join(", ")} set in both vite.config.ts (inline) and timber.config.ts. Move all config to timber.config.ts to avoid confusion. The inline value from vite.config.ts will be used.`);
|
|
7022
|
-
return conflicts;
|
|
7023
|
-
}
|
|
7024
|
-
/**
|
|
7025
|
-
* Merge file-based config into ctx.config. Inline config (already in ctx.config)
|
|
7026
|
-
* takes precedence — file config only fills in missing fields.
|
|
7027
|
-
*/
|
|
7028
|
-
function mergeFileConfig(ctx, fileConfig) {
|
|
7029
|
-
const inline = ctx.config;
|
|
7030
|
-
warnConfigConflicts(inline, fileConfig);
|
|
7031
|
-
ctx.config = {
|
|
7032
|
-
...fileConfig,
|
|
7033
|
-
...inline,
|
|
7034
|
-
...fileConfig.limits && inline.limits ? { limits: {
|
|
7035
|
-
...fileConfig.limits,
|
|
7036
|
-
...inline.limits
|
|
7037
|
-
} } : {},
|
|
7038
|
-
...fileConfig.dev && inline.dev ? { dev: {
|
|
7039
|
-
...fileConfig.dev,
|
|
7040
|
-
...inline.dev
|
|
7041
|
-
} } : {},
|
|
7042
|
-
...fileConfig.mdx && inline.mdx ? { mdx: {
|
|
7043
|
-
...fileConfig.mdx,
|
|
7044
|
-
...inline.mdx
|
|
7045
|
-
} } : {}
|
|
7046
|
-
};
|
|
7047
|
-
}
|
|
7048
|
-
//#endregion
|
|
7049
6894
|
//#region src/index.ts
|
|
7050
6895
|
/**
|
|
7051
6896
|
* Type-safe helper for timber.config.ts files.
|