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