diff --git a/.eslintignore b/.eslintignore index bda9362a870f..a8ca421a6ce2 100644 --- a/.eslintignore +++ b/.eslintignore @@ -16,3 +16,4 @@ packages/docusaurus-init/lib/ packages/docusaurus-plugin-content-blog/lib/ packages/docusaurus-plugin-content-docs/lib/ packages/docusaurus-plugin-content-pages/lib/ +packages/docusaurus-plugin-sitemap/lib/ diff --git a/.gitignore b/.gitignore index 929727c2751f..e230c5dcf9a5 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ packages/docusaurus-init/lib/ packages/docusaurus-plugin-content-blog/lib/ packages/docusaurus-plugin-content-docs/lib/ packages/docusaurus-plugin-content-pages/lib/ +packages/docusaurus-plugin-sitemap/lib/ diff --git a/.prettierignore b/.prettierignore index 7499928e82e3..a74d4b9bb16f 100644 --- a/.prettierignore +++ b/.prettierignore @@ -8,3 +8,4 @@ packages/docusaurus-init/lib/ packages/docusaurus-plugin-content-blog/lib/ packages/docusaurus-plugin-content-docs/lib/ packages/docusaurus-plugin-content-pages/lib/ +packages/docusaurus-plugin-sitemap/lib/ \ No newline at end of file diff --git a/CHANGELOG-2.x.md b/CHANGELOG-2.x.md index 98889efbae93..999e9334c482 100644 --- a/CHANGELOG-2.x.md +++ b/CHANGELOG-2.x.md @@ -2,17 +2,66 @@ ## Unreleased +- Add table of contents highlighting on scroll. + +## 2.0.0-alpha.32 + +### Features + +- Add `` component for easy client side redirect. Example Usage: + +```js +import React from 'react'; +import {Redirect} from '@docusaurus/router'; + +function Home() { + return ; +} +``` + +- Allow user to add custom HTML to footer items. [#1905](https://github.com/facebook/docusaurus/pull/1905) +- Added code block line highlighting feature (thanks @lex111)! If you have previously swizzled the `CodeBlock` theme component, it is recommended to update your source code to have this feature. ([#1860](https://github.com/facebook/Docusaurus/issues/1860)) + +### Bug Fixes + +- Fix `@theme/Tabs` component to be able to create tabs with only one item. +- Fix MDX `@theme/Heading` component. If there is no id, it should not create anchor link. +- Fixed a bug in which if `themeConfig.algolia` is not defined, the custom searchbar won't appear. If you've swizzled Algolia `SearchBar` component before, please update your source code otherwise CSS might break. See [#1909](https://github.com/facebook/docusaurus/pull/1909/files) for reference. + +```js +- ++
+``` + +- Slightly adjust search icon position to be more aligned on small width device. ([#1893](https://github.com/facebook/Docusaurus/issues/1893)) +- Fix algolia styling bug, previously search suggestion result is sometimes hidden. ([#1915](https://github.com/facebook/Docusaurus/issues/1915)) +- Changed the way we read the `USE_SSH` env variable during deployment to be the same as in v1. +- Fix accessing `docs/` or `/docs/xxxx` that does not match any existing doc page should return 404 (Not found) page, not blank page. ([#1903](https://github.com/facebook/Docusaurus/issues/1903)) +- Prioritize `@docusaurus/core` dependencies/ node_modules over user's node_modules. This fix a bug whereby if user has core-js@3 on its own node_modules but docusaurus depends on core-js@2, we previously encounter `Module not found: core-js/modules/xxxx` (because core-js@3 doesn't have that). +- Fix a bug where docs plugin add `/docs` route even if docs folder is empty. We also improved docs plugin test coverage to 100% for stability before working on docs versioning. ([#1912](https://github.com/facebook/Docusaurus/issues/1912)) + +### Performance Improvement + +- Reduce memory usage consumption. ([#1900](https://github.com/facebook/Docusaurus/issues/1900)) +- Significantly reduce main bundle size and initial HTML payload on production build. Generated files from webpack is also shorter in name. ([#1898](https://github.com/facebook/Docusaurus/issues/1898)) +- Simplify blog metadata. Previously, accessing `/blog/post-xxx` will request for next and prev blog post metadata too aside from target post metadata. We should only request target post metadata. ([#1908](https://github.com/facebook/Docusaurus/issues/1908)) + +### Others + +- Convert sitemap plugin to TypeScript. ([#1894](https://github.com/facebook/Docusaurus/issues/1894)) +- Refactor dark mode toggle into a hook. ([#1899](https://github.com/facebook/Docusaurus/issues/1899)) + ## 2.0.0-alpha.31 -- Footer is now sticky/ pinned to the bottom of the viewport in desktop browsers. +- Footer is now sticky/ pinned to the bottom of the viewport in desktop browsers. - Footer is now also displayed in docs page for consistency. - Remove empty doc sidebar container if sidebar for a particular doc page does not exist. Otherwise, it will cause an additional empty space. -- Default PostCSS loader now only polyfills stage 3+ features (previously it was stage 2) like Create React App. Stage 2 CSS is considered relatively unstable and subject to change while Stage 3 features will likely become a standard. +- Default PostCSS loader now only polyfills stage 3+ features (previously it was stage 2) like Create React App. Stage 2 CSS is considered relatively unstable and subject to change while Stage 3 features will likely become a standard. - Fix search bar focus bug. When you put the focus on search input, previously the focus will remain although we have clicked to other area outside of the search input. - New themeConfig option `sidebarCollapsible`. It is on by default. If explicitly set to `false`, all doc items in sidebar is expanded. Otherwise, it will still be a collapsible sidebar. - Disable adding hashes to the generated class names of CSS modules in dev mode. Generating unique identifiers takes some time, which can be saved since including paths to files in class names is enough to avoid collisions. +- Fix showing sidebar category with empty items. - Update infima from 0.2.0-alpha.2 to 0.2.0-alpha.3 - - Fix showing sidebar category with empty items. - Fix pagination nav and right sidebar color contrast ratio - Fix sidebar arrow color in dark mode - Fix footer mobile issue @@ -23,11 +72,12 @@ - Fix babel transpilation include/exclude logic to be more efficient. This also fix a very weird bug `TypeError: Cannot assign to read only property 'exports' of object '#'`.([#1868](https://github.com/facebook/docusaurus/pull/1868)) -If you are still encountering the error. Please check whether you use `module.exports` for your `.js` file instead of doing `export` (mixing CJS and ES). See https://github.com/webpack/webpack/issues/4039#issuecomment-477779322 and https://github.com/webpack/webpack/issues/4039#issuecomment-273804003 for more context. +If you are still encountering the error. Please check whether you use `module.exports` for your `.js` file instead of doing `export` (mixing CJS and ES). See https://github.com/webpack/webpack/issues/4039#issuecomment-477779322 and https://github.com/webpack/webpack/issues/4039#issuecomment-273804003 for more context. ## 2.0.0-alpha.29 -**HOTFIX for 2.0.0-alpha.28**. +**HOTFIX for 2.0.0-alpha.28**. + - Fix missing `core-js` dependencies on `@docusaurus/core`. - Fix wrong `@babel/env` preset configuration that causes build compilation error. - New UI for webpack compilation progress bar. @@ -42,7 +92,7 @@ If you are still encountering the error. Please check whether you use `module.ex - Fix logo URL in footer to be appended with baseUrl automatically. - Add the option `--no-open` for `start` command. - Set `@babel/env` useBuiltins to `usage`. This will automatically use browserlist and import polyfills required. -- Modified TerserWebpackPlugin `terserOptions` for better cross-browser compatibility. +- Modified TerserWebpackPlugin `terserOptions` for better cross-browser compatibility. - **BREAKING** `withBaseUrl` is renamed to `useBaseUrl` because its a React Hooks. Make sure you import/rename it correctly. Eg: `import useBaseUrl from '@docusaurus/useBaseUrl`; - Fix potential security vulnerability because we're exposing the directory structure of the host machine. - Upgrade dependencies. @@ -52,7 +102,7 @@ If you are still encountering the error. Please check whether you use `module.ex - Add `@theme/Tabs` which can be used to implement multi-language code tabs. - Implement `custom_edit_url` and `hide_title` markdown header for docusaurus v1 feature parity. - Reduce memory usage and slightly faster production build. -- Misc dependency upgrades. +- Misc dependency upgrades. ## 2.0.0-alpha.26 diff --git a/CHANGELOG.md b/CHANGELOG.md index bc1686dff805..9616eaa82fa4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a **Docs** -- docs: document docker is optional ([#1848])(https://github.com/facebook/docusaurus/pull/1848) +- docs: document docker is optional ([#1848](https://github.com/facebook/docusaurus/pull/1848)) ## [1.13.0] - 2019-09-15 @@ -1178,7 +1178,8 @@ N/A - Blog - Documentation -[unreleased]: https://github.com/facebook/docusaurus/compare/v1.13.0...HEAD +[unreleased]: https://github.com/facebook/docusaurus/compare/v1.14.0...HEAD +[1.14.0]: https://github.com/facebook/docusaurus/compare/v1.13.0...v1.14.0 [1.13.0]: https://github.com/facebook/docusaurus/compare/v1.12.0...v1.13.0 [1.12.0]: https://github.com/facebook/docusaurus/compare/v1.11.1...v1.12.0 [1.11.1]: https://github.com/facebook/docusaurus/compare/v1.11.0...v1.11.1 diff --git a/README.md b/README.md index 39e7b2a101ce..e2b253329606 100644 --- a/README.md +++ b/README.md @@ -19,15 +19,15 @@ Docusaurus is a project for easily building, deploying, and maintaining open source project websites. -- **Simple to Start** Docusaurus is built to be easy to [get up and running](https://docusaurus.io/docs/en/installation.html) in as little time possible. We've built Docusaurus to handle the website build process so you can focus on your project. -- **Localizable** Docusaurus ships with [localization support](https://docusaurus.io/docs/en/translation.html) via CrowdIn. Empower and grow your international community by translating your documentation. -- **Customizable** While Docusaurus ships with the key pages and sections you need to get started, including a home page, a docs section, a [blog](https://docusaurus.io/docs/en/blog.html), and additional support pages, it is also [customizable](https://docusaurus.io/docs/en/custom-pages.html) as well to ensure you have a site that is [uniquely yours](https://docusaurus.io/docs/en/api-pages.html). +- **Simple to Start** Docusaurus is built to be easy to [get up and running](https://docusaurus.io/docs/en/installation/) in as little time possible. We've built Docusaurus to handle the website build process so you can focus on your project. +- **Localizable** Docusaurus ships with [localization support](https://docusaurus.io/docs/en/translation/) via CrowdIn. Empower and grow your international community by translating your documentation. +- **Customizable** While Docusaurus ships with the key pages and sections you need to get started, including a home page, a docs section, a [blog](https://docusaurus.io/docs/en/adding-blog/), and additional support pages, it is also [customizable](https://docusaurus.io/docs/en/custom-pages/) as well to ensure you have a site that is [uniquely yours](https://docusaurus.io/docs/en/api-pages/). ## Installation Docusaurus is available as the [`docusaurus` package](https://www.npmjs.com/package/docusaurus) on [npm](https://www.npmjs.com). -We have also released the [`docusaurus-init` package](https://www.npmjs.com/package/docusaurus-init) to make [getting started](https://docusaurus.io/docs/en/installation.html) with Docusaurus even easier. +We have also released the [`docusaurus-init` package](https://www.npmjs.com/package/docusaurus-init) to make [getting started](https://docusaurus.io/docs/en/installation/) with Docusaurus even easier. ## Contributing diff --git a/docs/getting-started-publishing.md b/docs/getting-started-publishing.md index 90ee88864fb6..9ad308c983c4 100644 --- a/docs/getting-started-publishing.md +++ b/docs/getting-started-publishing.md @@ -97,6 +97,7 @@ __Note:__ Not setting the `url` and `baseUrl` of your project might result in in To run the script directly from the command-line, you can use the following, filling in the parameter values as appropriate. +**Bash** ```bash GIT_USER= \ CURRENT_BRANCH=master \ @@ -104,6 +105,11 @@ GIT_USER= \ yarn run publish-gh-pages # or `npm run publish-gh-pages` ``` +**Windows** +```batch +cmd /C "set GIT_USER= && set CURRENT_BRANCH=master && set USE_SSH=true && yarn run publish-gh-pages" +``` + There are also two optional parameters that are set as environment variables: | Name | Description | diff --git a/jest.config.js b/jest.config.js index 07bf8d64ec38..3afda9ceec2c 100644 --- a/jest.config.js +++ b/jest.config.js @@ -7,20 +7,23 @@ const path = require('path'); +const ignorePatterns = [ + '/node_modules/', + '__fixtures__', + '/packages/docusaurus/lib', + '/packages/docusaurus-utils/lib', + '/packages/docusaurus-plugin-content-blog/lib', + '/packages/docusaurus-plugin-content-docs/lib', + '/packages/docusaurus-plugin-content-pages/lib', +]; + module.exports = { rootDir: path.resolve(__dirname), verbose: true, testURL: 'http://localhost/', testEnvironment: 'node', - testPathIgnorePatterns: [ - '/node_modules/', - '__fixtures__', - '/packages/docusaurus/lib', - '/packages/docusaurus-utils/lib', - '/packages/docusaurus-plugin-content-blog/lib', - '/packages/docusaurus-plugin-content-docs-legacy/lib', - '/packages/docusaurus-plugin-content-pages/lib', - ], + testPathIgnorePatterns: ignorePatterns, + coveragePathIgnorePatterns: ignorePatterns, transform: { '^.+\\.[jt]sx?$': 'babel-jest', }, diff --git a/lerna.json b/lerna.json index 20fda1265a22..01efff751eb3 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "3.14.1", - "version": "2.0.0-alpha.31", + "version": "2.0.0-alpha.32", "npmClient": "yarn", "useWorkspaces": true } diff --git a/packages/docusaurus-1.x/examples/basics/Dockerfile b/packages/docusaurus-1.x/examples/basics/Dockerfile index d369844d5bdf..c7f1856c1419 100644 --- a/packages/docusaurus-1.x/examples/basics/Dockerfile +++ b/packages/docusaurus-1.x/examples/basics/Dockerfile @@ -1,4 +1,4 @@ -FROM node:8.11.4 +FROM node:lts WORKDIR /app/website diff --git a/packages/docusaurus-1.x/lib/core/__tests__/__snapshots__/anchors.test.js.snap b/packages/docusaurus-1.x/lib/core/__tests__/__snapshots__/anchors.test.js.snap deleted file mode 100644 index fb2ff82f4654..000000000000 --- a/packages/docusaurus-1.x/lib/core/__tests__/__snapshots__/anchors.test.js.snap +++ /dev/null @@ -1,5 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Anchors rendering 1`] = `"

"`; - -exports[`Anchors rendering 2`] = `"

"`; diff --git a/packages/docusaurus-1.x/lib/core/__tests__/anchors.test.js b/packages/docusaurus-1.x/lib/core/__tests__/anchors.test.js deleted file mode 100644 index 489f6ca1cd65..000000000000 --- a/packages/docusaurus-1.x/lib/core/__tests__/anchors.test.js +++ /dev/null @@ -1,125 +0,0 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -const rules = require('remarkable/lib/rules'); -const anchors = require('../anchors'); - -const md = { - renderer: { - rules: { - heading_open: rules.heading_open, - }, - }, -}; - -anchors(md); - -const render = md.renderer.rules.heading_open; - -test('Anchors rendering', () => { - expect( - render([{hLevel: 1}, {content: 'Hello world'}], 0, {}, {}), - ).toMatchSnapshot(); - expect( - render([{hLevel: 2}, {content: 'Hello small world'}], 0, {}, {}), - ).toMatchSnapshot(); - expect( - render([{hLevel: 2}, {content: 'Some _ Heading'}], 0, {}, {}), - ).toContain('id="some-_-heading"'); - expect(render([{hLevel: 2}, {content: 'foo-_ bar'}], 0, {}, {})).toContain( - 'id="foo-_-bar"', - ); -}); - -test('Each anchor is unique across rendered document', () => { - const tokens = [ - {hLevel: 1}, - {content: 'Almost unique heading'}, - {hLevel: 1}, - {content: 'Almost unique heading'}, - {hLevel: 1}, - {content: 'Almost unique heading 1'}, - {hLevel: 1}, - {content: 'Almost unique heading 1'}, - {hLevel: 1}, - {content: 'Almost unique heading 2'}, - {hLevel: 1}, - {content: 'Almost unique heading'}, - ]; - const options = {}; - const env = {}; - - expect(render(tokens, 0, options, env)).toContain( - 'id="almost-unique-heading"', - ); - expect(render(tokens, 2, options, env)).toContain( - 'id="almost-unique-heading-1"', - ); - expect(render(tokens, 4, options, env)).toContain( - 'id="almost-unique-heading-1-1"', - ); - expect(render(tokens, 6, options, env)).toContain( - 'id="almost-unique-heading-1-2"', - ); - expect(render(tokens, 8, options, env)).toContain( - 'id="almost-unique-heading-2"', - ); - expect(render(tokens, 10, options, env)).toContain( - 'id="almost-unique-heading-3"', - ); -}); - -test('Each anchor is unique across rendered document. Case 2', () => { - const tokens = [ - {hLevel: 1}, - {content: 'foo'}, - {hLevel: 1}, - {content: 'foo 1'}, - {hLevel: 1}, - {content: 'foo'}, - {hLevel: 1}, - {content: 'foo 1'}, - ]; - const options = {}; - const env = {}; - - expect(render(tokens, 0, options, env)).toContain('id="foo"'); - expect(render(tokens, 2, options, env)).toContain('id="foo-1"'); - expect(render(tokens, 4, options, env)).toContain('id="foo-2"'); - expect(render(tokens, 6, options, env)).toContain('id="foo-1-1"'); -}); - -test('Anchor index resets on each render', () => { - const tokens = [ - {hLevel: 1}, - {content: 'Almost unique heading'}, - {hLevel: 1}, - {content: 'Almost unique heading'}, - ]; - const options = {}; - const env = {}; - const env2 = {}; - - expect(render(tokens, 0, options, env)).toContain( - 'id="almost-unique-heading"', - ); - expect(render(tokens, 2, options, env)).toContain( - 'id="almost-unique-heading-1"', - ); - - expect(render(tokens, 0, options, env2)).toContain( - 'id="almost-unique-heading"', - ); - expect(render(tokens, 2, options, env2)).toContain( - 'id="almost-unique-heading-1"', - ); -}); - -test('Anchor uses default renderer when empty', () => { - expect(render([{hLevel: 1}, {content: null}], 0, {}, {})).toEqual('

'); - expect(render([{hLevel: 2}, {content: ''}], 0, {}, {})).toEqual('

'); -}); diff --git a/packages/docusaurus-1.x/lib/core/renderMarkdown.js b/packages/docusaurus-1.x/lib/core/renderMarkdown.js index 4b6cac348cff..6adbb66d79ed 100644 --- a/packages/docusaurus-1.x/lib/core/renderMarkdown.js +++ b/packages/docusaurus-1.x/lib/core/renderMarkdown.js @@ -7,7 +7,8 @@ const _ = require('lodash'); const hljs = require('highlight.js'); -const Markdown = require('remarkable'); +const {Remarkable: Markdown} = require('remarkable'); +const {linkify} = require('remarkable/linkify'); const prismjs = require('prismjs'); const loadLanguages = require('prismjs/components/index'); const chalk = require('chalk'); @@ -83,7 +84,6 @@ class MarkdownRenderer { return ''; }, html: true, - linkify: true, }; // Allow overriding default options @@ -100,6 +100,9 @@ class MarkdownRenderer { // Register anchors plugin md.use(anchors); + // Linkify + md.use(linkify); + // Allow client sites to register their own plugins if (siteConfig.markdownPlugins) { siteConfig.markdownPlugins.forEach(plugin => { diff --git a/packages/docusaurus-1.x/lib/core/toc.js b/packages/docusaurus-1.x/lib/core/toc.js index 36626be16a26..0c84b9470584 100644 --- a/packages/docusaurus-1.x/lib/core/toc.js +++ b/packages/docusaurus-1.x/lib/core/toc.js @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -const Remarkable = require('remarkable'); +const {Remarkable} = require('remarkable'); const mdToc = require('markdown-toc'); const striptags = require('striptags'); const toSlug = require('./toSlug'); diff --git a/packages/docusaurus-1.x/lib/static/css/main.css b/packages/docusaurus-1.x/lib/static/css/main.css index 38ad9224f792..e808532f145f 100644 --- a/packages/docusaurus-1.x/lib/static/css/main.css +++ b/packages/docusaurus-1.x/lib/static/css/main.css @@ -843,7 +843,7 @@ input[type='search'] { padding-left: 10px; position: absolute; right: 10px; - top: 15px; + top: 10px; } .navSearchWrapper:before { @@ -1382,6 +1382,7 @@ input::placeholder { transition: background-color 0.2s cubic-bezier(0.68, -0.55, 0.265, 1.55), width 0.2s cubic-bezier(0.68, -0.55, 0.265, 1.55), color 0.2s ease; width: 100%; + height: 30px; } .reactNavSearchWrapper input#search_input_react:focus, @@ -1977,7 +1978,8 @@ input::placeholder { color: #717171; } -.onPageNav .toc-headings > li > a.active { +.onPageNav .toc-headings > li > a.active, +.onPageNav .toc-headings > li > a.hover { font-weight: 600; color: $primaryColor; } diff --git a/packages/docusaurus-1.x/package.json b/packages/docusaurus-1.x/package.json index 679628af0492..2e59306f8365 100644 --- a/packages/docusaurus-1.x/package.json +++ b/packages/docusaurus-1.x/package.json @@ -1,7 +1,7 @@ { "name": "docusaurus", "description": "Easy to Maintain Open Source Documentation Websites", - "version": "2.0.0-alpha.31", + "version": "2.0.0-alpha.32", "license": "MIT", "keywords": [ "documentation", @@ -35,10 +35,10 @@ "@babel/register": "^7.6.2", "@babel/traverse": "^7.6.3", "@babel/types": "^7.6.3", - "autoprefixer": "^9.6.1", + "autoprefixer": "^9.7.0", "babylon": "^6.18.0", "chalk": "^2.4.2", - "chokidar": "^3.0.2", + "chokidar": "^3.2.3", "classnames": "^2.2.6", "color": "^2.0.1", "commander": "^2.20.0", @@ -50,8 +50,8 @@ "feed": "^1.1.0", "fs-extra": "^8.1.0", "gaze": "^1.1.3", - "glob": "^7.1.3", - "highlight.js": "^9.15.8", + "glob": "^7.1.5", + "highlight.js": "^9.16.1", "imagemin": "^6.0.0", "imagemin-gifsicle": "^6.0.1", "imagemin-jpegtran": "^6.0.0", @@ -60,13 +60,13 @@ "lodash": "^4.17.15", "markdown-toc": "^1.2.0", "mkdirp": "^0.5.1", - "portfinder": "^1.0.21", - "postcss": "^7.0.17", + "portfinder": "^1.0.25", + "postcss": "^7.0.21", "prismjs": "^1.17.1", "react": "^16.8.4", - "react-dev-utils": "^9.0.1", + "react-dev-utils": "^9.1.0", "react-dom": "^16.8.4", - "remarkable": "^1.7.4", + "remarkable": "^2.0.0", "request": "^2.88.0", "shelljs": "^0.8.3", "sitemap": "^3.2.2", @@ -74,6 +74,6 @@ "tcp-port-used": "^1.0.1", "tiny-lr": "^1.1.1", "tree-node-cli": "^1.2.5", - "truncate-html": "^1.0.2" + "truncate-html": "^1.0.3" } } diff --git a/packages/docusaurus-init/package.json b/packages/docusaurus-init/package.json index a6ee1a57d1be..6ba49ada72ab 100644 --- a/packages/docusaurus-init/package.json +++ b/packages/docusaurus-init/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/init", - "version": "2.0.0-alpha.31", + "version": "2.0.0-alpha.32", "description": "Create Docusaurus app easily", "repository": { "type": "git", diff --git a/packages/docusaurus-init/templates/classic/docs/doc1.md b/packages/docusaurus-init/templates/classic/docs/doc1.md index a350ace5a639..8fddcad47912 100644 --- a/packages/docusaurus-init/templates/classic/docs/doc1.md +++ b/packages/docusaurus-init/templates/classic/docs/doc1.md @@ -110,6 +110,12 @@ No language indicated, so no syntax highlighting. But let's throw in a tag. ``` +```js {2} +function highlightMe() { + console.log('This line can be highlighted!'); +} +``` + --- ## Tables diff --git a/packages/docusaurus-init/templates/classic/package.json b/packages/docusaurus-init/templates/classic/package.json index e4d27d9d8a71..385432843243 100644 --- a/packages/docusaurus-init/templates/classic/package.json +++ b/packages/docusaurus-init/templates/classic/package.json @@ -1,17 +1,16 @@ { "name": "docusaurus-2-classic-template", - "version": "2.0.0-alpha.31", + "version": "2.0.0-alpha.32", "private": true, "scripts": { - "docusaurus": "docusaurus", "start": "docusaurus start", "build": "docusaurus build", "swizzle": "docusaurus swizzle", "deploy": "docusaurus deploy" }, "dependencies": { - "@docusaurus/core": "^2.0.0-alpha.31", - "@docusaurus/preset-classic": "^2.0.0-alpha.31", + "@docusaurus/core": "^2.0.0-alpha.32", + "@docusaurus/preset-classic": "^2.0.0-alpha.32", "classnames": "^2.2.6", "react": "^16.8.4", "react-dom": "^16.8.4" diff --git a/packages/docusaurus-init/templates/classic/src/css/custom.css b/packages/docusaurus-init/templates/classic/src/css/custom.css index a7470eafc7ba..e719d7f09c83 100644 --- a/packages/docusaurus-init/templates/classic/src/css/custom.css +++ b/packages/docusaurus-init/templates/classic/src/css/custom.css @@ -21,3 +21,10 @@ --ifm-color-primary-lighter: rgb(102, 212, 189); --ifm-color-primary-lightest: rgb(146, 224, 208); } + +.docusaurus-highlight-code-line { + background-color: rgb(72, 77, 91); + display: block; + margin: 0 calc(-1 * var(--ifm-pre-padding)); + padding: 0 var(--ifm-pre-padding); +} diff --git a/packages/docusaurus-mdx-loader/package.json b/packages/docusaurus-mdx-loader/package.json index 63abfbd3ce67..936e5d845d21 100644 --- a/packages/docusaurus-mdx-loader/package.json +++ b/packages/docusaurus-mdx-loader/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/mdx-loader", - "version": "2.0.0-alpha.31", + "version": "2.0.0-alpha.32", "description": "Docusaurus Loader for MDX", "main": "src/index.js", "publishConfig": { diff --git a/packages/docusaurus-plugin-content-blog/package.json b/packages/docusaurus-plugin-content-blog/package.json index 770cae3ed75a..13f7297c3383 100644 --- a/packages/docusaurus-plugin-content-blog/package.json +++ b/packages/docusaurus-plugin-content-blog/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/plugin-content-blog", - "version": "2.0.0-alpha.31", + "version": "2.0.0-alpha.32", "description": "Blog plugin for Docusaurus", "main": "lib/index.js", "scripts": { @@ -11,11 +11,11 @@ }, "license": "MIT", "devDependencies": { - "@docusaurus/types": "^2.0.0-alpha.31" + "@docusaurus/types": "^2.0.0-alpha.32" }, "dependencies": { - "@docusaurus/mdx-loader": "^2.0.0-alpha.31", - "@docusaurus/utils": "^2.0.0-alpha.31", + "@docusaurus/mdx-loader": "^2.0.0-alpha.32", + "@docusaurus/utils": "^2.0.0-alpha.32", "fs-extra": "^8.1.0", "globby": "^10.0.1", "loader-utils": "^1.2.3", diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts index 7a4b606db4f9..ccb51d252996 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts @@ -31,6 +31,14 @@ describe('loadBlog', () => { }, ); const {blogPosts} = await plugin.loadContent(); + const noDateSource = path.join('@site', pluginPath, 'no date.md'); + const noDateSourceBirthTime = (await fs.stat( + noDateSource.replace('@site', siteDir), + )).birthtime; + const noDatePermalink = `/blog/${noDateSourceBirthTime + .toISOString() + .substr(0, '2019-01-01'.length) + .replace(/-/g, '/')}/no date`; expect( blogPosts.find(v => v.metadata.title === 'date-matter').metadata, @@ -41,6 +49,14 @@ describe('loadBlog', () => { description: `date inside front matter`, date: new Date('2019-01-01'), tags: [], + nextItem: { + permalink: '/blog/2018/12/14/Happy-First-Birthday-Slash', + title: 'Happy 1st Birthday Slash!', + }, + prevItem: { + permalink: noDatePermalink, + title: 'no date', + }, }); expect( blogPosts.find(v => v.metadata.title === 'Happy 1st Birthday Slash!') @@ -56,24 +72,25 @@ describe('loadBlog', () => { description: `pattern name`, date: new Date('2018-12-14'), tags: [], + prevItem: { + permalink: '/blog/2019/01/01/date-matter', + title: 'date-matter', + }, }); - const noDateSource = path.join('@site', pluginPath, 'no date.md'); - const noDateSourceBirthTime = (await fs.stat( - noDateSource.replace('@site', siteDir), - )).birthtime; expect( blogPosts.find(v => v.metadata.title === 'no date').metadata, ).toEqual({ - permalink: `/blog/${noDateSourceBirthTime - .toISOString() - .substr(0, '2019-01-01'.length) - .replace(/-/g, '/')}/no date`, + permalink: noDatePermalink, source: noDateSource, title: 'no date', description: `no date`, date: noDateSourceBirthTime, tags: [], + nextItem: { + permalink: '/blog/2019/01/01/date-matter', + title: 'date-matter', + }, }); }); }); diff --git a/packages/docusaurus-plugin-content-blog/src/index.ts b/packages/docusaurus-plugin-content-blog/src/index.ts index c8f7dce0b740..1904f11814f3 100644 --- a/packages/docusaurus-plugin-content-blog/src/index.ts +++ b/packages/docusaurus-plugin-content-blog/src/index.ts @@ -23,7 +23,6 @@ import { import { LoadContext, PluginContentLoadedActions, - RouteModule, ConfigureWebpackUtils, } from '@docusaurus/types'; import {Configuration} from 'webpack'; @@ -138,6 +137,25 @@ export default function pluginContentBlog( (a, b) => b.metadata.date.getTime() - a.metadata.date.getTime(), ); + // Colocate next and prev metadata + blogPosts.forEach((blogPost, index) => { + const prevItem = index > 0 ? blogPosts[index - 1] : null; + if (prevItem) { + blogPost.metadata.prevItem = { + title: prevItem.metadata.title, + permalink: prevItem.metadata.permalink, + }; + } + const nextItem = + index < blogPosts.length - 1 ? blogPosts[index + 1] : null; + if (nextItem) { + blogPost.metadata.nextItem = { + title: nextItem.metadata.title, + permalink: nextItem.metadata.permalink, + }; + } + }); + // Blog pagination routes. // Example: `/blog`, `/blog/page/1`, `/blog/page/2` const totalCount = blogPosts.length; @@ -267,10 +285,7 @@ export default function pluginContentBlog( }), ); - blogItems.forEach((blogItem, index) => { - const prevItem = index > 0 ? blogItems[index - 1] : null; - const nextItem = - index < blogItems.length - 1 ? blogItems[index + 1] : null; + blogItems.map(blogItem => { const {metadata, metadataPath} = blogItem; const {source, permalink} = metadata; @@ -281,9 +296,7 @@ export default function pluginContentBlog( modules: { content: source, metadata: aliasedSource(metadataPath), - prevItem: prevItem && aliasedSource(prevItem.metadataPath), - nextItem: nextItem && aliasedSource(nextItem.metadataPath), - } as RouteModule, + }, }); }); diff --git a/packages/docusaurus-plugin-content-blog/src/types.ts b/packages/docusaurus-plugin-content-blog/src/types.ts index 0c8076e9c7c2..c050e9e9366a 100644 --- a/packages/docusaurus-plugin-content-blog/src/types.ts +++ b/packages/docusaurus-plugin-content-blog/src/types.ts @@ -51,6 +51,13 @@ export interface MetaData { date: Date; tags: (Tag | string)[]; title: string; + prevItem?: Paginator; + nextItem?: Paginator; +} + +export interface Paginator { + title: string; + permalink: string; } export interface Tag { diff --git a/packages/docusaurus-plugin-content-docs/package.json b/packages/docusaurus-plugin-content-docs/package.json index 6594906ea785..269358868a60 100644 --- a/packages/docusaurus-plugin-content-docs/package.json +++ b/packages/docusaurus-plugin-content-docs/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/plugin-content-docs", - "version": "2.0.0-alpha.31", + "version": "2.0.0-alpha.32", "description": "Docs content plugin for Docusaurus", "main": "lib/index.js", "scripts": { @@ -11,11 +11,11 @@ }, "license": "MIT", "devDependencies": { - "@docusaurus/types": "^2.0.0-alpha.31" + "@docusaurus/types": "^2.0.0-alpha.32" }, "dependencies": { - "@docusaurus/mdx-loader": "^2.0.0-alpha.31", - "@docusaurus/utils": "^2.0.0-alpha.31", + "@docusaurus/mdx-loader": "^2.0.0-alpha.32", + "@docusaurus/utils": "^2.0.0-alpha.32", "cross-spawn": "^7.0.1", "fs-extra": "^8.1.0", "globby": "^10.0.1", diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/bad-site/docs/invalid-id.md b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/bad-site/docs/invalid-id.md new file mode 100644 index 000000000000..1ffe4fa38eac --- /dev/null +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/bad-site/docs/invalid-id.md @@ -0,0 +1,5 @@ +--- +id: hello/super +--- + +Lorem diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/empty-site/docusaurus.config.js b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/empty-site/docusaurus.config.js new file mode 100644 index 000000000000..4b278c9a7b13 --- /dev/null +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/empty-site/docusaurus.config.js @@ -0,0 +1,16 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +module.exports = { + title: 'My Site', + tagline: 'The tagline of my site', + url: 'https://your-docusaurus-test-site.com', + baseUrl: '/', + favicon: 'img/favicon.ico', + organizationName: 'facebook', // Usually your GitHub org/user name. + projectName: 'docusaurus', // Usually your repo name. +}; diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/sidebars/sidebars-category-wrong-items.json b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/sidebars/sidebars-category-wrong-items.json new file mode 100644 index 000000000000..25bdf99e2032 --- /dev/null +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/sidebars/sidebars-category-wrong-items.json @@ -0,0 +1,11 @@ +{ + "docs": { + "Test": [ + { + "type": "category", + "label": "Category Label", + "items": "doc1" + } + ] + } +} diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/website/sidebars-category.js b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/sidebars/sidebars-category.js similarity index 100% rename from packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/website/sidebars-category.js rename to packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/sidebars/sidebars-category.js diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/website/bad-sidebars.json b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/sidebars/sidebars-unknown-type.json similarity index 100% rename from packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/website/bad-sidebars.json rename to packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/sidebars/sidebars-unknown-type.json diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/sidebars/sidebars-wrong-field.json b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/sidebars/sidebars-wrong-field.json new file mode 100644 index 000000000000..43dff88d7c96 --- /dev/null +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/sidebars/sidebars-wrong-field.json @@ -0,0 +1,20 @@ +{ + "docs": { + "Test": [ + "foo/bar", + "foo/baz", + { + "type": "category", + "label": "category", + "href": "https://github.com" + }, + { + "type": "ref", + "id": "hello" + } + ], + "Guides": [ + "hello" + ] + } +} diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/website/sidebars.json b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/sidebars/sidebars.json similarity index 100% rename from packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/website/sidebars.json rename to packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/sidebars/sidebars.json diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/website/docs/foo/bar.md b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/foo/bar.md similarity index 100% rename from packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/website/docs/foo/bar.md rename to packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/foo/bar.md diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/website/docs/foo/baz.md b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/foo/baz.md similarity index 100% rename from packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/website/docs/foo/baz.md rename to packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/foo/baz.md diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/website/docs/hello.md b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/hello.md similarity index 100% rename from packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/website/docs/hello.md rename to packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/hello.md diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/website/docs/lorem.md b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/lorem.md similarity index 89% rename from packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/website/docs/lorem.md rename to packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/lorem.md index 15589144c4a9..b088a6ec006b 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/website/docs/lorem.md +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/lorem.md @@ -1,5 +1,4 @@ --- -id: lorem custom_edit_url: https://github.com/customUrl/docs/lorem.md --- diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/website/docs/permalink.md b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/permalink.md similarity index 100% rename from packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/website/docs/permalink.md rename to packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/permalink.md diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docusaurus.config.js b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docusaurus.config.js new file mode 100644 index 000000000000..4b278c9a7b13 --- /dev/null +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docusaurus.config.js @@ -0,0 +1,16 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +module.exports = { + title: 'My Site', + tagline: 'The tagline of my site', + url: 'https://your-docusaurus-test-site.com', + baseUrl: '/', + favicon: 'img/favicon.ico', + organizationName: 'facebook', // Usually your GitHub org/user name. + projectName: 'docusaurus', // Usually your repo name. +}; diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/sidebars.json b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/sidebars.json new file mode 100644 index 000000000000..7892de099a43 --- /dev/null +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/sidebars.json @@ -0,0 +1,23 @@ +{ + "docs": { + "Test": [ + { + "type": "category", + "label": "foo", + "items": ["foo/bar", "foo/baz"] + }, + { + "type": "link", + "label": "Github", + "href": "https://github.com" + }, + { + "type": "ref", + "id": "hello" + } + ], + "Guides": [ + "hello" + ] + } +} diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/wrong-sidebars.json b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/wrong-sidebars.json new file mode 100644 index 000000000000..6f56ce2c0b5a --- /dev/null +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/wrong-sidebars.json @@ -0,0 +1,7 @@ +{ + "docs": { + "Test": [ + "goku" + ] + } +} diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap new file mode 100644 index 000000000000..c59be9c120ee --- /dev/null +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap @@ -0,0 +1,110 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`simple website content 1`] = ` +Object { + "docs": Array [ + Object { + "items": Array [ + Object { + "items": Array [ + Object { + "href": "/docs/foo/bar", + "label": "Bar", + "type": "link", + }, + Object { + "href": "/docs/foo/baz", + "label": "baz", + "type": "link", + }, + ], + "label": "foo", + "type": "category", + }, + Object { + "href": "https://github.com", + "label": "Github", + "type": "link", + }, + Object { + "href": "/docs/hello", + "label": "Hello, World !", + "type": "link", + }, + ], + "label": "Test", + "type": "category", + }, + Object { + "items": Array [ + Object { + "href": "/docs/hello", + "label": "Hello, World !", + "type": "link", + }, + ], + "label": "Guides", + "type": "category", + }, + ], +} +`; + +exports[`simple website content 2`] = ` +Array [ + Object { + "component": "@theme/DocPage", + "modules": Object { + "docsMetadata": "@docusaurus-plugin-content-docs/docs-b5f.json", + }, + "path": "/docs", + "routes": Array [ + Object { + "component": "@theme/DocItem", + "exact": true, + "modules": Object { + "content": "@site/docs/permalink.md", + "metadata": "@docusaurus-plugin-content-docs/docs-endiliey-permalink-086.json", + }, + "path": "/docs/endiliey/permalink", + }, + Object { + "component": "@theme/DocItem", + "exact": true, + "modules": Object { + "content": "@site/docs/foo/bar.md", + "metadata": "@docusaurus-plugin-content-docs/docs-foo-bar-cef.json", + }, + "path": "/docs/foo/bar", + }, + Object { + "component": "@theme/DocItem", + "exact": true, + "modules": Object { + "content": "@site/docs/foo/baz.md", + "metadata": "@docusaurus-plugin-content-docs/docs-foo-baz-dd9.json", + }, + "path": "/docs/foo/baz", + }, + Object { + "component": "@theme/DocItem", + "exact": true, + "modules": Object { + "content": "@site/docs/hello.md", + "metadata": "@docusaurus-plugin-content-docs/docs-hello-da2.json", + }, + "path": "/docs/hello", + }, + Object { + "component": "@theme/DocItem", + "exact": true, + "modules": Object { + "content": "@site/docs/lorem.md", + "metadata": "@docusaurus-plugin-content-docs/docs-lorem-17b.json", + }, + "path": "/docs/lorem", + }, + ], + }, +] +`; diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts index a338bed2aadb..a044c52325b7 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/index.test.ts @@ -6,32 +6,109 @@ */ import path from 'path'; - +import {validate} from 'webpack'; +import fs from 'fs-extra'; import pluginContentDocs from '../index'; -import {LoadContext} from '@docusaurus/types'; - -describe('loadDocs', () => { - test('simple website', async () => { - const siteDir = path.join(__dirname, '__fixtures__', 'website'); - const generatedFilesDir: string = path.resolve(siteDir, '.docusaurus'); - const siteConfig = { - title: 'Hello', - baseUrl: '/', - url: 'https://docusaurus.io', - }; - const context = { - siteDir, - siteConfig, - generatedFilesDir, - } as LoadContext; - const sidebarPath = path.join(siteDir, 'sidebars.json'); - const pluginPath = 'docs'; - const plugin = pluginContentDocs(context, { - path: pluginPath, - sidebarPath, +import {loadContext} from '@docusaurus/core/src/server/index'; +import {applyConfigureWebpack} from '@docusaurus/core/src/webpack/utils'; +import {RouteConfig} from '@docusaurus/types'; + +const createFakeActions = (routeConfigs: RouteConfig[], contentDir) => { + return { + addRoute: (config: RouteConfig) => { + config.routes.sort((a, b) => + a.path > b.path ? 1 : b.path > a.path ? -1 : 0, + ); + routeConfigs.push(config); + }, + createData: async (name, _content) => { + return path.join(contentDir, name); + }, + }; +}; + +test('site with wrong sidebar file', async () => { + const siteDir = path.join(__dirname, '__fixtures__', 'simple-site'); + const context = loadContext(siteDir); + const sidebarPath = path.join(siteDir, 'wrong-sidebars.json'); + const plugin = pluginContentDocs(context, { + sidebarPath, + }); + return plugin + .loadContent() + .catch(e => + expect(e).toMatchInlineSnapshot( + `[Error: Improper sidebars file, document with id 'goku' not found.]`, + ), + ); +}); + +describe('empty/no docs website', () => { + const siteDir = path.join(__dirname, '__fixtures__', 'empty-site'); + const context = loadContext(siteDir); + + test('no files in docs folder', async () => { + await fs.ensureDir(path.join(siteDir, 'docs')); + const plugin = pluginContentDocs(context, {}); + const content = await plugin.loadContent(); + const {docsMetadata, docsSidebars} = content; + expect(docsMetadata).toMatchInlineSnapshot(`Object {}`); + expect(docsSidebars).toMatchInlineSnapshot(`Object {}`); + + const routeConfigs = []; + const pluginContentDir = path.join(context.generatedFilesDir, plugin.name); + const actions = createFakeActions(routeConfigs, pluginContentDir); + + await plugin.contentLoaded({ + content, + actions, }); - const {docsMetadata} = await plugin.loadContent(); + expect(routeConfigs).toEqual([]); + }); + + test('docs folder does not exist', async () => { + const plugin = pluginContentDocs(context, {path: '/path/does/not/exist/'}); + const content = await plugin.loadContent(); + expect(content).toBeNull(); + }); +}); + +describe('simple website', () => { + const siteDir = path.join(__dirname, '__fixtures__', 'simple-site'); + const context = loadContext(siteDir); + const sidebarPath = path.join(siteDir, 'sidebars.json'); + const pluginPath = 'docs'; + const plugin = pluginContentDocs(context, { + path: pluginPath, + sidebarPath, + }); + const pluginContentDir = path.join(context.generatedFilesDir, plugin.name); + + test('getPathToWatch', () => { + const pathToWatch = plugin.getPathsToWatch(); + expect(pathToWatch).not.toEqual([]); + }); + + test('configureWebpack', async () => { + const config = applyConfigureWebpack( + plugin.configureWebpack, + { + entry: './src/index.js', + output: { + filename: 'main.js', + path: path.resolve(__dirname, 'dist'), + }, + }, + false, + ); + const errors = validate(config); + expect(errors.length).toBe(0); + }); + + test('content', async () => { + const content = await plugin.loadContent(); + const {docsMetadata, docsSidebars} = content; expect(docsMetadata.hello).toEqual({ id: 'hello', permalink: '/docs/hello', @@ -57,5 +134,18 @@ describe('loadDocs', () => { title: 'Bar', description: 'This is custom description', }); + + expect(docsSidebars).toMatchSnapshot(); + + const routeConfigs = []; + const actions = createFakeActions(routeConfigs, pluginContentDir); + + await plugin.contentLoaded({ + content, + actions, + }); + + expect(routeConfigs).not.toEqual([]); + expect(routeConfigs).toMatchSnapshot(); }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/lastUpdate.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/lastUpdate.test.ts index bf088ed828d0..52210e918478 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/lastUpdate.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/lastUpdate.test.ts @@ -7,15 +7,17 @@ import fs from 'fs'; import path from 'path'; +import shell from 'shelljs'; +import spawn from 'cross-spawn'; import lastUpdate from '../lastUpdate'; describe('lastUpdate', () => { + const existingFilePath = path.join( + __dirname, + '__fixtures__/simple-site/docs/hello.md', + ); test('existing test file in repository with Git timestamp', () => { - const existingFilePath = path.join( - __dirname, - '__fixtures__/website/docs/hello.md', - ); const lastUpdateData = lastUpdate(existingFilePath); expect(lastUpdateData).not.toBeNull(); @@ -44,4 +46,30 @@ describe('lastUpdate', () => { expect(lastUpdate(tempFilePath)).toBeNull(); fs.unlinkSync(tempFilePath); }); + + test('Git does not exist', () => { + const mock = jest.spyOn(shell, 'which').mockImplementationOnce(() => null); + const consoleMock = jest.spyOn(console, 'warn').mockImplementation(); + const lastUpdateData = lastUpdate(existingFilePath); + expect(lastUpdateData).toBeNull(); + expect(consoleMock).toHaveBeenLastCalledWith( + 'Sorry, the docs plugin last update options require Git.', + ); + + consoleMock.mockRestore(); + mock.mockRestore(); + }); + + test('Error', () => { + const mock = jest.spyOn(spawn, 'sync').mockImplementationOnce(() => { + throw new Error('PERMISSION Error'); + }); + const consoleMock = jest.spyOn(console, 'error').mockImplementation(); + const lastUpdateData = lastUpdate('/fake/path/'); + expect(lastUpdateData).toBeNull(); + expect(consoleMock).toHaveBeenLastCalledWith(new Error('PERMISSION Error')); + + consoleMock.mockRestore(); + mock.mockRestore(); + }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/metadata.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/metadata.test.ts index 1a6ca22a172b..1caaab4a17cf 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/metadata.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/metadata.test.ts @@ -9,14 +9,15 @@ import path from 'path'; import processMetadata from '../metadata'; describe('processMetadata', () => { - const siteDir = path.join(__dirname, '__fixtures__', 'website'); + const fixtureDir = path.join(__dirname, '__fixtures__'); + const simpleSiteDir = path.join(fixtureDir, 'simple-site'); const siteConfig = { title: 'Hello', baseUrl: '/', url: 'https://docusaurus.io', }; const pluginPath = 'docs'; - const docsDir = path.resolve(siteDir, pluginPath); + const docsDir = path.resolve(simpleSiteDir, pluginPath); test('normal docs', async () => { const sourceA = path.join('foo', 'bar.md'); @@ -29,7 +30,7 @@ describe('processMetadata', () => { order: {}, siteConfig, docsBasePath: pluginPath, - siteDir, + siteDir: simpleSiteDir, }), processMetadata({ source: sourceB, @@ -37,7 +38,7 @@ describe('processMetadata', () => { order: {}, siteConfig, docsBasePath: pluginPath, - siteDir, + siteDir: simpleSiteDir, }), ]); @@ -65,7 +66,7 @@ describe('processMetadata', () => { order: {}, siteConfig, docsBasePath: pluginPath, - siteDir, + siteDir: simpleSiteDir, }); expect(data).toEqual({ @@ -87,7 +88,7 @@ describe('processMetadata', () => { order: {}, siteConfig, docsBasePath: pluginPath, - siteDir, + siteDir: simpleSiteDir, editUrl, }); @@ -110,7 +111,7 @@ describe('processMetadata', () => { order: {}, siteConfig, docsBasePath: pluginPath, - siteDir, + siteDir: simpleSiteDir, }); expect(data).toEqual({ @@ -122,4 +123,46 @@ describe('processMetadata', () => { description: 'Lorem ipsum.', }); }); + + test('docs with last update time and author', async () => { + const source = 'lorem.md'; + const data = await processMetadata({ + source, + docsDir, + order: {}, + siteConfig, + docsBasePath: pluginPath, + siteDir: simpleSiteDir, + showLastUpdateAuthor: true, + showLastUpdateTime: true, + }); + + expect(data).toEqual({ + id: 'lorem', + permalink: '/docs/lorem', + source: path.join('@site', pluginPath, source), + title: 'lorem', + editUrl: 'https://github.com/customUrl/docs/lorem.md', + description: 'Lorem ipsum.', + lastUpdatedAt: '1539502055', + lastUpdatedBy: 'Author', + }); + }); + + test('docs with invalid id', async () => { + const badSiteDir = path.join(fixtureDir, 'bad-site'); + + return processMetadata({ + source: 'invalid-id.md', + docsDir: path.join(badSiteDir, 'docs'), + order: {}, + siteConfig, + docsBasePath: 'docs', + siteDir: simpleSiteDir, + }).catch(e => + expect(e).toMatchInlineSnapshot( + `[Error: Document id cannot include "/".]`, + ), + ); + }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/order.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/order.test.ts index 1f237318b747..7cdc265dbdd0 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/order.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/order.test.ts @@ -218,6 +218,29 @@ describe('createOrder', () => { }); }); + test('multiple sidebars with unknown sidebar item type', () => { + expect(() => + createOrder({ + docs: [ + { + type: 'category', + label: 'Category1', + items: [{type: 'endi', id: 'doc1'}, {type: 'doc', id: 'doc2'}], + }, + ], + otherDocs: [ + { + type: 'category', + label: 'Category1', + items: [{type: 'doc', id: 'doc5'}], + }, + ], + }), + ).toThrowErrorMatchingInlineSnapshot( + `"Unknown item type: endi. Item: {\\"type\\":\\"endi\\",\\"id\\":\\"doc1\\"}"`, + ); + }); + test('edge cases', () => { expect(createOrder({})).toEqual({}); expect(createOrder(undefined)).toEqual({}); diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/sidebars.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/sidebars.test.ts index 9239041d57c1..0a153e45f8d7 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/sidebars.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/sidebars.test.ts @@ -11,40 +11,43 @@ import loadSidebars from '../sidebars'; /* eslint-disable global-require, import/no-dynamic-require */ describe('loadSidebars', () => { + const fixtureDir = path.join(__dirname, '__fixtures__', 'sidebars'); test('sidebars with known sidebar item type', async () => { - const sidebarPath = path.join( - __dirname, - '__fixtures__', - 'website', - 'sidebars.json', - ); + const sidebarPath = path.join(fixtureDir, 'sidebars.json'); const result = loadSidebars(sidebarPath); expect(result).toMatchSnapshot(); }); test('sidebars with deep level of category', async () => { - const sidebarPath = path.join( - __dirname, - '__fixtures__', - 'website', - 'sidebars-category.js', - ); + const sidebarPath = path.join(fixtureDir, 'sidebars-category.js'); const result = loadSidebars(sidebarPath); expect(result).toMatchSnapshot(); }); - test('sidebars with unknown sidebar item type', async () => { + test('sidebars with category but category.items is not an array', async () => { const sidebarPath = path.join( - __dirname, - '__fixtures__', - 'website', - 'bad-sidebars.json', + fixtureDir, + 'sidebars-category-wrong-items.json', + ); + expect(() => loadSidebars(sidebarPath)).toThrowErrorMatchingInlineSnapshot( + `"Error loading \\"Category Label\\" category. Category items must be array."`, ); + }); + + test('sidebars with unknown sidebar item type', async () => { + const sidebarPath = path.join(fixtureDir, 'sidebars-unknown-type.json'); expect(() => loadSidebars(sidebarPath)).toThrowErrorMatchingInlineSnapshot( `"Unknown sidebar item type: superman"`, ); }); + test('sidebars with known sidebar item type but wrong field', async () => { + const sidebarPath = path.join(fixtureDir, 'sidebars-wrong-field.json'); + expect(() => loadSidebars(sidebarPath)).toThrowErrorMatchingInlineSnapshot( + `"Unknown sidebar item keys: href. Item: {\\"type\\":\\"category\\",\\"label\\":\\"category\\",\\"href\\":\\"https://github.com\\"}"`, + ); + }); + test('no sidebars', () => { const result = loadSidebars(null); expect(result).toEqual({}); diff --git a/packages/docusaurus-plugin-content-docs/src/index.ts b/packages/docusaurus-plugin-content-docs/src/index.ts index c40852153818..a2e1061c29c9 100644 --- a/packages/docusaurus-plugin-content-docs/src/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/index.ts @@ -177,9 +177,8 @@ export default function pluginContentDocs( case 'doc': return convertDocLink(item as SidebarItemDoc); case 'link': - break; default: - throw new Error(`Unknown sidebar item type: ${item.type}`); + break; } return item as SidebarItemLink; }); @@ -208,7 +207,7 @@ export default function pluginContentDocs( }, async contentLoaded({content, actions}) { - if (!content) { + if (!content || Object.keys(content.docsMetadata).length === 0) { return; } diff --git a/packages/docusaurus-plugin-content-docs/src/lastUpdate.ts b/packages/docusaurus-plugin-content-docs/src/lastUpdate.ts index c1ac941e3411..da24c3add86d 100644 --- a/packages/docusaurus-plugin-content-docs/src/lastUpdate.ts +++ b/packages/docusaurus-plugin-content-docs/src/lastUpdate.ts @@ -33,7 +33,7 @@ export default function getFileLastUpdate( if (!shell.which('git')) { if (!showedGitRequirementError) { showedGitRequirementError = true; - console.log('Sorry, the docs plugin last update options require Git.'); + console.warn('Sorry, the docs plugin last update options require Git.'); } return null; diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars.ts b/packages/docusaurus-plugin-content-docs/src/sidebars.ts index a8cb3c7516c4..dd0d108a41b2 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars.ts @@ -44,7 +44,7 @@ function normalizeCategory( if (!Array.isArray(category.items)) { throw new Error( - `Error loading ${category.label} category. Category items must be array.`, + `Error loading "${category.label}" category. Category items must be array.`, ); } @@ -62,15 +62,11 @@ function normalizeCategory( assertItem(item, ['href', 'label']); break; case 'ref': + case 'doc': assertItem(item, ['id']); break; default: - if (item.type !== 'doc') { - throw new Error(`Unknown sidebar item type: ${item.type}`); - } - - assertItem(item, ['id']); - break; + throw new Error(`Unknown sidebar item type: ${item.type}`); } return item as SidebarItem; diff --git a/packages/docusaurus-plugin-content-pages/package.json b/packages/docusaurus-plugin-content-pages/package.json index 0041bd63fa96..8a591e961a27 100644 --- a/packages/docusaurus-plugin-content-pages/package.json +++ b/packages/docusaurus-plugin-content-pages/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/plugin-content-pages", - "version": "2.0.0-alpha.31", + "version": "2.0.0-alpha.32", "description": "Pages content plugin for Docusaurus", "main": "lib/index.js", "scripts": { @@ -11,8 +11,8 @@ }, "license": "MIT", "dependencies": { - "@docusaurus/types": "^2.0.0-alpha.31", - "@docusaurus/utils": "^2.0.0-alpha.31", + "@docusaurus/types": "^2.0.0-alpha.32", + "@docusaurus/utils": "^2.0.0-alpha.32", "globby": "^10.0.1" }, "peerDependencies": { diff --git a/packages/docusaurus-plugin-google-analytics/package.json b/packages/docusaurus-plugin-google-analytics/package.json index 3196e44f539e..bb73a3a1c18e 100644 --- a/packages/docusaurus-plugin-google-analytics/package.json +++ b/packages/docusaurus-plugin-google-analytics/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/plugin-google-analytics", - "version": "2.0.0-alpha.31", + "version": "2.0.0-alpha.32", "description": "Global analytics (analytics.js) plugin for Docusaurus", "main": "src/index.js", "publishConfig": { diff --git a/packages/docusaurus-plugin-google-gtag/package.json b/packages/docusaurus-plugin-google-gtag/package.json index 1473c596d22d..5060c8f955ff 100644 --- a/packages/docusaurus-plugin-google-gtag/package.json +++ b/packages/docusaurus-plugin-google-gtag/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/plugin-google-gtag", - "version": "2.0.0-alpha.31", + "version": "2.0.0-alpha.32", "description": "Global Site Tag (gtag.js) plugin for Docusaurus", "main": "src/index.js", "publishConfig": { diff --git a/packages/docusaurus-plugin-ideal-image/package.json b/packages/docusaurus-plugin-ideal-image/package.json index fb1d056abe1c..e39c706abea7 100644 --- a/packages/docusaurus-plugin-ideal-image/package.json +++ b/packages/docusaurus-plugin-ideal-image/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/plugin-ideal-image", - "version": "2.0.0-alpha.31", + "version": "2.0.0-alpha.32", "description": "Docusaurus Plugin to generate an almost ideal image (responsive, lazy-loading, and low quality placeholder)", "main": "src/index.js", "publishConfig": { diff --git a/packages/docusaurus-plugin-sitemap/package.json b/packages/docusaurus-plugin-sitemap/package.json index af6761849d76..d3c366c3663a 100644 --- a/packages/docusaurus-plugin-sitemap/package.json +++ b/packages/docusaurus-plugin-sitemap/package.json @@ -1,13 +1,17 @@ { "name": "@docusaurus/plugin-sitemap", - "version": "2.0.0-alpha.31", + "version": "2.0.0-alpha.32", "description": "Simple sitemap generation plugin for Docusaurus", - "main": "src/index.js", + "main": "lib/index.js", + "scripts": { + "tsc": "tsc" + }, "publishConfig": { "access": "public" }, "license": "MIT", "dependencies": { + "@docusaurus/types": "^2.0.0-alpha.32", "sitemap": "^3.2.2" }, "peerDependencies": { diff --git a/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.js b/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.ts similarity index 70% rename from packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.js rename to packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.ts index f5cf466f0940..1f849716fc6b 100644 --- a/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.js +++ b/packages/docusaurus-plugin-sitemap/src/__tests__/createSitemap.test.ts @@ -6,23 +6,30 @@ */ import createSitemap from '../createSitemap'; +import {DocusaurusConfig} from '@docusaurus/types'; +import DEFAULT_OPTIONS from '../index'; describe('createSitemap', () => { test('simple site', () => { - const sitemap = createSitemap({ - siteConfig: { + const sitemap = createSitemap( + { url: 'https://example.com', + } as DocusaurusConfig, + ['/', '/test'], + { + cacheTime: 600, + changefreq: 'daily', + priority: 0.7, }, - routesPaths: ['/', '/test'], - }); - expect(sitemap).toContain( + ); + expect(sitemap.toString()).toContain( ``, ); }); test('empty site', () => { expect(() => { - createSitemap({}); + createSitemap({} as any, [], {} as any); }).toThrowErrorMatchingInlineSnapshot( `"Url in docusaurus.config.js cannot be empty/undefined"`, ); diff --git a/packages/docusaurus-plugin-sitemap/src/createSitemap.js b/packages/docusaurus-plugin-sitemap/src/createSitemap.js deleted file mode 100644 index f9cc6318007e..000000000000 --- a/packages/docusaurus-plugin-sitemap/src/createSitemap.js +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2017-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -const sitemap = require('sitemap'); - -module.exports = function createSitemap({ - siteConfig = {}, - routesPaths, - options = {}, -}) { - const {url: hostname} = siteConfig; - if (!hostname) { - throw new Error('Url in docusaurus.config.js cannot be empty/undefined'); - } - - const urls = routesPaths.map(routesPath => ({ - url: routesPath, - changefreq: options.changefreq, - priority: options.priority, - })); - - return sitemap - .createSitemap({ - hostname, - cacheTime: options.cacheTime, - urls, - }) - .toString(); -}; diff --git a/packages/docusaurus-plugin-sitemap/src/createSitemap.ts b/packages/docusaurus-plugin-sitemap/src/createSitemap.ts new file mode 100644 index 000000000000..50aa2be44e7c --- /dev/null +++ b/packages/docusaurus-plugin-sitemap/src/createSitemap.ts @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import sitemap, {SitemapItemOptions} from 'sitemap'; +import {PluginOptions} from './types'; +import {DocusaurusConfig} from '@docusaurus/types'; + +export default function createSitemap( + siteConfig: DocusaurusConfig, + routesPaths: string[], + options: PluginOptions, +) { + const {url: hostname} = siteConfig; + if (!hostname) { + throw new Error('Url in docusaurus.config.js cannot be empty/undefined'); + } + + const urls = routesPaths.map( + routesPath => + ({ + url: routesPath, + changefreq: options.changefreq, + priority: options.priority, + } as SitemapItemOptions), + ); + + return sitemap.createSitemap({ + hostname, + cacheTime: options.cacheTime, + urls, + }); +} diff --git a/packages/docusaurus-plugin-sitemap/src/index.js b/packages/docusaurus-plugin-sitemap/src/index.ts similarity index 61% rename from packages/docusaurus-plugin-sitemap/src/index.js rename to packages/docusaurus-plugin-sitemap/src/index.ts index eb43d8338480..0394d40eb08a 100644 --- a/packages/docusaurus-plugin-sitemap/src/index.js +++ b/packages/docusaurus-plugin-sitemap/src/index.ts @@ -5,30 +5,34 @@ * LICENSE file in the root directory of this source tree. */ -const fs = require('fs'); -const path = require('path'); +import fs from 'fs'; +import path from 'path'; +import {PluginOptions} from './types'; +import createSitemap from './createSitemap'; +import {LoadContext, Props} from '@docusaurus/types'; -const createSitemap = require('./createSitemap'); - -const DEFAULT_OPTIONS = { +const DEFAULT_OPTIONS: PluginOptions = { cacheTime: 600 * 1000, // 600 sec - cache purge period changefreq: 'weekly', priority: 0.5, }; -module.exports = function(context, opts) { +export default function pluginSitemap( + _context: LoadContext, + opts: Partial, +) { const options = {...DEFAULT_OPTIONS, ...opts}; return { name: 'docusaurus-plugin-sitemap', - async postBuild({siteConfig = {}, routesPaths = [], outDir}) { + async postBuild({siteConfig, routesPaths, outDir}: Props) { // Generate sitemap - const generatedSitemap = createSitemap({ + const generatedSitemap = createSitemap( siteConfig, routesPaths, options, - }).toString(); + ).toString(); // Write sitemap file const sitemapPath = path.join(outDir, 'sitemap.xml'); @@ -39,4 +43,4 @@ module.exports = function(context, opts) { }); }, }; -}; +} diff --git a/packages/docusaurus-plugin-sitemap/src/types.ts b/packages/docusaurus-plugin-sitemap/src/types.ts new file mode 100644 index 000000000000..418f15aa0f0a --- /dev/null +++ b/packages/docusaurus-plugin-sitemap/src/types.ts @@ -0,0 +1,12 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +export interface PluginOptions { + cacheTime: number; + changefreq: string; + priority: number; +} diff --git a/packages/docusaurus-plugin-sitemap/tsconfig.json b/packages/docusaurus-plugin-sitemap/tsconfig.json new file mode 100644 index 000000000000..f5902ba1089b --- /dev/null +++ b/packages/docusaurus-plugin-sitemap/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "incremental": true, + "tsBuildInfoFile": "./lib/.tsbuildinfo", + "rootDir": "src", + "outDir": "lib" + } +} diff --git a/packages/docusaurus-preset-classic/package.json b/packages/docusaurus-preset-classic/package.json index 30a58c55a8c5..40aba4386c03 100644 --- a/packages/docusaurus-preset-classic/package.json +++ b/packages/docusaurus-preset-classic/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/preset-classic", - "version": "2.0.0-alpha.31", + "version": "2.0.0-alpha.32", "description": "Preset for classic Docusaurus", "main": "src/index.js", "publishConfig": { @@ -8,14 +8,14 @@ }, "license": "MIT", "dependencies": { - "@docusaurus/plugin-content-blog": "^2.0.0-alpha.31", - "@docusaurus/plugin-content-docs": "^2.0.0-alpha.31", - "@docusaurus/plugin-content-pages": "^2.0.0-alpha.31", - "@docusaurus/plugin-google-analytics": "^2.0.0-alpha.31", - "@docusaurus/plugin-google-gtag": "^2.0.0-alpha.31", - "@docusaurus/plugin-sitemap": "^2.0.0-alpha.31", - "@docusaurus/theme-classic": "^2.0.0-alpha.31", - "@docusaurus/theme-search-algolia": "^2.0.0-alpha.31" + "@docusaurus/plugin-content-blog": "^2.0.0-alpha.32", + "@docusaurus/plugin-content-docs": "^2.0.0-alpha.32", + "@docusaurus/plugin-content-pages": "^2.0.0-alpha.32", + "@docusaurus/plugin-google-analytics": "^2.0.0-alpha.32", + "@docusaurus/plugin-google-gtag": "^2.0.0-alpha.32", + "@docusaurus/plugin-sitemap": "^2.0.0-alpha.32", + "@docusaurus/theme-classic": "^2.0.0-alpha.32", + "@docusaurus/theme-search-algolia": "^2.0.0-alpha.32" }, "peerDependencies": { "@docusaurus/core": "^2.0.0" diff --git a/packages/docusaurus-theme-classic/package.json b/packages/docusaurus-theme-classic/package.json index bdac8087f0b8..559a6e5436c4 100644 --- a/packages/docusaurus-theme-classic/package.json +++ b/packages/docusaurus-theme-classic/package.json @@ -1,6 +1,6 @@ { "name": "@docusaurus/theme-classic", - "version": "2.0.0-alpha.31", + "version": "2.0.0-alpha.32", "description": "Classic theme for Docusaurus", "main": "src/index.js", "publishConfig": { @@ -13,6 +13,7 @@ "classnames": "^2.2.6", "clipboard": "^2.0.4", "infima": "0.2.0-alpha.3", + "parse-numeric-range": "^0.0.2", "prism-react-renderer": "^1.0.2", "react-toggle": "^4.1.1" }, diff --git a/packages/docusaurus-theme-classic/src/theme/BlogPostPage/index.js b/packages/docusaurus-theme-classic/src/theme/BlogPostPage/index.js index bb3ffb80509e..38e5b0330030 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogPostPage/index.js +++ b/packages/docusaurus-theme-classic/src/theme/BlogPostPage/index.js @@ -12,7 +12,7 @@ import BlogPostItem from '@theme/BlogPostItem'; import BlogPostPaginator from '@theme/BlogPostPaginator'; function BlogPostPage(props) { - const {content: BlogPostContents, metadata, nextItem, prevItem} = props; + const {content: BlogPostContents, metadata} = props; const {frontMatter} = BlogPostContents; return ( @@ -24,7 +24,10 @@ function BlogPostPage(props) {
- +
diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.js b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.js index 1914e65b7856..044710053c8a 100644 --- a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.js +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.js @@ -10,10 +10,13 @@ import classnames from 'classnames'; import Highlight, {defaultProps} from 'prism-react-renderer'; import defaultTheme from 'prism-react-renderer/themes/palenight'; import Clipboard from 'clipboard'; +import rangeParser from 'parse-numeric-range'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import styles from './styles.module.css'; -export default ({children, className: languageClassName}) => { +const highlightLinesRangeRegex = /{([\d,-]+)}/; + +export default ({children, className: languageClassName, metastring}) => { const { siteConfig: { themeConfig: {prismTheme}, @@ -22,6 +25,12 @@ export default ({children, className: languageClassName}) => { const [showCopied, setShowCopied] = useState(false); const target = useRef(null); const button = useRef(null); + let highlightLines = []; + + if (metastring && highlightLinesRangeRegex.test(metastring)) { + const highlightLinesRange = metastring.match(highlightLinesRangeRegex)[1]; + highlightLines = rangeParser.parse(highlightLinesRange).filter(n => n > 0); + } useEffect(() => { let clipboard; @@ -61,13 +70,21 @@ export default ({children, className: languageClassName}) => { ref={target} className={classnames(className, styles.codeBlock)} style={style}> - {tokens.map((line, i) => ( -
- {line.map((token, key) => ( - - ))} -
- ))} + {tokens.map((line, i) => { + const lineProps = getLineProps({line, key: i}); + + if (highlightLines.includes(i + 1)) { + lineProps.className = `${lineProps.className} docusaurus-highlight-code-line`; + } + + return ( +
+ {line.map((token, key) => ( + + ))} +
+ ); + })}