1*46f023faSEvan Bacon/**
2*46f023faSEvan Bacon * Copyright © 2022 650 Industries.
3*46f023faSEvan Bacon *
4*46f023faSEvan Bacon * This source code is licensed under the MIT license found in the
5*46f023faSEvan Bacon * LICENSE file in the root directory of this source tree.
6*46f023faSEvan Bacon */
7*46f023faSEvan Baconimport resolveFrom from 'resolve-from';
8*46f023faSEvan Bacon
9*46f023faSEvan Baconimport { getRoutePaths } from './router';
10*46f023faSEvan Bacon
11*46f023faSEvan Baconexport type ExpoRouterServerManifestV1Route<TRegex = string> = {
12*46f023faSEvan Bacon  page: string;
13*46f023faSEvan Bacon  routeKeys: Record<string, string>;
14*46f023faSEvan Bacon  namedRegex: TRegex;
15*46f023faSEvan Bacon  generated?: boolean;
16*46f023faSEvan Bacon};
17*46f023faSEvan Bacon
18*46f023faSEvan Baconexport type ExpoRouterServerManifestV1<TRegex = string> = {
19*46f023faSEvan Bacon  apiRoutes: ExpoRouterServerManifestV1Route<TRegex>[];
20*46f023faSEvan Bacon  htmlRoutes: ExpoRouterServerManifestV1Route<TRegex>[];
21*46f023faSEvan Bacon  notFoundRoutes: ExpoRouterServerManifestV1Route<TRegex>[];
22*46f023faSEvan Bacon};
23*46f023faSEvan Bacon
24*46f023faSEvan Baconfunction getExpoRouteManifestBuilderAsync(projectRoot: string) {
25*46f023faSEvan Bacon  return require(resolveFrom(projectRoot, 'expo-router/build/routes-manifest'))
26*46f023faSEvan Bacon    .createRoutesManifest as typeof import('expo-router/build/routes-manifest').createRoutesManifest;
27*46f023faSEvan Bacon}
28*46f023faSEvan Bacon
29*46f023faSEvan Bacon// TODO: Simplify this now that we use Node.js directly, no need for the Metro bundler caching layer.
30*46f023faSEvan Baconexport async function fetchManifest<TRegex = string>(
31*46f023faSEvan Bacon  projectRoot: string,
32*46f023faSEvan Bacon  options: { asJson?: boolean; appDir: string }
33*46f023faSEvan Bacon): Promise<ExpoRouterServerManifestV1<TRegex> | null> {
34*46f023faSEvan Bacon  const getManifest = getExpoRouteManifestBuilderAsync(projectRoot);
35*46f023faSEvan Bacon  const paths = getRoutePaths(options.appDir);
36*46f023faSEvan Bacon  // Get the serialized manifest
37*46f023faSEvan Bacon  const jsonManifest = getManifest(paths);
38*46f023faSEvan Bacon
39*46f023faSEvan Bacon  if (!jsonManifest) {
40*46f023faSEvan Bacon    return null;
41*46f023faSEvan Bacon  }
42*46f023faSEvan Bacon
43*46f023faSEvan Bacon  if (!jsonManifest.htmlRoutes || !jsonManifest.apiRoutes) {
44*46f023faSEvan Bacon    throw new Error('Routes manifest is malformed: ' + JSON.stringify(jsonManifest, null, 2));
45*46f023faSEvan Bacon  }
46*46f023faSEvan Bacon
47*46f023faSEvan Bacon  if (!options.asJson) {
48*46f023faSEvan Bacon    // @ts-expect-error
49*46f023faSEvan Bacon    return inflateManifest(jsonManifest);
50*46f023faSEvan Bacon  }
51*46f023faSEvan Bacon  // @ts-expect-error
52*46f023faSEvan Bacon  return jsonManifest;
53*46f023faSEvan Bacon}
54*46f023faSEvan Bacon
55*46f023faSEvan Bacon// Convert the serialized manifest to a usable format
56*46f023faSEvan Baconexport function inflateManifest(
57*46f023faSEvan Bacon  json: ExpoRouterServerManifestV1<string>
58*46f023faSEvan Bacon): ExpoRouterServerManifestV1<RegExp> {
59*46f023faSEvan Bacon  return {
60*46f023faSEvan Bacon    ...json,
61*46f023faSEvan Bacon    htmlRoutes: json.htmlRoutes?.map((value) => {
62*46f023faSEvan Bacon      return {
63*46f023faSEvan Bacon        ...value,
64*46f023faSEvan Bacon        namedRegex: new RegExp(value.namedRegex),
65*46f023faSEvan Bacon      };
66*46f023faSEvan Bacon    }),
67*46f023faSEvan Bacon    apiRoutes: json.apiRoutes?.map((value) => {
68*46f023faSEvan Bacon      return {
69*46f023faSEvan Bacon        ...value,
70*46f023faSEvan Bacon        namedRegex: new RegExp(value.namedRegex),
71*46f023faSEvan Bacon      };
72*46f023faSEvan Bacon    }),
73*46f023faSEvan Bacon    notFoundRoutes: json.notFoundRoutes?.map((value) => {
74*46f023faSEvan Bacon      return {
75*46f023faSEvan Bacon        ...value,
76*46f023faSEvan Bacon        namedRegex: new RegExp(value.namedRegex),
77*46f023faSEvan Bacon      };
78*46f023faSEvan Bacon    }),
79*46f023faSEvan Bacon  };
80*46f023faSEvan Bacon}
81