@react-router/dev 7.0.0-pre.4 → 7.0.0-pre.5

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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # `@remix-run/dev`
2
2
 
3
+ ## 7.0.0-pre.5
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies:
8
+ - `react-router@7.0.0-pre.5`
9
+ - `@react-router/node@7.0.0-pre.5`
10
+ - `@react-router/serve@7.0.0-pre.5`
11
+
3
12
  ## 7.0.0-pre.4
4
13
 
5
14
  ### Patch Changes
@@ -1,2 +1 @@
1
-
2
- export { }
1
+ #!/usr/bin/env node
package/dist/cli/index.js CHANGED
@@ -1,5 +1,6 @@
1
+ #!/usr/bin/env node
1
2
  /**
2
- * @react-router/dev v7.0.0-pre.4
3
+ * @react-router/dev v7.0.0-pre.5
3
4
  *
4
5
  * Copyright (c) Remix Software Inc.
5
6
  *
@@ -83,6 +84,10 @@ var init_node_adapter = __esm({
83
84
  async function preloadViteEsm() {
84
85
  vite = await import("vite");
85
86
  }
87
+ function importViteEsmSync() {
88
+ invariant(vite, "importViteEsmSync() called before preloadViteEsm()");
89
+ return vite;
90
+ }
86
91
  var vite;
87
92
  var init_import_vite_esm_sync = __esm({
88
93
  "vite/import-vite-esm-sync.ts"() {
@@ -141,6 +146,44 @@ var init_remove_exports = __esm({
141
146
  });
142
147
 
143
148
  // config/routes.ts
149
+ function configRoutesToRouteManifest(routes2, rootId = "root") {
150
+ let routeManifest = {};
151
+ function walk(route, parentId) {
152
+ let id2 = route.id || createRouteId(route.file);
153
+ let manifestItem = {
154
+ id: id2,
155
+ parentId,
156
+ file: route.file,
157
+ path: route.path,
158
+ index: route.index,
159
+ caseSensitive: route.caseSensitive
160
+ };
161
+ if (routeManifest.hasOwnProperty(id2)) {
162
+ throw new Error(
163
+ `Unable to define routes with duplicate route id: "${id2}"`
164
+ );
165
+ }
166
+ routeManifest[id2] = manifestItem;
167
+ if (route.children) {
168
+ for (let child of route.children) {
169
+ walk(child, id2);
170
+ }
171
+ }
172
+ }
173
+ for (let route of routes2) {
174
+ walk(route, rootId);
175
+ }
176
+ return routeManifest;
177
+ }
178
+ function createRouteId(file) {
179
+ return normalizeSlashes(stripFileExtension(file));
180
+ }
181
+ function normalizeSlashes(file) {
182
+ return file.split(import_node_path.win32.sep).join("/");
183
+ }
184
+ function stripFileExtension(file) {
185
+ return file.replace(/\.[a-z0-9]+$/i, "");
186
+ }
144
187
  var import_node_path, v, import_pick, routeConfigEntrySchema, resolvedRouteConfigSchema;
145
188
  var init_routes = __esm({
146
189
  "config/routes.ts"() {
@@ -174,7 +217,14 @@ var init_detectPackageManager = __esm({
174
217
  });
175
218
 
176
219
  // vite/config.ts
177
- var import_node_child_process, import_node_path2, import_fs_extra, import_picocolors, import_pick2, import_omit, import_package_json, branchRouteProperties, configRouteToBranchRoute;
220
+ function findEntry(dir, basename2) {
221
+ for (let ext of entryExts) {
222
+ let file = import_node_path2.default.resolve(dir, basename2 + ext);
223
+ if (import_fs_extra.default.existsSync(file)) return import_node_path2.default.relative(dir, file);
224
+ }
225
+ return void 0;
226
+ }
227
+ var import_node_child_process, import_node_path2, import_fs_extra, import_picocolors, import_pick2, import_omit, import_package_json, branchRouteProperties, configRouteToBranchRoute, entryExts;
178
228
  var init_config = __esm({
179
229
  "vite/config.ts"() {
180
230
  "use strict";
@@ -195,6 +245,7 @@ var init_config = __esm({
195
245
  "index"
196
246
  ];
197
247
  configRouteToBranchRoute = (configRoute) => (0, import_pick2.default)(configRoute, branchRouteProperties);
248
+ entryExts = [".js", ".jsx", ".ts", ".tsx"];
198
249
  }
199
250
  });
200
251
 
@@ -211,6 +262,43 @@ var init_with_props = __esm({
211
262
  });
212
263
 
213
264
  // vite/vite-node.ts
265
+ async function createContext(viteConfig = {}) {
266
+ await preloadViteEsm();
267
+ const vite2 = importViteEsmSync();
268
+ const devServer = await vite2.createServer(
269
+ vite2.mergeConfig(
270
+ {
271
+ server: {
272
+ preTransformRequests: false,
273
+ hmr: false
274
+ },
275
+ optimizeDeps: {
276
+ noDiscovery: true
277
+ },
278
+ configFile: false,
279
+ envFile: false,
280
+ plugins: []
281
+ },
282
+ viteConfig
283
+ )
284
+ );
285
+ await devServer.pluginContainer.buildStart({});
286
+ const server = new import_server.ViteNodeServer(devServer);
287
+ (0, import_source_map.installSourcemapsSupport)({
288
+ getSourceMap: (source) => server.getSourceMap(source)
289
+ });
290
+ const runner = new import_client.ViteNodeRunner({
291
+ root: devServer.config.root,
292
+ base: devServer.config.base,
293
+ fetchModule(id2) {
294
+ return server.fetchModule(id2);
295
+ },
296
+ resolveId(id2, importer) {
297
+ return server.resolveId(id2, importer);
298
+ }
299
+ });
300
+ return { devServer, server, runner };
301
+ }
214
302
  var import_server, import_client, import_source_map;
215
303
  var init_vite_node = __esm({
216
304
  "vite/vite-node.ts"() {
@@ -275,9 +363,9 @@ async function loadPluginContext({
275
363
  }
276
364
  return ctx;
277
365
  }
278
- function findConfig(dir, basename3, extensions) {
366
+ function findConfig(dir, basename2, extensions) {
279
367
  for (let ext of extensions) {
280
- let name = basename3 + ext;
368
+ let name = basename2 + ext;
281
369
  let file = path4.join(dir, name);
282
370
  if (fse2.existsSync(file)) return file;
283
371
  }
@@ -382,7 +470,7 @@ var init_profiler = __esm({
382
470
  });
383
471
  };
384
472
  profileCount = 0;
385
- stop = (log) => {
473
+ stop = (log2) => {
386
474
  let session = getSession();
387
475
  if (!session) return;
388
476
  return new Promise((res, rej) => {
@@ -390,7 +478,7 @@ var init_profiler = __esm({
390
478
  if (err) return rej(err);
391
479
  let outPath = import_node_path3.default.resolve(`./react-router-${profileCount++}.cpuprofile`);
392
480
  import_node_fs.default.writeFileSync(outPath, JSON.stringify(profile));
393
- log(
481
+ log2(
394
482
  import_picocolors3.default.yellow(
395
483
  `CPU profile written to ${import_picocolors3.default.white(import_picocolors3.default.dim(outPath))}`
396
484
  )
@@ -562,7 +650,7 @@ async function build(root, {
562
650
  const ctx = await extractPluginContext(viteConfig);
563
651
  if (!ctx) {
564
652
  console.error(
565
- import_picocolors4.default.red("React Router Vite plugin not found in Vite config")
653
+ import_picocolors6.default.red("React Router Vite plugin not found in Vite config")
566
654
  );
567
655
  process.exit(1);
568
656
  }
@@ -614,13 +702,13 @@ async function build(root, {
614
702
  viteConfig
615
703
  });
616
704
  }
617
- var import_node_path4, import_fs_extra2, import_picocolors4;
705
+ var import_node_path4, import_fs_extra2, import_picocolors6;
618
706
  var init_build = __esm({
619
707
  "vite/build.ts"() {
620
708
  "use strict";
621
709
  import_node_path4 = __toESM(require("path"));
622
710
  import_fs_extra2 = __toESM(require("fs-extra"));
623
- import_picocolors4 = __toESM(require("picocolors"));
711
+ import_picocolors6 = __toESM(require("picocolors"));
624
712
  init_plugin();
625
713
  init_config();
626
714
  init_invariant();
@@ -658,7 +746,7 @@ async function dev(root, {
658
746
  });
659
747
  if (!server.config.plugins.find((plugin2) => plugin2.name === "react-router")) {
660
748
  console.error(
661
- import_picocolors5.default.red("React Router Vite plugin not found in Vite config")
749
+ import_picocolors7.default.red("React Router Vite plugin not found in Vite config")
662
750
  );
663
751
  process.exit(1);
664
752
  }
@@ -681,11 +769,11 @@ async function dev(root, {
681
769
  ];
682
770
  server.bindCLIShortcuts({ print: true, customShortcuts });
683
771
  }
684
- var import_picocolors5;
772
+ var import_picocolors7;
685
773
  var init_dev = __esm({
686
774
  "vite/dev.ts"() {
687
775
  "use strict";
688
- import_picocolors5 = __toESM(require("picocolors"));
776
+ import_picocolors7 = __toESM(require("picocolors"));
689
777
  init_import_vite_esm_sync();
690
778
  init_profiler();
691
779
  }
@@ -694,34 +782,14 @@ var init_dev = __esm({
694
782
  // cli/run.ts
695
783
  var import_arg = __toESM(require("arg"));
696
784
  var import_semver = __toESM(require("semver"));
697
-
698
- // colors.ts
699
- var import_chalk = __toESM(require("chalk"));
700
- var useColor = import_chalk.default.supportsColor && !process.env.NO_COLOR;
701
- var identity = (x) => x;
702
- var safe = (style) => useColor ? style : identity;
703
- var heading = safe(import_chalk.default.underline);
704
- var arg = safe(import_chalk.default.yellowBright);
705
- var error = safe(import_chalk.default.red);
706
- var warning = safe(import_chalk.default.yellow);
707
- var hint = safe(import_chalk.default.blue);
708
- var logoBlue = safe(import_chalk.default.blueBright);
709
- var logoGreen = safe(import_chalk.default.greenBright);
710
- var logoYellow = safe(import_chalk.default.yellowBright);
711
- var logoPink = safe(import_chalk.default.magentaBright);
712
- var logoRed = safe(import_chalk.default.redBright);
713
- var bold = safe(import_chalk.default.bold);
714
- var blue = safe(import_chalk.default.blue);
715
- var cyan = safe(import_chalk.default.cyan);
716
- var gray = safe(import_chalk.default.gray);
717
- var red = safe(import_chalk.default.red);
718
- var yellow = safe(import_chalk.default.yellow);
785
+ var import_picocolors9 = __toESM(require("picocolors"));
719
786
 
720
787
  // cli/commands.ts
721
788
  var path7 = __toESM(require("path"));
722
789
  var import_fs_extra3 = __toESM(require("fs-extra"));
723
790
  var import_package_json2 = __toESM(require("@npmcli/package-json"));
724
791
  var import_exit_hook = __toESM(require("exit-hook"));
792
+ var import_picocolors8 = __toESM(require("picocolors"));
725
793
 
726
794
  // config/format.ts
727
795
  function formatRoutes(routeManifest, format) {
@@ -803,12 +871,53 @@ function transpile(tsx, options = {}) {
803
871
  // cli/commands.ts
804
872
  init_profiler();
805
873
 
806
- // typescript/typegen.ts
874
+ // typegen.ts
807
875
  var import_node_fs2 = __toESM(require("fs"));
808
876
  var import_chokidar = __toESM(require("chokidar"));
809
877
  var import_dedent2 = __toESM(require("dedent"));
810
878
  var Path = __toESM(require("pathe"));
811
879
  var Pathe = __toESM(require("pathe/utils"));
880
+ var import_picocolors5 = __toESM(require("picocolors"));
881
+
882
+ // logger.ts
883
+ var import_picocolors4 = __toESM(require("picocolors"));
884
+ var DATE_TIME_FORMAT = new Intl.DateTimeFormat([], {
885
+ hour: "2-digit",
886
+ minute: "2-digit",
887
+ second: "2-digit",
888
+ hour12: false
889
+ });
890
+ var log = (level) => (body, options = {}) => {
891
+ const dest = level === "error" ? process.stderr : process.stdout;
892
+ let message = getPrefix(level, options) + " " + body;
893
+ if (options.durationMs) {
894
+ const duration = options.durationMs < 1e3 ? `${Math.round(options.durationMs)}ms` : `${(options.durationMs / 1e3).toFixed(2)}s`;
895
+ message += " " + import_picocolors4.default.dim(duration);
896
+ }
897
+ dest.write(message + "\n");
898
+ };
899
+ function getPrefix(level, options) {
900
+ const timestamp = `${DATE_TIME_FORMAT.format(/* @__PURE__ */ new Date())}`;
901
+ const prefix = [];
902
+ if (level === "error" || level === "warn") {
903
+ prefix.push(import_picocolors4.default.bold(timestamp));
904
+ prefix.push(`[${level.toUpperCase()}]`);
905
+ } else {
906
+ prefix.push(timestamp);
907
+ }
908
+ if (options.label) {
909
+ prefix.push(`[${options.label}]`);
910
+ }
911
+ if (level === "error") return import_picocolors4.default.red(prefix.join(" "));
912
+ if (level === "warn") return import_picocolors4.default.yellow(prefix.join(" "));
913
+ if (prefix.length === 1) return import_picocolors4.default.dim(prefix[0]);
914
+ return import_picocolors4.default.dim(prefix[0]) + " " + import_picocolors4.default.blue(prefix.splice(1).join(" "));
915
+ }
916
+ var info = log("info");
917
+ var warn = log("warn");
918
+ var error = log("error");
919
+
920
+ // typegen.ts
812
921
  init_routes();
813
922
  init_vite_node();
814
923
  init_config();
@@ -816,19 +925,100 @@ init_plugin();
816
925
  function getDirectory(ctx) {
817
926
  return Path.join(ctx.rootDirectory, ".react-router/types");
818
927
  }
819
- function getPath(ctx, route) {
820
- return Path.join(
821
- getDirectory(ctx),
822
- Path.basename(ctx.appDirectory),
823
- Path.dirname(route.file),
824
- "+types." + Pathe.filename(route.file) + ".d.ts"
928
+ async function watch(rootDirectory, options = {}) {
929
+ const watchStart = performance.now();
930
+ const vitePluginCtx = await loadPluginContext({
931
+ root: rootDirectory,
932
+ configFile: options.configFile
933
+ });
934
+ const routeConfigFile = findEntry(
935
+ vitePluginCtx.reactRouterConfig.appDirectory,
936
+ "routes"
825
937
  );
938
+ if (!routeConfigFile) {
939
+ warn(
940
+ `Could not find route config within ${import_picocolors5.default.blue(
941
+ Path.relative(
942
+ vitePluginCtx.rootDirectory,
943
+ vitePluginCtx.reactRouterConfig.appDirectory
944
+ )
945
+ )}`
946
+ );
947
+ process.exit(1);
948
+ }
949
+ const routeConfigPath = Path.join(
950
+ vitePluginCtx.reactRouterConfig.appDirectory,
951
+ routeConfigFile
952
+ );
953
+ const routesViteNodeContext = await createContext({
954
+ root: rootDirectory
955
+ });
956
+ async function getRoutes() {
957
+ const routes2 = {};
958
+ const rootRouteFile = findEntry(
959
+ vitePluginCtx.reactRouterConfig.appDirectory,
960
+ "root"
961
+ );
962
+ if (rootRouteFile) {
963
+ routes2.root = { path: "", id: "root", file: rootRouteFile };
964
+ } else {
965
+ warn(`Could not find \`root\` route`);
966
+ }
967
+ routesViteNodeContext.devServer.moduleGraph.invalidateAll();
968
+ routesViteNodeContext.runner.moduleCache.clear();
969
+ const routeConfig = (await routesViteNodeContext.runner.executeFile(routeConfigPath)).routes;
970
+ return {
971
+ ...routes2,
972
+ ...configRoutesToRouteManifest(await routeConfig)
973
+ };
974
+ }
975
+ const ctx = {
976
+ rootDirectory,
977
+ appDirectory: vitePluginCtx.reactRouterConfig.appDirectory,
978
+ routes: await getRoutes()
979
+ };
980
+ await writeAll(ctx);
981
+ info("generated initial types", {
982
+ durationMs: performance.now() - watchStart
983
+ });
984
+ const watcher = import_chokidar.default.watch(ctx.appDirectory, { ignoreInitial: true });
985
+ watcher.on("all", async (event, path8) => {
986
+ const eventStart = performance.now();
987
+ path8 = Path.normalize(path8);
988
+ ctx.routes = await getRoutes();
989
+ const routeConfigChanged = Boolean(
990
+ routesViteNodeContext.devServer.moduleGraph.getModuleById(path8)
991
+ );
992
+ if (routeConfigChanged) {
993
+ await writeAll(ctx);
994
+ info("changed route config", {
995
+ durationMs: performance.now() - eventStart
996
+ });
997
+ return;
998
+ }
999
+ const route = Object.values(ctx.routes).find(
1000
+ (route2) => path8 === Path.join(ctx.appDirectory, route2.file)
1001
+ );
1002
+ if (route && (event === "add" || event === "unlink")) {
1003
+ await writeAll(ctx);
1004
+ info(
1005
+ `${event === "add" ? "added" : "removed"} route ${import_picocolors5.default.blue(route.file)}`,
1006
+ { durationMs: performance.now() - eventStart }
1007
+ );
1008
+ return;
1009
+ }
1010
+ });
826
1011
  }
