xref: /expo/docs/constants/navigation.js (revision 6eefacaa)
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      ],
86      { expanded: false }
87    ),
88    makeGroup(
89      'Development builds',
90      [
91        makePage('develop/development-builds/introduction.mdx'),
92        makePage('develop/development-builds/installation.mdx'),
93        makePage('develop/development-builds/create-a-build.mdx'),
94        makePage('develop/development-builds/use-development-builds.mdx'),
95        makePage('develop/development-builds/share-with-your-team.mdx'),
96        makePage('develop/development-builds/parallel-installation.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('workflow/using-libraries.mdx'),
137    makePage('guides/permissions.mdx'),
138    makePage('guides/environment-variables.mdx'),
139    makePage('guides/linking.mdx'),
140    makePage('guides/deep-linking.mdx'),
141    makeGroup(
142      'Custom native code',
143      [
144        makePage('workflow/continuous-native-generation.mdx'),
145        makePage('workflow/customizing.mdx'),
146        makePage('workflow/prebuild.mdx'),
147        makePage('guides/adopting-prebuild.mdx'),
148      ],
149      { expanded: false }
150    ),
151    makeGroup(
152      'Web',
153      [
154        makePage('workflow/web.mdx'),
155        makePage('guides/progressive-web-apps.mdx'),
156        makePage('distribution/publishing-websites.mdx'),
157        makePage('guides/customizing-metro.mdx'),
158        makePage('guides/customizing-webpack.mdx'),
159        makePage('guides/web-performance.mdx'),
160      ],
161      { expanded: false }
162    ),
163    makeGroup(
164      'Reference',
165      [
166        makePage('guides/monorepos.mdx'),
167        makePage('workflow/logging.mdx'),
168        makePage('workflow/development-mode.mdx'),
169        makePage('workflow/common-development-errors.mdx'),
170        makePage('workflow/android-studio-emulator.mdx'),
171        makePage('workflow/ios-simulator.mdx'),
172      ],
173      { expanded: false }
174    ),
175  ]),
176  makeSection('Expo Router', [
177    makeGroup('Advanced', [
178      makePage('router/advanced/root-layout.mdx'),
179      makePage('router/advanced/stack.mdx'),
180      makePage('router/advanced/tabs.mdx'),
181      makePage('router/advanced/drawer.mdx'),
182      makePage('router/advanced/nesting-navigators.mdx'),
183      makePage('router/advanced/modals.mdx'),
184      makePage('router/advanced/platform-specific-modules.mdx'),
185      makePage('router/advanced/shared-routes.mdx'),
186      makePage('router/advanced/router-settings.mdx'),
187      makePage('router/advanced/apple-handoff.mdx'),
188    ]),
189    makeGroup('Reference', [
190      makePage('router/reference/hooks.mdx'),
191      makePage('router/reference/search-parameters.mdx'),
192      makePage('router/reference/redirects.mdx'),
193      makePage('router/reference/static-rendering.mdx'),
194      makePage('router/reference/async-routes.mdx'),
195      makePage('router/reference/sitemap.mdx'),
196      makePage('router/reference/typed-routes.mdx'),
197      makePage('router/reference/authentication.mdx'),
198      makePage('router/reference/screen-tracking.mdx'),
199      makePage('router/reference/src-directory.mdx'),
200      makePage('router/reference/testing.mdx'),
201      makePage('router/reference/troubleshooting.mdx'),
202      makePage('router/reference/faq.mdx'),
203    ]),
204    makeGroup('Migration', [makePage('router/migrate/from-react-navigation.mdx')]),
205  ]),
206  makeSection(
207    'Expo Modules API',
208    [
209      makePage('modules/overview.mdx'),
210      makePage('modules/get-started.mdx'),
211      makeSection('Tutorials', [
212        makePage('modules/native-module-tutorial.mdx'),
213        makePage('modules/native-view-tutorial.mdx'),
214        makePage('modules/config-plugin-and-native-module-tutorial.mdx'),
215        makePage('modules/use-standalone-expo-module-in-your-project.mdx'),
216        makePage('modules/third-party-library.mdx'),
217        makePage('modules/existing-library.mdx'),
218      ]),
219      makeSection('Reference', [
220        makePage('modules/module-api.mdx'),
221        makePage('modules/android-lifecycle-listeners.mdx'),
222        makePage('modules/appdelegate-subscribers.mdx'),
223        makePage('modules/autolinking.mdx'),
224        makePage('modules/module-config.mdx'),
225      ]),
226    ],
227    { expanded: false }
228  ),
229  makeSection('EAS', [makePage('eas/index.mdx')]),
230  makeSection('EAS Build', [
231    makePage('build/introduction.mdx'),
232    makePage('build/setup.mdx'),
233    makePage('build/eas-json.mdx'),
234    makePage('build/internal-distribution.mdx'),
235    makePage('build/automate-submissions.mdx'),
236    makePage('build/updates.mdx'),
237    makePage('build/building-on-ci.mdx'),
238    makePage('build/building-from-github.mdx'),
239    makeGroup(
240      'App Signing',
241      [
242        makePage('app-signing/app-credentials.mdx'),
243        makePage('app-signing/managed-credentials.mdx'),
244        makePage('app-signing/local-credentials.mdx'),
245        makePage('app-signing/existing-credentials.mdx'),
246        makePage('app-signing/syncing-credentials.mdx'),
247        makePage('app-signing/security.mdx'),
248      ],
249      { expanded: false }
250    ),
251    makeGroup(
252      'Custom builds',
253      [
254        makePage('custom-builds/get-started.mdx'),
255        makePage('custom-builds/schema.mdx'),
256        makePage('custom-builds/functions.mdx'),
257      ],
258      { expanded: false }
259    ),
260    makeGroup(
261      'Reference',
262      [
263        makePage('build-reference/eas-json.mdx'),
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  ]),
454];
455
456const archive = [
457  makeSection('Classic Builds', [
458    makePage('archive/classic-updates/building-standalone-apps.mdx'),
459    makePage('archive/classic-updates/turtle-cli.mdx'),
460  ]),
461  makeSection('Classic Updates', [
462    makePage('archive/classic-updates/introduction.mdx'),
463    makeSection('Guides', [
464      makePage('archive/classic-updates/configuring-updates.mdx'),
465      makePage('archive/classic-updates/preloading-and-caching-assets.mdx'),
466    ]),
467    makeSection('Distribution', [
468      makePage('archive/classic-updates/release-channels.mdx'),
469      makePage('archive/classic-updates/advanced-release-channels.mdx'),
470      makePage('archive/classic-updates/hosting-your-app.mdx'),
471      makePage('archive/classic-updates/offline-support.mdx'),
472      makePage('archive/classic-updates/optimizing-updates.mdx'),
473    ]),
474    makeSection('Workflow', [makePage('archive/classic-updates/publishing.mdx')]),
475    makeSection('Bare Workflow', [makePage('archive/classic-updates/updating-your-app.mdx')]),
476  ]),
477  makeSection('Technical Specs', [makePage('archive/technical-specs/expo-updates-0.mdx')]),
478  makeSection('More', [
479    makePage('archive/expo-cli.mdx'),
480    makePage('archive/managed-vs-bare.mdx'),
481    makePage('archive/notification-channels.mdx'),
482    makePage('archive/glossary.mdx'),
483  ]),
484];
485
486const featurePreview = [];
487
488const versionsReference = VERSIONS.reduce(
489  (all, version) => ({
490    ...all,
491    [version]: [
492      makeSection('Configuration files', pagesFromDir(`versions/${version}/config`), {
493        expanded: true,
494      }),
495      makeSection('Expo SDK', pagesFromDir(`versions/${version}/sdk`), { expanded: true }),
496      makeSection('Technical specs', [
497        makePage('technical-specs/expo-updates-1.mdx'),
498        makePage('technical-specs/expo-sfv-0.mdx'),
499      ]),
500      makeSection('More', [makePage('more/expo-cli.mdx'), makePage('more/glossary-of-terms.mdx')], {
501        expanded: true,
502      }),
503      makeSection(
504        'React Native',
505        [
506          make('page', {
507            href: 'https://reactnative.dev/docs/components-and-apis',
508            sidebarTitle: 'Visit documentation',
509          }),
510        ],
511        { expanded: true }
512      ),
513    ],
514  }),
515  {}
516);
517
518const reference = { ...versionsReference, latest: versionsReference['latest'] };
519
520export default {
521  home,
522  general,
523  learn,
524  preview,
525  archive,
526  featurePreview,
527  reference,
528  generalDirectories,
529  previewDirectories,
530  referenceDirectories,
531  archiveDirectories,
532  homeDirectories,
533  learnDirectories,
534};
535
536// --- MDX methods ---
537
538function makeSection(name, children = [], props = {}) {
539  return make('section', { name, ...{ expanded: false, ...props } }, children);
540}
541
542function makeGroup(name, children = [], props = {}) {
543  return make('group', { name, ...props }, children);
544}
545
546/**
547 * Parse the MDX page and extract the frontmatter/yaml page information.
548 * It will only look for the frontmatter/yaml block in the root nodes.
549 * This requires the `remark-frontmatter` MDX plugin.
550 *
551 * @param {string} file
552 */
553function makePage(file) {
554  const filePath = path.resolve(PAGES_DIR, file);
555  const contents = fs.readFileSync(filePath, 'utf-8');
556  const url = pageUrl(filePath);
557  const data = frontmatter(contents).attributes;
558
559  if (!data) {
560    console.error('Page YAML block is unreadable:', file);
561  } else if (!data.title) {
562    console.error('Page does not have a `title`:', file);
563    data.title = '';
564  }
565
566  const result = {
567    // TODO(cedric): refactor name into title
568    name: data.title,
569    // TODO(cedric): refactor href into url
570    href: url,
571  };
572  // TODO(cedric): refactor sidebarTitle into metadata
573  if (data.sidebar_title) {
574    result.sidebarTitle = data.sidebar_title;
575  }
576  // TODO(cedric): refactor hidden into `isHidden` and move it to metadata
577  if (data.hidden) {
578    result.hidden = data.hidden;
579  }
580  return make('page', result);
581}
582
583// --- Other helpers ---
584
585/**
586 * Load all pages from a single directory.
587 */
588function pagesFromDir(dir) {
589  return fs
590    .readdirSync(path.resolve(PAGES_DIR, dir), { withFileTypes: true })
591    .filter(entity => entity.isFile())
592    .map(file => makePage(path.join(dir, file.name)));
593}
594
595/**
596 * Create the page url using the absolute file path.
597 * This parses the URL, relatively from PAGES_DIR.
598 * It also strips the file extension, and name if its `index`.
599 * These urls are pathnames, without trailing slashes.
600 */
601function pageUrl(file) {
602  const filePath = path.parse(file);
603  const { pathname } = new URL(path.relative(PAGES_DIR, file), 'https://docs.expo.dev');
604  return pathname
605    .replace(filePath.base, filePath.name === 'index' ? '' : filePath.name)
606    .replace(/\/$/, '');
607}
608