xref: /expo/docs/constants/navigation.js (revision f7a14300)
1import frontmatter from 'front-matter';
2import fs from 'fs';
3import path from 'path';
4import { u as make } from 'unist-builder';
5import { URL, fileURLToPath } from 'url';
6
7import { VERSIONS } from './versions.js';
8
9const dirname = path.dirname(fileURLToPath(import.meta.url));
10const PAGES_DIR = path.resolve(dirname, '../pages');
11
12// TODO(cedric): refactor docs to get rid of the directory lists
13
14/** Manual list of directories to categorize as "Home" */
15const homeDirectories = [
16  'get-started',
17  'develop',
18  'config-plugins',
19  'debugging',
20  'deploy',
21  'routing',
22];
23/** Manual list of directories to categorize as "Learn" */
24const learnDirectories = ['tutorial', 'ui-programming', 'additional-resources'];
25/** Manual list of directories to categorize as "Archive" */
26const archiveDirectories = ['archive'];
27/** Manual list of directories to categorize as "Reference" */
28const referenceDirectories = ['versions', 'technical-specs', 'more'];
29/** Private preview section which isn't linked in the documentation */
30const previewDirectories = ['feature-preview', 'preview'];
31
32/** All other unlisted directories */
33const generalDirectories = fs
34  .readdirSync(PAGES_DIR, { withFileTypes: true })
35  .filter(entity => entity.isDirectory())
36  .map(dir => dir.name)
37  .filter(
38    name =>
39      name !== 'api' &&
40      name !== 'versions' &&
41      ![
42        ...homeDirectories,
43        ...archiveDirectories,
44        ...referenceDirectories,
45        ...learnDirectories,
46        ...previewDirectories,
47      ].includes(name)
48  );
49
50// --- Navigation ---
51
52const home = [
53  makeSection('', [makePage('overview.mdx')]),
54  makeSection('Get started', [
55    makePage('get-started/installation.mdx'),
56    makePage('get-started/expo-go.mdx'),
57    makePage('get-started/create-a-project.mdx'),
58  ]),
59  makeSection('Develop', [
60    makePage('develop/project-structure.mdx'),
61    makeGroup(
62      'User interface',
63      [
64        makePage('develop/user-interface/splash-screen.mdx'),
65        makePage('develop/user-interface/app-icons.mdx'),
66        makePage('develop/user-interface/safe-areas.mdx'),
67        makePage('develop/user-interface/fonts.mdx'),
68        makePage('develop/user-interface/color-themes.mdx'),
69        makePage('develop/user-interface/animation.mdx'),
70        makePage('develop/user-interface/store-data.mdx'),
71        makePage('develop/user-interface/next-steps.mdx'),
72      ],
73      { expanded: false }
74    ),
75    makeGroup(
76      'Routing',
77      [
78        makePage('routing/introduction.mdx'),
79        makePage('routing/installation.mdx'),
80        makePage('routing/create-pages.mdx'),
81        makePage('routing/navigating-pages.mdx'),
82        makePage('routing/layouts.mdx'),
83        makePage('routing/appearance.mdx'),
84        makePage('routing/error-handling.mdx'),
85        makePage('routing/next-steps.mdx'),
86      ],
87      { expanded: false }
88    ),
89    makeGroup(
90      'Development builds',
91      [
92        makePage('develop/development-builds/introduction.mdx'),
93        makePage('develop/development-builds/installation.mdx'),
94        makePage('develop/development-builds/create-a-build.mdx'),
95        makePage('develop/development-builds/use-development-builds.mdx'),
96        makePage('develop/development-builds/share-with-your-team.mdx'),
97        makePage('develop/development-builds/development-workflows.mdx'),
98        makePage('develop/development-builds/next-steps.mdx'),
99      ],
100      { expanded: false }
101    ),
102    makeGroup(
103      'Config plugins',
104      [
105        makePage('config-plugins/introduction.mdx'),
106        makePage('config-plugins/plugins-and-mods.mdx'),
107        makePage('config-plugins/development-and-debugging.mdx'),
108      ],
109      { expanded: false }
110    ),
111    makeGroup(
112      'Debugging',
113      [
114        makePage('debugging/errors-and-warnings.mdx'),
115        makePage('debugging/runtime-issues.mdx'),
116        makePage('debugging/tools.mdx'),
117      ],
118      { expanded: false }
119    ),
120    makePage('develop/authentication.mdx'),
121    makePage('develop/unit-testing.mdx'),
122  ]),
123  makeSection('Deploy', [
124    makePage('deploy/build-project.mdx'),
125    makePage('deploy/submit-to-app-stores.mdx'),
126    makePage('deploy/app-stores-metadata.mdx'),
127    makePage('deploy/instant-updates.mdx'),
128  ]),
129  makeSection('More', [makePage('core-concepts.mdx'), makePage('faq.mdx')]),
130];
131
132const general = [
133  makeSection('', [makePage('guides/overview.mdx')]),
134  makeSection('Development process', [
135    makePage('workflow/configuration.mdx'),
136    makePage('guides/local-app-development.mdx'),
137    makePage('workflow/using-libraries.mdx'),
138    makePage('guides/permissions.mdx'),
139    makePage('guides/environment-variables.mdx'),
140    makePage('guides/linking.mdx'),
141    makePage('guides/deep-linking.mdx'),
142    makeGroup(
143      'Custom native code',
144      [
145        makePage('workflow/continuous-native-generation.mdx'),
146        makePage('workflow/customizing.mdx'),
147        makePage('workflow/prebuild.mdx'),
148        makePage('guides/adopting-prebuild.mdx'),
149      ],
150      { expanded: false }
151    ),
152    makeGroup(
153      'Web',
154      [
155        makePage('workflow/web.mdx'),
156        makePage('guides/progressive-web-apps.mdx'),
157        makePage('distribution/publishing-websites.mdx'),
158        makePage('guides/customizing-metro.mdx'),
159        makePage('guides/customizing-webpack.mdx'),
160        makePage('guides/web-performance.mdx'),
161      ],
162      { expanded: false }
163    ),
164    makeGroup(
165      'Reference',
166      [
167        makePage('guides/monorepos.mdx'),
168        makePage('workflow/logging.mdx'),
169        makePage('workflow/development-mode.mdx'),
170        makePage('workflow/common-development-errors.mdx'),
171        makePage('workflow/android-studio-emulator.mdx'),
172        makePage('workflow/ios-simulator.mdx'),
173      ],
174      { expanded: false }
175    ),
176  ]),
177  makeSection('Expo Router', [
178    makeGroup('Advanced', [
179      makePage('router/advanced/root-layout.mdx'),
180      makePage('router/advanced/stack.mdx'),
181      makePage('router/advanced/tabs.mdx'),
182      makePage('router/advanced/drawer.mdx'),
183      makePage('router/advanced/nesting-navigators.mdx'),
184      makePage('router/advanced/modals.mdx'),
185      makePage('router/advanced/platform-specific-modules.mdx'),
186      makePage('router/advanced/shared-routes.mdx'),
187      makePage('router/advanced/router-settings.mdx'),
188      makePage('router/advanced/apple-handoff.mdx'),
189    ]),
190    makeGroup('Reference', [
191      makePage('router/reference/hooks.mdx'),
192      makePage('router/reference/search-parameters.mdx'),
193      makePage('router/reference/redirects.mdx'),
194      makePage('router/reference/static-rendering.mdx'),
195      makePage('router/reference/async-routes.mdx'),
196      makePage('router/reference/sitemap.mdx'),
197      makePage('router/reference/typed-routes.mdx'),
198      makePage('router/reference/authentication.mdx'),
199      makePage('router/reference/screen-tracking.mdx'),
200      makePage('router/reference/src-directory.mdx'),
201      makePage('router/reference/testing.mdx'),
202      makePage('router/reference/troubleshooting.mdx'),
203      makePage('router/reference/faq.mdx'),
204    ]),
205    makeGroup('Migration', [makePage('router/migrate/from-react-navigation.mdx')]),
206  ]),
207  makeSection(
208    'Expo Modules API',
209    [
210      makePage('modules/overview.mdx'),
211      makePage('modules/get-started.mdx'),
212      makeSection('Tutorials', [
213        makePage('modules/native-module-tutorial.mdx'),
214        makePage('modules/native-view-tutorial.mdx'),
215        makePage('modules/config-plugin-and-native-module-tutorial.mdx'),
216        makePage('modules/use-standalone-expo-module-in-your-project.mdx'),
217        makePage('modules/third-party-library.mdx'),
218        makePage('modules/existing-library.mdx'),
219      ]),
220      makeSection('Reference', [
221        makePage('modules/module-api.mdx'),
222        makePage('modules/android-lifecycle-listeners.mdx'),
223        makePage('modules/appdelegate-subscribers.mdx'),
224        makePage('modules/autolinking.mdx'),
225        makePage('modules/module-config.mdx'),
226      ]),
227    ],
228    { expanded: false }
229  ),
230  makeSection('EAS', [makePage('eas/index.mdx'), makePage('eas/json.mdx')]),
231  makeSection('EAS Build', [
232    makePage('build/introduction.mdx'),
233    makePage('build/setup.mdx'),
234    makePage('build/eas-json.mdx'),
235    makePage('build/internal-distribution.mdx'),
236    makePage('build/automate-submissions.mdx'),
237    makePage('build/updates.mdx'),
238    makePage('build/building-on-ci.mdx'),
239    makePage('build/building-from-github.mdx'),
240    makeGroup(
241      'App Signing',
242      [
243        makePage('app-signing/app-credentials.mdx'),
244        makePage('app-signing/managed-credentials.mdx'),
245        makePage('app-signing/local-credentials.mdx'),
246        makePage('app-signing/existing-credentials.mdx'),
247        makePage('app-signing/syncing-credentials.mdx'),
248        makePage('app-signing/security.mdx'),
249      ],
250      { expanded: false }
251    ),
252    makeGroup(
253      'Custom builds',
254      [
255        makePage('custom-builds/get-started.mdx'),
256        makePage('custom-builds/schema.mdx'),
257        makePage('custom-builds/functions.mdx'),
258      ],
259      { expanded: false }
260    ),
261    makeGroup(
262      'Reference',
263      [
264        makePage('build-reference/migrating.mdx'),
265        makePage('build-reference/npm-hooks.mdx'),
266        makePage('build-reference/private-npm-packages.mdx'),
267        makePage('build-reference/git-submodules.mdx'),
268        makePage('build-reference/npm-cache-with-yarn.mdx'),
269        makePage('build-reference/build-with-monorepos.mdx'),
270        makePage('build-reference/variables.mdx'),
271        makePage('build-reference/apk.mdx'),
272        makePage('build-reference/simulators.mdx'),
273        makePage('build-reference/app-versions.mdx'),
274        makePage('build-reference/troubleshooting.mdx'),
275        makePage('build-reference/variants.mdx'),
276        makePage('build-reference/ios-capabilities.mdx'),
277        makePage('build-reference/local-builds.mdx'),
278        makePage('build-reference/caching.mdx'),
279        makePage('build-reference/android-builds.mdx'),
280        makePage('build-reference/ios-builds.mdx'),
281        makePage('build-reference/build-configuration.mdx'),
282        makePage('build-reference/infrastructure.mdx'),
283        makePage('build-reference/app-extensions.mdx'),
284        makePage('build-reference/e2e-tests.mdx'),
285        makePage('build-reference/limitations.mdx'),
286      ],
287      { expanded: false }
288    ),
289  ]),
290  makeSection('EAS Submit', [
291    makePage('submit/introduction.mdx'),
292    makePage('submit/eas-json.mdx'),
293    makePage('submit/android.mdx'),
294    makePage('submit/ios.mdx'),
295  ]),
296  makeSection('EAS Update', [
297    makePage('eas-update/introduction.mdx'),
298    makePage('eas-update/getting-started.mdx'),
299    makePage('eas-update/github-actions.mdx'),
300    makePage('eas-update/eas-cli.mdx'),
301    makePage('eas-update/develop-faster.mdx'),
302    makeGroup('Concepts', [
303      makePage('eas-update/how-it-works.mdx'),
304      makePage('eas-update/runtime-versions.mdx'),
305      makePage('eas-update/deployment-patterns.mdx'),
306    ]),
307    makeGroup('Troubleshoot', [
308      makePage('eas-update/debug.mdx'),
309      makePage('eas-update/debug-advanced.mdx'),
310      makePage('eas-update/expo-dev-client.mdx'),
311      makePage('eas-update/build-locally.mdx'),
312    ]),
313    makeGroup('Advanced', [
314      makePage('eas-update/optimize-assets.mdx'),
315      makePage('eas-update/environment-variables.mdx'),
316      makePage('eas-update/code-signing.mdx'),
317      makePage('eas-update/rollouts.mdx'),
318    ]),
319    makeGroup('Reference', [
320      makePage('eas-update/migrate-from-classic-updates.mdx'),
321      makePage('eas-update/codepush.mdx'),
322      makePage('eas-update/updating-your-app.mdx'),
323      makePage('eas-update/faq.mdx'),
324      makePage('eas-update/known-issues.mdx'),
325    ]),
326  ]),
327  makeSection('EAS Metadata', [
328    makePage('eas/metadata/index.mdx'),
329    makePage('eas/metadata/getting-started.mdx'),
330    makeGroup(
331      'Reference',
332      [
333        makePage('eas/metadata/config.mdx'),
334        makePage('eas/metadata/schema.mdx'),
335        makePage('eas/metadata/faq.mdx'),
336      ],
337      { expanded: false }
338    ),
339  ]),
340  makeSection('EAS Insights', [makePage('eas-insights/introduction.mdx')]),
341  makeSection('Push notifications', [
342    makePage('push-notifications/overview.mdx'),
343    makePage('push-notifications/push-notifications-setup.mdx'),
344    makePage('push-notifications/sending-notifications.mdx'),
345    makePage('push-notifications/receiving-notifications.mdx'),
346    makeGroup(
347      'Reference',
348      [
349        makePage('push-notifications/sending-notifications-custom.mdx'),
350        makePage('push-notifications/faq.mdx'),
351      ],
352      { expanded: false }
353    ),
354  ]),
355  makeSection('Distribution', [
356    makePage('distribution/introduction.mdx'),
357    makePage('distribution/app-stores.mdx'),
358    makePage('distribution/runtime-versions.mdx'),
359    makePage('distribution/custom-updates-server.mdx'),
360    makePage('distribution/app-transfers.mdx'),
361  ]),
362  makeSection(
363    'More',
364    [
365      makePage('workflow/upgrading-expo-sdk-walkthrough.mdx'),
366      makePage('eas/webhooks.mdx'),
367      makeSection('Assorted', [
368        makePage('guides/authentication.mdx'),
369        makePage('guides/troubleshooting-proxies.mdx'),
370        makePage('guides/sharing-preview-releases.mdx'),
371        makePage('guides/using-hermes.mdx'),
372        makePage('guides/ios-developer-mode.mdx'),
373        makePage('guides/icons.mdx'),
374        makePage('guides/localization.mdx'),
375        makePage('guides/configuring-js-engines.mdx'),
376      ]),
377      makeSection('Integrations', [
378        makePage('guides/using-analytics.mdx'),
379        makePage('guides/facebook-authentication.mdx'),
380        makePage('guides/using-firebase.mdx'),
381        makePage('guides/using-flipper.mdx'),
382        makePage('guides/google-authentication.mdx'),
383        makePage('guides/using-eslint.mdx'),
384        makePage('guides/using-nextjs.mdx'),
385        makePage('guides/using-sentry.mdx'),
386        makePage('guides/typescript.mdx'),
387      ]),
388      makeSection('Expo accounts', [
389        makePage('accounts/account-types.mdx'),
390        makePage('accounts/two-factor.mdx'),
391        makePage('accounts/programmatic-access.mdx'),
392        makePage('accounts/working-together.mdx'),
393        makePage('accounts/sso.mdx'),
394      ]),
395      makeSection('Bare React Native', [
396        makePage('bare/overview.mdx'),
397        makePage('bare/installing-expo-modules.mdx'),
398        makePage('bare/using-expo-cli.mdx'),
399        makePage('bare/installing-updates.mdx'),
400        makePage('bare/using-expo-client.mdx'),
401        makePage('bare/install-dev-builds-in-bare.mdx'),
402        makePage('bare/error-recovery.mdx'),
403      ]),
404    ],
405    { expanded: true }
406  ),
407  makeSection('Regulatory compliance', [
408    makePage('regulatory-compliance/data-and-privacy-protection.mdx'),
409    makePage('regulatory-compliance/gdpr.mdx'),
410    makePage('regulatory-compliance/hipaa.mdx'),
411    makePage('regulatory-compliance/privacy-shield.mdx'),
412  ]),
413];
414
415const learn = [
416  makeSection(
417    'Get started',
418    [
419      makePage('tutorial/introduction.mdx'),
420      makePage('tutorial/create-your-first-app.mdx'),
421      makePage('tutorial/build-a-screen.mdx'),
422      makePage('tutorial/image-picker.mdx'),
423      makePage('tutorial/create-a-modal.mdx'),
424      makePage('tutorial/gestures.mdx'),
425      makePage('tutorial/screenshot.mdx'),
426      makePage('tutorial/platform-differences.mdx'),
427      makePage('tutorial/configuration.mdx'),
428      makePage('tutorial/follow-up.mdx'),
429    ],
430    { expanded: true }
431  ),
432  makeSection(
433    'UI programming',
434    [
435      makePage('ui-programming/image-background.mdx'),
436      makePage('ui-programming/implementing-a-checkbox.mdx'),
437      makePage('ui-programming/z-index.mdx'),
438      makePage('ui-programming/using-svgs.mdx'),
439      makePage('ui-programming/react-native-toast.mdx'),
440      makePage('ui-programming/react-native-styling-buttons.mdx'),
441      makePage('ui-programming/user-interface-libraries.mdx'),
442    ],
443    { expanded: true }
444  ),
445  makeSection('More', [makePage('additional-resources/index.mdx')]),
446];
447
448const preview = [
449  makeSection('Preview', [
450    makePage('preview/introduction.mdx'),
451    makePage('preview/support.mdx'),
452    { expanded: true },
453    makeSection('Expo Router', [makePage('preview/api-routes.mdx')]),
454  ]),
455];
456
457const archive = [
458  makeSection('Classic Builds', [
459    makePage('archive/classic-updates/building-standalone-apps.mdx'),
460    makePage('archive/classic-updates/turtle-cli.mdx'),
461  ]),
462  makeSection('Classic Updates', [
463    makePage('archive/classic-updates/introduction.mdx'),
464    makeSection('Guides', [
465      makePage('archive/classic-updates/configuring-updates.mdx'),
466      makePage('archive/classic-updates/preloading-and-caching-assets.mdx'),
467    ]),
468    makeSection('Distribution', [
469      makePage('archive/classic-updates/release-channels.mdx'),
470      makePage('archive/classic-updates/advanced-release-channels.mdx'),
471      makePage('archive/classic-updates/hosting-your-app.mdx'),
472      makePage('archive/classic-updates/offline-support.mdx'),
473      makePage('archive/classic-updates/optimizing-updates.mdx'),
474    ]),
475    makeSection('Workflow', [makePage('archive/classic-updates/publishing.mdx')]),
476    makeSection('Bare Workflow', [makePage('archive/classic-updates/updating-your-app.mdx')]),
477  ]),
478  makeSection('Technical Specs', [makePage('archive/technical-specs/expo-updates-0.mdx')]),
479  makeSection('More', [
480    makePage('archive/expo-cli.mdx'),
481    makePage('archive/managed-vs-bare.mdx'),
482    makePage('archive/notification-channels.mdx'),
483    makePage('archive/glossary.mdx'),
484  ]),
485];
486
487const featurePreview = [];
488
489const versionsReference = VERSIONS.reduce(
490  (all, version) => ({
491    ...all,
492    [version]: [
493      makeSection('Configuration files', pagesFromDir(`versions/${version}/config`), {
494        expanded: true,
495      }),
496      makeSection('Expo SDK', pagesFromDir(`versions/${version}/sdk`), { expanded: true }),
497      makeSection('Technical specs', [
498        makePage('technical-specs/expo-updates-1.mdx'),
499        makePage('technical-specs/expo-sfv-0.mdx'),
500      ]),
501      makeSection('More', [makePage('more/expo-cli.mdx'), makePage('more/glossary-of-terms.mdx')], {
502        expanded: true,
503      }),
504      makeSection(
505        'React Native',
506        [
507          make('page', {
508            href: 'https://reactnative.dev/docs/components-and-apis',
509            sidebarTitle: 'Visit documentation',
510          }),
511        ],
512        { expanded: true }
513      ),
514    ],
515  }),
516  {}
517);
518
519const reference = { ...versionsReference, latest: versionsReference['latest'] };
520
521export default {
522  home,
523  general,
524  learn,
525  preview,
526  archive,
527  featurePreview,
528  reference,
529  generalDirectories,
530  previewDirectories,
531  referenceDirectories,
532  archiveDirectories,
533  homeDirectories,
534  learnDirectories,
535};
536
537// --- MDX methods ---
538
539function makeSection(name, children = [], props = {}) {
540  return make('section', { name, ...{ expanded: false, ...props } }, children);
541}
542
543function makeGroup(name, children = [], props = {}) {
544  return make('group', { name, ...props }, children);
545}
546
547/**
548 * Parse the MDX page and extract the frontmatter/yaml page information.
549 * It will only look for the frontmatter/yaml block in the root nodes.
550 * This requires the `remark-frontmatter` MDX plugin.
551 *
552 * @param {string} file
553 */
554function makePage(file) {
555  const filePath = path.resolve(PAGES_DIR, file);
556  const contents = fs.readFileSync(filePath, 'utf-8');
557  const url = pageUrl(filePath);
558  const data = frontmatter(contents).attributes;
559
560  if (!data) {
561    console.error('Page YAML block is unreadable:', file);
562  } else if (!data.title) {
563    console.error('Page does not have a `title`:', file);
564    data.title = '';
565  }
566
567  const result = {
568    // TODO(cedric): refactor name into title
569    name: data.title,
570    // TODO(cedric): refactor href into url
571    href: url,
572  };
573  // TODO(cedric): refactor sidebarTitle into metadata
574  if (data.sidebar_title) {
575    result.sidebarTitle = data.sidebar_title;
576  }
577  // TODO(cedric): refactor hidden into `isHidden` and move it to metadata
578  if (data.hidden) {
579    result.hidden = data.hidden;
580  }
581  return make('page', result);
582}
583
584// --- Other helpers ---
585
586/**
587 * Load all pages from a single directory.
588 */
589function pagesFromDir(dir) {
590  return fs
591    .readdirSync(path.resolve(PAGES_DIR, dir), { withFileTypes: true })
592    .filter(entity => entity.isFile())
593    .map(file => makePage(path.join(dir, file.name)));
594}
595
596/**
597 * Create the page url using the absolute file path.
598 * This parses the URL, relatively from PAGES_DIR.
599 * It also strips the file extension, and name if its `index`.
600 * These urls are pathnames, without trailing slashes.
601 */
602function pageUrl(file) {
603  const filePath = path.parse(file);
604  const { pathname } = new URL(path.relative(PAGES_DIR, file), 'https://docs.expo.dev');
605  return pathname
606    .replace(filePath.base, filePath.name === 'index' ? '' : filePath.name)
607    .replace(/\/$/, '');
608}
609