Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(theme-classic): completely migrate package to TypeScript #5459

Merged
merged 8 commits into from
Sep 1, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/docusaurus-theme-classic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@
},
"devDependencies": {
"@docusaurus/module-type-aliases": "2.0.0-beta.5",
"@types/mdx-js__react": "^1.5.4",
"@types/parse-numeric-range": "^0.0.1",
"@types/rtlcss": "^3.1.1",
"utility-types": "^3.10.0"
},
"peerDependencies": {
Expand Down
13 changes: 8 additions & 5 deletions packages/docusaurus-theme-classic/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type {ThemeConfig} from '@docusaurus/theme-common';
import {getTranslationFiles, translateThemeConfig} from './translations';
import path from 'path';
import Module from 'module';
import type {AcceptedPlugin, Result, Plugin as PostCssPlugin} from 'postcss';
import type {AcceptedPlugin, Plugin as PostCssPlugin} from 'postcss';
import rtlcss from 'rtlcss';
import {readDefaultCodeTranslationMessages} from '@docusaurus/utils';

Expand All @@ -25,7 +25,10 @@ const ContextReplacementPlugin = requireFromDocusaurusCore(
// Need to be inlined to prevent dark mode FOUC
// Make sure that the 'storageKey' is the same as the one in `/theme/hooks/useTheme.js`
const ThemeStorageKey = 'theme';
const noFlashColorMode = ({defaultMode, respectPrefersColorScheme}) => {
const noFlashColorMode = ({
defaultMode,
respectPrefersColorScheme,
}: ThemeConfig['colorMode']) => {
return `(function() {
var defaultMode = '${defaultMode}';
var respectPrefersColorScheme = ${respectPrefersColorScheme};
Expand Down Expand Up @@ -83,7 +86,7 @@ const AnnouncementBarInlineJavaScript = `
document.documentElement.setAttribute('${AnnouncementBarDismissDataAttribute}', isDismissed());
})();`;

function getInfimaCSSFile(direction) {
function getInfimaCSSFile(direction: string) {
return `infima/dist/css/default/default${
direction === 'rtl' ? '-rtl' : ''
}.css`;
Expand Down Expand Up @@ -183,13 +186,13 @@ export default function docusaurusThemeClassic(
const resolvedInfimaFile = require.resolve(getInfimaCSSFile(direction));
const plugin: PostCssPlugin = {
postcssPlugin: 'RtlCssPlugin',
prepare: (result: Result) => {
prepare: (result) => {
const file = result.root?.source?.input?.file;
// Skip Infima as we are using the its RTL version.
if (file === resolvedInfimaFile) {
return {};
}
return rtlcss(result.root);
return rtlcss((result.root as unknown) as rtlcss.ConfigOptions);
},
};
postCssOptions.plugins.push(plugin);
Expand Down
90 changes: 51 additions & 39 deletions packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,51 +18,63 @@ import styles from './styles.module.css';

import {useThemeConfig, parseCodeBlockTitle} from '@docusaurus/theme-common';

const highlightLinesRangeRegex = /{([\d,-]+)}/;
const HighlightLinesRangeRegex = /{([\d,-]+)}/;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I understand PascalCased variables should be objects right? (Also noticed this in docusaurus-init where TypeScriptTemplateSuffix is PascalCased)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a strong opinion about JS constant namings as long as it's clear enough those are constants. We already have this convention in other places so just made it consistent, but we can also redefine those conventions if needed


const HighlightLanguages = ['js', 'jsBlock', 'jsx', 'python', 'html'] as const;
type HighlightLanguage = typeof HighlightLanguages[number];

type HighlightLanguageConfig = {
start: string;
end: string;
};

// Supported types of highlight comments
const HighlightComments: Record<HighlightLanguage, HighlightLanguageConfig> = {
js: {
start: '\\/\\/',
end: '',
},
jsBlock: {
start: '\\/\\*',
end: '\\*\\/',
},
jsx: {
start: '\\{\\s*\\/\\*',
end: '\\*\\/\\s*\\}',
},
python: {
start: '#',
end: '',
},
html: {
start: '<!--',
end: '-->',
},
};

// Supported highlight directives
const HighlightDirectives = [
'highlight-next-line',
'highlight-start',
'highlight-end',
];

const getHighlightDirectiveRegex = (
languages = ['js', 'jsBlock', 'jsx', 'python', 'html'],
) => {
// supported types of comments
const comments = {
js: {
start: '\\/\\/',
end: '',
},
jsBlock: {
start: '\\/\\*',
end: '\\*\\/',
},
jsx: {
start: '\\{\\s*\\/\\*',
end: '\\*\\/\\s*\\}',
},
python: {
start: '#',
end: '',
},
html: {
start: '<!--',
end: '-->',
},
};
// supported directives
const directives = [
'highlight-next-line',
'highlight-start',
'highlight-end',
].join('|');
languages: readonly HighlightLanguage[] = HighlightLanguages,
): RegExp => {
// to be more reliable, the opening and closing comment must match
const commentPattern = languages
.map(
(lang) =>
`(?:${comments[lang].start}\\s*(${directives})\\s*${comments[lang].end})`,
)
.map((lang) => {
const {start, end} = HighlightComments[lang];
return `(?:${start}\\s*(${HighlightDirectives.join('|')})\\s*${end})`;
})
.join('|');
// white space is allowed, but otherwise it should be on it's own line
return new RegExp(`^\\s*(?:${commentPattern})\\s*$`);
};

// select comment styles based on language
const highlightDirectiveRegex = (lang: string) => {
const highlightDirectiveRegex = (lang: string): RegExp => {
switch (lang) {
case 'js':
case 'javascript':
Expand Down Expand Up @@ -123,9 +135,9 @@ export default function CodeBlock({
? children.join('')
: (children as string);

if (metastring && highlightLinesRangeRegex.test(metastring)) {
if (metastring && HighlightLinesRangeRegex.test(metastring)) {
// Tested above
const highlightLinesRange = metastring.match(highlightLinesRangeRegex)![1];
const highlightLinesRange = metastring.match(HighlightLinesRangeRegex)![1];
highlightLines = rangeParser(highlightLinesRange).filter((n) => n > 0);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function useShowAnnouncementBar() {
return showAnnouncementBar;
}

function HideableSidebarButton({onClick}) {
function HideableSidebarButton({onClick}: {onClick: React.MouseEventHandler}) {
return (
<button
type="button"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ import type {

import styles from './styles.module.css';

const isActiveSidebarItem = (item: Props['item'], activePath: string) => {
const isActiveSidebarItem = (
item: Props['item'],
activePath: string,
): boolean => {
if (item.type === 'link') {
return isSamePath(item.href, activePath);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,12 @@ const BannerLabelComponents: Record<

function BannerLabel(props: BannerLabelComponentProps) {
const BannerLabelComponent =
BannerLabelComponents[props.versionMetadata.banner];
BannerLabelComponents[
props.versionMetadata.banner as Exclude<
Props['versionMetadata']['banner'],
'none'
>
];
return <BannerLabelComponent {...props} />;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ import {
import type {Props} from '@theme/NavbarItem/DocsVersionDropdownNavbarItem';
import {useDocsPreferredVersion} from '@docusaurus/theme-common';
import {translate} from '@docusaurus/Translate';
import type {GlobalDataVersion} from '@docusaurus/plugin-content-docs-types';

const getVersionMainDoc = (version) =>
version.docs.find((doc) => doc.id === version.mainDocId);
const getVersionMainDoc = (version: GlobalDataVersion) =>
version.docs.find((doc) => doc.id === version.mainDocId)!;

export default function DocsVersionDropdownNavbarItem({
mobile,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ import type {Types, Props} from '@theme/NavbarItem';

const NavbarItemComponents: Record<
Exclude<Types, undefined>,
() => (props) => JSX.Element
// TODO: properly type this
// eslint-disable-next-line @typescript-eslint/no-explicit-any
() => (props: any) => JSX.Element
> = {
default: () => DefaultNavbarItem,
localeDropdown: () => LocaleDropdownNavbarItem,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ const useTabGroupChoice = (): useTabGroupChoiceReturns => {

useEffect(() => {
try {
const localStorageChoices = {};
const localStorageChoices: Record<string, string> = {};
listStorageKeys().forEach((storageKey) => {
if (storageKey.startsWith(TAB_CHOICE_PREFIX)) {
const groupId = storageKey.substring(TAB_CHOICE_PREFIX.length);
localStorageChoices[groupId] = createStorageSlot(storageKey).get();
localStorageChoices[groupId] = createStorageSlot(storageKey).get()!;
}
});
setChoices(localStorageChoices);
Expand Down
15 changes: 15 additions & 0 deletions packages/docusaurus-theme-classic/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -756,3 +756,18 @@ declare module '@theme/Tag' {

export default function Tag(props: Props): JSX.Element;
}

declare module '@theme/prism-include-languages' {
import type * as PrismNamespace from 'prismjs';

export default function prismIncludeLanguages(
PrismObject: typeof PrismNamespace,
): void;
}

declare module 'prism-react-renderer/prism' {
import type * as PrismNamespace from 'prismjs';

const Prism: typeof PrismNamespace;
export default Prism;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
* LICENSE file in the root directory of this source tree.
*/

const {Joi, URISchema} = require('@docusaurus/utils-validation');
import {Joi, URISchema} from '@docusaurus/utils-validation';
import type {ThemeConfig, Validate, ValidationResult} from '@docusaurus/types';

const DEFAULT_DOCS_CONFIG = {
versionPersistence: 'localStorage',
Expand Down Expand Up @@ -81,7 +82,7 @@ const DocItemSchema = NavbarItemBaseSchema.append({
docsPluginId: Joi.string(),
});

const itemWithType = (type) => {
const itemWithType = (type: string | undefined) => {
// because equal(undefined) is not supported :/
const typeSchema = type
? Joi.string().required().equal(type)
Expand All @@ -95,7 +96,7 @@ const itemWithType = (type) => {

const DropdownSubitemSchema = Joi.object({
position: Joi.forbidden(),
}).when({
}).when('.', {
switch: [
{
is: itemWithType('docsVersion'),
Expand Down Expand Up @@ -150,7 +151,7 @@ const SearchItemSchema = Joi.object({

const NavbarItemSchema = Joi.object({
position: NavbarItemPosition,
}).when({
}).when('.', {
switch: [
{
is: itemWithType('docsVersion'),
Expand Down Expand Up @@ -178,7 +179,7 @@ const NavbarItemSchema = Joi.object({
},
{
is: itemWithType(undefined),
then: Joi.object().when({
then: Joi.object().when('.', {
// Dropdown item can be specified without type field
is: Joi.object({
items: Joi.array().required(),
Expand Down Expand Up @@ -246,12 +247,12 @@ const CustomCssSchema = Joi.alternatives()

const ThemeConfigSchema = Joi.object({
// TODO temporary (@alpha-58)
disableDarkMode: Joi.any().forbidden(false).messages({
disableDarkMode: Joi.any().forbidden().messages({
'any.unknown':
'disableDarkMode theme config is deprecated. Please use the new colorMode attribute. You likely want: config.themeConfig.colorMode.disableSwitch = true',
}),
// TODO temporary (@alpha-58)
defaultDarkMode: Joi.any().forbidden(false).messages({
defaultDarkMode: Joi.any().forbidden().messages({
'any.unknown':
'defaultDarkMode theme config is deprecated. Please use the new colorMode attribute. You likely want: config.themeConfig.colorMode.defaultMode = "dark"',
}),
Expand Down Expand Up @@ -329,8 +330,15 @@ const ThemeConfigSchema = Joi.object({
'The themeConfig.sidebarCollapsible has been moved to docs plugin options. See: https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-docs',
}),
});
exports.ThemeConfigSchema = ThemeConfigSchema;

exports.validateThemeConfig = ({validate, themeConfig}) => {
export {ThemeConfigSchema};

export function validateThemeConfig({
validate,
themeConfig,
}: {
validate: Validate<ThemeConfig>;
themeConfig: ThemeConfig;
}): ValidationResult<ThemeConfig> {
return validate(ThemeConfigSchema, themeConfig);
};
}
1 change: 0 additions & 1 deletion packages/docusaurus-theme-classic/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
"lib": ["DOM", "ES2019"],
"module": "esnext",
"noEmit": true,
"noImplicitAny": false,
"jsx": "react",
"baseUrl": "src"
},
Expand Down
22 changes: 18 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4220,6 +4220,13 @@
dependencies:
"@types/unist" "*"

"@types/mdx-js__react@^1.5.4":
version "1.5.4"
resolved "https://registry.yarnpkg.com/@types/mdx-js__react/-/mdx-js__react-1.5.4.tgz#75ed343b5a1f56d9518e902d956e1b611da4a297"
integrity sha512-hce+Hymj3cEMOma13eQRhpT3mhQrOkN4CAYEwKWB/qj2BiuUrrTpCkOShEERGmLVgDc3nxF4Dc0k7W999EQxnQ==
dependencies:
"@types/react" "*"

"@types/micromatch@^4.0.2":
version "4.0.2"
resolved "https://registry.yarnpkg.com/@types/micromatch/-/micromatch-4.0.2.tgz#ce29c8b166a73bf980a5727b1e4a4d099965151d"
Expand Down Expand Up @@ -4419,6 +4426,13 @@
dependencies:
"@types/node" "*"

"@types/rtlcss@^3.1.1":
version "3.1.1"
resolved "https://registry.yarnpkg.com/@types/rtlcss/-/rtlcss-3.1.1.tgz#f091b04a2c48b92317228113a2a235c755d51c77"
integrity sha512-xj8SSY1sadjWrU9we6pm0jaSsZiZoZeEuzN5ebYW6SKCi6xIWLFCkKr58bHTaopqoDiyhwLbCvxIQ7uW4SK98g==
dependencies:
postcss "^8.2.x"

"@types/sax@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@types/sax/-/sax-1.2.1.tgz#e0248be936ece791a82db1a57f3fb5f7c87e8172"
Expand Down Expand Up @@ -16035,10 +16049,10 @@ postcss-zindex@^5.0.1:
source-map "^0.6.1"
supports-color "^6.1.0"

postcss@^8.1.7, postcss@^8.2.15, postcss@^8.2.4, postcss@^8.2.9:
version "8.3.1"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.1.tgz#71f380151c227f83b898294a46481f689f86b70a"
integrity sha512-9qH0MGjsSm+fjxOi3GnwViL1otfi7qkj+l/WX5gcRGmZNGsIcqc+A5fBkE6PUobEQK4APqYVaES+B3Uti98TCw==
postcss@^8.1.7, postcss@^8.2.15, postcss@^8.2.4, postcss@^8.2.9, postcss@^8.2.x:
version "8.3.6"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.6.tgz#2730dd76a97969f37f53b9a6096197be311cc4ea"
integrity sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A==
dependencies:
colorette "^1.2.2"
nanoid "^3.1.23"
Expand Down