├── .editorconfig ├── .env-dist ├── .env.testing ├── .eslintignore ├── .eslintrc.cjs ├── .flake8 ├── .gitattributes ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ └── bug-report.yml ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml ├── labeler.yml └── workflows │ ├── auto-merge.yml │ ├── dev-build.yml │ ├── developing.yml │ ├── glean-probe-scraper.yml │ ├── labeler.yml │ ├── mark-as-idle-issues-pr.yml │ ├── new-issues.yml │ ├── npm-publish.yml │ ├── npm-published-simulation.yml │ ├── performance.yml │ ├── pr-bundlesize-compare.yml │ ├── pr-commit-signatures.yml │ ├── pr-deployer.yml │ ├── pr-docs.yml │ ├── pr-kumascript.yml │ ├── pr-rebase-needed.yml │ ├── prod-build.yml │ ├── review-deploy.yml │ ├── stage-build.yml │ ├── test-build.yml │ └── testing.yml ├── .gitignore ├── .husky ├── .gitignore └── pre-commit ├── .npmignore ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── .release-please-manifest.json ├── .stylelintignore ├── .stylelintrc.json ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── LICENSE ├── Procfile.dev ├── Procfile.rari ├── Procfile.rari.dev ├── Procfile.start ├── README.md ├── SECURITY.md ├── assets ├── nonprod │ └── robots.txt └── prod │ └── robots.txt ├── bins ├── build.mjs ├── server.mjs └── tool.mjs ├── build ├── blog.ts ├── build-blog.ts ├── build-curriculum.ts ├── build-options.ts ├── check-images.ts ├── cli.ts ├── code-headers.ts ├── curriculum.ts ├── document-utils.ts ├── extract-sections.ts ├── extract-sidebar.ts ├── extract-specifications.ts ├── extract-summary.ts ├── flaws │ ├── bad-bcd-queries.ts │ ├── broken-links.ts │ ├── heading-links.ts │ ├── index.ts │ ├── pre-tags.ts │ ├── safe-to-https-domains.json │ ├── sections.ts │ ├── translation-differences.ts │ └── unsafe-html.ts ├── format-notecards.ts ├── git-history.ts ├── index.ts ├── matches.ts ├── page-title.ts ├── resolve-bcd.ts ├── search-index.ts ├── sentry.ts ├── sitemaps.ts ├── spas.ts ├── ssr-cli.ts ├── ssr.ts ├── utils.ts ├── web-features.ts ├── web-specs.ts └── wrap-tables.ts ├── client ├── config │ ├── env.js │ ├── getHttpsConfig.js │ ├── jest │ │ ├── babelTransform.js │ │ ├── cssTransform.js │ │ ├── fileTransform.js │ │ └── rawTransform.js │ ├── paths.js │ ├── webpack.config.js │ ├── webpack │ │ └── persistentCache │ │ │ └── createEnvironmentHash.js │ └── webpackDevServer.config.js ├── jest-setup.ts ├── package.json ├── public │ ├── apple-touch-icon.png │ ├── assets │ │ ├── afree.png │ │ ├── ai-help.png │ │ ├── ai-help │ │ │ ├── ai-help_dark.png │ │ │ ├── ai-help_light.png │ │ │ ├── context.svg │ │ │ ├── gpt-4.svg │ │ │ ├── history.svg │ │ │ └── lightbulb-question.svg │ │ ├── app-dl-apple.svg │ │ ├── app-dl-google.svg │ │ ├── app-dl-ms.png │ │ ├── avatar.png │ │ ├── badges.svg │ │ ├── collections.png │ │ ├── curriculum │ │ │ ├── curriculum-landing-stairway-1.svg │ │ │ ├── curriculum-landing-stairway-2-small.svg │ │ │ ├── curriculum-landing-stairway-2.svg │ │ │ ├── curriculum-landing-top.svg │ │ │ ├── curriculum-partner-banner-illustration-large-dark.svg │ │ │ ├── curriculum-partner-banner-illustration-large-light.svg │ │ │ ├── curriculum-topic-practices.svg │ │ │ ├── curriculum-topic-scripting.svg │ │ │ ├── curriculum-topic-standards.svg │ │ │ ├── curriculum-topic-styling.svg │ │ │ ├── curriculum-topic-tooling.svg │ │ │ └── fullscreen-enter.svg │ │ ├── mdn_contributor.png │ │ ├── notifications_light.png │ │ ├── observatory │ │ │ ├── assessment.svg │ │ │ ├── fail-icon.svg │ │ │ ├── landing-illustration.svg │ │ │ ├── lines.svg │ │ │ ├── mdn.svg │ │ │ ├── pass-icon.svg │ │ │ ├── results-icon.svg │ │ │ ├── scanning.svg │ │ │ ├── security.svg │ │ │ ├── stars.svg │ │ │ ├── summary-icon.svg │ │ │ └── tooltip-arrow.svg │ │ ├── offline.png │ │ ├── playground.png │ │ ├── plus-docs │ │ │ ├── ai-help │ │ │ │ ├── code-examples-playground.png │ │ │ │ ├── code-examples-queue.png │ │ │ │ ├── example-question-answering.png │ │ │ │ ├── example-question-editing.png │ │ │ │ ├── history-banner.png │ │ │ │ ├── history-settings.png │ │ │ │ ├── issue-template.png │ │ │ │ ├── login-signup.png │ │ │ │ ├── rate-answers.png │ │ │ │ └── report-feedback.png │ │ │ ├── collections │ │ │ │ ├── collections-dashboard.png │ │ │ │ ├── desktop-collections-dashboard-delete.png │ │ │ │ ├── desktop-collections-delete-fva.png │ │ │ │ ├── desktop-collections-edit-dialog-add-note.png │ │ │ │ ├── desktop-collections-edit-dialog.png │ │ │ │ ├── desktop-collections-edit-menu.png │ │ │ │ ├── desktop-collections-filter.png │ │ │ │ ├── desktop-collections-fva.png │ │ │ │ ├── desktop-collections-sort.png │ │ │ │ ├── desktop-collections-three-dot-menu.png │ │ │ │ ├── desktop-collections-undo.png │ │ │ │ ├── desktop-collections-user-menu.png │ │ │ │ ├── desktop-page-add-note.png │ │ │ │ ├── desktop-page-dialog-save.png │ │ │ │ ├── desktop-page-open-dialog.png │ │ │ │ ├── desktop-remove-saved-delete.png │ │ │ │ ├── desktop-remove-saved.png │ │ │ │ ├── desktop-saving-page.png │ │ │ │ ├── mobile-add-note.png │ │ │ │ ├── mobile-burger-menu.png │ │ │ │ ├── mobile-collections-dashboard-delete-entry.png │ │ │ │ ├── mobile-collections-dashboard-edit-entry.png │ │ │ │ ├── mobile-collections-dashboard-edit.png │ │ │ │ ├── mobile-collections-dashboard-three-dots.png │ │ │ │ ├── mobile-collections-dashboard.png │ │ │ │ ├── mobile-collections-delete-entry.png │ │ │ │ ├── mobile-collections-fva-undo.png │ │ │ │ ├── mobile-collections-menu-item.png │ │ │ │ ├── mobile-collections-undo.png │ │ │ │ ├── mobile-menu.png │ │ │ │ ├── mobile-open-article-actions.png │ │ │ │ ├── mobile-plus-menu.png │ │ │ │ ├── mobile-save-page-step-one.png │ │ │ │ ├── mobile-save-page.png │ │ │ │ └── mobile-saved-page.png │ │ │ ├── notifications │ │ │ │ ├── access-notifications-from-main-menu.png │ │ │ │ ├── bulk-unwatch-dashboard.png │ │ │ │ ├── mobile-notifications-user-menu.png │ │ │ │ ├── notifications-user-menu.png │ │ │ │ ├── star-notification.png │ │ │ │ ├── unwatch-dashboard.png │ │ │ │ ├── unwatch-page.png │ │ │ │ ├── watch-list.png │ │ │ │ └── watch-page.png │ │ │ ├── offline │ │ │ │ ├── desktop-offline-clear-data.png │ │ │ │ ├── desktop-offline-enable-auto-update.png │ │ │ │ ├── desktop-offline-enable-offline.png │ │ │ │ ├── desktop-offline-manual-update.png │ │ │ │ └── desktop-offline-user-menu.png │ │ │ ├── playground │ │ │ │ ├── playground-example.png │ │ │ │ ├── playground-menu.png │ │ │ │ └── playground-sample.png │ │ │ └── updates │ │ │ │ ├── collections.png │ │ │ │ ├── updates.png │ │ │ │ ├── updates_bcd.png │ │ │ │ ├── updates_collection.png │ │ │ │ ├── updates_filter.png │ │ │ │ └── updates_search.png │ │ └── updates.png │ ├── contribute.json │ ├── favicon-128x128.png │ ├── favicon-150x150.png │ ├── favicon-16x16.png │ ├── favicon-192x192.png │ ├── favicon-32x32.png │ ├── favicon-48x48-flawless.png │ ├── favicon-48x48-flaws-fixable.png │ ├── favicon-48x48-flaws.png │ ├── favicon-48x48.png │ ├── favicon-512x512.png │ ├── favicon-64x64.png │ ├── favicon.ico │ ├── favicon.svg │ ├── index.html │ ├── manifest.json │ ├── mdn-social-share.png │ └── opensearch.xml ├── pwa │ ├── README.md │ ├── package.json │ ├── src │ │ ├── caches.ts │ │ ├── db.ts │ │ ├── fetch-interceptors.ts │ │ ├── fetcher.ts │ │ ├── service-worker.ts │ │ └── unpack-cache.ts │ ├── tsconfig.json │ ├── webpack.config.js │ ├── webpack.production.config.js │ └── yarn.lock ├── scripts │ ├── build.js │ ├── start.js │ └── test.js ├── src │ ├── about │ │ ├── _mixins.scss │ │ ├── index.scss │ │ └── index.tsx │ ├── advertising │ │ ├── index.tsx │ │ └── with_us │ │ │ ├── index.scss │ │ │ └── index.tsx │ ├── app.scss │ ├── app.test.tsx │ ├── app.tsx │ ├── assets │ │ ├── about │ │ │ ├── accurate-sm.svg │ │ │ ├── accurate.svg │ │ │ ├── building-dark.svg │ │ │ ├── building.svg │ │ │ ├── collaborative-sm.svg │ │ │ ├── collaborative.svg │ │ │ ├── dot-dark.svg │ │ │ ├── dot.svg │ │ │ ├── education.svg │ │ │ ├── global-impact-dark.svg │ │ │ ├── global-impact.svg │ │ │ ├── handshake.svg │ │ │ ├── inclusive-sm.svg │ │ │ ├── inclusive.svg │ │ │ ├── line-dot.svg │ │ │ ├── sparkle.svg │ │ │ ├── text-box-check-outline.svg │ │ │ └── web-check.svg │ │ ├── article-footer │ │ │ └── article-footer.svg │ │ ├── clippy.svg │ │ ├── community │ │ │ ├── community-calls-dark.svg │ │ │ ├── community-calls.svg │ │ │ ├── discord-dark.svg │ │ │ ├── discord.svg │ │ │ ├── people-dark.svg │ │ │ ├── people.svg │ │ │ ├── quote-end-dark.svg │ │ │ ├── quote-end.svg │ │ │ ├── quote-start-dark.svg │ │ │ ├── quote-start.svg │ │ │ ├── video-bg-dark.svg │ │ │ ├── video-bg.svg │ │ │ ├── video-thumbnail.png │ │ │ └── youtube-play.svg │ │ ├── curriculum-landing-arrow.svg │ │ ├── curriculum-partner-bg.svg │ │ ├── curriculum-scrim-bg.svg │ │ ├── curriculum │ │ │ ├── landing-scrim.png │ │ │ ├── scrim-bg.png │ │ │ ├── scrim-hexagons.svg │ │ │ ├── scrim-play.svg │ │ │ └── scrimba-logo.svg │ │ ├── dino.svg │ │ ├── fonts │ │ │ ├── BarlowCondensed-SemiBold.woff2 │ │ │ ├── Inter.var.woff2 │ │ │ ├── Montserrat-SemiBold.woff │ │ │ ├── Montserrat-SemiBold.woff2 │ │ │ ├── Montserrat-VF.woff2 │ │ │ ├── inter-v3-latin-600.woff │ │ │ ├── inter-v3-latin-600.woff2 │ │ │ ├── inter-v3-latin-regular.woff │ │ │ └── inter-v3-latin-regular.woff2 │ │ ├── hero-dino.png │ │ ├── home-masthead-background.svg │ │ ├── icons │ │ │ ├── add-filled.svg │ │ │ ├── add.svg │ │ │ ├── ai-help.svg │ │ │ ├── alert-circle.svg │ │ │ ├── altname.svg │ │ │ ├── baseline │ │ │ │ ├── browser-check.svg │ │ │ │ ├── browser-cross.svg │ │ │ │ ├── chrome.svg │ │ │ │ ├── edge.svg │ │ │ │ ├── firefox.svg │ │ │ │ ├── high-dark.svg │ │ │ │ ├── high.svg │ │ │ │ ├── limited-dark.svg │ │ │ │ ├── limited.svg │ │ │ │ ├── low-dark.svg │ │ │ │ ├── low.svg │ │ │ │ └── safari.svg │ │ │ ├── bell-filled.svg │ │ │ ├── bell-ring.svg │ │ │ ├── bell.svg │ │ │ ├── bluesky.svg │ │ │ ├── bookmark-filled.svg │ │ │ ├── bookmark.svg │ │ │ ├── cancel.svg │ │ │ ├── caret.svg │ │ │ ├── chatgpt.svg │ │ │ ├── checkmark.svg │ │ │ ├── chevron.svg │ │ │ ├── chrome.svg │ │ │ ├── critical.svg │ │ │ ├── curriculum-about-covered.svg │ │ │ ├── curriculum-about-detail.svg │ │ │ ├── curriculum-about-educators.svg │ │ │ ├── curriculum-about-not.svg │ │ │ ├── curriculum-about-students.svg │ │ │ ├── curriculum-bullet.svg │ │ │ ├── curriculum-ext-resource.svg │ │ │ ├── curriculum-landing-about-beginner.svg │ │ │ ├── curriculum-landing-about-bullet.svg │ │ │ ├── curriculum-landing-about-free.svg │ │ │ ├── curriculum-landing-about-pace.svg │ │ │ ├── curriculum-landing-started-advanced.svg │ │ │ ├── curriculum-landing-started-beginner.svg │ │ │ ├── curriculum-landing-started-educator.svg │ │ │ ├── curriculum-landing-started-employment.svg │ │ │ ├── curriculum-mdn-resource.svg │ │ │ ├── curriculum-modules-underline.svg │ │ │ ├── curriculum-next.svg │ │ │ ├── curriculum-partner-underline-large.svg │ │ │ ├── curriculum-partner-underline-small.svg │ │ │ ├── curriculum-prev.svg │ │ │ ├── curriculum-resources.svg │ │ │ ├── curriculum-started-underline.svg │ │ │ ├── deno.svg │ │ │ ├── deprecated.svg │ │ │ ├── desktop.svg │ │ │ ├── disabled.svg │ │ │ ├── edge.svg │ │ │ ├── edit-filled.svg │ │ │ ├── edit.svg │ │ │ ├── ellipses.svg │ │ │ ├── experimental.svg │ │ │ ├── external.svg │ │ │ ├── eye-filled.svg │ │ │ ├── eye.svg │ │ │ ├── feed.svg │ │ │ ├── feedback.svg │ │ │ ├── filter.svg │ │ │ ├── firefox.svg │ │ │ ├── footnote.svg │ │ │ ├── fullscreen-enter.svg │ │ │ ├── github-mark-small.svg │ │ │ ├── highlight.svg │ │ │ ├── history.svg │ │ │ ├── ie.svg │ │ │ ├── information.svg │ │ │ ├── language.svg │ │ │ ├── mastodon.svg │ │ │ ├── menu-filled.svg │ │ │ ├── menu.svg │ │ │ ├── message-question.svg │ │ │ ├── message.svg │ │ │ ├── mobile.svg │ │ │ ├── more.svg │ │ │ ├── new-topic.svg │ │ │ ├── next.svg │ │ │ ├── no.svg │ │ │ ├── nodejs.svg │ │ │ ├── nonstandard.svg │ │ │ ├── note-deprecated.svg │ │ │ ├── note-info.svg │ │ │ ├── note-warning.svg │ │ │ ├── offline.svg │ │ │ ├── opera.svg │ │ │ ├── padlock.svg │ │ │ ├── partial.svg │ │ │ ├── play.svg │ │ │ ├── prefix.svg │ │ │ ├── preview.svg │ │ │ ├── previous.svg │ │ │ ├── progress-check.svg │ │ │ ├── progress-helper.svg │ │ │ ├── question-mark.svg │ │ │ ├── queue.svg │ │ │ ├── queued.svg │ │ │ ├── quote.svg │ │ │ ├── return.svg │ │ │ ├── safari.svg │ │ │ ├── samsunginternet.svg │ │ │ ├── search.svg │ │ │ ├── send.svg │ │ │ ├── server.svg │ │ │ ├── sidebar-filled.svg │ │ │ ├── sidebar.svg │ │ │ ├── simple-firefox.svg │ │ │ ├── small-arrow.svg │ │ │ ├── star-filled.svg │ │ │ ├── star.svg │ │ │ ├── survey.svg │ │ │ ├── theme-dark.svg │ │ │ ├── theme-light.svg │ │ │ ├── theme-os-default.svg │ │ │ ├── thumbs-down.svg │ │ │ ├── thumbs-up.svg │ │ │ ├── trash-filled.svg │ │ │ ├── trash.svg │ │ │ ├── twitter-x.svg │ │ │ ├── unknown.svg │ │ │ ├── warning.svg │ │ │ ├── webview.svg │ │ │ ├── wifi.svg │ │ │ ├── yes-circle.svg │ │ │ └── yes.svg │ │ ├── lines.svg │ │ ├── logo.svg │ │ ├── m-icon.svg │ │ ├── m-logo.svg │ │ ├── mdn-docs-logo.svg │ │ ├── mdn-footer-logo.svg │ │ ├── mdn-logo.svg │ │ ├── mdn-plus-logo.svg │ │ ├── moz-logo.svg │ │ └── tiled-dinos.svg │ ├── blog │ │ ├── index.scss │ │ ├── index.tsx │ │ ├── post.scss │ │ └── post.tsx │ ├── community │ │ ├── index.scss │ │ └── index.tsx │ ├── constants.ts │ ├── contributor-spotlight │ │ ├── index.scss │ │ └── index.tsx │ ├── curriculum │ │ ├── about.scss │ │ ├── about.tsx │ │ ├── body.tsx │ │ ├── default.tsx │ │ ├── index.scss │ │ ├── index.tsx │ │ ├── landing.scss │ │ ├── landing.tsx │ │ ├── layout.tsx │ │ ├── module.scss │ │ ├── module.tsx │ │ ├── modules-list.scss │ │ ├── modules-list.tsx │ │ ├── overview.tsx │ │ ├── partner-banner.scss │ │ ├── partner-banner.tsx │ │ ├── prev-next.scss │ │ ├── prev-next.tsx │ │ ├── sidebar.tsx │ │ ├── topic-icon.scss │ │ ├── topic-icon.tsx │ │ └── utils.ts │ ├── document │ │ ├── baseline-indicator.scss │ │ ├── baseline-indicator.tsx │ │ ├── code │ │ │ ├── ai-explain.ts │ │ │ ├── copy.ts │ │ │ ├── playground.ts │ │ │ ├── render-md.ts │ │ │ └── syntax-highlight.tsx │ │ ├── hooks.ts │ │ ├── index.scss │ │ ├── index.test.tsx │ │ ├── index.tsx │ │ ├── ingredients │ │ │ ├── prose.tsx │ │ │ ├── spec-section.tsx │ │ │ └── utils.tsx │ │ ├── interactive-examples.scss │ │ ├── languages.css │ │ ├── mathml-polyfill │ │ │ ├── font │ │ │ │ └── STIXTwoMath-Regular.woff2 │ │ │ ├── index.tsx │ │ │ ├── mathml-font.scss │ │ │ ├── mathml.css │ │ │ └── polyfill.tsx │ │ ├── molecules │ │ │ ├── localized-content-note │ │ │ │ └── index.tsx │ │ │ ├── note-banner │ │ │ │ └── index.tsx │ │ │ └── tooltip │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ ├── on-github.tsx │ │ ├── organisms │ │ │ ├── article-footer │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── sidebar │ │ │ │ ├── SidebarFilterer.ts │ │ │ │ ├── filter.scss │ │ │ │ ├── filter.tsx │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ └── toc │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ ├── preloading.tsx │ │ └── toolbar │ │ │ ├── edit-actions.scss │ │ │ ├── edit-actions.tsx │ │ │ ├── flaws.scss │ │ │ ├── flaws.tsx │ │ │ ├── index.scss │ │ │ └── index.tsx │ ├── env.ts │ ├── flaw-utils.js │ ├── flaws │ │ ├── index.scss │ │ └── index.tsx │ ├── ga-context.tsx │ ├── homepage │ │ ├── contributor-spotlight │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ ├── featured-articles │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ ├── homepage-hero │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ ├── index.scss │ │ ├── index.tsx │ │ ├── latest-news │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ ├── recent-contributions │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ ├── static-page │ │ │ └── index.tsx │ │ └── types.tsx │ ├── hooks.ts │ ├── index.tsx │ ├── lit │ │ ├── about.js │ │ ├── community │ │ │ ├── contributor-list.js │ │ │ ├── contributor-list.scss │ │ │ └── types.d.ts │ │ ├── compat │ │ │ ├── compat-table.js │ │ │ ├── feature-row.js │ │ │ ├── global.scss │ │ │ ├── index-desktop-md.scss │ │ │ ├── index-desktop-xl.scss │ │ │ ├── index-desktop.scss │ │ │ ├── index-mobile.scss │ │ │ ├── index.scss │ │ │ ├── lazy-compat-table.js │ │ │ ├── legend.js │ │ │ ├── types.ts │ │ │ └── utils.js │ │ ├── curriculum │ │ │ ├── scrim-inline.global.css │ │ │ ├── scrim-inline.js │ │ │ └── scrim-inline.scss │ │ ├── glean-mixin.js │ │ ├── globals.d.ts │ │ ├── interactive-example │ │ │ ├── global.scss │ │ │ ├── index.js │ │ │ ├── index.scss │ │ │ ├── tabs.js │ │ │ ├── tabs.panel.scss │ │ │ ├── tabs.tab.scss │ │ │ ├── tabs.wrapper.scss │ │ │ ├── utils.js │ │ │ ├── with-choices.js │ │ │ ├── with-console.js │ │ │ └── with-tabs.js │ │ ├── modules.d.ts │ │ ├── play │ │ │ ├── console-utils.js │ │ │ ├── console.js │ │ │ ├── console.scss │ │ │ ├── controller.js │ │ │ ├── editor.js │ │ │ ├── editor.scss │ │ │ ├── runner.js │ │ │ ├── runner.scss │ │ │ └── types.d.ts │ │ ├── theme-controller.js │ │ ├── tsconfig.json │ │ └── viewed-controller.js │ ├── minimal-prism.scss │ ├── newsletter │ │ ├── index.scss │ │ └── index.tsx │ ├── observatory │ │ ├── benchmark-chart │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ ├── docs │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ ├── index.scss │ │ ├── index.tsx │ │ ├── landing.scss │ │ ├── landing.tsx │ │ ├── layout.tsx │ │ ├── progress │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ ├── results.scss │ │ ├── results.tsx │ │ ├── results │ │ │ ├── benchmark.tsx │ │ │ ├── cookies.tsx │ │ │ ├── csp.tsx │ │ │ ├── headers.tsx │ │ │ ├── history.tsx │ │ │ ├── human-duration.tsx │ │ │ ├── rating.tsx │ │ │ ├── rescan-button.tsx │ │ │ └── tests.tsx │ │ ├── tooltip │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ ├── types.ts │ │ └── utils.tsx │ ├── page-not-found │ │ ├── fallback-link.tsx │ │ ├── index.scss │ │ └── index.tsx │ ├── placement-context.tsx │ ├── playground │ │ ├── forms.tsx │ │ ├── index.scss │ │ ├── index.tsx │ │ ├── loader.scss │ │ ├── loader.tsx │ │ ├── queue │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ └── utils.ts │ ├── plus │ │ ├── ai-help │ │ │ ├── banners.tsx │ │ │ ├── constants.tsx │ │ │ ├── history.scss │ │ │ ├── history.tsx │ │ │ ├── index.scss │ │ │ ├── index.tsx │ │ │ ├── landing.scss │ │ │ ├── landing.tsx │ │ │ ├── rust-types.ts │ │ │ ├── use-ai.test.ts │ │ │ ├── use-ai.ts │ │ │ └── utils.ts │ │ ├── app.tsx │ │ ├── collections │ │ │ ├── api.ts │ │ │ ├── collection.scss │ │ │ ├── collection.tsx │ │ │ ├── frequently-viewed.tsx │ │ │ ├── index.scss │ │ │ ├── index.tsx │ │ │ ├── new-edit-collection-modal.tsx │ │ │ └── rust-types.ts │ │ ├── common │ │ │ ├── api.tsx │ │ │ ├── index.tsx │ │ │ ├── login-banner.scss │ │ │ ├── login-banner.tsx │ │ │ ├── plus-tabs.tsx │ │ │ └── tabs.tsx │ │ ├── icon-card │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ ├── index.scss │ │ ├── index.tsx │ │ ├── offer-overview │ │ │ ├── index.tsx │ │ │ ├── offer-hero │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── offer-overview-feature │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ └── offer-overview-subscribe │ │ │ │ ├── index.scss │ │ │ │ ├── index.tsx │ │ │ │ └── stripe.tsx │ │ ├── plus-docs │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ ├── search-filter │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ ├── updates │ │ │ ├── api.ts │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ └── utils.ts │ ├── react-app.d.ts │ ├── search-utils.ts │ ├── search.tsx │ ├── settings │ │ ├── ai-help.tsx │ │ ├── clear.tsx │ │ ├── db.ts │ │ ├── index.scss │ │ ├── index.tsx │ │ ├── manage.tsx │ │ ├── mdn-worker.tsx │ │ ├── newsletter.tsx │ │ ├── offline-settings.tsx │ │ └── update.tsx │ ├── setupProxy.js │ ├── site-search │ │ ├── form.tsx │ │ ├── index.scss │ │ ├── index.tsx │ │ ├── search-results.scss │ │ ├── search-results.tsx │ │ └── utils.tsx │ ├── sitemap │ │ ├── index.scss │ │ └── index.tsx │ ├── telemetry │ │ ├── constants.ts │ │ ├── generated │ │ │ ├── .gitkeep │ │ │ ├── element.ts │ │ │ ├── navigator.ts │ │ │ ├── page.ts │ │ │ └── pings.ts │ │ ├── glean-context.tsx │ │ ├── interactive-examples.ts │ │ ├── metrics.yaml │ │ ├── pings.yaml │ │ └── sidebar-click.ts │ ├── translations │ │ ├── dashboard │ │ │ └── index.tsx │ │ ├── differences │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ ├── index.scss │ │ ├── index.tsx │ │ └── missing │ │ │ └── index.tsx │ ├── types │ │ ├── notecards.ts │ │ ├── notifications.ts │ │ ├── playground.ts │ │ └── theme.ts │ ├── ui-context.tsx │ ├── ui │ │ ├── README.md │ │ ├── _color-palette.scss │ │ ├── _mixins.scss │ │ ├── _vars.scss │ │ ├── atoms │ │ │ ├── auth-disabled │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── avatar │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── button │ │ │ │ ├── _mixins.scss │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── checkbox │ │ │ │ └── index.tsx │ │ │ ├── container │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── form │ │ │ │ ├── expanding-textarea.tsx │ │ │ │ ├── index.scss │ │ │ │ └── limited-input.tsx │ │ │ ├── icon │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── internal-link │ │ │ │ └── index.tsx │ │ │ ├── limit-banner │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── loading │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── login-link │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── logo │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── modal │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── notification │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── page-content │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── search │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── signout │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── signup-link │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── spinner │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── svg │ │ │ │ ├── bookmark.svg │ │ │ │ ├── darkmode.svg │ │ │ │ ├── mandala.svg │ │ │ │ ├── mdn-plus-features.svg │ │ │ │ ├── offline.svg │ │ │ │ └── premium-features.svg │ │ │ ├── switch │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── themed-picture │ │ │ │ └── index.tsx │ │ │ ├── thumbs │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ └── toast │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ ├── base │ │ │ ├── _mdn.scss │ │ │ ├── _prism.scss │ │ │ ├── _reset.scss │ │ │ ├── _themes.scss │ │ │ └── _typography.scss │ │ ├── molecules │ │ │ ├── a11y-nav │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── auth-container │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── breadcrumbs │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── card │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── document-survey │ │ │ │ ├── index.scss │ │ │ │ ├── index.tsx │ │ │ │ ├── surveys.tsx │ │ │ │ └── utils.ts │ │ │ ├── dropdown │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── get_involved │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── grids │ │ │ │ ├── _document-page.scss │ │ │ │ ├── _standard-page.scss │ │ │ │ └── grids.scss │ │ │ ├── learn-menu │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── main-menu │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── maintenance │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── mandala │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── menu │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── notecards │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── offline-status-bar │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── pagination │ │ │ │ └── index.scss │ │ │ ├── paginator │ │ │ │ └── index.tsx │ │ │ ├── plus-menu │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── quote │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── reference-menu │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── search │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── submenu │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── tabs │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── theme-switcher │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── tools-menu │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ └── user-menu │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ └── organisms │ │ │ ├── article-actions-container │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ │ ├── article-actions │ │ │ ├── bookmark-menu │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── index.scss │ │ │ ├── index.tsx │ │ │ ├── language-menu │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ └── manage-upgrade-dialog │ │ │ │ └── index.tsx │ │ │ ├── footer │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ │ ├── placement │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ │ ├── top-navigation-main │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ │ └── top-navigation │ │ │ ├── index.scss │ │ │ └── index.tsx │ ├── user-context.tsx │ ├── utils.ts │ └── writers-homepage │ │ ├── index.scss │ │ ├── index.tsx │ │ ├── viewed-documents.scss │ │ └── viewed-documents.tsx └── tsconfig.json ├── cloud-function ├── .env-dist ├── .gcloudignore ├── .gitignore ├── Procfile ├── README.md ├── package-lock.json ├── package.json ├── src │ ├── app.ts │ ├── build-canonicals.ts │ ├── build-redirects.ts │ ├── canonicals.ts │ ├── constants.ts │ ├── env.ts │ ├── handlers │ │ ├── handle-stripe-plans.ts │ │ ├── proxy-api.ts │ │ ├── proxy-bsa.ts │ │ ├── proxy-content-assets.ts │ │ ├── proxy-content.ts │ │ ├── proxy-kevel.ts │ │ ├── proxy-pong.ts │ │ ├── proxy-shared-assets.ts │ │ └── proxy-telemetry.ts │ ├── headers.ts │ ├── index.ts │ ├── middlewares │ │ ├── lowercase-pathname.ts │ │ ├── not-found.ts │ │ ├── redirect-enforce-trailing-slash.ts │ │ ├── redirect-fundamental.ts │ │ ├── redirect-leading-slash.ts │ │ ├── redirect-locale.ts │ │ ├── redirect-moved-pages.ts │ │ ├── redirect-non-canonicals.ts │ │ ├── redirect-preferred-locale.ts │ │ ├── redirect-trailing-slash.ts │ │ ├── require-origin.ts │ │ ├── resolve-index-html.ts │ │ └── stripForwardedHostHeaders.ts │ ├── proxy.ts │ ├── stripe-plans │ │ ├── index.ts │ │ ├── prod.ts │ │ └── stage.ts │ └── utils.ts └── tsconfig.json ├── content ├── document-paths.ts ├── document.test.ts ├── document.ts ├── file-attachment.ts ├── githistories.ts ├── index.ts ├── popularities.ts ├── redirect.test.ts ├── redirect.ts ├── translation.ts ├── translations.ts ├── utils.ts └── wikihistories.ts ├── deployer ├── README.md ├── poetry.lock ├── pyproject.toml └── src │ └── deployer │ ├── __init__.py │ ├── constants.py │ ├── main.py │ ├── search │ ├── __init__.py │ ├── models.py │ └── test_search.py │ └── utils.py ├── docs ├── README.md ├── REVIEWING.md ├── architecture.md ├── cli-tool.md ├── conventions.md ├── debugging-sitesearch.md ├── deployments.md ├── envvars.md ├── experiments │ ├── 0001_site-search-x-cache.md │ └── 0002_language-preferredcookie-before.md ├── google-analytics.md ├── kumascript │ ├── README.md │ └── troubleshooting-errors.md ├── npm-packaging.md ├── npm-releases.md ├── popularities.md ├── proxying.md ├── signingin.md ├── spas.md └── typescript.md ├── filecheck ├── checker.ts └── cli.ts ├── jest.config.json ├── kumascript ├── AUTHORS ├── README.md ├── index.ts ├── macros │ ├── APIListAlpha.ejs │ ├── APIRef.ejs │ ├── AccessibilitySidebar.ejs │ ├── AddonSidebar.ejs │ ├── AddonSidebarMain.ejs │ ├── AvailableInWorkers.ejs │ ├── CSP.ejs │ ├── CSSAnimatedProperties.ejs │ ├── CSSInfo.ejs │ ├── CSSRef.ejs │ ├── CSSSyntax.ejs │ ├── CSS_Ref.ejs │ ├── Compat.ejs │ ├── DOMxRef.ejs │ ├── DefaultAPISidebar.ejs │ ├── Deprecated_Header.ejs │ ├── Deprecated_Inline.ejs │ ├── EmbedGHLiveSample.ejs │ ├── EmbedInteractiveExample.ejs │ ├── EmbedLiveSample.ejs │ ├── EmbedYouTube.ejs │ ├── ExperimentalBadge.ejs │ ├── FirefoxSidebar.ejs │ ├── Firefox_for_developers.ejs │ ├── GamesSidebar.ejs │ ├── Glossary.ejs │ ├── GlossaryDisambiguation.ejs │ ├── GlossarySidebar.ejs │ ├── HTMLElement.ejs │ ├── HTMLSidebar.ejs │ ├── HTTPMethod.ejs │ ├── HTTPSidebar.ejs │ ├── HTTPStatus.ejs │ ├── InheritanceDiagram.ejs │ ├── JSFiddleEmbed.ejs │ ├── JSRef.ejs │ ├── JsSidebar.ejs │ ├── LandingPageListSubpages.ejs │ ├── LearnSidebar.ejs │ ├── ListGroups.ejs │ ├── ListSubpages.ejs │ ├── ListSubpagesForSidebar.ejs │ ├── LiveSampleLink.ejs │ ├── LiveSampleURL.ejs │ ├── MDNSidebar.ejs │ ├── MathMLElement.ejs │ ├── MathMLRef.ejs │ ├── Next.ejs │ ├── NextMenu.ejs │ ├── Non-standard_Header.ejs │ ├── Non-standard_Inline.ejs │ ├── NonStandardBadge.ejs │ ├── PWASidebar.ejs │ ├── Previous.ejs │ ├── PreviousMenu.ejs │ ├── PreviousMenuNext.ejs │ ├── PreviousNext.ejs │ ├── QuickLinksWithSubpages.ejs │ ├── RFC.ejs │ ├── ReadOnlyInline.ejs │ ├── SVGAttr.ejs │ ├── SVGElement.ejs │ ├── SVGRef.ejs │ ├── SeeCompatTable.ejs │ ├── Specifications.ejs │ ├── SubpagesWithSummaries.ejs │ ├── WebAssemblySidebar.ejs │ ├── WebExtAPIRef.ejs │ ├── WebExtAPISidebar.ejs │ ├── WebExtAllCompatTables.ejs │ ├── WebExtAllExamples.ejs │ ├── WebExtExamples.ejs │ ├── XsltRef.ejs │ ├── XsltSidebar.ejs │ ├── cssxref.ejs │ ├── event.ejs │ ├── experimental_inline.ejs │ ├── httpheader.ejs │ ├── js_property_attributes.ejs │ ├── jsxref.ejs │ ├── no_tag_omission.ejs │ ├── optional_inline.ejs │ ├── page.ejs │ ├── propertiesbox.ejs │ ├── secureContext_header.ejs │ ├── secureContext_inline.ejs │ ├── svginfo.ejs │ ├── unimplementedGeneric.ejs │ ├── xref_csscomputed.ejs │ ├── xref_cssinherited.ejs │ └── xref_cssinitial.ejs ├── src │ ├── api │ │ ├── mdn.ts │ │ ├── page.ts │ │ ├── util.ts │ │ ├── web.ts │ │ └── wiki.ts │ ├── environment.ts │ ├── errors.ts │ ├── info.ts │ ├── lib │ │ ├── badges.ts │ │ └── css-syntax.ts │ ├── live-sample.ts │ ├── parser.js │ ├── parser.pegjs │ ├── render.ts │ └── templates.ts └── tests │ ├── environment.test.ts │ ├── fixtures │ ├── render │ │ ├── macros │ │ │ ├── asyncMacro.ejs │ │ │ ├── bar.ejs │ │ │ ├── echo.ejs │ │ │ ├── env.ejs │ │ │ ├── includeError.ejs │ │ │ ├── syntax.ejs │ │ │ ├── throw.ejs │ │ │ └── undefined.ejs │ │ ├── macros1.txt │ │ ├── syntax1 │ │ ├── syntax2 │ │ ├── syntax3 │ │ ├── syntax4 │ │ ├── testcase1 │ │ │ ├── input │ │ │ ├── macros │ │ │ │ ├── PlainText.ejs │ │ │ │ └── test.ejs │ │ │ └── output │ │ ├── testcase2 │ │ │ ├── input │ │ │ ├── macros │ │ │ │ ├── Alpha_Macro_123.ejs │ │ │ │ ├── Bracepocalypse.ejs │ │ │ │ ├── HelloWorld.ejs │ │ │ │ ├── MacroUsingParams.ejs │ │ │ │ ├── ParenTastic.ejs │ │ │ │ ├── macrowithjson.ejs │ │ │ │ ├── multi-line-macro.ejs │ │ │ │ └── 頁尾附註.ejs │ │ │ ├── output │ │ │ ├── output_selective_remove │ │ │ └── output_selective_render │ │ ├── testcase3 │ │ │ ├── input │ │ │ ├── macros │ │ │ │ └── jsonify.ejs │ │ │ └── output │ │ └── testcase4 │ │ │ ├── input │ │ │ ├── macros │ │ │ └── jsonify.ejs │ │ │ └── output │ ├── server │ │ ├── documents │ │ │ ├── autorequire-expected.txt │ │ │ ├── autorequire.txt │ │ │ ├── document1-expected.txt │ │ │ ├── document1.txt │ │ │ ├── document2-expected.txt │ │ │ ├── document2.txt │ │ │ ├── library-test-expected.txt │ │ │ ├── library-test.txt │ │ │ ├── memcache-expected.txt │ │ │ ├── memcache.txt │ │ │ ├── request-variables-expected.txt │ │ │ ├── request-variables.txt │ │ │ ├── require-test-expected.txt │ │ │ ├── require-test.txt │ │ │ ├── template-exec-expected.txt │ │ │ ├── template-exec.txt │ │ │ ├── 시작하기-expected.txt │ │ │ └── 시작하기.txt │ │ ├── homepage-expected.html │ │ ├── macros-expected.json │ │ └── macros │ │ │ ├── autorequire-lib1.ejs │ │ │ ├── autorequire-used.ejs │ │ │ ├── broken2.ejs │ │ │ ├── broken3.ejs │ │ │ ├── json.ejs │ │ │ ├── json_unescaped.ejs │ │ │ ├── library1-used.ejs │ │ │ ├── library1.ejs │ │ │ ├── memcache-user.ejs │ │ │ ├── reqlocale.ejs │ │ │ ├── require-used.ejs │ │ │ ├── reqvar-json.ejs │ │ │ ├── reqvar.ejs │ │ │ ├── t1.ejs │ │ │ ├── t2.ejs │ │ │ ├── t3.ejs │ │ │ ├── template-exec-template.ejs │ │ │ └── template-exec.ejs │ └── templates │ │ ├── duplicate_macros │ │ ├── dup │ │ │ ├── test.ejs │ │ │ └── test.json │ │ └── test.ejs │ │ ├── empty_macro_dir │ │ └── README │ │ └── macros │ │ ├── Test2.ejs │ │ ├── async.ejs │ │ └── test1.ejs │ ├── index.test.ts │ ├── lib │ ├── __snapshots__ │ │ └── css-syntax.test.ts.snap │ └── css-syntax.test.ts │ ├── macros.test.ts │ ├── macros │ ├── Compat.test.ts │ ├── DefaultAPISidebar.test.ts │ ├── Deprecated.test.ts │ ├── EmbedInteractiveExample.test.ts │ ├── EmbedLiveSample.test.ts │ ├── HTTPSidebar.test.ts │ ├── ListGroups.test.ts │ ├── LiveSampleURL.test.ts │ ├── Specifications.test.ts │ ├── addonsidebar.test.ts │ ├── apiref.test.ts │ ├── cssxref.test.ts │ ├── firefoxsidebar.test.ts │ ├── fixtures │ │ ├── apiref │ │ │ ├── commonl10n.json │ │ │ ├── groupdata.json │ │ │ ├── interfacedata.json │ │ │ ├── interfacedata_no_entries.json │ │ │ └── subpages.json │ │ ├── compat │ │ │ ├── alternative_name.json │ │ │ ├── content_areas.json │ │ │ ├── feature_labels.json │ │ │ ├── flags.json │ │ │ ├── notes.json │ │ │ ├── prefixes.json │ │ │ └── support_variations.json │ │ ├── defaultapisidebar │ │ │ ├── commonl10n.json │ │ │ ├── groupdata.json │ │ │ └── pages.json │ │ ├── documentData1.json │ │ ├── documentData2.json │ │ └── listgroups │ │ │ └── groupdata.json │ ├── gamessidebar.test.ts │ ├── httpheader.test.ts │ ├── jsxref.test.ts │ ├── page-api.test.ts │ ├── svgattr.test.ts │ ├── svginfo.test.ts │ ├── utils.test.ts │ ├── utils.ts │ └── wiki-api.test.ts │ ├── parser.test.ts │ ├── render.test.ts │ └── templates.test.ts ├── libs ├── constants │ ├── index.d.ts │ ├── index.js │ ├── index.test.ts │ └── package.json ├── env │ ├── index.d.ts │ ├── index.js │ └── package.json ├── fundamental-redirects │ ├── index.d.ts │ ├── index.js │ └── package.json ├── l10n │ └── l10n.ts ├── languages │ ├── index.d.ts │ ├── index.js │ └── package.json ├── locale-utils │ ├── index.d.ts │ ├── index.js │ ├── package.json │ └── yarn.lock ├── play │ ├── index.d.ts │ ├── index.js │ ├── package-lock.json │ ├── package.json │ └── tsconfig.json ├── pong │ ├── cc2ip.d.ts │ ├── cc2ip.js │ ├── coding.d.ts │ ├── coding.js │ ├── image.d.ts │ ├── image.js │ ├── index.d.ts │ ├── index.js │ ├── package.json │ ├── pong.d.ts │ ├── pong.js │ ├── pong2.d.ts │ ├── pong2.js │ ├── types.d.ts │ ├── validate-cc2ip.js │ └── yarn.lock ├── slug-utils │ ├── index.d.ts │ ├── index.js │ ├── package.json │ └── yarn.lock └── types │ ├── blog.ts │ ├── core.ts │ ├── curriculum.ts │ ├── document.ts │ ├── hydration.ts │ └── package.json ├── lint-staged.config.js ├── markdown ├── .gitignore ├── h2m │ └── index.ts ├── index.ts ├── localizations │ ├── de.json │ ├── en-US.json │ ├── es.json │ ├── fr.json │ ├── ja.json │ ├── ko.json │ ├── pl.json │ ├── pt-BR.json │ ├── ru.json │ ├── zh-CN.json │ └── zh-TW.json ├── m2h │ ├── cli.ts │ ├── handlers │ │ ├── code.ts │ │ ├── dl.ts │ │ └── index.ts │ └── index.ts └── utils │ └── index.ts ├── mdn-web-docs.svg ├── package.json ├── playwright.config.js ├── release-please-config.json ├── scripts ├── ai-help-macros.ts ├── ai-help.sql ├── developing.sh ├── lint.sh ├── reorder-search-index.mjs └── testing.sh ├── server ├── cli.ts ├── document.ts ├── fake-v1-api.ts ├── filename.ts ├── flaws.ts ├── index.ts ├── middlewares.ts ├── search-index.ts ├── static.ts ├── translations.ts └── types.ts ├── ssr ├── .gitignore ├── ga.ts ├── include.d.ts ├── index.ts ├── meta-description.ts ├── modules.d.ts ├── mozilla.dnthelper.min.js ├── prepare.ts ├── print.css ├── render.tsx ├── theme.js ├── tsconfig.json └── webpack.config.js ├── testing ├── README.md ├── content │ └── files │ │ ├── en-us │ │ ├── _redirects.txt │ │ ├── _wikihistory.json │ │ ├── glossary │ │ │ └── bézier_curve │ │ │ │ ├── cubic_bézier_curves_with_grid.png │ │ │ │ └── index.html │ │ ├── learn │ │ │ ├── css │ │ │ │ └── css_layout │ │ │ │ │ └── introduction │ │ │ │ │ ├── flex │ │ │ │ │ ├── index.html │ │ │ │ │ └── stuff │ │ │ │ │ │ └── index.html │ │ │ │ │ ├── grid │ │ │ │ │ └── index.html │ │ │ │ │ └── index.html │ │ │ └── some_code │ │ │ │ └── index.html │ │ ├── markdown │ │ │ ├── index.md │ │ │ └── tool │ │ │ │ └── m2h │ │ │ │ ├── expected.html │ │ │ │ └── index.md │ │ └── web │ │ │ ├── api │ │ │ ├── blob │ │ │ │ └── index.html │ │ │ ├── index.html │ │ │ └── page_visibility_api │ │ │ │ └── index.html │ │ │ ├── badbcdqueries │ │ │ └── index.html │ │ │ ├── bar │ │ │ └── index.html │ │ │ ├── bcd_table_extraction │ │ │ └── index.html │ │ │ ├── brokenlinks │ │ │ ├── broken_http_link │ │ │ │ └── index.html │ │ │ ├── index.html │ │ │ ├── self_links │ │ │ │ └── index.html │ │ │ └── without_locale_prefix │ │ │ │ └── index.html │ │ │ ├── brokenlinks_markdown │ │ │ ├── broken_http_link │ │ │ │ └── index.md │ │ │ ├── index.md │ │ │ ├── self_links │ │ │ │ └── index.md │ │ │ └── without_locale_prefix │ │ │ │ └── index.md │ │ │ ├── brokenlinks_repeats │ │ │ └── index.html │ │ │ ├── check_notecards │ │ │ └── index.html │ │ │ ├── css │ │ │ └── number │ │ │ │ └── index.html │ │ │ ├── donttranslatethese │ │ │ └── index.html │ │ │ ├── duplicate_ids │ │ │ └── index.html │ │ │ ├── embeddable │ │ │ ├── index.html │ │ │ └── legacy │ │ │ │ └── index.md │ │ │ ├── empty_image │ │ │ └── index.html │ │ │ ├── externallinks │ │ │ └── index.html │ │ │ ├── fixable_flaws │ │ │ ├── bad_pre_tags │ │ │ │ └── index.html │ │ │ ├── deprecated_macros │ │ │ │ └── index.html │ │ │ ├── images │ │ │ │ ├── fixable.png │ │ │ │ └── index.html │ │ │ └── index.html │ │ │ ├── foo │ │ │ ├── index.html │ │ │ └── screenshot.png │ │ │ ├── fubar │ │ │ └── index.html │ │ │ ├── heading_links │ │ │ └── index.html │ │ │ ├── homepage_links │ │ │ └── index.html │ │ │ ├── html │ │ │ └── element │ │ │ │ └── a │ │ │ │ └── index.html │ │ │ ├── html_headings │ │ │ └── index.html │ │ │ ├── images │ │ │ ├── bad_src │ │ │ │ ├── actuallynota.png │ │ │ │ ├── actuallynota.svg │ │ │ │ ├── empty.gif │ │ │ │ └── index.md │ │ │ ├── florian.png │ │ │ ├── images_in_samples │ │ │ │ ├── image.png │ │ │ │ ├── index.html │ │ │ │ └── pic.gif │ │ │ ├── index.html │ │ │ ├── linked_to │ │ │ │ ├── dino.svg │ │ │ │ └── index.html │ │ │ ├── repeated_external_images │ │ │ │ └── index.html │ │ │ ├── srcless │ │ │ │ └── index.html │ │ │ └── styled │ │ │ │ └── index.html │ │ │ ├── index.html │ │ │ ├── interactiveexample │ │ │ └── index.html │ │ │ ├── javascript │ │ │ └── reference │ │ │ │ ├── global_objects │ │ │ │ └── boolean │ │ │ │ │ └── index.html │ │ │ │ └── strict_mode │ │ │ │ └── index.html │ │ │ ├── not_lowercase_anchors │ │ │ └── index.html │ │ │ ├── sectioning_headers │ │ │ └── index.html │ │ │ ├── seo_summarized │ │ │ └── index.html │ │ │ ├── spec_section_extraction │ │ │ └── index.html │ │ │ ├── unsafe_html │ │ │ └── index.html │ │ │ └── wrong_xref_macro │ │ │ └── index.html │ │ ├── jsondata │ │ ├── GroupData.json │ │ ├── InterfaceData.json │ │ ├── L10n-CSS.json │ │ ├── L10n-Common.json │ │ ├── L10n-JavaScript.json │ │ ├── L10n-SVG.json │ │ ├── README.md │ │ ├── SVGData.json │ │ └── SpecData.json │ │ └── popularities.json ├── integration │ ├── README.md │ ├── conftest.py │ ├── headless │ │ ├── __init__.py │ │ ├── map_301.py │ │ ├── test_cdn.py │ │ ├── test_endpoints.py │ │ ├── test_redirects.py │ │ └── test_robots.py │ ├── poetry.lock │ ├── pyproject.toml │ └── utils │ │ ├── __init__.py │ │ └── urls.py ├── scripts │ └── functional-test.sh ├── tests │ ├── csp.test.ts │ ├── destructive.test.ts │ ├── developing.spec.ts │ ├── filecheck.test.ts │ ├── filechecker │ │ ├── samplefiles-html │ │ │ ├── index.html │ │ │ ├── onhandler.svg │ │ │ ├── orphan.png │ │ │ ├── png.jpeg │ │ │ ├── script.svg │ │ │ └── zero.gif │ │ └── samplefiles-md │ │ │ ├── circle.svg │ │ │ ├── index.md │ │ │ └── orphan.png │ ├── headless.auth.spec.ts │ ├── headless.index.spec.ts │ ├── headless.plus.bookmarks.spec.ts │ ├── headless.search.spec.ts │ ├── headless.sitesearch.spec.ts │ ├── index.test.ts │ ├── offline-db.test.ts │ └── redirects.test.ts └── translated-content │ └── files │ ├── fr │ └── web │ │ ├── embeddable │ │ └── index.html │ │ ├── foo │ │ └── index.html │ │ └── spec_section_extraction │ │ └── index.html │ ├── zh-cn │ └── web │ │ └── foo │ │ └── index.md │ └── zh-tw │ └── web │ └── foo │ └── index.html ├── tool ├── README.md ├── cli.ts ├── macro-usage-report.ts ├── popularities.ts ├── sync-translated-content.ts └── whatsdeployed.ts ├── tsconfig.dist.json ├── tsconfig.json ├── type-fixes └── front-matter.ts └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | 14 | [*.py] 15 | indent_size = 4 16 | -------------------------------------------------------------------------------- /.env-dist: -------------------------------------------------------------------------------- 1 | CONTENT_ROOT=../content/files 2 | #CONTENT_TRANSLATED_ROOT=../translated-content/files 3 | #CONTRIBUTOR_SPOTLIGHT_ROOT=../mdn-contributor-spotlight/contributors 4 | #GENERIC_CONTENT_ROOT=../generic-content/files 5 | 6 | REACT_APP_DEV_MODE=true 7 | 8 | # See documentation in docs/envvars.md for more information about this 9 | #BUILD_FLAW_LEVELS=broken_links:error, macros:ignore 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | *.min.js 2 | client/build/ 3 | dist/ 4 | ssr/dist/ 5 | libs/ 6 | client/public/service-worker.js 7 | client/public/ 8 | client/src/document/*.js 9 | cloud-function/src/internal/ 10 | cloud-function/**/*.js 11 | filecheck/*.js 12 | mdn/content/ 13 | tool/*.js 14 | bins/*.mjs 15 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | # Black recommends 88-char lines and ignoring the following lints: 3 | # - E203 - whitespace before ':' 4 | # - E501 - line too long 5 | # - W503 - line break before binary operator 6 | max-line-length=88 7 | ignore = E203, E501, W503 8 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | build/** linguist-generated=false 2 | 3 | -------------------------------------------------------------------------------- /.github/workflows/glean-probe-scraper.yml: -------------------------------------------------------------------------------- 1 | name: Glean probe-scraper 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | glean-probe-scraper: 11 | if: github.repository == 'mdn/yari' 12 | uses: mozilla/probe-scraper/.github/workflows/glean.yaml@main 13 | -------------------------------------------------------------------------------- /.github/workflows/labeler.yml: -------------------------------------------------------------------------------- 1 | name: "Pull Request Labeler" 2 | on: 3 | - pull_request_target 4 | 5 | jobs: 6 | triage: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/labeler@v5.0.0 10 | with: 11 | repo-token: "${{ secrets.GITHUB_TOKEN }}" 12 | -------------------------------------------------------------------------------- /.github/workflows/mark-as-idle-issues-pr.yml: -------------------------------------------------------------------------------- 1 | name: mark-as-idle 2 | on: 3 | schedule: 4 | - cron: "49 11,23 * * *" 5 | 6 | jobs: 7 | idle-issues-prs: 8 | uses: mdn/workflows/.github/workflows/idle.yml@main 9 | with: 10 | target-repo: "mdn/yari" 11 | -------------------------------------------------------------------------------- /.github/workflows/new-issues.yml: -------------------------------------------------------------------------------- 1 | name: "Mark new issues with needs-triage label" 2 | on: 3 | issues: 4 | types: 5 | - reopened 6 | - opened 7 | 8 | jobs: 9 | label-new-issues: 10 | uses: mdn/workflows/.github/workflows/new-issues.yml@main 11 | with: 12 | target-repo: "mdn/yari" 13 | -------------------------------------------------------------------------------- /.github/workflows/pr-rebase-needed.yml: -------------------------------------------------------------------------------- 1 | name: "PR Needs Rebase" 2 | 3 | on: 4 | push: 5 | pull_request_target: 6 | types: [synchronize] 7 | 8 | jobs: 9 | label-rebase-needed: 10 | uses: mdn/workflows/.github/workflows/pr-rebase-needed.yml@main 11 | with: 12 | target-repo: "mdn/yari" 13 | secrets: 14 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 15 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | yarn install --ignore-scripts && yarn lint-staged 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v20 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "overrides": [ 4 | { 5 | "files": ["**/package.json"], 6 | "options": { 7 | "plugins": ["prettier-plugin-packagejson"] 8 | } 9 | }, 10 | { 11 | "files": ["**/*.md"], 12 | "options": { 13 | "proseWrap": "always" 14 | } 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.release-please-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | ".": "4.10.1" 3 | } 4 | -------------------------------------------------------------------------------- /.stylelintignore: -------------------------------------------------------------------------------- 1 | **/*.css 2 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Community Participation Guidelines 2 | 3 | This repository is governed by Mozilla's code of conduct and etiquette 4 | guidelines. For more details, please read the 5 | [Mozilla Community Participation Guidelines](https://www.mozilla.org/about/governance/policies/participation/). 6 | 7 | ## How to Report 8 | 9 | For more information on how to report violations of the Community Participation 10 | Guidelines, please read our 11 | [How to Report](https://www.mozilla.org/about/governance/policies/participation/reporting/) 12 | page. 13 | -------------------------------------------------------------------------------- /Procfile.dev: -------------------------------------------------------------------------------- 1 | server: yarn start:server 2 | type-check: cd client && tsc --noEmit --watch 3 | web: yarn start:client 4 | ssr: yarn watch:ssr 5 | -------------------------------------------------------------------------------- /Procfile.rari: -------------------------------------------------------------------------------- 1 | server: yarn start:rari-server 2 | web: yarn start:client 3 | -------------------------------------------------------------------------------- /Procfile.rari.dev: -------------------------------------------------------------------------------- 1 | server: yarn start:rari-server 2 | type-check: cd client && tsc --noEmit --watch 3 | web: yarn start:client 4 | ssr: yarn watch:ssr 5 | -------------------------------------------------------------------------------- /Procfile.start: -------------------------------------------------------------------------------- 1 | server: yarn start:server 2 | web: yarn start:client 3 | -------------------------------------------------------------------------------- /assets/nonprod/robots.txt: -------------------------------------------------------------------------------- 1 | User-Agent: * 2 | 3 | Disallow: / 4 | -------------------------------------------------------------------------------- /assets/prod/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Sitemap: https://developer.mozilla.org/sitemap.xml 3 | 4 | Disallow: /api/ 5 | Disallow: /*/files/ 6 | Disallow: /media 7 | -------------------------------------------------------------------------------- /build/build-blog.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import { 3 | buildAuthors, 4 | buildBlogFeed, 5 | buildBlogIndex, 6 | buildBlogPosts, 7 | buildBlogSitemap, 8 | } from "./blog.js"; 9 | 10 | await buildBlogIndex({ verbose: true }); 11 | await buildBlogPosts({ verbose: true }); 12 | await buildAuthors({ verbose: true }); 13 | await buildBlogFeed({ verbose: true }); 14 | await buildBlogSitemap({ verbose: true }); 15 | -------------------------------------------------------------------------------- /build/build-curriculum.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import { buildCurriculum, buildCurriculumSitemap } from "./curriculum.js"; 3 | 4 | await buildCurriculum({ verbose: true }); 5 | await buildCurriculumSitemap({ verbose: true }); 6 | -------------------------------------------------------------------------------- /build/flaws/sections.ts: -------------------------------------------------------------------------------- 1 | import { FLAW_LEVELS } from "../../libs/constants/index.js"; 2 | 3 | export function injectSectionFlaws(doc, flaws, options) { 4 | if (!flaws.length) { 5 | return; 6 | } 7 | 8 | const level = options.flawLevels.get("sectioning"); 9 | if (level === FLAW_LEVELS.ERROR) { 10 | throw new Error(flaws.join(" ")); 11 | } else if (level === FLAW_LEVELS.WARN) { 12 | doc.flaws.sectioning = flaws.map((explanation, i) => { 13 | const id = `sectioning${i + 1}`; 14 | return { id, explanation }; 15 | }); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /build/resolve-bcd.ts: -------------------------------------------------------------------------------- 1 | import bcdUntyped from "@mdn/browser-compat-data/forLegacyNode"; 2 | import { CompatData, Identifier } from "@mdn/browser-compat-data/types"; 3 | 4 | const bcd = bcdUntyped as CompatData; 5 | 6 | export function packageBCD(query) { 7 | const data: Identifier = query.split(".").reduce((prev, curr) => { 8 | return prev && Object.prototype.hasOwnProperty.call(prev, curr) 9 | ? prev[curr] 10 | : undefined; 11 | }, bcd); 12 | return { browsers: bcd.browsers, data }; 13 | } 14 | -------------------------------------------------------------------------------- /build/sentry.ts: -------------------------------------------------------------------------------- 1 | import { init, captureConsoleIntegration, NodeOptions } from "@sentry/node"; 2 | 3 | export function initSentry( 4 | dsn: string, 5 | options?: Omit 6 | ) { 7 | init({ 8 | dsn, 9 | environment: process.env.SENTRY_ENVIRONMENT || "dev", 10 | integrations: [ 11 | captureConsoleIntegration({ levels: ["warn", "error", "assert"] }), 12 | ], 13 | tracesSampleRate: 1.0, 14 | ...options, 15 | }); 16 | } 17 | -------------------------------------------------------------------------------- /build/wrap-tables.ts: -------------------------------------------------------------------------------- 1 | // Wraps tables in a scrollable figure to avoid overlapping with the TOC sidebar. 2 | // Before: ...
3 | // After:
...
4 | import * as cheerio from "cheerio"; 5 | 6 | export function wrapTables($: cheerio.CheerioAPI) { 7 | const figure = $('
'); 8 | $("table, math[display=block]").wrap(figure); 9 | } 10 | -------------------------------------------------------------------------------- /client/config/jest/babelTransform.js: -------------------------------------------------------------------------------- 1 | import { createRequire } from "node:module"; 2 | import babelJest from "babel-jest"; 3 | 4 | const require = createRequire(import.meta.url); 5 | 6 | export default babelJest.createTransformer({ 7 | presets: [ 8 | [ 9 | require.resolve("babel-preset-react-app"), 10 | { 11 | runtime: "automatic", 12 | }, 13 | ], 14 | ], 15 | babelrc: false, 16 | configFile: false, 17 | }); 18 | -------------------------------------------------------------------------------- /client/config/jest/cssTransform.js: -------------------------------------------------------------------------------- 1 | // This is a custom Jest transformer turning style imports into empty objects. 2 | // http://facebook.github.io/jest/docs/en/webpack.html 3 | 4 | const transform = { 5 | process() { 6 | return { code: "module.exports = {};" }; 7 | }, 8 | getCacheKey() { 9 | // The output is always the same. 10 | return "cssTransform"; 11 | }, 12 | }; 13 | 14 | export default transform; 15 | -------------------------------------------------------------------------------- /client/config/jest/rawTransform.js: -------------------------------------------------------------------------------- 1 | // This is a custom Jest transformer turning raw imports into empty strings. 2 | // http://facebook.github.io/jest/docs/en/webpack.html 3 | 4 | const transform = { 5 | process() { 6 | return { code: "module.exports = '';" }; 7 | }, 8 | getCacheKey() { 9 | // The output is always the same. 10 | return "rawTransform"; 11 | }, 12 | }; 13 | 14 | export default transform; 15 | -------------------------------------------------------------------------------- /client/config/webpack/persistentCache/createEnvironmentHash.js: -------------------------------------------------------------------------------- 1 | import { createHash } from "node:crypto"; 2 | 3 | const createEnvironmentHash = (env) => { 4 | const hash = createHash("md5"); 5 | hash.update(JSON.stringify(env)); 6 | 7 | return hash.digest("hex"); 8 | }; 9 | 10 | export default createEnvironmentHash; 11 | -------------------------------------------------------------------------------- /client/jest-setup.ts: -------------------------------------------------------------------------------- 1 | //globalThis.IS_REACT_ACT_ENVIRONMENT = true; 2 | 3 | if (!globalThis.TextEncoder || !globalThis.TextDecoder) { 4 | // eslint-disable-next-line @typescript-eslint/no-var-requires 5 | const { TextDecoder, TextEncoder } = require("node:util"); 6 | globalThis.TextEncoder = TextEncoder; 7 | globalThis.TextDecoder = TextDecoder; 8 | } 9 | -------------------------------------------------------------------------------- /client/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/apple-touch-icon.png -------------------------------------------------------------------------------- /client/public/assets/afree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/afree.png -------------------------------------------------------------------------------- /client/public/assets/ai-help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/ai-help.png -------------------------------------------------------------------------------- /client/public/assets/ai-help/ai-help_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/ai-help/ai-help_dark.png -------------------------------------------------------------------------------- /client/public/assets/ai-help/ai-help_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/ai-help/ai-help_light.png -------------------------------------------------------------------------------- /client/public/assets/app-dl-ms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/app-dl-ms.png -------------------------------------------------------------------------------- /client/public/assets/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/avatar.png -------------------------------------------------------------------------------- /client/public/assets/collections.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/collections.png -------------------------------------------------------------------------------- /client/public/assets/curriculum/curriculum-topic-standards.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | -------------------------------------------------------------------------------- /client/public/assets/mdn_contributor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/mdn_contributor.png -------------------------------------------------------------------------------- /client/public/assets/notifications_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/notifications_light.png -------------------------------------------------------------------------------- /client/public/assets/observatory/pass-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/public/assets/observatory/results-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | -------------------------------------------------------------------------------- /client/public/assets/observatory/stars.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/public/assets/observatory/tooltip-arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /client/public/assets/offline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/offline.png -------------------------------------------------------------------------------- /client/public/assets/playground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/playground.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/ai-help/code-examples-playground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/ai-help/code-examples-playground.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/ai-help/code-examples-queue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/ai-help/code-examples-queue.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/ai-help/example-question-answering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/ai-help/example-question-answering.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/ai-help/example-question-editing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/ai-help/example-question-editing.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/ai-help/history-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/ai-help/history-banner.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/ai-help/history-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/ai-help/history-settings.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/ai-help/issue-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/ai-help/issue-template.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/ai-help/login-signup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/ai-help/login-signup.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/ai-help/rate-answers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/ai-help/rate-answers.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/ai-help/report-feedback.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/ai-help/report-feedback.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/collections-dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/collections-dashboard.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/desktop-collections-dashboard-delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/desktop-collections-dashboard-delete.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/desktop-collections-delete-fva.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/desktop-collections-delete-fva.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/desktop-collections-edit-dialog-add-note.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/desktop-collections-edit-dialog-add-note.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/desktop-collections-edit-dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/desktop-collections-edit-dialog.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/desktop-collections-edit-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/desktop-collections-edit-menu.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/desktop-collections-filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/desktop-collections-filter.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/desktop-collections-fva.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/desktop-collections-fva.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/desktop-collections-sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/desktop-collections-sort.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/desktop-collections-three-dot-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/desktop-collections-three-dot-menu.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/desktop-collections-undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/desktop-collections-undo.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/desktop-collections-user-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/desktop-collections-user-menu.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/desktop-page-add-note.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/desktop-page-add-note.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/desktop-page-dialog-save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/desktop-page-dialog-save.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/desktop-page-open-dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/desktop-page-open-dialog.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/desktop-remove-saved-delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/desktop-remove-saved-delete.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/desktop-remove-saved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/desktop-remove-saved.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/desktop-saving-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/desktop-saving-page.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/mobile-add-note.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/mobile-add-note.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/mobile-burger-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/mobile-burger-menu.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/mobile-collections-dashboard-delete-entry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/mobile-collections-dashboard-delete-entry.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/mobile-collections-dashboard-edit-entry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/mobile-collections-dashboard-edit-entry.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/mobile-collections-dashboard-edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/mobile-collections-dashboard-edit.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/mobile-collections-dashboard-three-dots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/mobile-collections-dashboard-three-dots.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/mobile-collections-dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/mobile-collections-dashboard.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/mobile-collections-delete-entry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/mobile-collections-delete-entry.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/mobile-collections-fva-undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/mobile-collections-fva-undo.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/mobile-collections-menu-item.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/mobile-collections-menu-item.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/mobile-collections-undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/mobile-collections-undo.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/mobile-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/mobile-menu.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/mobile-open-article-actions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/mobile-open-article-actions.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/mobile-plus-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/mobile-plus-menu.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/mobile-save-page-step-one.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/mobile-save-page-step-one.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/mobile-save-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/mobile-save-page.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/collections/mobile-saved-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/collections/mobile-saved-page.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/notifications/access-notifications-from-main-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/notifications/access-notifications-from-main-menu.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/notifications/bulk-unwatch-dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/notifications/bulk-unwatch-dashboard.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/notifications/mobile-notifications-user-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/notifications/mobile-notifications-user-menu.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/notifications/notifications-user-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/notifications/notifications-user-menu.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/notifications/star-notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/notifications/star-notification.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/notifications/unwatch-dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/notifications/unwatch-dashboard.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/notifications/unwatch-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/notifications/unwatch-page.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/notifications/watch-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/notifications/watch-list.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/notifications/watch-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/notifications/watch-page.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/offline/desktop-offline-clear-data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/offline/desktop-offline-clear-data.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/offline/desktop-offline-enable-auto-update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/offline/desktop-offline-enable-auto-update.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/offline/desktop-offline-enable-offline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/offline/desktop-offline-enable-offline.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/offline/desktop-offline-manual-update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/offline/desktop-offline-manual-update.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/offline/desktop-offline-user-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/offline/desktop-offline-user-menu.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/playground/playground-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/playground/playground-example.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/playground/playground-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/playground/playground-menu.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/playground/playground-sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/playground/playground-sample.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/updates/collections.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/updates/collections.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/updates/updates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/updates/updates.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/updates/updates_bcd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/updates/updates_bcd.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/updates/updates_collection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/updates/updates_collection.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/updates/updates_filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/updates/updates_filter.png -------------------------------------------------------------------------------- /client/public/assets/plus-docs/updates/updates_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/plus-docs/updates/updates_search.png -------------------------------------------------------------------------------- /client/public/assets/updates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/assets/updates.png -------------------------------------------------------------------------------- /client/public/favicon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/favicon-128x128.png -------------------------------------------------------------------------------- /client/public/favicon-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/favicon-150x150.png -------------------------------------------------------------------------------- /client/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/favicon-16x16.png -------------------------------------------------------------------------------- /client/public/favicon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/favicon-192x192.png -------------------------------------------------------------------------------- /client/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/favicon-32x32.png -------------------------------------------------------------------------------- /client/public/favicon-48x48-flawless.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/favicon-48x48-flawless.png -------------------------------------------------------------------------------- /client/public/favicon-48x48-flaws-fixable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/favicon-48x48-flaws-fixable.png -------------------------------------------------------------------------------- /client/public/favicon-48x48-flaws.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/favicon-48x48-flaws.png -------------------------------------------------------------------------------- /client/public/favicon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/favicon-48x48.png -------------------------------------------------------------------------------- /client/public/favicon-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/favicon-512x512.png -------------------------------------------------------------------------------- /client/public/favicon-64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/favicon-64x64.png -------------------------------------------------------------------------------- /client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/favicon.ico -------------------------------------------------------------------------------- /client/public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | MDN Logo 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 15 | MDN Web Docs 16 | 17 | 18 |
19 | 20 | 21 | -------------------------------------------------------------------------------- /client/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "MDN", 3 | "name": "MDN Web Docs", 4 | "icons": [ 5 | { 6 | "src": "/favicon-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/favicon-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "start_url": ".", 17 | "display": "standalone", 18 | "theme_color": "#000000", 19 | "background_color": "#ffffff" 20 | } 21 | -------------------------------------------------------------------------------- /client/public/mdn-social-share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/public/mdn-social-share.png -------------------------------------------------------------------------------- /client/public/opensearch.xml: -------------------------------------------------------------------------------- 1 | 2 | MDN Web Docs 3 | Search the MDN Web Docs 4 | UTF-8 5 | https://developer.mozilla.org/favicon.ico 6 | 7 | 8 | -------------------------------------------------------------------------------- /client/pwa/README.md: -------------------------------------------------------------------------------- 1 | # MDN Offline 2 | 3 | This is MDN's ServiceWorker that powers MDN Offline. It's not being build by 4 | default for local development. And for now it requires a running instance of 5 | [kuma](https://github.com/mdn/kuma) to work. We might add support for local 6 | development and update this README. 7 | -------------------------------------------------------------------------------- /client/pwa/src/caches.ts: -------------------------------------------------------------------------------- 1 | declare var __COMMIT_HASH__: string; 2 | 3 | export const cacheName = `mdn-app-${__COMMIT_HASH__}`; 4 | export const contentCache = "mdn-content-v1"; 5 | 6 | export function openCache(): Promise { 7 | return caches.open(cacheName); 8 | } 9 | 10 | export function openContentCache(): Promise { 11 | return caches.open(contentCache); 12 | } 13 | -------------------------------------------------------------------------------- /client/pwa/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "lib": ["dom", "dom.iterable", "es2021", "webworker"], 5 | "allowImportingTsExtensions": false, 6 | "noEmit": false, 7 | "preserveConstEnums": true, 8 | "strictNullChecks": false, 9 | "target": "ES2021" 10 | }, 11 | "include": ["src"], 12 | "exclude": [] 13 | } 14 | -------------------------------------------------------------------------------- /client/src/app.test.tsx: -------------------------------------------------------------------------------- 1 | import { createRoot } from "react-dom/client"; 2 | import { MemoryRouter } from "react-router-dom"; 3 | 4 | import { App } from "./app"; 5 | 6 | it("renders without crashing", () => { 7 | const app = ( 8 | 9 | 10 | 11 | ); 12 | const div = document.createElement("div"); 13 | const root = createRoot(div!); 14 | root.render(app); 15 | root.unmount(); 16 | }); 17 | -------------------------------------------------------------------------------- /client/src/assets/about/accurate-sm.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/about/accurate.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/about/dot-dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/about/dot.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/about/handshake.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/about/line-dot.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/about/sparkle.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/about/text-box-check-outline.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/community/community-calls-dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/community/community-calls.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/community/quote-end-dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/community/quote-end.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/community/quote-start-dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/community/quote-start.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/community/video-thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/src/assets/community/video-thumbnail.png -------------------------------------------------------------------------------- /client/src/assets/curriculum/landing-scrim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/src/assets/curriculum/landing-scrim.png -------------------------------------------------------------------------------- /client/src/assets/curriculum/scrim-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/src/assets/curriculum/scrim-bg.png -------------------------------------------------------------------------------- /client/src/assets/curriculum/scrim-play.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/fonts/BarlowCondensed-SemiBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/src/assets/fonts/BarlowCondensed-SemiBold.woff2 -------------------------------------------------------------------------------- /client/src/assets/fonts/Inter.var.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/src/assets/fonts/Inter.var.woff2 -------------------------------------------------------------------------------- /client/src/assets/fonts/Montserrat-SemiBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/src/assets/fonts/Montserrat-SemiBold.woff -------------------------------------------------------------------------------- /client/src/assets/fonts/Montserrat-SemiBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/src/assets/fonts/Montserrat-SemiBold.woff2 -------------------------------------------------------------------------------- /client/src/assets/fonts/Montserrat-VF.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/src/assets/fonts/Montserrat-VF.woff2 -------------------------------------------------------------------------------- /client/src/assets/fonts/inter-v3-latin-600.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/src/assets/fonts/inter-v3-latin-600.woff -------------------------------------------------------------------------------- /client/src/assets/fonts/inter-v3-latin-600.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/src/assets/fonts/inter-v3-latin-600.woff2 -------------------------------------------------------------------------------- /client/src/assets/fonts/inter-v3-latin-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/src/assets/fonts/inter-v3-latin-regular.woff -------------------------------------------------------------------------------- /client/src/assets/fonts/inter-v3-latin-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/src/assets/fonts/inter-v3-latin-regular.woff2 -------------------------------------------------------------------------------- /client/src/assets/hero-dino.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/src/assets/hero-dino.png -------------------------------------------------------------------------------- /client/src/assets/icons/ai-help.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/icons/baseline/browser-check.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/icons/baseline/browser-cross.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/icons/baseline/high-dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/icons/baseline/high.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/icons/baseline/limited-dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/icons/baseline/limited.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/icons/bluesky.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /client/src/assets/icons/bookmark-filled.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/bookmark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/cancel.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/caret.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/checkmark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/chevron.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/chrome.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /client/src/assets/icons/critical.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /client/src/assets/icons/curriculum-next.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/curriculum-prev.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/curriculum-started-underline.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /client/src/assets/icons/disabled.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/edit-filled.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/icons/edit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /client/src/assets/icons/ellipses.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /client/src/assets/icons/experimental.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /client/src/assets/icons/external.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /client/src/assets/icons/feed.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/icons/feedback.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/icons/filter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/footnote.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /client/src/assets/icons/highlight.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /client/src/assets/icons/information.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /client/src/assets/icons/menu-filled.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /client/src/assets/icons/menu.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /client/src/assets/icons/message.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/mobile.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/more.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /client/src/assets/icons/next.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/no.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/nodejs.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /client/src/assets/icons/nonstandard.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/note-deprecated.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/note-info.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/note-warning.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/partial.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/preview.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /client/src/assets/icons/previous.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/progress-helper.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/icons/queue.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/queued.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/quote.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /client/src/assets/icons/send.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/icons/server.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/icons/sidebar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /client/src/assets/icons/small-arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/theme-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/theme-os-default.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /client/src/assets/icons/trash-filled.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/icons/twitter-x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/icons/unknown.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/icons/warning.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /client/src/assets/icons/webview.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/icons/yes-circle.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/icons/yes.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/lines.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/assets/m-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | MDN Logo 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /client/src/assets/m-logo.svg: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /client/src/constants.ts: -------------------------------------------------------------------------------- 1 | // Constants that are used outside of the client. 2 | export { MDN_PLUS_TITLE, VALID_LOCALES } from "../../libs/constants"; 3 | 4 | // Constants that are NOT used outside of the client. 5 | export enum FeatureId { 6 | PLUS_UPDATES_V2 = "plus_updates_v2", 7 | PLUS_NEWSLETTER = "plus_newsletter", 8 | PLUS_AI_HELP = "plus_ai_help", 9 | } 10 | -------------------------------------------------------------------------------- /client/src/curriculum/prev-next.scss: -------------------------------------------------------------------------------- 1 | .curriculum-prev-next { 2 | display: flex; 3 | flex-wrap: wrap; 4 | gap: 0 1rem; 5 | justify-content: space-between; 6 | margin-top: 2rem; 7 | width: 100%; 8 | 9 | a { 10 | margin: 0.5rem 0; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /client/src/curriculum/topic-icon.scss: -------------------------------------------------------------------------------- 1 | svg.topic-icon { 2 | circle { 3 | fill: var(--background-primary); 4 | } 5 | 6 | path { 7 | fill: var(--curriculum-color-topic); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /client/src/document/languages.css: -------------------------------------------------------------------------------- 1 | .document-languages { 2 | float: right; 3 | font-size: 80%; 4 | } 5 | .document-languages .translations { 6 | z-index: 10; 7 | position: absolute; 8 | background-color: white; 9 | opacity: 0.95; 10 | } 11 | .document-languages .choices { 12 | position: relative; 13 | } 14 | 15 | .document-languages .translations { 16 | padding: 10px; 17 | left: -100px; 18 | width: 200px; 19 | } 20 | .document-languages .translations ul { 21 | padding: 0; 22 | } 23 | .document-languages .translations li { 24 | list-style-type: none; 25 | } 26 | -------------------------------------------------------------------------------- /client/src/document/mathml-polyfill/font/STIXTwoMath-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/src/document/mathml-polyfill/font/STIXTwoMath-Regular.woff2 -------------------------------------------------------------------------------- /client/src/document/mathml-polyfill/mathml-font.scss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "STIXTwoMath-Regular"; 3 | font-weight: normal; 4 | src: 5 | local("STIXTwoMath-Regular"), 6 | url("./font/STIXTwoMath-Regular.woff2") format("woff2"); 7 | } 8 | 9 | math { 10 | font-family: "STIXTwoMath-Regular"; 11 | } 12 | -------------------------------------------------------------------------------- /client/src/document/mathml-polyfill/polyfill.tsx: -------------------------------------------------------------------------------- 1 | // This file exists so that when React.Suspense loads, it notices that there's 2 | // 'mathml.css' file that needs to be loaded into the DOM. 3 | // See the component which conditionally loads this 4 | // component. 5 | 6 | import "./mathml.css"; 7 | 8 | function MathMLPolyfill() { 9 | return null; 10 | } 11 | 12 | export default MathMLPolyfill; 13 | -------------------------------------------------------------------------------- /client/src/document/toolbar/edit-actions.scss: -------------------------------------------------------------------------------- 1 | .edit-actions { 2 | align-items: center; 3 | display: flex; 4 | justify-content: space-between; 5 | // width: 100%; 6 | 7 | li { 8 | .button { 9 | max-width: unset; 10 | } 11 | } 12 | 13 | a { 14 | color: var(--text-link); 15 | } 16 | 17 | p.editor-opening-error { 18 | font-weight: var(--font-body-strong-weight); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /client/src/homepage/index.scss: -------------------------------------------------------------------------------- 1 | @use "../ui/vars" as *; 2 | 3 | .homepage { 4 | align-items: center; 5 | display: flex; 6 | flex-direction: column; 7 | overflow-x: clip; 8 | overflow-y: visible; 9 | position: relative; 10 | 11 | width: 100%; 12 | 13 | > * { 14 | margin-top: 2rem; 15 | } 16 | 17 | > *:first-child { 18 | margin-top: 0; 19 | } 20 | 21 | a:hover { 22 | text-decoration: underline; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /client/src/homepage/types.tsx: -------------------------------------------------------------------------------- 1 | export interface FeedEntry { 2 | title: string; 3 | pubDate: string; 4 | url: string; 5 | creator: string; 6 | summary: string; 7 | } 8 | -------------------------------------------------------------------------------- /client/src/lit/community/types.d.ts: -------------------------------------------------------------------------------- 1 | export interface ContributorData { 2 | name: string; 3 | github: string; 4 | org?: string; 5 | } 6 | -------------------------------------------------------------------------------- /client/src/lit/compat/index-desktop-xl.scss: -------------------------------------------------------------------------------- 1 | @use "../../ui/vars" as *; 2 | 3 | @media (min-width: $screen-xl) { 4 | .table-container { 5 | margin: 0; 6 | width: 100%; 7 | } 8 | 9 | .table-container-inner { 10 | padding: 0; 11 | } 12 | 13 | .bc-table { 14 | // 33% for feature, 67% for browser columns. 15 | grid-template-columns: minmax(33%, max-content) repeat( 16 | var(--browser-count), 17 | calc(67% / var(--browser-count)) 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /client/src/lit/curriculum/scrim-inline.global.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "BarlowCondensed-SemiBold"; 3 | font-weight: 600; 4 | font-display: block; 5 | src: 6 | local("BarlowCondensed-SemiBold"), 7 | url("../../assets/fonts/BarlowCondensed-SemiBold.woff2") format("woff2"); 8 | } 9 | -------------------------------------------------------------------------------- /client/src/lit/glean-mixin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @template {new (...args: any[]) => {}} TBase 3 | * @param {TBase} Base 4 | */ 5 | export const GleanMixin = (Base) => 6 | class extends Base { 7 | /** @param {string} detail */ 8 | _gleanClick(detail) { 9 | window.dispatchEvent(new CustomEvent("glean-click", { detail })); 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /client/src/lit/interactive-example/tabs.panel.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | flex: 1; 3 | min-height: 0; 4 | } 5 | -------------------------------------------------------------------------------- /client/src/lit/interactive-example/tabs.wrapper.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: flex; 3 | flex-direction: column; 4 | overflow: hidden; 5 | } 6 | 7 | #tablist { 8 | background: var(--background-secondary); 9 | border-bottom: 1px solid var(--border-secondary); 10 | display: flex; 11 | flex-shrink: 0; 12 | gap: 0.5rem; 13 | overflow-x: auto; 14 | } 15 | -------------------------------------------------------------------------------- /client/src/lit/modules.d.ts: -------------------------------------------------------------------------------- 1 | // once https://github.com/microsoft/TypeScript/issues/46135 is fixed 2 | // we'll be able to do something like: 3 | // declare module '*' with {type: 'css'} { 4 | declare module "*?css" { 5 | const sheet: CSSStyleSheet; 6 | export default sheet; 7 | } 8 | 9 | declare module "*?raw" { 10 | const src: string; 11 | export default src; 12 | } 13 | -------------------------------------------------------------------------------- /client/src/lit/play/console.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | background-color: var(--code-background-inline); 3 | box-sizing: border-box; 4 | display: flex; 5 | flex-direction: column; 6 | font-size: 0.875rem; 7 | margin: 0; 8 | overflow: auto; 9 | width: 100%; 10 | } 11 | 12 | ul { 13 | list-style: none; 14 | margin: 0; 15 | padding: 0; 16 | } 17 | 18 | li { 19 | padding: 0 0.5em; 20 | 21 | &::before { 22 | content: ">"; 23 | } 24 | } 25 | 26 | code { 27 | font-family: var(--font-code); 28 | tab-size: 4; 29 | white-space: pre-wrap; 30 | } 31 | -------------------------------------------------------------------------------- /client/src/lit/play/runner.scss: -------------------------------------------------------------------------------- 1 | iframe { 2 | border: none; 3 | height: 100%; 4 | width: 100%; 5 | } 6 | -------------------------------------------------------------------------------- /client/src/lit/play/types.d.ts: -------------------------------------------------------------------------------- 1 | export interface VConsole { 2 | prop: string; 3 | args: any[]; 4 | } 5 | 6 | export type RunnerDefaults = "ix-tabbed" | "ix-wat" | "ix-choice"; 7 | -------------------------------------------------------------------------------- /client/src/newsletter/index.scss: -------------------------------------------------------------------------------- 1 | .section-newsletter { 2 | margin: 0 auto; 3 | max-width: 35rem; 4 | padding: 2rem; 5 | 6 | input[type="email"], 7 | button { 8 | width: 100%; 9 | } 10 | 11 | form { 12 | margin-bottom: 2rem; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /client/src/page-not-found/index.scss: -------------------------------------------------------------------------------- 1 | @use "sass:math"; 2 | 3 | .page-not-found { 4 | .fallback-document { 5 | .fallback-link { 6 | font-size: 1rem; 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /client/src/plus/ai-help/utils.ts: -------------------------------------------------------------------------------- 1 | import { useUserData } from "../../user-context"; 2 | 3 | export function isExternalUrl(url: string) { 4 | return url.startsWith("//") || !url.startsWith("/"); 5 | } 6 | 7 | export function useAIHelpSettings() { 8 | const user = useUserData(); 9 | const isHistoryEnabled = user?.settings?.aiHelpHistory ?? false; 10 | 11 | return { 12 | isHistoryEnabled, 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /client/src/plus/common/plus-tabs.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from "../../ui/atoms/button"; 2 | 3 | export function showMoreButton(setSelectAllChecked, setOffset, list: any[]) { 4 | return ( 5 |
6 | 15 |
16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /client/src/plus/offer-overview/index.tsx: -------------------------------------------------------------------------------- 1 | import { useScrollToAnchor } from "../../hooks"; 2 | import OfferHero from "./offer-hero"; 3 | import OfferOverviewFeatures from "./offer-overview-feature"; 4 | import OfferOverviewSubscribe from "./offer-overview-subscribe"; 5 | 6 | function OfferOverview() { 7 | useScrollToAnchor(); 8 | return ( 9 |
10 | 11 | 12 | 13 |
14 | ); 15 | } 16 | 17 | export default OfferOverview; 18 | -------------------------------------------------------------------------------- /client/src/plus/offer-overview/offer-overview-subscribe/stripe.tsx: -------------------------------------------------------------------------------- 1 | import "@stripe/stripe-js"; 2 | export default function Stripe() { 3 | return <>; 4 | } 5 | -------------------------------------------------------------------------------- /client/src/telemetry/generated/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/client/src/telemetry/generated/.gitkeep -------------------------------------------------------------------------------- /client/src/translations/index.scss: -------------------------------------------------------------------------------- 1 | .translation-choices { 2 | padding: 100px; 3 | text-align: center; 4 | 5 | a.button { 6 | display: inline; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /client/src/types/notecards.ts: -------------------------------------------------------------------------------- 1 | type NotecardType = 2 | | "success" 3 | | "warning" 4 | | "deprecated" 5 | | "error" 6 | | "negative" 7 | | "info" 8 | | "experimental"; 9 | 10 | export type { NotecardType }; 11 | -------------------------------------------------------------------------------- /client/src/types/notifications.ts: -------------------------------------------------------------------------------- 1 | interface Notification { 2 | id: number; 3 | title: string; 4 | text: string; 5 | created: Date; 6 | url: string; 7 | read: boolean; 8 | deleted: boolean; 9 | } 10 | 11 | interface NotificationData { 12 | items: Array; 13 | } 14 | 15 | export type { Notification, NotificationData }; 16 | -------------------------------------------------------------------------------- /client/src/types/playground.ts: -------------------------------------------------------------------------------- 1 | export interface QueueEntry { 2 | key: number; 3 | id: string; 4 | lang?: string | null; 5 | } 6 | -------------------------------------------------------------------------------- /client/src/types/theme.ts: -------------------------------------------------------------------------------- 1 | type Scheme = "dark" | "light"; 2 | type Theme = Scheme | "os-default"; 3 | 4 | export type { Scheme, Theme }; 5 | -------------------------------------------------------------------------------- /client/src/ui/_color-palette.scss: -------------------------------------------------------------------------------- 1 | @use "sass:color"; 2 | 3 | @function tint($color, $percentage) { 4 | @return color.mix(white, $color, $percentage); 5 | } 6 | 7 | @function shade($color, $percentage) { 8 | @return color.mix(black, $color, $percentage); 9 | } 10 | 11 | @function mdn-color($color, $value) { 12 | @if $value < 50 { 13 | @return tint($color, 100 - ($value * 2)); 14 | } 15 | @if $value > 50 { 16 | @return shade($color, ($value * 2) - 100); 17 | } 18 | @return $color; 19 | } 20 | -------------------------------------------------------------------------------- /client/src/ui/atoms/auth-disabled/index.scss: -------------------------------------------------------------------------------- 1 | @use "../../vars" as *; 2 | 3 | .auth-disabled { 4 | border: 1px solid var(--border-primary); 5 | border-radius: var(--elem-radius); 6 | box-shadow: var(--shadow-01); 7 | color: var(--text-secondary); 8 | padding: 16px; 9 | 10 | p { 11 | margin-bottom: 0; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /client/src/ui/atoms/auth-disabled/index.tsx: -------------------------------------------------------------------------------- 1 | import "./index.scss"; 2 | 3 | export function AuthDisabled() { 4 | return ( 5 |
6 |

7 | Authentication disabled: Authentication and the user 8 | settings app is currently disabled. 9 |

10 |
11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /client/src/ui/atoms/container/index.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | margin-left: auto; 3 | margin-right: auto; 4 | max-width: var(--max-width); 5 | padding-left: var(--gutter); 6 | padding-right: var(--gutter); 7 | width: 100%; 8 | } 9 | -------------------------------------------------------------------------------- /client/src/ui/atoms/container/index.tsx: -------------------------------------------------------------------------------- 1 | import "./index.scss"; 2 | 3 | export default function Container({ 4 | children, 5 | extraClasses, 6 | optional, 7 | }: { 8 | children: React.ReactNode; 9 | extraClasses?: string; 10 | optional?: boolean; 11 | }) { 12 | return ( 13 | <> 14 | {optional === true ? ( 15 | <>{children} 16 | ) : ( 17 |
{children}
18 | )} 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /client/src/ui/atoms/internal-link/index.tsx: -------------------------------------------------------------------------------- 1 | import { Link, LinkProps } from "react-router-dom"; 2 | 3 | /** 4 | * Returns a Link, or an anchor, if it targets a hash. 5 | */ 6 | export default function InternalLink(props: LinkProps) { 7 | const href = props.to; 8 | 9 | if (typeof href === "string" && href.includes("#")) { 10 | return ( 11 | 12 | {props.children} 13 | 14 | ); 15 | } 16 | 17 | return {props.children}; 18 | } 19 | -------------------------------------------------------------------------------- /client/src/ui/atoms/limit-banner/index.scss: -------------------------------------------------------------------------------- 1 | @use "../../vars.scss" as *; 2 | 3 | .limit-banner { 4 | background: var(--background-primary); 5 | border: 1px solid var(--border-secondary); 6 | border-radius: var(--elem-radius); 7 | margin-top: 0.5rem; 8 | padding-bottom: 0.5rem; 9 | padding-top: 0.5rem; 10 | text-align: center; 11 | 12 | p { 13 | margin: 0.5rem; 14 | } 15 | 16 | a { 17 | color: var(--text-link); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /client/src/ui/atoms/loading/index.scss: -------------------------------------------------------------------------------- 1 | @use "~@mdn/minimalist/sass/mixins/animation" as *; 2 | 3 | .generic-loading { 4 | align-items: center; 5 | /* add short delay so the animation starts from white instead of dark gray */ 6 | animation-delay: 1s; 7 | display: flex; 8 | justify-content: center; 9 | width: 100%; 10 | @include slow-pulse(); 11 | } 12 | -------------------------------------------------------------------------------- /client/src/ui/atoms/login-link/index.scss: -------------------------------------------------------------------------------- 1 | @use "../../vars" as *; 2 | 3 | .auth-container { 4 | .login-link { 5 | align-items: center; 6 | display: inline-flex; 7 | font-weight: var(--font-body-strong-weight); 8 | height: 2rem; 9 | text-align: center; 10 | 11 | &:link, 12 | &:visited { 13 | color: var(--text-secondary); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /client/src/ui/atoms/notification/index.scss: -------------------------------------------------------------------------------- 1 | @use "../../vars" as *; 2 | 3 | .notification-container { 4 | background-color: $mdn-color-violet-90; 5 | color: #fff; 6 | padding: 12px; 7 | text-align: center; 8 | 9 | p { 10 | margin-bottom: 0; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /client/src/ui/atoms/notification/index.tsx: -------------------------------------------------------------------------------- 1 | import "./index.scss"; 2 | 3 | export default function Notification({ children }) { 4 | return
{children}
; 5 | } 6 | -------------------------------------------------------------------------------- /client/src/ui/atoms/page-content/index.scss: -------------------------------------------------------------------------------- 1 | .main-content.standalone { 2 | margin: 0 auto; 3 | max-width: var(--max-width); 4 | width: 100%; 5 | } 6 | -------------------------------------------------------------------------------- /client/src/ui/atoms/signout/index.scss: -------------------------------------------------------------------------------- 1 | @use "../../vars" as *; 2 | 3 | .signout-form { 4 | padding: 0.5rem; 5 | 6 | @media (min-width: $screen-md) { 7 | border-top: 1px solid var(--border-primary); 8 | } 9 | } 10 | 11 | button.signout-button { 12 | width: 100%; 13 | 14 | &:hover, 15 | &:focus { 16 | background-color: var(--background-secondary); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /client/src/ui/atoms/signup-link/index.scss: -------------------------------------------------------------------------------- 1 | @use "../../vars" as *; 2 | 3 | .mdn-plus-subscribe-link { 4 | --button-padding: 1rem; 5 | 6 | margin: 0 auto; 7 | max-width: 150px; 8 | text-align: center; 9 | white-space: nowrap; 10 | } 11 | -------------------------------------------------------------------------------- /client/src/ui/atoms/spinner/index.tsx: -------------------------------------------------------------------------------- 1 | import "./index.scss"; 2 | 3 | export function Spinner({ extraClasses }: { extraClasses?: string | null }) { 4 | return ( 5 |
6 |
7 |
8 |
9 |
10 |
11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /client/src/ui/base/_typography.scss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-display: swap; 3 | font-family: "Inter"; 4 | font-stretch: 75% 100%; 5 | font-style: oblique 0deg 20deg; 6 | font-weight: 1 999; 7 | src: 8 | url("../../assets/fonts/Inter.var.woff2") 9 | format("woff2 supports variations"), 10 | url("../../assets/fonts/Inter.var.woff2") format("woff2-variations"); 11 | } 12 | -------------------------------------------------------------------------------- /client/src/ui/molecules/auth-container/index.tsx: -------------------------------------------------------------------------------- 1 | import LogInLink from "../../atoms/login-link"; 2 | import { SignUpLink } from "../../atoms/signup-link"; 3 | 4 | import "./index.scss"; 5 | 6 | export const AuthContainer = ({ logInGleanContext, signUpGleanContext }) => { 7 | return ( 8 |
    9 |
  • 10 | 11 |
  • 12 |
  • 13 | 14 |
  • 15 |
16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /client/src/ui/molecules/card/index.tsx: -------------------------------------------------------------------------------- 1 | import "./index.scss"; 2 | 3 | export function Card({ 4 | featured, 5 | children, 6 | }: { 7 | featured: boolean; 8 | children: React.ReactNode; 9 | }) { 10 | return ( 11 |
15 | {children} 16 |
17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /client/src/ui/molecules/grids/_standard-page.scss: -------------------------------------------------------------------------------- 1 | @use "../../vars" as *; 2 | 3 | .page-wrapper { 4 | grid-template-columns: 100%; 5 | } 6 | 7 | .standard-page { 8 | max-width: inherit; 9 | } 10 | -------------------------------------------------------------------------------- /client/src/ui/molecules/grids/grids.scss: -------------------------------------------------------------------------------- 1 | @use "./document-page"; 2 | @use "./standard-page"; 3 | -------------------------------------------------------------------------------- /client/src/ui/molecules/learn-menu/index.scss: -------------------------------------------------------------------------------- 1 | @use "sass:color"; 2 | @use "../../vars" as *; 3 | 4 | .learn { 5 | .submenu .submenu-item-heading { 6 | font-size: var(--type-smaller-font-size); 7 | font-weight: initial; 8 | } 9 | 10 | .desktop-only { 11 | display: none; 12 | } 13 | 14 | @media (min-width: $screen-lg) { 15 | .desktop-only { 16 | display: inherit; 17 | } 18 | 19 | .mobile-only { 20 | display: none; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /client/src/ui/molecules/maintenance/index.tsx: -------------------------------------------------------------------------------- 1 | import { useUserData } from "../../../user-context"; 2 | import "./index.scss"; 3 | 4 | export default function Maintenance() { 5 | const userData = useUserData(); 6 | return ( 7 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /client/src/ui/molecules/notecards/index.tsx: -------------------------------------------------------------------------------- 1 | import { NotecardType } from "../../../types/notecards"; 2 | 3 | export default function NoteCard({ 4 | children, 5 | type = "info", 6 | extraClasses, 7 | }: { 8 | children: JSX.Element | JSX.Element[]; 9 | type?: NotecardType; 10 | extraClasses?: string | null; 11 | }) { 12 | const classes = `notecard ${type !== "info" ? type : ""} ${ 13 | extraClasses || "" 14 | }`.trim(); 15 | 16 | return
{children}
; 17 | } 18 | -------------------------------------------------------------------------------- /client/src/ui/molecules/offline-status-bar/index.scss: -------------------------------------------------------------------------------- 1 | .offline-status-bar { 2 | background-color: var(--accent-primary-engage); // rgba(24, 112, 240, 0.1) 3 | color: var(--text-primary); 4 | display: none; 5 | 6 | &.is-offline, 7 | &.is-online { 8 | display: block; 9 | padding: 1rem; 10 | text-align: center; 11 | } 12 | 13 | &.is-online { 14 | animation: fade-out 3s ease-out 0.5s; 15 | } 16 | } 17 | 18 | @keyframes fade-out { 19 | 0% { 20 | opacity: 1; 21 | } 22 | 23 | 100% { 24 | opacity: 0; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /client/src/ui/molecules/pagination/index.scss: -------------------------------------------------------------------------------- 1 | @use "../../../ui/vars" as *; 2 | 3 | .pagination { 4 | align-items: center; 5 | display: flex; 6 | gap: 1rem; 7 | justify-content: center; 8 | padding: 1rem 0; 9 | 10 | &-label { 11 | font-size: var(--type-smaller-font-size); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /client/src/ui/molecules/plus-menu/index.scss: -------------------------------------------------------------------------------- 1 | @use "sass:color"; 2 | @use "../../vars" as *; 3 | 4 | .mdn-plus { 5 | .submenu-icon { 6 | background-color: var(--plus-accent-color); 7 | } 8 | 9 | .note { 10 | background-color: var(--background-information); 11 | 12 | .submenu-item-description { 13 | display: block; 14 | margin: 0.125rem; 15 | } 16 | } 17 | 18 | @media (min-width: $screen-lg) { 19 | .mobile-only { 20 | display: none; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /client/src/ui/molecules/tabs/index.scss: -------------------------------------------------------------------------------- 1 | .tabs { 2 | border-bottom: 1px solid var(--border-primary); 3 | } 4 | 5 | .tabs ul { 6 | display: flex; 7 | gap: 1rem; 8 | } 9 | 10 | .tabs .tab-item { 11 | border-bottom: 2px solid transparent; 12 | padding: 0.5rem 0; 13 | } 14 | 15 | .tabs a.tab-item { 16 | color: var(--text-primary); 17 | display: block; 18 | font-size: var(--type-smaller-font-size); 19 | } 20 | 21 | .tabs .tab-item[aria-current="true"] { 22 | border-bottom-color: var(--text-link); 23 | } 24 | -------------------------------------------------------------------------------- /client/src/ui/molecules/tools-menu/index.scss: -------------------------------------------------------------------------------- 1 | @use "../../vars" as *; 2 | 3 | @media screen and (min-width: $screen-lg) { 4 | #tools-button { 5 | display: flex; 6 | 7 | &::after { 8 | display: none; 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /client/src/writers-homepage/index.scss: -------------------------------------------------------------------------------- 1 | #writers-homepage { 2 | .homepage-hero-search { 3 | margin-bottom: 60px; 4 | 5 | .search-button { 6 | top: 0.25rem; 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /client/src/writers-homepage/viewed-documents.scss: -------------------------------------------------------------------------------- 1 | #recently-viewed-documents { 2 | a small { 3 | color: #808080; 4 | } 5 | 6 | td { 7 | padding: 6px; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /cloud-function/.env-dist: -------------------------------------------------------------------------------- 1 | ORIGIN_MAIN="localhost" 2 | ORIGIN_LIVE_SAMPLES="localhost" 3 | 4 | SOURCE_CONTENT=http://localhost:8100/ 5 | SOURCE_RUMBA=http://localhost:8000/ 6 | -------------------------------------------------------------------------------- /cloud-function/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env* 3 | !.env-dist 4 | *.log 5 | canonicals.json 6 | redirects.json 7 | src/**/*.js 8 | src/internal 9 | -------------------------------------------------------------------------------- /cloud-function/Procfile: -------------------------------------------------------------------------------- 1 | proxy: npm run proxy 2 | server: npm run server:watch 3 | -------------------------------------------------------------------------------- /cloud-function/src/canonicals.ts: -------------------------------------------------------------------------------- 1 | import { createRequire } from "node:module"; 2 | 3 | const require = createRequire(import.meta.url); 4 | 5 | export const CANONICALS = require("../canonicals.json"); 6 | -------------------------------------------------------------------------------- /cloud-function/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const DEFAULT_COUNTRY = "US"; 2 | 3 | export const PROXY_TIMEOUT = 115000; 4 | 5 | export const THIRTY_DAYS = 3600 * 24 * 30; 6 | -------------------------------------------------------------------------------- /cloud-function/src/handlers/proxy-api.ts: -------------------------------------------------------------------------------- 1 | import { createProxyMiddleware, fixRequestBody } from "http-proxy-middleware"; 2 | 3 | import { Source, sourceUri } from "../env.js"; 4 | import { PROXY_TIMEOUT } from "../constants.js"; 5 | 6 | export const proxyApi = createProxyMiddleware({ 7 | target: sourceUri(Source.api), 8 | changeOrigin: true, 9 | autoRewrite: true, 10 | proxyTimeout: PROXY_TIMEOUT, 11 | xfwd: true, 12 | on: { 13 | proxyReq: fixRequestBody, 14 | }, 15 | }); 16 | -------------------------------------------------------------------------------- /cloud-function/src/handlers/proxy-pong.ts: -------------------------------------------------------------------------------- 1 | import { BSA_ENABLED } from "../env.js"; 2 | import { proxyBSA } from "./proxy-bsa.js"; 3 | import { proxyKevel } from "./proxy-kevel.js"; 4 | 5 | import type { Request, Response } from "express"; 6 | 7 | export async function proxyPong(req: Request, res: Response) { 8 | if (BSA_ENABLED) { 9 | return proxyBSA(req, res); 10 | } 11 | return proxyKevel(req, res); 12 | } 13 | -------------------------------------------------------------------------------- /cloud-function/src/handlers/proxy-telemetry.ts: -------------------------------------------------------------------------------- 1 | import { createProxyMiddleware, fixRequestBody } from "http-proxy-middleware"; 2 | 3 | import { PROXY_TIMEOUT } from "../constants.js"; 4 | 5 | export const proxyTelemetry = createProxyMiddleware({ 6 | target: "https://incoming.telemetry.mozilla.org", 7 | changeOrigin: true, 8 | autoRewrite: true, 9 | proxyTimeout: PROXY_TIMEOUT, 10 | xfwd: true, 11 | on: { 12 | proxyReq: fixRequestBody, 13 | }, 14 | }); 15 | -------------------------------------------------------------------------------- /cloud-function/src/index.ts: -------------------------------------------------------------------------------- 1 | import { createHandler } from "./app.js"; 2 | import { http } from "@google-cloud/functions-framework"; 3 | import * as Sentry from "@sentry/google-cloud-serverless"; 4 | 5 | let handler = createHandler(); 6 | 7 | if (process.env["SENTRY_DSN"]) { 8 | Sentry.init(); 9 | handler = Sentry.wrapHttpFunction(handler); 10 | } 11 | 12 | http("mdnHandler", handler); 13 | -------------------------------------------------------------------------------- /cloud-function/src/middlewares/not-found.ts: -------------------------------------------------------------------------------- 1 | import type { Request, Response } from "express"; 2 | 3 | export async function notFound(_req: Request, res: Response) { 4 | res.sendStatus(404).end(); 5 | } 6 | -------------------------------------------------------------------------------- /cloud-function/src/middlewares/stripForwardedHostHeaders.ts: -------------------------------------------------------------------------------- 1 | import { NextFunction, Request, Response } from "express"; 2 | 3 | // Don't strip other `X-Forwarded-*` headers. 4 | const HEADER_REGEXP = /^(x-forwarded-host|forwarded)$/i; 5 | 6 | export async function stripForwardedHostHeaders( 7 | req: Request, 8 | _res: Response, 9 | next: NextFunction 10 | ) { 11 | Object.keys(req.headers) 12 | .filter((name) => HEADER_REGEXP.test(name)) 13 | .forEach((name) => delete req.headers[name]); 14 | next(); 15 | } 16 | -------------------------------------------------------------------------------- /content/index.ts: -------------------------------------------------------------------------------- 1 | export * as Document from "./document.js"; 2 | export * as Translation from "./translation.js"; 3 | export { getPopularities } from "./popularities.js"; 4 | export * as Redirect from "./redirect.js"; 5 | export * as FileAttachment from "./file-attachment.js"; 6 | export { 7 | buildURL, 8 | memoize, 9 | slugToFolder, 10 | execGit, 11 | getRoot, 12 | urlToFolderPath, 13 | MEMOIZE_INVALIDATE, 14 | } from "./utils.js"; 15 | export { resolveFundamental } from "../libs/fundamental-redirects/index.js"; 16 | export { translationsOf } from "./translations.js"; 17 | -------------------------------------------------------------------------------- /deployer/src/deployer/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "0.3.0" 2 | -------------------------------------------------------------------------------- /deployer/src/deployer/constants.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from decouple import AutoConfig 4 | 5 | config = AutoConfig(os.curdir) 6 | 7 | CI = config("CI", default=False, cast=bool) 8 | 9 | # If you're doing local development, you can download and install your own 10 | # instance of Elasticsearch 7 and start it. Then set this environment variable 11 | # value to `http://localhost:9200` 12 | ELASTICSEARCH_URL = config("DEPLOYER_ELASTICSEARCH_URL", default=None) 13 | -------------------------------------------------------------------------------- /jest.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionsToTreatAsEsm": [".ts", ".tsx"], 3 | "moduleNameMapper": { 4 | "^(\\.{1,2}/.*)\\.js$": "$1" 5 | }, 6 | "preset": "ts-jest/presets/default-esm", 7 | "testPathIgnorePatterns": ["headless*", "developing.spec.ts"], 8 | "transform": { 9 | "\\.tsx?$": [ 10 | "ts-jest", 11 | { 12 | "babelConfig": true, 13 | "isolatedModules": true, 14 | "tsconfig": { "moduleResolution": "node" }, 15 | "useESM": true 16 | } 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /kumascript/README.md: -------------------------------------------------------------------------------- 1 | # Kumascript in Yari 2 | 3 | ## Signaling macro deprecation 4 | 5 | If a macro should no longer be used and is marked for removal, add the following 6 | to the top of the relevant macro: 7 | 8 | ```js 9 | // Throw a MacroDeprecatedError flaw 10 | mdn.deprecated(); 11 | ``` 12 | 13 | It is also useful to add a code comment to the macro detailing what the blockers 14 | are for removal. See the following pull request for reference: 15 | [Deprecate the {{index}} macro](https://github.com/mdn/yari/pull/5607) 16 | -------------------------------------------------------------------------------- /kumascript/macros/CSP.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | 3 | let lang = env.locale; 4 | let directive = $0; 5 | let str = $1 || $0; 6 | let URL = "/" + lang + '/docs/Web/HTTP/Headers/Content-Security-Policy/' + directive; 7 | let anch = ''; 8 | 9 | if ($2) { 10 | str = str + '.' + $2; 11 | anch = '#' + $2; 12 | } 13 | 14 | let code = ''; 15 | let endcode = ''; 16 | if (!$3) { code = ''; endcode = '' } 17 | 18 | %><%- code %><%- str %><%- endcode %> 19 | -------------------------------------------------------------------------------- /kumascript/macros/CSSSyntax.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | /* 3 | * Displays the formal syntax for a CSS property, using the values found in 4 | * the https://github.com/w3c/webref package. 5 | * 6 | * The property name is taken from the page slug. 7 | * 8 | * The syntax is pretty-printed and syntax-highlighted. 9 | */ 10 | %> 11 | <%-await page.cssSyntax($0)%> 12 | -------------------------------------------------------------------------------- /kumascript/macros/EmbedYouTube.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | // Embeds a YouTube video into the article. 3 | // 4 | // Parameters: 5 | // $0 Video ID 6 | // $1 title (optional) 7 | 8 | var video = ''; 13 | %> 14 | 15 | <%-video%> 16 | -------------------------------------------------------------------------------- /kumascript/macros/Glossary.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | // Inserts a link to a term's entry in our glossary. 3 | // 4 | // Parameters: 5 | // 6 | // $0 - Term name 7 | // $1 - name to display (optional) 8 | 9 | let str = $1 || $0; 10 | 11 | const basePath = `/${env.locale}/docs/Glossary/`; 12 | const subPath = $0.replace(/\s+/g,'_'); 13 | const link = web.smartLink(basePath + subPath, null, str, subPath, basePath); 14 | %><%- link %> 15 | -------------------------------------------------------------------------------- /kumascript/macros/HTTPMethod.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | 3 | let lang = env.locale; 4 | let method = $0.toUpperCase(); // Methods are always uppercase 5 | let str = $1 || $0; 6 | let URL = "/" + lang + '/docs/Web/HTTP/Methods/' + method; 7 | let anch = ''; 8 | 9 | if ($2) { 10 | str = str + '.' + $2; 11 | anch = '#' + $2; 12 | } 13 | 14 | let code = ''; 15 | let endcode = ''; 16 | if (!$3) { code = ''; endcode = '' } 17 | 18 | %><%- code %><%- str %><%- endcode %> 19 | -------------------------------------------------------------------------------- /kumascript/macros/HTTPStatus.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | 3 | let lang = env.locale; 4 | let status = $0; 5 | let str = $1 || $0; 6 | let URL = "/" + lang + '/docs/Web/HTTP/Status/' + status; 7 | let anch = ''; 8 | 9 | if ($2) { 10 | str = str + '.' + $2; 11 | anch = '#' + $2; 12 | } 13 | 14 | let code = ''; 15 | let endcode = ''; 16 | if (!$3) { code = ''; endcode = '' } 17 | 18 | %><%- code %><%- str %><%- endcode %> 19 | -------------------------------------------------------------------------------- /kumascript/macros/JSFiddleEmbed.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | // Embeds a JSFiddle. 3 | // 4 | // Parameters: 5 | // $0 - jsfiddle.net url 6 | // $1 - which tabs to display (optional); this is a string such as "html,css" or "html,js" 7 | // $2 - height of the iframe (optional) 8 | 9 | var options = $1 || ""; 10 | 11 | if (options.length != 0) { 12 | options += "/"; 13 | } 14 | 15 | var s_result = '

'; 16 | 17 | %><%- s_result %> 18 | -------------------------------------------------------------------------------- /kumascript/macros/LandingPageListSubpages.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | // Inserts a definition list of the subpages of the current page, with each 3 | // page's title as the
term and its SEO summary as the
term. The 4 | // List is presented in a two-column view where possible. 5 | // 6 | // Parameters: 7 | // None 8 | %> 9 | <%-await template("SubpagesWithSummaries")%> 10 | -------------------------------------------------------------------------------- /kumascript/macros/LiveSampleLink.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | // Links to a live sample given the ID of its header block. 3 | // 4 | // Example: {{ LiveSampleLink('Full_IndexedDB_example', "Test the online live demo") }} 5 | // 6 | // Parameters: 7 | // $0 - The ID of the header block containing the sample 8 | // $1 - The link label 9 | // 10 | // See also : EmbedLiveSample 11 | // 12 | // We pass env.url as $1 to LiveSampleURL to enforce fallback to prebuild samples. 13 | %> 14 | <%=$1%> 15 | -------------------------------------------------------------------------------- /kumascript/macros/MathMLElement.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | var name = $0; 3 | 4 | var sectionname = mdn.localString({ 5 | "de": "Element", 6 | "en-US": "Element", 7 | "es": "Elemento" 8 | }); 9 | 10 | var dest = '/' + env.locale + '/docs/Web/MathML/' + sectionname + '/' + name; 11 | var result = '<' + name + '>'; 12 | %> 13 | <%- result %> 14 | -------------------------------------------------------------------------------- /kumascript/macros/Next.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | /* one parameter: path of Next page */ 3 | /* Calls PreviousNext to avoid duplication of translations */ 4 | 5 | %><%- await template("PreviousNext", ["",$0]) %> 6 | -------------------------------------------------------------------------------- /kumascript/macros/NextMenu.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | /* two parameters: path of Next page, and path to menu */ 3 | /* Calls PreviousMenuNext to avoid duplication of translations */ 4 | 5 | %><%- await template("PreviousMenuNext", ["",$0,$1]) %> 6 | -------------------------------------------------------------------------------- /kumascript/macros/Non-standard_Inline.ejs: -------------------------------------------------------------------------------- 1 | <%- await template("NonStandardBadge", [1]) %> 2 | -------------------------------------------------------------------------------- /kumascript/macros/Previous.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | /* one parameter: path of Previous page */ 3 | /* Calls PreviousNext to avoid duplication of translations */ 4 | %> 5 | <%- await template("PreviousNext", [$0]) %> 6 | -------------------------------------------------------------------------------- /kumascript/macros/PreviousMenu.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | /* two parameters: path of previous page and path to menu */ 3 | /* Calls PreviousNext to avoid duplication of translations */ 4 | %> 5 | <%- await template("PreviousMenuNext", [$0, "", $1]) %> 6 | -------------------------------------------------------------------------------- /kumascript/macros/PreviousNext.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | /* two parameters: path of previous page and path to next */ 3 | /* Calls PreviousMenuNext to avoid duplication of translations */ 4 | %> 5 | <%- await template("PreviousMenuNext", [$0, $1]) %> 6 | -------------------------------------------------------------------------------- /kumascript/macros/QuickLinksWithSubpages.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | // Constructs a QuickLinks box for the current page, using the subpages 3 | // of the specified page to generate the links. If no input is specified, 4 | // then the current page's subpages are used. 5 | // 6 | // Only two levels total of depth are permitted. 7 | // 8 | // Parameters: 9 | // 10 | // $0 Optional; the page whose subpages are to be included. 11 | %> 12 | 15 | -------------------------------------------------------------------------------- /kumascript/macros/SVGAttr.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | /* one parameter: attribute name */ 3 | var slug = mdn.localString({ 4 | "de": "Attribut", 5 | "en-US": "Attribute", 6 | }); 7 | 8 | var URL = "/" + env.locale + "/docs/Web/SVG/" + slug + "/" + $0; 9 | %> 10 | <%= $0 %> 11 | -------------------------------------------------------------------------------- /kumascript/macros/experimental_inline.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | // Inserts an "experimental" icon. This just calls through to the newer 3 | // ExperimentalBadge macro, which you should use instead. 4 | // 5 | %> 6 | <%-await template("ExperimentalBadge", [1])%> 7 | -------------------------------------------------------------------------------- /kumascript/macros/httpheader.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | 3 | let lang = env.locale; 4 | let header = $0; 5 | let str = $1 || $0; 6 | let URL = "/" + lang + '/docs/Web/HTTP/Headers/' + header; 7 | let anch = ''; 8 | 9 | if ($2) { 10 | str = str + '.' + $2; 11 | anch = '#' + $2; 12 | } 13 | 14 | let code = ''; 15 | let endcode = ''; 16 | if (!$3) { code = ''; endcode = '' } 17 | 18 | %><%- code %><%- str %><%- endcode %> 19 | -------------------------------------------------------------------------------- /kumascript/macros/propertiesbox.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | /* 3 | Outputs properties as a table 4 | 5 | $0 - String containing a serialized array of properties of the structure 6 | {"label": "foo", "value": "bar"} 7 | */ 8 | var properties = JSON.parse($0); 9 | var result = "" + 10 | ""; 11 | properties.forEach(function(property) { 12 | result += "" + 13 | "" + 14 | ""; 15 | }); 16 | result += "" + 17 | "
" + property.label + "" + property.value + "
"; 18 | %><%- result %> 19 | -------------------------------------------------------------------------------- /kumascript/macros/xref_csscomputed.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | let linkText = mdn.localString({ 3 | "de" : "Berechneter Wert", 4 | "en-US": "Computed value", 5 | "es" : "Valor calculado", 6 | "fr" : "Valeur calculée", 7 | "ja" : "計算値", 8 | "ko" : "계산 값", 9 | "ru" : "Обработка значения", 10 | "zh-CN": "计算值" 11 | }); 12 | %> 13 | <%- web.smartLink(`/${env.locale}/docs/Web/CSS/computed_value`, null, linkText) %> 14 | -------------------------------------------------------------------------------- /kumascript/macros/xref_cssinherited.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | let linkText = mdn.localString({ 3 | "de" : "Vererbt", 4 | "en-US": "Inherited", 5 | "es" : "Heredable", 6 | "fr" : "Héritée", 7 | "ja" : "継承", 8 | "ko" : "상속", 9 | "ru" : "Наследуется", 10 | "zh-CN": "是否是继承属性", 11 | "zh-TW": "繼承與否" 12 | }); 13 | %> 14 | <%- web.smartLink(`/${env.locale}/docs/Web/CSS/inheritance`, null, linkText) %> 15 | -------------------------------------------------------------------------------- /kumascript/macros/xref_cssinitial.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | let linkText = mdn.localString({ 3 | "de" : "Initialer Wert", 4 | "en-US": "Initial value", 5 | "es" : "Valor inicial", 6 | "fr" : "Valeur initiale", 7 | "ja" : "初期値", 8 | "ko" : "초기값", 9 | "ru" : "Начальное значение", 10 | "zh-CN": "初始值", 11 | "zh-TW": "預設值" 12 | 13 | }); 14 | %> 15 | <%- web.smartLink(`${env.locale}/docs/Web/CSS/initial_value`, null, linkText) %> 16 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/macros/asyncMacro.ejs: -------------------------------------------------------------------------------- 1 | <%= await env.after(500, 'yay!') -%> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/macros/bar.ejs: -------------------------------------------------------------------------------- 1 | (<%= await template('echo', ['included']) -%> 2 | <%= await template('echo', ['words']) -%>) -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/macros/echo.ejs: -------------------------------------------------------------------------------- 1 | <%= $0 -%> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/macros/env.ejs: -------------------------------------------------------------------------------- 1 | <%= env.x + env.y -%> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/macros/includeError.ejs: -------------------------------------------------------------------------------- 1 | <%= await template("throw") -%> 2 | <%= await template("nope") -%> 3 | 4 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/macros/syntax.ejs: -------------------------------------------------------------------------------- 1 | <% ### syntax error: this macro won't compile ### %> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/macros/throw.ejs: -------------------------------------------------------------------------------- 1 | <% throw new Error('artisanally thrown error'); %> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/macros/undefined.ejs: -------------------------------------------------------------------------------- 1 | <%= x -%> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/syntax1: -------------------------------------------------------------------------------- 1 | There is a trailing comma in the JSON arguments below. 2 | 3 | {{ MacroWithJson({ 4 | "es":"es/JavaScript/Acerca_de_JavaScript", 5 | "en": "en/JavaScript/About_JavaScript", 6 | }) }} 7 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/syntax2: -------------------------------------------------------------------------------- 1 | Trailing comma in the argument list is a syntax error. 2 | 3 | {{ add(1,) }} 4 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/syntax3: -------------------------------------------------------------------------------- 1 | Syntax error: ends with an unfinished macro {{ 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/syntax4: -------------------------------------------------------------------------------- 1 | Syntax error: ends with an unfinished macro {{ test( 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/testcase1/input: -------------------------------------------------------------------------------- 1 | Here is \{{ some more text \}} with double braces, but not a macro. 2 | But, we should also \\{ be able to use \ backslashes \\wherever \\\we like. 3 | Here is { some text } with braces, but not a macro. 4 | This is a {{ PlainText }} macro and {{PlainText()}} macro. 5 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/testcase1/macros/PlainText.ejs: -------------------------------------------------------------------------------- 1 | (This macro is plain text) -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/testcase1/macros/test.ejs: -------------------------------------------------------------------------------- 1 | This macro is plain text. 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/testcase1/output: -------------------------------------------------------------------------------- 1 | Here is {{ some more text }} with double braces, but not a macro. 2 | But, we should also \{ be able to use \ backslashes \\wherever \\\we like. 3 | Here is { some text } with braces, but not a macro. 4 | This is a (This macro is plain text) macro and (This macro is plain text) macro. 5 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/testcase2/macros/Alpha_Macro_123.ejs: -------------------------------------------------------------------------------- 1 | <%- JSON.stringify($$) -%> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/testcase2/macros/Bracepocalypse.ejs: -------------------------------------------------------------------------------- 1 | <%- JSON.stringify($$) -%> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/testcase2/macros/HelloWorld.ejs: -------------------------------------------------------------------------------- 1 | <%- JSON.stringify($$) -%> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/testcase2/macros/MacroUsingParams.ejs: -------------------------------------------------------------------------------- 1 | <%- JSON.stringify($$) -%> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/testcase2/macros/ParenTastic.ejs: -------------------------------------------------------------------------------- 1 | <%- JSON.stringify($$) -%> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/testcase2/macros/macrowithjson.ejs: -------------------------------------------------------------------------------- 1 | <%- JSON.stringify($$) -%> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/testcase2/macros/multi-line-macro.ejs: -------------------------------------------------------------------------------- 1 | <%- JSON.stringify($$) -%> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/testcase2/macros/頁尾附註.ejs: -------------------------------------------------------------------------------- 1 | <%- JSON.stringify($$) -%> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/testcase2/output: -------------------------------------------------------------------------------- 1 | The following items are all macros, though: 2 | 3 | * ["Foo","Bar","Baz"] 4 | * ["HéllöWôrld"] 5 | * ["下一頁","カタカナ","BLAH"] 6 | * ["Quoted, Comma","Another, quoted"] 7 | * ["()()()"] 8 | * ["{{}}{{}}{{}}"] 9 | 10 | Here is a ["With many","parameters","including \"quoted\"","text of both 'kinds'","even \"escaped\"","like 'these'","and numbers","-10","0","0.1","10","100"] that even works inline. 11 | 12 | Here is a [{"es":"es/JavaScript/Acerca_de_JavaScript","en":"en/JavaScript/About_JavaScript"}] that even works inline. 13 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/testcase2/output_selective_remove: -------------------------------------------------------------------------------- 1 | The following items are all macros, though: 2 | 3 | * {{ MacroUsingParams("Foo", "Bar", "Baz") }} 4 | * {{HelloWorld("HéllöWôrld")}} 5 | * 6 | * {{ Alpha_Macro_123 ( "Quoted, Comma", 'Another, quoted' ) }} 7 | * {{ ParenTastic ( "()()()" ) }} 8 | * {{ Bracepocalypse( "{{}}{{}}{{}}" ) }} 9 | 10 | Here is a that even works inline. 11 | 12 | Here is a that even works inline. 13 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/testcase3/macros/jsonify.ejs: -------------------------------------------------------------------------------- 1 | <%- JSON.stringify($$) -%> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/testcase3/output: -------------------------------------------------------------------------------- 1 | Decimals are not truncated to integers: 2 | * ["3.6"] 3 | * [{"x":3.6}] 4 | 5 | Quotes and escaped quotes work correctly 6 | * ["This is a \"test\""] 7 | * ["This is a 'test'"] 8 | * ["This is a \"test\""] 9 | * ["This is a 'test'"] 10 | * ["This is a 'test'"] 11 | * ["This is a \"test\""] 12 | * [{"x":"This is a 'test'"}] 13 | * [{"x":"This is a \"test\""}] 14 | 15 | Empty arguments are not elided 16 | * [""] 17 | * [""] 18 | * ["","",""] 19 | * ["docs/User:trevorh/aTest","docs/User:trevorh/Generic_template_test","","Anything"] 20 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/render/testcase4/macros/jsonify.ejs: -------------------------------------------------------------------------------- 1 | <%- JSON.stringify($$) -%> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/documents/autorequire-expected.txt: -------------------------------------------------------------------------------- 1 | This exercises autorequire: 2 | 3 | * The result is a SUCCESS! 4 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/documents/autorequire.txt: -------------------------------------------------------------------------------- 1 | This exercises autorequire: 2 | 3 | * {{ autorequire-used('SUCCESS') }} 4 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/documents/document2-expected.txt: -------------------------------------------------------------------------------- 1 | This document will use macros that will experience errors: 2 | * {{ broken1("this breaks first") }} 3 | * {{ broken2("this breaks second") }} 4 | * {{ broken3("this breaks third") }} 5 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/documents/document2.txt: -------------------------------------------------------------------------------- 1 | This document will use macros that will experience errors: 2 | * {{ broken1("this breaks first") }} 3 | * {{ broken2("this breaks second") }} 4 | * {{ broken3("this breaks third") }} 5 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/documents/library-test-expected.txt: -------------------------------------------------------------------------------- 1 | Testing a library: 2 | 3 | * First: The result was A HUGE SUCCESS! 4 | * Second: The result was A FOLLOWUP SUCCESS! 5 | * Third: The result was AN ENCORE! 6 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/documents/library-test.txt: -------------------------------------------------------------------------------- 1 | Testing a library: 2 | 3 | * First: {{ library1-used("A HUGE SUCCESS") }} 4 | * Second: {{ library1-used("A FOLLOWUP SUCCESS") }} 5 | * Third: {{ library1-used("AN ENCORE") }} 6 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/documents/memcache-expected.txt: -------------------------------------------------------------------------------- 1 | This is a test of a template using Memcache: 2 | 3 | * true 4 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/documents/memcache.txt: -------------------------------------------------------------------------------- 1 | This is a test of a template using Memcache: 2 | 3 | * {{ memcache-user() }} 4 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/documents/request-variables-expected.txt: -------------------------------------------------------------------------------- 1 | This is a test of request environment vars: 2 | 3 | * en-US 4 | * This is the alpha value 5 | * Consultez les forums dédiés de Mozilla 6 | * コミュニティ 7 | * 커뮤니티 8 | * ["one","two","three"] 9 | * {"a":1,"b":2,"c":3} 10 | 11 | That's all folks! 12 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/documents/request-variables.txt: -------------------------------------------------------------------------------- 1 | This is a test of request environment vars: 2 | 3 | * {{ reqlocale }} 4 | * {{ reqvar('alpha') }} 5 | * {{ reqvar('beta') }} 6 | * {{ reqvar('gamma') }} 7 | * {{ reqvar('delta') }} 8 | * {{ reqvar-json('foo') }} 9 | * {{ reqvar-json('bar') }} 10 | 11 | That's all folks! 12 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/documents/require-test-expected.txt: -------------------------------------------------------------------------------- 1 | Testing "require" of npm package: 2 | 3 | * First: Does "http.headers.Accept" exist? yes! 4 | * Second: Does "css.properties" exist? yes! 5 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/documents/require-test.txt: -------------------------------------------------------------------------------- 1 | Testing "require" of npm package: 2 | 3 | * First: {{ require-used("http.headers.Accept") }} 4 | * Second: {{ require-used("css.properties") }} 5 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/documents/template-exec-expected.txt: -------------------------------------------------------------------------------- 1 | Testing a library: 2 | 3 | * The result was a SUCCESS! 4 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/documents/template-exec.txt: -------------------------------------------------------------------------------- 1 | Testing a library: 2 | 3 | * {{ template-exec('SUCCESS') }} 4 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/documents/시작하기-expected.txt: -------------------------------------------------------------------------------- 1 | * 시작하기 2 | * foo 3 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/documents/시작하기.txt: -------------------------------------------------------------------------------- 1 | * 시작하기 2 | * {{t1}} 3 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/homepage-expected.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Hello from KumaScript!

4 | 5 | 6 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/macros/autorequire-lib1.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | export default buildAPI({ 3 | result: function (str) { 4 | return str + '!'; 5 | } 6 | }); 7 | %> 8 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/macros/autorequire-used.ejs: -------------------------------------------------------------------------------- 1 | The result is a <%= test_api.result($0) %> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/macros/broken2.ejs: -------------------------------------------------------------------------------- 1 | <%= ### while class -%> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/macros/broken3.ejs: -------------------------------------------------------------------------------- 1 | <% throw new Error("this macro throws"); %> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/macros/json.ejs: -------------------------------------------------------------------------------- 1 | <%= JSON.stringify( $$ ) %> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/macros/json_unescaped.ejs: -------------------------------------------------------------------------------- 1 | <%- JSON.stringify( $$ ) %> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/macros/library1-used.ejs: -------------------------------------------------------------------------------- 1 | <% var library1 = require_macro('library1'); %> 2 | The result <%= library1($0) %> 3 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/macros/library1.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | function result (str) { 3 | return "was " + str + "!"; 4 | }; 5 | 6 | export default result; 7 | %> 8 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/macros/memcache-user.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | var key = 'test-cache'; 3 | var value1 = cacheFn(key, 3600, function (next) { 4 | next("Cached"); 5 | }); 6 | var value2 = cacheFn(key, 3600, function (next) { 7 | next("THIS SHOULDN'T BE EXECUTED"); 8 | }); 9 | var used_cache = (value1 == value2); 10 | %> 11 | <%= used_cache %> 12 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/macros/reqlocale.ejs: -------------------------------------------------------------------------------- 1 | <%= env.locale %> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/macros/require-used.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | const bcd = require('@mdn/browser-compat-data'); 3 | 4 | var queryString = $0; 5 | 6 | function getData() { 7 | return queryString.split('.').reduce(function(prev, curr) { 8 | return prev ? prev[curr] : undefined 9 | }, bcd); 10 | } 11 | 12 | var output = `Does "${queryString}" exist? ${getData() ? 'yes!' : 'no!'}`; 13 | %> 14 | <%- output %> 15 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/macros/reqvar-json.ejs: -------------------------------------------------------------------------------- 1 | <%- JSON.stringify(env[$0]) %> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/macros/reqvar.ejs: -------------------------------------------------------------------------------- 1 | <%= env[$0] %> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/macros/t1.ejs: -------------------------------------------------------------------------------- 1 | foo 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/macros/t2.ejs: -------------------------------------------------------------------------------- 1 | <%= parseInt(arguments[0]) + parseInt(arguments[1]) %> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/macros/t3.ejs: -------------------------------------------------------------------------------- 1 | t3 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/macros/template-exec-template.ejs: -------------------------------------------------------------------------------- 1 | The result was a <%= $0 %>! 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/server/macros/template-exec.ejs: -------------------------------------------------------------------------------- 1 | <%= template('template-exec-template', [$0]) %> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/templates/duplicate_macros/dup/test.ejs: -------------------------------------------------------------------------------- 1 | <%= 2 %> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/templates/duplicate_macros/dup/test.json: -------------------------------------------------------------------------------- 1 | [{}] 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/templates/duplicate_macros/test.ejs: -------------------------------------------------------------------------------- 1 | <%= 1 %> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/templates/empty_macro_dir/README: -------------------------------------------------------------------------------- 1 | This file is here only because we need a directory with no macros 2 | in it, and if we use a completely empty directory, git will remove 3 | the directory itself from the repo 4 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/templates/macros/Test2.ejs: -------------------------------------------------------------------------------- 1 | <%= n+1 -%> 2 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/templates/macros/async.ejs: -------------------------------------------------------------------------------- 1 | <%_ let result = await async_adder(1); _%> 2 | <%= result %> 3 | <%= await async_adder(2) -%> 4 | -------------------------------------------------------------------------------- /kumascript/tests/fixtures/templates/macros/test1.ejs: -------------------------------------------------------------------------------- 1 | <%= 1 -%> 2 | -------------------------------------------------------------------------------- /kumascript/tests/macros/Deprecated.test.ts: -------------------------------------------------------------------------------- 1 | import { assert, itMacro, describeMacro } from "./utils.js"; 2 | 3 | // TODO: Add tests for other {{Deprecated_*}} macros 4 | describeMacro("Deprecated_Inline", function () { 5 | itMacro("No arguments (en-US)", function (macro) { 6 | return assert.eventually.equal( 7 | macro.call(), 8 | ` 9 | Deprecated 10 | ` 11 | ); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /kumascript/tests/macros/fixtures/apiref/groupdata.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "TestInterface": { 4 | "overview": ["TestInterface API"], 5 | "interfaces": ["AnInterface"], 6 | "methods": ["AnInterface.doOneThing()", "AnotherInterface.doAnother()"], 7 | "properties": [] 8 | } 9 | } 10 | ] 11 | -------------------------------------------------------------------------------- /kumascript/tests/macros/fixtures/compat/prefixes.json: -------------------------------------------------------------------------------- 1 | { 2 | "prefixes": { 3 | "feature": { 4 | "__compat": { 5 | "support": { 6 | "chrome": { 7 | "prefix": "-webkit-", 8 | "version_added": "10" 9 | }, 10 | "firefox": [ 11 | { 12 | "version_added": "12" 13 | }, 14 | { 15 | "prefix": "-moz-", 16 | "version_added": "5" 17 | } 18 | ] 19 | } 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /kumascript/tests/macros/fixtures/listgroups/groupdata.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "BTestInterface": { 4 | "overview": ["An overview page for BTestInterface API"] 5 | }, 6 | "A2TestInterface": { 7 | "overview": ["A2TestInterface overview"] 8 | }, 9 | "CTestInterface": {}, 10 | "ATestInterface": { 11 | "overview": ["An overview page for ATestInterface API"] 12 | } 13 | } 14 | ] 15 | -------------------------------------------------------------------------------- /kumascript/tests/macros/svgattr.test.ts: -------------------------------------------------------------------------------- 1 | import { assert, itMacro, describeMacro } from "./utils.js"; 2 | 3 | describeMacro("SVGAttr", () => { 4 | for (const locale of ["en-US", "fr"]) { 5 | for (const attr of ["min", "max"]) { 6 | itMacro(`${locale} ${attr} `, (macro) => { 7 | macro.ctx.env.locale = locale; 8 | return assert.eventually.equal( 9 | macro.call(attr), 10 | `${attr}` 11 | ); 12 | }); 13 | } 14 | } 15 | }); 16 | -------------------------------------------------------------------------------- /libs/constants/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@yari-internal/constants", 3 | "version": "0.0.1", 4 | "private": true, 5 | "license": "MPL-2.0", 6 | "type": "module", 7 | "exports": "./index.js", 8 | "main": "index.js", 9 | "types": "index.d.ts" 10 | } 11 | -------------------------------------------------------------------------------- /libs/env/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@yari-internal/env", 3 | "version": "0.0.1", 4 | "private": true, 5 | "license": "MPL-2.0", 6 | "type": "module", 7 | "exports": "./index.js", 8 | "main": "index.js", 9 | "types": "index.d.ts" 10 | } 11 | -------------------------------------------------------------------------------- /libs/fundamental-redirects/index.d.ts: -------------------------------------------------------------------------------- 1 | export function resolveFundamental(path: string): { 2 | url?: string; 3 | status?: 301 | 302; 4 | }; 5 | -------------------------------------------------------------------------------- /libs/fundamental-redirects/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@yari-internal/fundamental-redirects", 3 | "version": "0.0.1", 4 | "private": true, 5 | "license": "MPL-2.0", 6 | "type": "module", 7 | "exports": "./index.js", 8 | "main": "index.js", 9 | "types": "index.d.ts" 10 | } 11 | -------------------------------------------------------------------------------- /libs/languages/index.d.ts: -------------------------------------------------------------------------------- 1 | declare const _exports: Record; 2 | 3 | export default _exports; 4 | -------------------------------------------------------------------------------- /libs/languages/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@yari-internal/languages", 3 | "version": "0.0.1", 4 | "private": true, 5 | "license": "MPL-2.0", 6 | "type": "module", 7 | "exports": "./index.js", 8 | "main": "index.js", 9 | "types": "index.d.ts" 10 | } 11 | -------------------------------------------------------------------------------- /libs/locale-utils/index.d.ts: -------------------------------------------------------------------------------- 1 | export function getLocale(request: any, fallback?: string): any; 2 | export function isValidLocale(locale: any): locale is string; 3 | -------------------------------------------------------------------------------- /libs/locale-utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@yari-internal/locale-utils", 3 | "version": "0.0.1", 4 | "private": true, 5 | "license": "MPL-2.0", 6 | "type": "module", 7 | "exports": "./index.js", 8 | "main": "index.js", 9 | "types": "index.d.ts", 10 | "dependencies": { 11 | "accept-language-parser": "^1.5.0", 12 | "cookie": "^0.7.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /libs/play/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@yari-internal/play", 3 | "version": "0.0.1", 4 | "private": true, 5 | "license": "MPL-2.0", 6 | "type": "module", 7 | "main": "index.js", 8 | "types": "index.js", 9 | "dependencies": { 10 | "he": "^1.2.0" 11 | }, 12 | "devDependencies": { 13 | "@types/he": "^1.2.3" 14 | }, 15 | "engines": { 16 | "node": ">=20" 17 | }, 18 | "export": "index.js" 19 | } 20 | -------------------------------------------------------------------------------- /libs/play/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["*.js"], 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "strict": true, 7 | "declaration": true, 8 | "emitDeclarationOnly": true, 9 | "esModuleInterop": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /libs/pong/cc2ip.d.ts: -------------------------------------------------------------------------------- 1 | export const cc2ip: Record; 2 | export default function anonymousIpByCC(countryCode: string): string; 3 | -------------------------------------------------------------------------------- /libs/pong/coding.d.ts: -------------------------------------------------------------------------------- 1 | export class Coder { 2 | /** 3 | * Create a Coder to en/decode and sign/verify fields. 4 | * @param {string} signSecret - The signing secret. 5 | */ 6 | constructor(signSecret: string); 7 | /** 8 | * The signing secret. 9 | * @type {string} 10 | */ 11 | signSecret: string; 12 | encodeAndSign(s?: string): string; 13 | decodeAndVerify(tuple?: string): string | null; 14 | } 15 | -------------------------------------------------------------------------------- /libs/pong/image.d.ts: -------------------------------------------------------------------------------- 1 | export function fetchImage(src: string): Promise<{ 2 | buf: ArrayBuffer; 3 | contentType: string; 4 | }>; 5 | -------------------------------------------------------------------------------- /libs/pong/image.js: -------------------------------------------------------------------------------- 1 | /* global fetch */ 2 | export async function fetchImage(src) { 3 | const imageResponse = await fetch(src); 4 | const imageBuffer = await imageResponse.arrayBuffer(); 5 | const contentType = imageResponse.headers.get("content-type"); 6 | return { buf: imageBuffer, contentType }; 7 | } 8 | -------------------------------------------------------------------------------- /libs/pong/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from "./coding.js"; 2 | export * from "./image.js"; 3 | export * from "./pong.js"; 4 | export * from "./pong2.js"; 5 | -------------------------------------------------------------------------------- /libs/pong/index.js: -------------------------------------------------------------------------------- 1 | export * from "./coding.js"; 2 | export * from "./image.js"; 3 | export * from "./pong.js"; 4 | export * from "./pong2.js"; 5 | -------------------------------------------------------------------------------- /libs/pong/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@yari-internal/pong", 3 | "version": "0.0.1", 4 | "private": true, 5 | "license": "MPL-2.0", 6 | "type": "module", 7 | "main": "index.js", 8 | "dependencies": { 9 | "@adzerk/decision-sdk": "^1.0.0-beta.20", 10 | "he": "^1.2.0" 11 | }, 12 | "export": "./index.js" 13 | } 14 | -------------------------------------------------------------------------------- /libs/pong/types.d.ts: -------------------------------------------------------------------------------- 1 | type Colors = { 2 | textColor?: string; 3 | backgroundColor?: string; 4 | ctaTextColor?: string; 5 | ctaBackgroundColor?: string; 6 | textColorDark?: string; 7 | backgroundColorDark?: string; 8 | ctaTextColorDark?: string; 9 | ctaBackgroundColorDark?: string; 10 | }; 11 | 12 | export type Payload = { 13 | status: Status; 14 | click: string; 15 | view: string; 16 | copy?: string; 17 | image?: string; 18 | alt?: string; 19 | cta?: string; 20 | colors?: Colors; 21 | version: number; 22 | heading?: string; 23 | }; 24 | -------------------------------------------------------------------------------- /libs/pong/validate-cc2ip.js: -------------------------------------------------------------------------------- 1 | import { cc2ip } from "./cc2ip.js"; 2 | 3 | for (const [k, v] of Object.entries(cc2ip)) { 4 | const { country_code } = await (await fetch(`http://ipwho.is/${v}`)).json(); 5 | if (k !== country_code || (k === "UK" && country_code === "GB")) { 6 | console.log(`${k} -> ${v} : (${k === country_code}) (${country_code})`); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /libs/slug-utils/index.d.ts: -------------------------------------------------------------------------------- 1 | export function slugToFolder(slug: string, joiner?: string): string; 2 | export function decodePath(path: string): string; 3 | export function encodePath(path: string): string; 4 | -------------------------------------------------------------------------------- /libs/slug-utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@yari-internal/slug-utils", 3 | "version": "0.0.1", 4 | "private": true, 5 | "license": "MPL-2.0", 6 | "type": "module", 7 | "main": "index.js", 8 | "types": "index.d.ts", 9 | "dependencies": { 10 | "sanitize-filename": "^1.6.3" 11 | }, 12 | "export": "./index.js" 13 | } 14 | -------------------------------------------------------------------------------- /libs/types/core.ts: -------------------------------------------------------------------------------- 1 | export type Locale = 2 | | "de" 3 | | "en-US" 4 | | "es" 5 | | "fr" 6 | | "ja" 7 | | "ko" 8 | | "pt-BR" 9 | | "ru" 10 | | "zh-CN" 11 | | "zh-TW"; 12 | export type TranslatedLocale = Exclude; 13 | -------------------------------------------------------------------------------- /libs/types/hydration.ts: -------------------------------------------------------------------------------- 1 | import { BlogPostMetadata } from "./blog.js"; 2 | 3 | interface HydrationData { 4 | hyData?: T; 5 | doc?: S; 6 | blogMeta?: BlogPostMetadata | null; 7 | pageNotFound?: boolean; 8 | pageTitle?: any; 9 | pageDescription?: string; 10 | possibleLocales?: any; 11 | locale?: any; 12 | noIndexing?: boolean; 13 | onlyFollow?: boolean; 14 | image?: string | null; 15 | url: string; 16 | } 17 | 18 | export type { HydrationData }; 19 | -------------------------------------------------------------------------------- /libs/types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@yari-internal/types", 3 | "version": "0.0.1", 4 | "private": true, 5 | "license": "MPL-2.0", 6 | "type": "module", 7 | "main": "document.ts", 8 | "export": "./index.js" 9 | } 10 | -------------------------------------------------------------------------------- /lint-staged.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | "!*.{js,jsx,ts,tsx,css,scss}": "prettier --ignore-unknown --write", 3 | "*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"], 4 | "*.{css,scss}": ["stylelint --fix --allow-empty-input", "prettier --write"], 5 | }; 6 | -------------------------------------------------------------------------------- /markdown/.gitignore: -------------------------------------------------------------------------------- 1 | __image_snapshots__/ 2 | -------------------------------------------------------------------------------- /markdown/h2m/index.ts: -------------------------------------------------------------------------------- 1 | import { unified } from "unified"; 2 | import rehypeParse from "rehype-parse"; 3 | import rehypeRemark from "rehype-remark"; 4 | import remarkStringify from "remark-stringify"; 5 | import remarkGfm from "remark-gfm"; 6 | 7 | export function h2mSync(html: string) { 8 | const file = unified() 9 | .use(rehypeParse) 10 | .use(rehypeRemark) 11 | .use(remarkGfm) 12 | .use(remarkStringify) 13 | .processSync(html); 14 | return String(file); 15 | } 16 | -------------------------------------------------------------------------------- /markdown/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./utils/index.js"; 2 | export * from "./m2h/index.js"; 3 | export * from "./h2m/index.js"; 4 | -------------------------------------------------------------------------------- /markdown/localizations/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "translations": { 3 | "": { 4 | "card_note_label": { 5 | "msgid": "card_note_label", 6 | "msgstr": ["Hinweis:"] 7 | }, 8 | "card_warning_label": { 9 | "msgid": "card_warning_label", 10 | "msgstr": ["Warnung:"] 11 | }, 12 | "card_callout_label": { 13 | "msgid": "card_callout_label", 14 | "msgstr": ["Bemerkung:"] 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /markdown/localizations/en-US.json: -------------------------------------------------------------------------------- 1 | { 2 | "translations": { 3 | "": { 4 | "card_note_label": { 5 | "msgid": "card_note_label", 6 | "msgstr": ["Note:"] 7 | }, 8 | "card_warning_label": { 9 | "msgid": "card_warning_label", 10 | "msgstr": ["Warning:"] 11 | }, 12 | "card_callout_label": { 13 | "msgid": "card_callout_label", 14 | "msgstr": ["Callout:"] 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /markdown/localizations/es.json: -------------------------------------------------------------------------------- 1 | { 2 | "translations": { 3 | "": { 4 | "card_note_label": { 5 | "msgid": "card_note_label", 6 | "msgstr": ["Nota:"] 7 | }, 8 | "card_warning_label": { 9 | "msgid": "card_warning_label", 10 | "msgstr": ["Advertencia:"] 11 | }, 12 | "card_callout_label": { 13 | "msgid": "card_callout_label", 14 | "msgstr": ["Observación:"] 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /markdown/localizations/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "translations": { 3 | "": { 4 | "card_note_label": { 5 | "msgid": "card_note_label", 6 | "msgstr": ["Note :"] 7 | }, 8 | "card_warning_label": { 9 | "msgid": "card_warning_label", 10 | "msgstr": ["Attention :"] 11 | }, 12 | "card_callout_label": { 13 | "msgid": "card_callout_label", 14 | "msgstr": ["Remarque :"] 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /markdown/localizations/ja.json: -------------------------------------------------------------------------------- 1 | { 2 | "translations": { 3 | "": { 4 | "card_note_label": { 5 | "msgid": "card_note_label", 6 | "msgstr": ["メモ:"] 7 | }, 8 | "card_warning_label": { 9 | "msgid": "card_warning_label", 10 | "msgstr": ["警告:"] 11 | }, 12 | "card_callout_label": { 13 | "msgid": "card_callout_label", 14 | "msgstr": ["注目:"] 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /markdown/localizations/ko.json: -------------------------------------------------------------------------------- 1 | { 2 | "translations": { 3 | "": { 4 | "card_note_label": { 5 | "msgid": "card_note_label", 6 | "msgstr": ["참고:"] 7 | }, 8 | "card_warning_label": { 9 | "msgid": "card_warning_label", 10 | "msgstr": ["경고:"] 11 | }, 12 | "card_callout_label": { 13 | "msgid": "card_callout_label", 14 | "msgstr": ["알림:"] 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /markdown/localizations/pl.json: -------------------------------------------------------------------------------- 1 | { 2 | "translations": { 3 | "": { 4 | "card_note_label": { 5 | "msgid": "card_note_label", 6 | "msgstr": ["Uwaga:"] 7 | }, 8 | "card_warning_label": { 9 | "msgid": "card_warning_label", 10 | "msgstr": ["Ważne:"] 11 | }, 12 | "card_callout_label": { 13 | "msgid": "card_callout_label", 14 | "msgstr": ["Obserwacja:"] 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /markdown/localizations/pt-BR.json: -------------------------------------------------------------------------------- 1 | { 2 | "translations": { 3 | "": { 4 | "card_note_label": { 5 | "msgid": "card_note_label", 6 | "msgstr": ["Nota:"] 7 | }, 8 | "card_warning_label": { 9 | "msgid": "card_warning_label", 10 | "msgstr": ["Aviso:"] 11 | }, 12 | "card_callout_label": { 13 | "msgid": "card_callout_label", 14 | "msgstr": ["Observação:"] 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /markdown/localizations/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "translations": { 3 | "": { 4 | "card_note_label": { 5 | "msgid": "card_note_label", 6 | "msgstr": ["Примечание:"] 7 | }, 8 | "card_warning_label": { 9 | "msgid": "card_warning_label", 10 | "msgstr": ["Предупреждение:"] 11 | }, 12 | "card_callout_label": { 13 | "msgid": "card_callout_label", 14 | "msgstr": ["Сноска:"] 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /markdown/localizations/zh-CN.json: -------------------------------------------------------------------------------- 1 | { 2 | "translations": { 3 | "": { 4 | "card_note_label": { 5 | "msgid": "card_note_label", 6 | "msgstr": ["备注:"] 7 | }, 8 | "card_warning_label": { 9 | "msgid": "card_warning_label", 10 | "msgstr": ["警告:"] 11 | }, 12 | "card_callout_label": { 13 | "msgid": "card_callout_label", 14 | "msgstr": ["标注:"] 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /markdown/localizations/zh-TW.json: -------------------------------------------------------------------------------- 1 | { 2 | "translations": { 3 | "": { 4 | "card_note_label": { 5 | "msgid": "card_note_label", 6 | "msgstr": ["備註:"] 7 | }, 8 | "card_warning_label": { 9 | "msgid": "card_warning_label", 10 | "msgstr": ["警告:"] 11 | }, 12 | "card_callout_label": { 13 | "msgid": "card_callout_label", 14 | "msgstr": ["標註:"] 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /markdown/utils/index.ts: -------------------------------------------------------------------------------- 1 | const KS_RE = /{{([^}]*)}}/g; 2 | 3 | export function encodeKS(raw) { 4 | return raw.replace( 5 | KS_RE, 6 | (_, ks) => `{{${Buffer.from(ks).toString("base64")}}}` 7 | ); 8 | } 9 | 10 | export function decodeKS(raw) { 11 | return raw.replace( 12 | KS_RE, 13 | (_, ks) => `{{${Buffer.from(ks, "base64").toString()}}}` 14 | ); 15 | } 16 | 17 | export default { 18 | encodeKS, 19 | decodeKS, 20 | }; 21 | -------------------------------------------------------------------------------- /playwright.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | use: { 3 | channel: "chrome", 4 | // See more interesting options at https://playwright.dev/docs/test-configuration/ 5 | // viewport: { width: 1280, height: 720 }, 6 | // video: "retain-on-failure", 7 | }, 8 | }; 9 | -------------------------------------------------------------------------------- /server/filename.ts: -------------------------------------------------------------------------------- 1 | import { fileURLToPath } from "node:url"; 2 | export const filename = fileURLToPath(import.meta.resolve("./index.js")); 3 | -------------------------------------------------------------------------------- /server/types.ts: -------------------------------------------------------------------------------- 1 | export interface FlawFilters { 2 | popularity?: string; 3 | fixableFlaws?: string; 4 | flaws?: string; 5 | search_flaws?: string | Array; 6 | mdn_url?: string; 7 | title?: string; 8 | } 9 | -------------------------------------------------------------------------------- /ssr/.gitignore: -------------------------------------------------------------------------------- 1 | include.ts 2 | -------------------------------------------------------------------------------- /ssr/include.d.ts: -------------------------------------------------------------------------------- 1 | interface AssetManifest { 2 | files: Record; 3 | entrypoints: string[]; 4 | } 5 | 6 | export const WEBFONT_URLS: string[]; 7 | export const GTAG_PATH: null | string; 8 | export const BASE_URL: string; 9 | export const ALWAYS_ALLOW_ROBOTS: boolean; 10 | export const ASSET_MANIFEST: AssetManifest; 11 | -------------------------------------------------------------------------------- /ssr/index.ts: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { StaticRouter } from "react-router-dom"; 3 | 4 | import { App } from "../client/src/app"; 5 | import render from "./render"; 6 | import { HydrationData } from "../libs/types/hydration"; 7 | 8 | export function renderHTML(context: HydrationData) { 9 | return render( 10 | React.createElement( 11 | StaticRouter, 12 | { location: context.url }, 13 | React.createElement(App, context) 14 | ), 15 | context.url, 16 | context 17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /ssr/modules.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*?inline" { 2 | const source: string; 3 | export default source; 4 | } 5 | 6 | declare module "*?public" { 7 | const src: string; 8 | export default src; 9 | } 10 | -------------------------------------------------------------------------------- /ssr/print.css: -------------------------------------------------------------------------------- 1 | .article-actions-container, 2 | .main-menu-toggle, 3 | .document-toc-container, 4 | .on-github, 5 | .sidebar, 6 | .top-navigation-main, 7 | .page-footer, 8 | .top-banner, 9 | .place, 10 | ul.prev-next, 11 | .language-menu { 12 | display: none !important; 13 | } 14 | 15 | .main-page-content, 16 | .main-page-content pre { 17 | padding: 2px; 18 | } 19 | 20 | .main-page-content pre { 21 | border-left-width: 2px; 22 | } 23 | -------------------------------------------------------------------------------- /ssr/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../client/tsconfig.json", 3 | "include": [".", "../client/**/*.d.ts"], 4 | "exclude": ["dist"] 5 | } 6 | -------------------------------------------------------------------------------- /testing/content/files/en-us/_redirects.txt: -------------------------------------------------------------------------------- 1 | # FROM-URL TO-URL 2 | /en-US/docs/Web/Fuu /en-US/docs/Web/Foo 3 | /en-US/docs/Web/CSS/dumber /en-US/docs/Web/CSS/number 4 | /en-US/docs/Web/API/Bob /en-US/docs/Web/API/Blob 5 | /en-US/docs/Web/HTML/Element/anchor /en-US/docs/Web/HTML/Element/a 6 | /en-US/docs/Web/JavaScript/Reference/Stern_mode /en-US/docs/Web/JavaScript/Reference/Strict_mode 7 | /en-US/docs/Web/JavaScript/Reference/Global_Objects/Flag /en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean 8 | -------------------------------------------------------------------------------- /testing/content/files/en-us/glossary/bézier_curve/cubic_bézier_curves_with_grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/testing/content/files/en-us/glossary/bézier_curve/cubic_bézier_curves_with_grid.png -------------------------------------------------------------------------------- /testing/content/files/en-us/web/api/blob/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Blob 3 | slug: Web/API/Blob 4 | tags: 5 | - API 6 | - Blob 7 | - File API 8 | - Interface 9 | - Raw 10 | - Reference 11 | - data 12 | --- 13 |

You've reached the Blob test page.

14 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/api/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Web APIs 3 | slug: Web/API 4 | --- 5 | 6 |

This is a list of all the APIs that are available.

7 | 8 |
{{ListGroups}}
9 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/api/page_visibility_api/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Page Visibility API 3 | slug: Web/API/Page_Visibility_API 4 | browser-compat: api.Document.visibilityState 5 | tags: 6 | - API 7 | - DOM 8 | - Documents 9 | - Hidden Pages 10 | - Hiding Pages 11 | - Intermediate 12 | - Page Visibility 13 | - Page Visibility API 14 | - Showing Pages 15 | - Tutorials 16 | - Visibility 17 | - Visible Pages 18 | --- 19 | 20 |

Browser compatibility

21 | 22 |

{{Compat}}

23 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/badbcdqueries/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Bad BCD Queries 3 | slug: Web/BadBCDQueries 4 | browser-compat: api.Does.Not.exist 5 | --- 6 | 7 |

Browser compatibility

8 | 9 |

{{Compat}}

10 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/brokenlinks/broken_http_link/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Http:// link that is not a valid link 3 | slug: Web/BrokenLinks/Broken_http_link 4 | --- 5 | 6 |

http://

7 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/brokenlinks/self_links/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Links that link to the current page you're on 3 | slug: Web/BrokenLinks/Self_links 4 | --- 5 | 6 |

Straight up

7 | 8 |

Anchored

9 | 10 |

Self-link but wrong case

11 | 12 |

Self-link but wrong case and with anchor

13 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/brokenlinks/without_locale_prefix/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Broken links that lack a locale prefix 3 | slug: Web/BrokenLinks/Without_locale_prefix 4 | --- 5 | 6 |

A broken link due to lack of prefix

7 |

Will redirect

8 |

Will not help to try with 'en-US'

9 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/brokenlinks_markdown/broken_http_link/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Http:// link that is not a valid link 3 | slug: Web/BrokenLinks_Markdown/Broken_http_link 4 | --- 5 | [`http://`](http://) 6 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/brokenlinks_markdown/self_links/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Links that link to the current page you're on 3 | slug: Web/BrokenLinks_Markdown/Self_links 4 | --- 5 | [Straight up](/en-US/docs/Web/BrokenLinks_Markdown/Self_links) 6 | 7 | [Anchored](/en-US/docs/Web/BrokenLinks_Markdown/Self_links#anchored) 8 | 9 | [Self-link but wrong case](/en-US/docs/Web/BrokenLinks_Markdown/self_Links) 10 | 11 | [Self-link but wrong case and with anchor](/en-US/docs/Web/BrokenLinks_Markdown/self_Links#hash) 12 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/brokenlinks_markdown/without_locale_prefix/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Broken links that lack a locale prefix 3 | slug: Web/BrokenLinks_Markdown/Without_locale_prefix 4 | --- 5 | [A broken link due to lack of prefix](/docs/Web/CSS/number) 6 | 7 | [Will redirect](/docs/Web/CSS/dumber) 8 | 9 | [Will not help to try with 'en-US'](/docs/Hopelessly/Broken) 10 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/brokenlinks_repeats/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'A page peppered with broken links with repeats' 3 | slug: Web/BrokenLinks_Repeats 4 | --- 5 | 6 |

Will redirect

7 |

Also, make it appear as text too

8 |

Repeated a third time

9 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/css/number/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: 3 | slug: Web/CSS/number 4 | page-type: css-type 5 | --- 6 | 7 |

You've reached the number test page.

8 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/embeddable/legacy/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Legacy Live Samples 3 | slug: Web/Embeddable/Legacy 4 | --- 5 | 6 | # Foo 7 | 8 | ```html 9 | foo 10 | ``` 11 | 12 | ```css 13 | span { 14 | background-color: #pink; 15 | } 16 | ``` 17 | 18 | {{ EmbedLiveSample('foo', '100%', '70') }} 19 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/empty_image/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Empty tag 3 | slug: Web/Empty_image 4 | --- 5 | 6 |

7 | Check out this image: 8 | 9 | Pretty nihilistic, eh? 10 |

11 | 12 |

13 | This one is based on make sure we've solved: 14 | issue#3186 15 |

16 | 17 | 18 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/externallinks/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Lots of external links 3 | slug: Web/ExternalLinks 4 | --- 5 | 6 | 7 | 8 | 14 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/fixable_flaws/bad_pre_tags/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Fixable flawed
 tags
3 | slug: Web/Fixable_Flaws/Bad_pre_tags
4 | ---
5 | 
6 | 

Fixable pre tag...

7 |
<pre><code>code
8 | 
9 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/fixable_flaws/deprecated_macros/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Deprecated macros 3 | slug: Web/Fixable_Flaws/Deprecated_macros 4 | --- 5 | 6 |

Don't use macros no more

7 | 8 |
    9 |
  • {{event("abort")}}
  • 10 |
11 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/fixable_flaws/images/fixable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/testing/content/files/en-us/web/fixable_flaws/images/fixable.png -------------------------------------------------------------------------------- /testing/content/files/en-us/web/fixable_flaws/images/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Fixable flawed images 3 | slug: Web/Fixable_Flaws/Images 4 | --- 5 | 6 |

Fixable...

7 | 8 | 9 |

Hopeless...

10 | 11 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/foo/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: ': A test tag' 3 | slug: Web/Foo 4 | tags: 5 | - Tag1 6 | - Tag2 7 | --- 8 |

{{HTMLSidebar}}

9 | 10 |
11 |

This should not become the summary.

12 |
13 | 14 |

This becomes the summary.

15 | 16 |
17 | Screenshot of colors 18 |
A perfectly normal image
19 |
20 | 21 |

Heading 3

22 | 23 |

Heading 4 with own bad ID

24 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/foo/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/testing/content/files/en-us/web/foo/screenshot.png -------------------------------------------------------------------------------- /testing/content/files/en-us/web/fubar/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: ': A test page' 3 | slug: Web/Fubar 4 | tags: 5 | - slang 6 | - acronym 7 | --- 8 |
{{ EmbedLiveSample('example', '300', '300', "", "does/not/exist") }}
9 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/heading_links/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Naughty headings with tags in them' 3 | slug: Web/Heading_links 4 | --- 5 |

6 | This page exists to demonstrate the heading_links flaw. 7 |

8 | 9 |

One

10 | 11 |

12 | Two 13 |

14 | 15 |

Three

16 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/html/element/a/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: ': The Anchor element' 3 | slug: Web/HTML/Element/a 4 | tags: 5 | - Content 6 | - Element 7 | - HTML 8 | - HTML text-level semantics 9 | - 'HTML:Flow content' 10 | - 'HTML:Interactive content' 11 | - 'HTML:Palpable Content' 12 | - 'HTML:Phrasing content' 13 | - Inline element 14 | - Reference 15 | - Web 16 | --- 17 |

You've reached the HTML anchor element test page.

18 |

hef

19 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/html_headings/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: HTML Headings 3 | slug: Web/HTML_Headings 4 | --- 5 | 6 |

Here's some code

7 | 8 |

At the moment, you're allowed to have formatting in the <h2> and <h3> tags.

9 | 10 |

You can use escaped HTML tags like <pre> still

11 | 12 |

...in the heading tags too.

13 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/images/bad_src/actuallynota.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/testing/content/files/en-us/web/images/bad_src/actuallynota.png -------------------------------------------------------------------------------- /testing/content/files/en-us/web/images/bad_src/actuallynota.svg: -------------------------------------------------------------------------------- 1 | Not SVG 2 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/images/bad_src/empty.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/testing/content/files/en-us/web/images/bad_src/empty.gif -------------------------------------------------------------------------------- /testing/content/files/en-us/web/images/florian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/testing/content/files/en-us/web/images/florian.png -------------------------------------------------------------------------------- /testing/content/files/en-us/web/images/images_in_samples/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/testing/content/files/en-us/web/images/images_in_samples/image.png -------------------------------------------------------------------------------- /testing/content/files/en-us/web/images/images_in_samples/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'A page that references images but not as an tag' 3 | slug: Web/Images/Images_in_samples 4 | --- 5 | 6 |
 7 | body {
 8 |   background-image: url(image.png);
 9 | }
10 | 
11 | 12 |
13 |   <img src=pic.gif>
14 | 
15 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/images/images_in_samples/pic.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/testing/content/files/en-us/web/images/images_in_samples/pic.gif -------------------------------------------------------------------------------- /testing/content/files/en-us/web/images/linked_to/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Links to local file attachments 3 | slug: Web/Images/Linked_to 4 | --- 5 | 6 |

No problems here

7 | 8 |

Dino

9 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/images/repeated_external_images/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Repeated external images' 3 | slug: Web/Images/Repeated_External_Images 4 | --- 5 | 6 |

7 | One 8 | Alt 1 9 |

10 | 11 |

12 | Two, but same image URL 13 | Alt 2 14 |

15 | 16 |

17 | Three, but same image URL 18 | Alt 3 19 |

20 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/images/srcless/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: An img tag that doesn't have a src attribute 3 | slug: Web/Images/Srcless 4 | --- 5 | 6 | Just testing that the flaw checker doesn't crash 7 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Web technology for developers 3 | slug: Web 4 | tags: 5 | - Landing 6 | - Web 7 | --- 8 |

The open Web presents incredible opportunities for developers. To take full advantage of these technologies, you need to know how to use them. Below you'll find the links to MDN's documentation on Web technologies.

9 | 10 |

11 | Check out some sub-pages: 12 |

13 | 17 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/interactiveexample/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'I Have an Interactive Example' 3 | slug: Web/InteractiveExample 4 | tags: 5 | - TagX 6 | - TagY 7 | --- 8 |

{{HTMLSidebar}}

9 | 10 |

Below is a sample interactive example:

11 | 12 |
13 | {{EmbedInteractiveExample("pages/tabbed/video.html", "tabbed-standard")}} 14 |
15 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/javascript/reference/global_objects/boolean/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Boolean 3 | slug: Web/JavaScript/Reference/Global_Objects/Boolean 4 | tags: 5 | - Boolean 6 | - Class 7 | - JavaScript 8 | - Reference 9 | --- 10 |

You've reached the JavaScript Boolean object test page.

11 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/javascript/reference/strict_mode/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Strict mode 3 | slug: Web/JavaScript/Reference/Strict_mode 4 | tags: 5 | - ECMAScript 5 6 | - Guide 7 | - JavaScript 8 | - Strict Mode 9 | --- 10 |

You've reached the JavaScript strict-mode reference test page.

11 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/not_lowercase_anchors/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Anchor links that aren't lowercased 3 | slug: Web/Not_lowercase_anchors 4 | --- 5 | 6 | 14 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/seo_summarized/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'A page' 3 | slug: Web/SEO_Summarized 4 | --- 5 | 6 |

This is going to be the summary. But this is not.

7 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/spec_section_extraction/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Spec section extraction 3 | browser-compat: javascript.builtins.Array.toLocaleString 4 | slug: Web/Spec_Section_Extraction 5 | --- 6 | 7 |

Intro

8 |

Text in Intro

9 | 10 |

Specifications

11 | 12 |

{{Specifications}}

13 | 14 |

Browser compatibility

15 | 16 |

{{Compat}}

17 | 18 |

See also

19 | 20 |

More stuff

21 | -------------------------------------------------------------------------------- /testing/content/files/en-us/web/wrong_xref_macro/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Wrong xref macro(s) 3 | slug: Web/Wrong_xref_macro 4 | --- 5 | 6 |

7 | Promise is actually not a Web API: {{DOMxRef("Promise")}}
8 | It should have used the jsxref macro. 9 |

10 | -------------------------------------------------------------------------------- /testing/content/files/jsondata/L10n-JavaScript.json: -------------------------------------------------------------------------------- 1 | { 2 | "stdlib": { 3 | "en-US": "Standard built-in objects", 4 | "fr": "Objets standards", 5 | "ru": "Стандартные встроенные объекты", 6 | "zh-CN": "JavaScript 标准库" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /testing/content/files/popularities.json: -------------------------------------------------------------------------------- 1 | { 2 | "/en-US/docs/Web/Foo": 0.5, 3 | "/en-US/docs/Web/Bar": 0.51, 4 | "/en-US/docs/Web/Uhhh": 0.0001 5 | } 6 | -------------------------------------------------------------------------------- /testing/integration/headless/__init__.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | 4 | DEFAULT_TIMEOUT = 120 # seconds 5 | # Kuma web domains that are indexed 6 | INDEXED_WEB_DOMAINS = {"developer.mozilla.org"} 7 | 8 | 9 | def request(method, url, **kwargs): 10 | if "timeout" not in kwargs: 11 | kwargs.update(timeout=DEFAULT_TIMEOUT) 12 | if "allow_redirects" not in kwargs: 13 | kwargs.update(allow_redirects=False) 14 | return requests.request(method, url, **kwargs) 15 | -------------------------------------------------------------------------------- /testing/integration/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/testing/integration/utils/__init__.py -------------------------------------------------------------------------------- /testing/scripts/functional-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | export ENV_FILE=.env.testing 5 | 6 | yarn build:prepare 7 | yarn build:legacy 8 | yarn render:html 9 | 10 | yarn test:testing $@ 11 | -------------------------------------------------------------------------------- /testing/tests/filechecker/samplefiles-html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /testing/tests/filechecker/samplefiles-html/onhandler.svg: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /testing/tests/filechecker/samplefiles-html/orphan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/testing/tests/filechecker/samplefiles-html/orphan.png -------------------------------------------------------------------------------- /testing/tests/filechecker/samplefiles-html/png.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/testing/tests/filechecker/samplefiles-html/png.jpeg -------------------------------------------------------------------------------- /testing/tests/filechecker/samplefiles-html/script.svg: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /testing/tests/filechecker/samplefiles-html/zero.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/testing/tests/filechecker/samplefiles-html/zero.gif -------------------------------------------------------------------------------- /testing/tests/filechecker/samplefiles-md/circle.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /testing/tests/filechecker/samplefiles-md/index.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [Circle](circle.svg) 4 | -------------------------------------------------------------------------------- /testing/tests/filechecker/samplefiles-md/orphan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdn/yari/fd705f96722ee821ab5f4c7eeab8ace65b230997/testing/tests/filechecker/samplefiles-md/orphan.png -------------------------------------------------------------------------------- /testing/translated-content/files/fr/web/embeddable/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Incorporer un échantillon en direct avec et sans nom 3 | slug: Web/Embeddable 4 | --- 5 | 6 |

7 | This make exists to demonstrate that the French content has a difference in 8 | the EmbedLiveSample macro use. 9 |

10 | 11 |
{{EmbedInteractiveExample("pages/css/animation.html", "taller")}}
12 | -------------------------------------------------------------------------------- /testing/translated-content/files/fr/web/spec_section_extraction/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: Extraction de sections de spécifications 3 | slug: Web/Spec_Section_Extraction 4 | --- 5 | 6 |

7 | The purpose of this fixture is to test that this translated document can 8 | benefit from the browser-compat front-matter in it's en-US 9 | parent. 10 |

11 | 12 |

Spécifications

13 | 14 |

{{Specifications}}

15 | 16 |

Compatibilité des navigateur

17 | 18 |

{{Compat}}

19 | -------------------------------------------------------------------------------- /testing/translated-content/files/zh-tw/web/foo/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | title: ": 測試網頁" 3 | slug: Web/Foo 4 | --- 5 | 6 |

7 | Peter's note. I don't know how to express anything in Chinese beyond Google 8 | Translate 9 |

10 | 11 |
12 | 顏色的屏幕截圖 13 |
顏色的屏幕截圖
14 |
15 | -------------------------------------------------------------------------------- /tsconfig.dist.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "noEmit": false 5 | }, 6 | "include": ["build", "content", "filecheck", "markdown", "server", "tool"] 7 | } 8 | -------------------------------------------------------------------------------- /type-fixes/front-matter.ts: -------------------------------------------------------------------------------- 1 | import frontmatter from "../node_modules/front-matter/index.js"; 2 | 3 | // frontmatter 4.0.2 exposes incorrect types for an esm consumer: 4 | // types are on frontmatter.default, however frontmatter.default is actually undefined 5 | export default frontmatter as unknown as typeof frontmatter.default; 6 | --------------------------------------------------------------------------------