827
1012
  async function writeAll(ctx) {
828
1013
  import_node_fs2.default.rmSync(getDirectory(ctx), { recursive: true, force: true });
829
1014
  Object.values(ctx.routes).forEach((route) => {
830
1015
  if (!import_node_fs2.default.existsSync(Path.join(ctx.appDirectory, route.file))) return;
831
- const typesPath = getPath(ctx, route);
1016
+ const typesPath = Path.join(
1017
+ getDirectory(ctx),
1018
+ Path.relative(ctx.rootDirectory, ctx.appDirectory),
1019
+ Path.dirname(route.file),
1020
+ "+types." + Pathe.filename(route.file) + ".d.ts"
1021
+ );
832
1022
  const content = getModule(ctx.routes, route);
833
1023
  import_node_fs2.default.mkdirSync(Path.dirname(typesPath), { recursive: true });
834
1024
  import_node_fs2.default.writeFileSync(typesPath, content);
@@ -843,19 +1033,21 @@ function getModule(routes2, route) {
843
1033
 
844
1034
  export type Params = {${formattedParamsProperties(routes2, route)}}
845
1035
 
846
- type Route = typeof import("./${Pathe.filename(route.file)}")
1036
+ type RouteModule = typeof import("./${Pathe.filename(route.file)}")
847
1037
 
848
- export type LoaderData = T.CreateLoaderData<Route>
849
- export type ActionData = T.CreateActionData<Route>
1038
+ export namespace Route {
1039
+ export type LoaderData = T.CreateLoaderData<RouteModule>
1040
+ export type ActionData = T.CreateActionData<RouteModule>
850
1041
 
851
- export type LoaderArgs = T.CreateServerLoaderArgs<Params>
852
- export type ClientLoaderArgs = T.CreateClientLoaderArgs<Params, Route>
853
- export type ActionArgs = T.CreateServerActionArgs<Params>
854
- export type ClientActionArgs = T.CreateClientActionArgs<Params, Route>
1042
+ export type LoaderArgs = T.CreateServerLoaderArgs<Params>
1043
+ export type ClientLoaderArgs = T.CreateClientLoaderArgs<Params, RouteModule>
1044
+ export type ActionArgs = T.CreateServerActionArgs<Params>
1045
+ export type ClientActionArgs = T.CreateClientActionArgs<Params, RouteModule>
855
1046
 
856
- export type HydrateFallbackProps = T.CreateHydrateFallbackProps<Params>
857
- export type ComponentProps = T.CreateComponentProps<Params, LoaderData, ActionData>
858
- export type ErrorBoundaryProps = T.CreateErrorBoundaryProps<Params, LoaderData, ActionData>
1047
+ export type HydrateFallbackProps = T.CreateHydrateFallbackProps<Params>
1048
+ export type ComponentProps = T.CreateComponentProps<Params, LoaderData, ActionData>
1049
+ export type ErrorBoundaryProps = T.CreateErrorBoundaryProps<Params, LoaderData, ActionData>
1050
+ }
859
1051
  `;
860
1052
  }
861
1053
  function formattedParamsProperties(routes2, route) {
@@ -865,12 +1057,12 @@ function formattedParamsProperties(routes2, route) {
865
1057
  const properties = Object.entries(params).map(([name, values]) => {
866
1058
  if (values.length === 1) {
867
1059
  const isOptional = values[0];
868
- return indent + (isOptional ? `${name}?: string` : `${name}: string`);
1060
+ return indent + (isOptional ? `"${name}"?: string` : `"${name}": string`);
869
1061
  }
870
1062
  const items = values.map(
871
1063
  (isOptional) => isOptional ? "string | undefined" : "string"
872
1064
  );
873
- return indent + `${name}: [${items.join(", ")}]`;
1065
+ return indent + `"${name}": [${items.join(", ")}]`;
874
1066
  });
875
1067
  const body = properties.length === 0 ? "" : "\n" + properties.join("\n") + "\n";
876
1068
  return body;
@@ -898,6 +1090,8 @@ function parseParams(urlpath) {
898
1090
  result[param].push(isOptional);
899
1091
  return;
900
1092
  });
1093
+ const hasSplat = segments.at(-1) === "*";
1094
+ if (hasSplat) result["*"] = [false];
901
1095
  return result;
902
1096
  }
903
1097
 
@@ -909,7 +1103,7 @@ async function routes(reactRouterRoot, flags = {}) {
909
1103
  });
910
1104
  if (!ctx) {
911
1105
  console.error(
912
- red("React Router Vite plugin not found in Vite config")
1106
+ import_picocolors8.default.red("React Router Vite plugin not found in Vite config")
913
1107
  );
914
1108
  process.exit(1);
915
1109
  }
@@ -963,14 +1157,14 @@ async function generateEntry(entry, reactRouterRoot, flags = {}) {
963
1157
  let entriesArray = Array.from(entries);
964
1158
  let list = conjunctionListFormat.format(entriesArray);
965
1159
  console.error(
966
- error(`Invalid entry file. Valid entry files are ${list}`)
1160
+ import_picocolors8.default.red(`Invalid entry file. Valid entry files are ${list}`)
967
1161
  );
968
1162
  return;
969
1163
  }
970
1164
  let pkgJson = await import_package_json2.default.load(rootDirectory);
971
1165
  let deps = pkgJson.content.dependencies ?? {};
972
1166
  if (!deps["@react-router/node"]) {
973
- console.error(error(`No default server entry detected.`));
1167
+ console.error(import_picocolors8.default.red(`No default server entry detected.`));
974
1168
  return;
975
1169
  }
976
1170
  let defaultsDirectory = path7.resolve(
@@ -1000,7 +1194,7 @@ async function generateEntry(entry, reactRouterRoot, flags = {}) {
1000
1194
  await import_fs_extra3.default.writeFile(outputFile2, contents, "utf-8");
1001
1195
  }
1002
1196
  console.log(
1003
- blue(
1197
+ import_picocolors8.default.blue(
1004
1198
  `Entry file ${entry} created at ${path7.relative(
1005
1199
  rootDirectory,
1006
1200
  outputFile2
@@ -1013,8 +1207,8 @@ async function checkForEntry(rootDirectory, appDirectory, entries2) {
1013
1207
  let entryPath = path7.resolve(appDirectory, entry);
1014
1208
  let exists = await import_fs_extra3.default.pathExists(entryPath);
1015
1209
  if (exists) {
1016
- let relative5 = path7.relative(rootDirectory, entryPath);
1017
- console.error(error(`Entry file ${relative5} already exists.`));
1210
+ let relative6 = path7.relative(rootDirectory, entryPath);
1211
+ console.error(import_picocolors8.default.red(`Entry file ${relative6} already exists.`));
1018
1212
  return process.exit(1);
1019
1213
  }
1020
1214
  }
@@ -1029,8 +1223,15 @@ async function createClientEntry(rootDirectory, appDirectory, inputFile) {
1029
1223
  let contents = await import_fs_extra3.default.readFile(inputFile, "utf-8");
1030
1224
  return contents;
1031
1225
  }
1032
- async function typegen(root) {
1033
- let ctx = await loadPluginContext({ root });
1226
+ async function typegen(root, flags) {
1227
+ root ??= process.cwd();
1228
+ if (flags.watch) {
1229
+ await watch(root, { configFile: flags.config });
1230
+ await new Promise(() => {
1231
+ });
1232
+ return;
1233
+ }
1234
+ let ctx = await loadPluginContext({ root, configFile: flags.config });
1034
1235
  await writeAll({
1035
1236
  rootDirectory: root,
1036
1237
  appDirectory: ctx.reactRouterConfig.appDirectory,
@@ -1040,14 +1241,14 @@ async function typegen(root) {
1040
1241
 
1041
1242
  // cli/run.ts
1042
1243
  var helpText = `
1043
- ${logoBlue("react-router")}
1244
+ ${import_picocolors9.default.blueBright("react-router")}
1044
1245
 
1045
- ${heading("Usage")}:
1046
- $ react-router build [${arg("projectDir")}]
1047
- $ react-router dev [${arg("projectDir")}]
1048
- $ react-router routes [${arg("projectDir")}]
1246
+ ${import_picocolors9.default.underline("Usage")}:
1247
+ $ react-router build [${import_picocolors9.default.yellowBright("projectDir")}]
1248
+ $ react-router dev [${import_picocolors9.default.yellowBright("projectDir")}]
1249
+ $ react-router routes [${import_picocolors9.default.yellowBright("projectDir")}]
1049
1250
 
1050
- ${heading("Options")}:
1251
+ ${import_picocolors9.default.underline("Options")}:
1051
1252
  --help, -h Print this help message and exit
1052
1253
  --version, -v Print the CLI version and exit
1053
1254
  --no-color Disable ANSI colors in console output
@@ -1080,23 +1281,26 @@ ${logoBlue("react-router")}
1080
1281
  \`reveal\` Options:
1081
1282
  --config, -c Use specified Vite config file (string)
1082
1283
  --no-typescript Generate plain JavaScript files
1284
+ \`typegen\` Options:
1285
+ --config, -c Use specified Vite config file (string)
1286
+ --watch Automatically regenerate types whenever route config (\`routes.ts\`) or route modules change
1083
1287
 
1084
- ${heading("Build your project")}:
1288
+ ${import_picocolors9.default.underline("Build your project")}:
1085
1289
 
1086
1290
  $ react-router build
1087
1291
 
1088
- ${heading("Run your project locally in development")}:
1292
+ ${import_picocolors9.default.underline("Run your project locally in development")}:
1089
1293
 
1090
1294
  $ react-router dev
1091
1295
 
1092
- ${heading("Show all routes in your app")}:
1296
+ ${import_picocolors9.default.underline("Show all routes in your app")}:
1093
1297
 
1094
1298
  $ react-router routes
1095
1299
  $ react-router routes my-app
1096
1300
  $ react-router routes --json
1097
1301
  $ react-router routes --config vite.react-router.config.ts
1098
1302
 
1099
- ${heading("Reveal the used entry point")}:
1303
+ ${import_picocolors9.default.underline("Reveal the used entry point")}:
1100
1304
 
1101
1305
  $ react-router reveal entry.client
1102
1306
  $ react-router reveal entry.server
@@ -1104,9 +1308,11 @@ ${logoBlue("react-router")}
1104
1308
  $ react-router reveal entry.server --no-typescript
1105
1309
  $ react-router reveal entry.server --config vite.react-router.config.ts
1106
1310
 
1107
- ${heading("Generate types for route modules")}:
1311
+ ${import_picocolors9.default.underline("Generate types for route modules")}:
1108
1312
 
1109
1313
  $ react-router typegen
1314
+ $ react-router typegen --watch
1315
+ $ react-router typegen --config vite.react-router.config.ts
1110
1316
  `;
1111
1317
  async function run(argv = process.argv.slice(2)) {
1112
1318
  let versions = process.versions;
@@ -1116,8 +1322,8 @@ async function run(argv = process.argv.slice(2)) {
1116
1322
  `\uFE0F\u{1F6A8} Oops, Node v${versions.node} detected. react-router requires a Node version greater than ${MINIMUM_NODE_VERSION}.`
1117
1323
  );
1118
1324
  }
1119
- let isBooleanFlag = (arg3) => {
1120
- let index = argv.indexOf(arg3);
1325
+ let isBooleanFlag = (arg2) => {
1326
+ let index = argv.indexOf(arg2);
1121
1327
  let nextArg = argv[index + 1];
1122
1328
  return !nextArg || nextArg.startsWith("-");
1123
1329
  };
@@ -1150,7 +1356,8 @@ async function run(argv = process.argv.slice(2)) {
1150
1356
  "--strictPort": Boolean,
1151
1357
  "--profile": Boolean,
1152
1358
  "--sourcemapClient": isBooleanFlag("--sourcemapClient") ? Boolean : String,
1153
- "--sourcemapServer": isBooleanFlag("--sourcemapServer") ? Boolean : String
1359
+ "--sourcemapServer": isBooleanFlag("--sourcemapServer") ? Boolean : String,
1360
+ "--watch": Boolean
1154
1361
  },
1155
1362
  {
1156
1363
  argv
@@ -1191,7 +1398,7 @@ async function run(argv = process.argv.slice(2)) {
1191
1398
  await dev2(input[1], flags);
1192
1399
  break;
1193
1400
  case "typegen":
1194
- await typegen(input[1]);
1401
+ await typegen(input[1], flags);
1195
1402
  break;
1196
1403
  default:
1197
1404
  await dev2(input[0], flags);
package/dist/routes.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v7.0.0-pre.4
2
+ * @react-router/dev v7.0.0-pre.5
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v7.0.0-pre.4
2
+ * @react-router/dev v7.0.0-pre.5
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/dist/vite.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v7.0.0-pre.4
2
+ * @react-router/dev v7.0.0-pre.5
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-router/dev",
3
- "version": "7.0.0-pre.4",
3
+ "version": "7.0.0-pre.5",
4
4
  "description": "Dev tools and CLI for React Router",
5
5
  "homepage": "https://reactrouter.com",
6
6
  "bugs": {
@@ -12,7 +12,6 @@
12
12
  "directory": "packages/react-router-dev"
13
13
  },
14
14
  "license": "MIT",
15
- "main": "./dist/typescript/plugin.ts",
16
15
  "exports": {
17
16
  "./routes": {
18
17
  "types": "./dist/routes.d.ts",
@@ -61,7 +60,6 @@
61
60
  "@npmcli/package-json": "^4.0.1",
62
61
  "arg": "^5.0.1",
63
62
  "babel-dead-code-elimination": "^1.0.6",
64
- "chalk": "^4.1.2",
65
63
  "chokidar": "^4.0.0",
66
64
  "dedent": "^1.5.3",
67
65
  "es-module-lexer": "^1.3.1",
@@ -71,7 +69,7 @@
71
69
  "jsesc": "3.0.2",
72
70
  "lodash": "^4.17.21",
73
71
  "pathe": "^1.1.2",
74
- "picocolors": "^1.0.0",
72
+ "picocolors": "^1.1.1",
75
73
  "picomatch": "^2.3.1",
76
74
  "prettier": "^2.7.1",
77
75
  "react-refresh": "^0.14.0",
@@ -79,7 +77,7 @@
79
77
  "set-cookie-parser": "^2.6.0",
80
78
  "valibot": "^0.41.0",
81
79
  "vite-node": "^1.6.0",
82
- "@react-router/node": "7.0.0-pre.4"
80
+ "@react-router/node": "7.0.0-pre.5"
83
81
  },
84
82
  "devDependencies": {
85
83
  "@types/babel__core": "^7.20.5",
@@ -108,15 +106,15 @@
108
106
  "vite": "^5.1.0",
109
107
  "wireit": "0.14.9",
110
108
  "wrangler": "^3.28.2",
111
- "@react-router/serve": "7.0.0-pre.4",
112
- "react-router": "^7.0.0-pre.4"
109
+ "@react-router/serve": "7.0.0-pre.5",
110
+ "react-router": "^7.0.0-pre.5"
113
111
  },
114
112
  "peerDependencies": {
115
113
  "typescript": "^5.1.0",
116
114
  "vite": "^5.1.0",
117
115
  "wrangler": "^3.28.2",
118
- "@react-router/serve": "^7.0.0-pre.4",
119
- "react-router": "^7.0.0-pre.4"
116
+ "@react-router/serve": "^7.0.0-pre.5",
117
+ "react-router": "^7.0.0-pre.5"
120
118
  },
121
119
  "peerDependenciesMeta": {
122
120
  "@react-router/serve": {
@@ -1,7 +0,0 @@
1
- import ts from 'typescript/lib/tsserverlibrary';
2
-
3
- declare function init(): {
4
- create: (info: ts.server.PluginCreateInfo) => ts.LanguageService;
5
- };
6
-
7
- export { init as default };
@@ -1,500 +0,0 @@
1
- /**
2
- * @react-router/dev v7.0.0-pre.4
3
- *
4
- * Copyright (c) Remix Software Inc.
5
- *
6
- * This source code is licensed under the MIT license found in the
7
- * LICENSE.md file in the root directory of this source tree.
8
- *
9
- * @license MIT
10
- */
11
- "use strict";
12
- var __create = Object.create;
13
- var __defProp = Object.defineProperty;
14
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
15
- var __getOwnPropNames = Object.getOwnPropertyNames;
16
- var __getProtoOf = Object.getPrototypeOf;
17
- var __hasOwnProp = Object.prototype.hasOwnProperty;
18
- var __export = (target, all) => {
19
- for (var name in all)
20
- __defProp(target, name, { get: all[name], enumerable: true });
21
- };
22
- var __copyProps = (to, from, except, desc) => {
23
- if (from && typeof from === "object" || typeof from === "function") {
24
- for (let key of __getOwnPropNames(from))
25
- if (!__hasOwnProp.call(to, key) && key !== except)
26
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
27
- }
28
- return to;
29
- };
30
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
31
- // If the importer is in node compatibility mode or this is not an ESM
32
- // file that has been converted to a CommonJS file using a Babel-
33
- // compatible transform (i.e. "__esModule" has not been set), then set
34
- // "default" to the CommonJS "module.exports" for node compatibility.
35
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
36
- mod
37
- ));
38
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
39
-
40
- // typescript/plugin.ts
41
- var plugin_exports = {};
42
- __export(plugin_exports, {
43
- default: () => init
44
- });
45
- module.exports = __toCommonJS(plugin_exports);
46
- var Path2 = __toESM(require("pathe"));
47
-
48
- // typescript/typegen.ts
49
- var import_node_fs = __toESM(require("fs"));
50
- var import_chokidar = __toESM(require("chokidar"));
51
- var import_dedent2 = __toESM(require("dedent"));
52
- var Path = __toESM(require("pathe"));
53
- var Pathe = __toESM(require("pathe/utils"));
54
-
55
- // config/routes.ts
56
- var import_node_path = require("path");
57
- var v = __toESM(require("valibot"));
58
- var import_pick = __toESM(require("lodash/pick"));
59
-
60
- // invariant.ts
61
- function invariant(value, message) {
62
- if (value === false || value === null || typeof value === "undefined") {
63
- console.error(
64
- "The following error is a bug in React Router; please open an issue! https://github.com/remix-run/react-router/issues/new/choose"
65
- );
66
- throw new Error(message);
67
- }
68
- }
69
-
70
- // config/routes.ts
71
- var routeConfigEntrySchema = v.pipe(
72
- v.custom((value) => {
73
- return !(typeof value === "object" && value !== null && "then" in value && "catch" in value);
74
- }, "Invalid type: Expected object but received a promise. Did you forget to await?"),
75
- v.object({
76
- id: v.optional(v.string()),
77
- path: v.optional(v.string()),
78
- index: v.optional(v.boolean()),
79
- caseSensitive: v.optional(v.boolean()),
80
- file: v.string(),
81
- children: v.optional(v.array(v.lazy(() => routeConfigEntrySchema)))
82
- })
83
- );
84
- var resolvedRouteConfigSchema = v.array(routeConfigEntrySchema);
85
- function configRoutesToRouteManifest(routes, rootId = "root") {
86
- let routeManifest = {};
87
- function walk(route, parentId) {
88
- let id2 = route.id || createRouteId(route.file);
89
- let manifestItem = {
90
- id: id2,
91
- parentId,
92
- file: route.file,
93
- path: route.path,
94
- index: route.index,
95
- caseSensitive: route.caseSensitive
96
- };
97
- if (routeManifest.hasOwnProperty(id2)) {
98
- throw new Error(
99
- `Unable to define routes with duplicate route id: "${id2}"`
100
- );
101
- }
102
- routeManifest[id2] = manifestItem;
103
- if (route.children) {
104
- for (let child of route.children) {
105
- walk(child, id2);
106
- }
107
- }
108
- }
109
- for (let route of routes) {
110
- walk(route, rootId);
111
- }
112
- return routeManifest;
113
- }
114
- function createRouteId(file) {
115
- return normalizeSlashes(stripFileExtension(file));
116
- }
117
- function normalizeSlashes(file) {
118
- return file.split(import_node_path.win32.sep).join("/");
119
- }
120
- function stripFileExtension(file) {
121
- return file.replace(/\.[a-z0-9]+$/i, "");
122
- }
123
-
124
- // vite/vite-node.ts
125
- var import_server = require("vite-node/server");
126
- var import_client = require("vite-node/client");
127
- var import_source_map = require("vite-node/source-map");
128
-
129
- // vite/import-vite-esm-sync.ts
130
- var vite;
131
- async function preloadViteEsm() {
132
- vite = await import("vite");
133
- }
134
- function importViteEsmSync() {
135
- invariant(vite, "importViteEsmSync() called before preloadViteEsm()");
136
- return vite;
137
- }
138
-
139
- // vite/vite-node.ts
140
- async function createContext(viteConfig = {}) {
141
- await preloadViteEsm();
142
- const vite2 = importViteEsmSync();
143
- const devServer = await vite2.createServer(
144
- vite2.mergeConfig(
145
- {
146
- server: {
147
- preTransformRequests: false,
148
- hmr: false
149
- },
150
- optimizeDeps: {
151
- noDiscovery: true
152
- },
153
- configFile: false,
154
- envFile: false,
155
- plugins: []
156
- },
157
- viteConfig
158
- )
159
- );
160
- await devServer.pluginContainer.buildStart({});
161
- const server = new import_server.ViteNodeServer(devServer);
162
- (0, import_source_map.installSourcemapsSupport)({
163
- getSourceMap: (source) => server.getSourceMap(source)
164
- });
165
- const runner = new import_client.ViteNodeRunner({
166
- root: devServer.config.root,
167
- base: devServer.config.base,
168
- fetchModule(id2) {
169
- return server.fetchModule(id2);
170
- },
171
- resolveId(id2, importer) {
172
- return server.resolveId(id2, importer);
173
- }
174
- });
175
- return { devServer, server, runner };
176
- }
177
-
178
- // vite/config.ts
179
- var import_node_child_process = require("child_process");
180
- var import_node_path2 = __toESM(require("path"));
181
- var import_fs_extra = __toESM(require("fs-extra"));
182
- var import_picocolors = __toESM(require("picocolors"));
183
- var import_pick2 = __toESM(require("lodash/pick"));
184
- var import_omit = __toESM(require("lodash/omit"));
185
- var import_package_json = __toESM(require("@npmcli/package-json"));
186
- var entryExts = [".js", ".jsx", ".ts", ".tsx"];
187
- function findEntry(dir, basename3) {
188
- for (let ext of entryExts) {
189
- let file = import_node_path2.default.resolve(dir, basename3 + ext);
190
- if (import_fs_extra.default.existsSync(file)) return import_node_path2.default.relative(dir, file);
191
- }
192
- return void 0;
193
- }
194
-
195
- // vite/plugin.ts
196
- var import_node_crypto = require("crypto");
197
- var path4 = __toESM(require("path"));
198
- var url = __toESM(require("url"));
199
- var fse2 = __toESM(require("fs-extra"));
200
- var babel = __toESM(require("@babel/core"));
201
- var import_react_router2 = require("react-router");
202
- var import_es_module_lexer = require("es-module-lexer");
203
- var import_jsesc = __toESM(require("jsesc"));
204
- var import_picocolors2 = __toESM(require("picocolors"));
205
-
206
- // vite/babel.ts
207
- var import_parser = require("@babel/parser");
208
- var t = __toESM(require("@babel/types"));
209
- var traverse = require("@babel/traverse").default;
210
- var generate = require("@babel/generator").default;
211
-
212
- // vite/node-adapter.ts
213
- var import_node_events = require("events");
214
- var import_node_stream = require("stream");
215
- var import_set_cookie_parser = require("set-cookie-parser");
216
- var import_node = require("@react-router/node");
217
-
218
- // vite/styles.ts
219
- var path3 = __toESM(require("path"));
220
- var import_react_router = require("react-router");
221
-
222
- // vite/resolve-file-url.ts
223
- var path2 = __toESM(require("path"));
224
-
225
- // vite/styles.ts
226
- var cssFileRegExp = /\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(?:$|\?)/;
227
- var cssModulesRegExp = new RegExp(`\\.module${cssFileRegExp.source}`);
228
-
229
- // vite/vmod.ts
230
- var id = (name) => `virtual:react-router/${name}`;
231
-
232
- // vite/remove-exports.ts
233
- var import_babel_dead_code_elimination = require("babel-dead-code-elimination");
234
-
235
- // vite/with-props.ts
236
- var import_dedent = __toESM(require("dedent"));
237
- var vmodId = id("with-props");
238
-
239
- // vite/plugin.ts
240
- async function resolveViteConfig({
241
- configFile,
242
- mode,
243
- root
244
- }) {
245
- let vite2 = await import("vite");
246
- let viteConfig = await vite2.resolveConfig(
247
- { mode, configFile, root },
248
- "build",
249
- // command
250
- "production",
251
- // default mode
252
- "production"
253
- // default NODE_ENV
254
- );
255
- if (typeof viteConfig.build.manifest === "string") {
256
- throw new Error("Custom Vite manifest paths are not supported");
257
- }
258
- return viteConfig;
259
- }
260
- async function extractPluginContext(viteConfig) {
261
- return viteConfig["__reactRouterPluginContext"];
262
- }
263
- async function loadPluginContext({
264
- configFile,
265
- root
266
- }) {
267
- if (!root) {
268
- root = process.env.REACT_ROUTER_ROOT || process.cwd();
269
- }
270
- configFile = configFile ?? findConfig(root, "vite.config", [
271
- ".ts",
272
- ".cts",
273
- ".mts",
274
- ".js",
275
- ".cjs",
276
- ".mjs"
277
- ]);
278
- if (!configFile) {
279
- console.error(import_picocolors2.default.red("Vite config file not found"));
280
- process.exit(1);
281
- }
282
- let viteConfig = await resolveViteConfig({ configFile, root });
283
- let ctx = await extractPluginContext(viteConfig);
284
- if (!ctx) {
285
- console.error(
286
- import_picocolors2.default.red("React Router Vite plugin not found in Vite config")
287
- );
288
- process.exit(1);
289
- }
290
- return ctx;
291
- }
292
- var serverBuildId = id("server-build");
293
- var serverManifestId = id("server-manifest");
294
- var browserManifestId = id("browser-manifest");
295
- var hmrRuntimeId = id("hmr-runtime");
296
- var injectHmrRuntimeId = id("inject-hmr-runtime");
297
- var defaultEntriesDir = path4.resolve(
298
- path4.dirname(require.resolve("@react-router/dev/package.json")),
299
- "dist",
300
- "config",
301
- "defaults"
302
- );
303
- var defaultEntries = fse2.readdirSync(defaultEntriesDir).map((filename2) => path4.join(defaultEntriesDir, filename2));
304
- invariant(defaultEntries.length > 0, "No default entries found");
305
- function findConfig(dir, basename3, extensions) {
306
- for (let ext of extensions) {
307
- let name = basename3 + ext;
308
- let file = path4.join(dir, name);
309
- if (fse2.existsSync(file)) return file;
310
- }
311
- return void 0;
312
- }
313
- var REACT_REFRESH_HEADER = `
314
- import RefreshRuntime from "${hmrRuntimeId}";
315
-
316
- const inWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
317
- let prevRefreshReg;
318
- let prevRefreshSig;
319
-
320
- if (import.meta.hot && !inWebWorker) {
321
- if (!window.__vite_plugin_react_preamble_installed__) {
322
- throw new Error(
323
- "React Router Vite plugin can't detect preamble. Something is wrong."
324
- );
325
- }
326
-
327
- prevRefreshReg = window.$RefreshReg$;
328
- prevRefreshSig = window.$RefreshSig$;
329
- window.$RefreshReg$ = (type, id) => {
330
- RefreshRuntime.register(type, __SOURCE__ + " " + id)
331
- };
332
- window.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform;
333
- }`.trim();
334
- var REACT_REFRESH_FOOTER = `
335
- if (import.meta.hot && !inWebWorker) {
336
- window.$RefreshReg$ = prevRefreshReg;
337
- window.$RefreshSig$ = prevRefreshSig;
338
- RefreshRuntime.__hmr_import(import.meta.url).then((currentExports) => {
339
- RefreshRuntime.registerExportsForReactRefresh(__SOURCE__, currentExports);
340
- import.meta.hot.accept((nextExports) => {
341
- if (!nextExports) return;
342
- __ROUTE_ID__ && window.__reactRouterRouteModuleUpdates.set(__ROUTE_ID__, nextExports);
343
- const invalidateMessage = RefreshRuntime.validateRefreshBoundaryAndEnqueueUpdate(currentExports, nextExports, __ACCEPT_EXPORTS__);
344
- if (invalidateMessage) import.meta.hot.invalidate(invalidateMessage);
345
- });
346
- });
347
- }`.trim();
348
-
349
- // typescript/typegen.ts
350
- function getDirectory(ctx) {
351
- return Path.join(ctx.rootDirectory, ".react-router/types");
352
- }
353
- function getPath(ctx, route) {
354
- return Path.join(
355
- getDirectory(ctx),
356
- Path.basename(ctx.appDirectory),
357
- Path.dirname(route.file),
358
- "+types." + Pathe.filename(route.file) + ".d.ts"
359
- );
360
- }
361
- async function watch(rootDirectory) {
362
- const vitePluginCtx = await loadPluginContext({ root: rootDirectory });
363
- const routesTsPath = Path.join(
364
- vitePluginCtx.reactRouterConfig.appDirectory,
365
- "routes.ts"
366
- );
367
- const routesViteNodeContext = await createContext({
368
- root: rootDirectory
369
- });
370
- async function getRoutes() {
371
- const routes = {};
372
- const rootRouteFile = findEntry(
373
- vitePluginCtx.reactRouterConfig.appDirectory,
374
- "root"
375
- );
376
- if (rootRouteFile) {
377
- routes.root = { path: "", id: "root", file: rootRouteFile };
378
- }
379
- routesViteNodeContext.devServer.moduleGraph.invalidateAll();
380
- routesViteNodeContext.runner.moduleCache.clear();
381
- const routeConfig = (await routesViteNodeContext.runner.executeFile(routesTsPath)).routes;
382
- return {
383
- ...routes,
384
- ...configRoutesToRouteManifest(await routeConfig)
385
- };
386
- }
387
- const ctx = {
388
- rootDirectory,
389
- appDirectory: vitePluginCtx.reactRouterConfig.appDirectory,
390
- routes: await getRoutes()
391
- };
392
- await writeAll(ctx);
393
- const watcher = import_chokidar.default.watch(ctx.appDirectory, { ignoreInitial: true });
394
- watcher.on("all", async (event, path5) => {
395
- path5 = Path.normalize(path5);
396
- ctx.routes = await getRoutes();
397
- const routeConfigChanged = Boolean(
398
- routesViteNodeContext.devServer.moduleGraph.getModuleById(path5)
399
- );
400
- if (routeConfigChanged) {
401
- await writeAll(ctx);
402
- return;
403
- }
404
- const isRoute = Object.values(ctx.routes).find(
405
- (route) => path5 === Path.join(ctx.appDirectory, route.file)
406
- );
407
- if (isRoute && (event === "add" || event === "unlink")) {
408
- await writeAll(ctx);
409
- return;
410
- }
411
- });
412
- }
413
- async function writeAll(ctx) {
414
- import_node_fs.default.rmSync(getDirectory(ctx), { recursive: true, force: true });
415
- Object.values(ctx.routes).forEach((route) => {
416
- if (!import_node_fs.default.existsSync(Path.join(ctx.appDirectory, route.file))) return;
417
- const typesPath = getPath(ctx, route);
418
- const content = getModule(ctx.routes, route);
419
- import_node_fs.default.mkdirSync(Path.dirname(typesPath), { recursive: true });
420
- import_node_fs.default.writeFileSync(typesPath, content);
421
- });
422
- }
423
- function getModule(routes, route) {
424
- return import_dedent2.default`
425
- // React Router generated types for route:
426
- // ${route.file}
427
-
428
- import * as T from "react-router/types"
429
-
430
- export type Params = {${formattedParamsProperties(routes, route)}}
431
-
432
- type Route = typeof import("./${Pathe.filename(route.file)}")
433
-
434
- export type LoaderData = T.CreateLoaderData<Route>
435
- export type ActionData = T.CreateActionData<Route>
436
-
437
- export type LoaderArgs = T.CreateServerLoaderArgs<Params>
438
- export type ClientLoaderArgs = T.CreateClientLoaderArgs<Params, Route>
439
- export type ActionArgs = T.CreateServerActionArgs<Params>
440
- export type ClientActionArgs = T.CreateClientActionArgs<Params, Route>
441
-
442
- export type HydrateFallbackProps = T.CreateHydrateFallbackProps<Params>
443
- export type ComponentProps = T.CreateComponentProps<Params, LoaderData, ActionData>
444
- export type ErrorBoundaryProps = T.CreateErrorBoundaryProps<Params, LoaderData, ActionData>
445
- `;
446
- }
447
- function formattedParamsProperties(routes, route) {
448
- const urlpath = routeLineage(routes, route).map((route2) => route2.path).join("/");
449
- const params = parseParams(urlpath);
450
- const indent = " ".repeat(3);
451
- const properties = Object.entries(params).map(([name, values]) => {
452
- if (values.length === 1) {
453
- const isOptional = values[0];
454
- return indent + (isOptional ? `${name}?: string` : `${name}: string`);
455
- }
456
- const items = values.map(
457
- (isOptional) => isOptional ? "string | undefined" : "string"
458
- );
459
- return indent + `${name}: [${items.join(", ")}]`;
460
- });
461
- const body = properties.length === 0 ? "" : "\n" + properties.join("\n") + "\n";
462
- return body;
463
- }
464
- function routeLineage(routes, route) {
465
- const result = [];
466
- while (route) {
467
- result.push(route);
468
- if (!route.parentId) break;
469
- route = routes[route.parentId];
470
- }
471
- result.reverse();
472
- return result;
473
- }
474
- function parseParams(urlpath) {
475
- const result = {};
476
- let segments = urlpath.split("/");
477
- segments.filter((s) => s.startsWith(":")).forEach((param) => {
478
- param = param.slice(1);
479
- let isOptional = param.endsWith("?");
480
- if (isOptional) {
481
- param = param.slice(0, -1);
482
- }
483
- result[param] ??= [];
484
- result[param].push(isOptional);
485
- return;
486
- });
487
- return result;
488
- }
489
-
490
- // typescript/plugin.ts
491
- function init() {
492
- function create(info) {
493
- const { logger } = info.project.projectService;
494
- logger.info("[react-router] setup");
495
- const rootDirectory = Path2.normalize(info.project.getCurrentDirectory());
496
- watch(rootDirectory);
497
- return info.languageService;
498
- }
499
- return { create };
500
- }