chore: fix ESLint warnings, restrict export all syntax (#6605)

* chore: fix ESLint warnings, forbid export all syntax

* fix...

* reorder
This commit is contained in:
Joshua Chen 2022-02-04 21:57:10 +08:00 committed by GitHub
parent 3fd99ad8d4
commit 45f6f8b869
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 220 additions and 148 deletions

View file

@ -69,8 +69,6 @@ module.exports = {
'no-param-reassign': [WARNING, {props: false}],
'no-prototype-builtins': WARNING,
'no-restricted-exports': OFF,
'no-useless-escape': WARNING,
'no-template-curly-in-string': WARNING,
'no-restricted-imports': [
ERROR,
{
@ -97,8 +95,33 @@ module.exports = {
],
},
],
'no-restricted-syntax': WARNING,
'no-restricted-syntax': [
WARNING,
// Copied from airbnb, removed for...of statement, added export all
{
selector: 'ForInStatement',
message:
'for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array.',
},
{
selector: 'LabeledStatement',
message:
'Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand.',
},
{
selector: 'WithStatement',
message:
'`with` is disallowed in strict mode because it makes code impossible to predict and optimize.',
},
{
selector: 'ExportAllDeclaration',
message:
"Export all does't work well if imported in ESM due to how they are transpiled, and they can also lead to unexpected exposure of internal methods.",
},
],
'no-template-curly-in-string': WARNING,
'no-unused-expressions': [WARNING, {allowTaggedTemplates: true}],
'no-useless-escape': WARNING,
'prefer-destructuring': WARNING,
'prefer-named-capture-group': WARNING,
'prefer-template': WARNING,

View file

@ -182,7 +182,6 @@ const templates = (
await fs.readdir('./packages/create-docusaurus/templates')
).filter((name) => !excludes.includes(name));
console.log(`Will generate examples for templates: ${templates.join(',')}`);
// eslint-disable-next-line no-restricted-syntax
for (const template of templates) {
await generateTemplateExample(template);
}

View file

@ -240,11 +240,11 @@ declare module '@docusaurus/Translate' {
}
declare module '@docusaurus/router' {
// eslint-disable-next-line import/no-extraneous-dependencies
// eslint-disable-next-line import/no-extraneous-dependencies, no-restricted-syntax
export * from 'react-router-dom';
}
declare module '@docusaurus/history' {
// eslint-disable-next-line import/no-extraneous-dependencies
// eslint-disable-next-line import/no-extraneous-dependencies, no-restricted-syntax
export * from 'history';
}

View file

@ -27,7 +27,8 @@ export interface BlogContent {
export interface BlogTags {
// TODO, the key is the tag slug/permalink
// This is due to legacy frontmatter: tags: [{label: "xyz", permalink: "/1"}, {label: "xyz", permalink: "/2"}
// This is due to legacy frontmatter: tags:
// [{label: "xyz", permalink: "/1"}, {label: "xyz", permalink: "/2"}]
// Soon we should forbid declaring permalink through frontmatter
[tagKey: string]: BlogTag;
}

View file

@ -5,7 +5,7 @@
"main": "lib/index.js",
"exports": {
"./client": "./lib/client/index.js",
"./server": "./lib/server/index.js",
"./server": "./lib/server-export.js",
".": "./lib/index.js"
},
"types": "src/plugin-content-docs.d.ts",

View file

@ -1,108 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {useLocation} from '@docusaurus/router';
import useGlobalData, {
// useAllPluginInstancesData,
usePluginData,
} from '@docusaurus/useGlobalData';
import {
getActivePlugin,
getLatestVersion,
getActiveVersion,
getActiveDocContext,
getDocVersionSuggestions,
} from './docsClientUtils';
import type {
GlobalPluginData,
GlobalVersion,
ActivePlugin,
ActiveDocContext,
DocVersionSuggestions,
GetActivePluginOptions,
} from '@docusaurus/plugin-content-docs/client';
// Important to use a constant object to avoid React useEffect executions etc.
// see https://github.com/facebook/docusaurus/issues/5089
const StableEmptyObject = {};
// Not using useAllPluginInstancesData() because in blog-only mode, docs hooks
// are still used by the theme. We need a fail-safe fallback when the docs
// plugin is not in use
export const useAllDocsData = (): Record<string, GlobalPluginData> =>
// useAllPluginInstancesData('docusaurus-plugin-content-docs');
useGlobalData()['docusaurus-plugin-content-docs'] ?? StableEmptyObject;
export const useDocsData = (pluginId: string | undefined): GlobalPluginData =>
usePluginData('docusaurus-plugin-content-docs', pluginId) as GlobalPluginData;
// TODO this feature should be provided by docusaurus core
export const useActivePlugin = (
options: GetActivePluginOptions = {},
): ActivePlugin | undefined => {
const data = useAllDocsData();
const {pathname} = useLocation();
return getActivePlugin(data, pathname, options);
};
export const useActivePluginAndVersion = (
options: GetActivePluginOptions = {},
):
| undefined
| {activePlugin: ActivePlugin; activeVersion: GlobalVersion | undefined} => {
const activePlugin = useActivePlugin(options);
const {pathname} = useLocation();
if (activePlugin) {
const activeVersion = getActiveVersion(activePlugin.pluginData, pathname);
return {
activePlugin,
activeVersion,
};
}
return undefined;
};
// versions are returned ordered (most recent first)
export const useVersions = (pluginId: string | undefined): GlobalVersion[] => {
const data = useDocsData(pluginId);
return data.versions;
};
export const useLatestVersion = (
pluginId: string | undefined,
): GlobalVersion => {
const data = useDocsData(pluginId);
return getLatestVersion(data);
};
// Note: return undefined on doc-unrelated pages,
// because there's no version currently considered as active
export const useActiveVersion = (
pluginId: string | undefined,
): GlobalVersion | undefined => {
const data = useDocsData(pluginId);
const {pathname} = useLocation();
return getActiveVersion(data, pathname);
};
export const useActiveDocContext = (
pluginId: string | undefined,
): ActiveDocContext => {
const data = useDocsData(pluginId);
const {pathname} = useLocation();
return getActiveDocContext(data, pathname);
};
// Useful to say "hey, you are not on the latest docs version, please switch"
export const useDocVersionSuggestions = (
pluginId: string | undefined,
): DocVersionSuggestions => {
const data = useDocsData(pluginId);
const {pathname} = useLocation();
return getDocVersionSuggestions(data, pathname);
};

View file

@ -5,4 +5,100 @@
* LICENSE file in the root directory of this source tree.
*/
export * from './globalDataHooks';
import {useLocation} from '@docusaurus/router';
import useGlobalData, {usePluginData} from '@docusaurus/useGlobalData';
import {
getActivePlugin,
getLatestVersion,
getActiveVersion,
getActiveDocContext,
getDocVersionSuggestions,
} from './docsClientUtils';
import type {
GlobalPluginData,
GlobalVersion,
ActivePlugin,
ActiveDocContext,
DocVersionSuggestions,
GetActivePluginOptions,
} from '@docusaurus/plugin-content-docs/client';
// Important to use a constant object to avoid React useEffect executions etc.
// see https://github.com/facebook/docusaurus/issues/5089
const StableEmptyObject = {};
// Not using useAllPluginInstancesData() because in blog-only mode, docs hooks
// are still used by the theme. We need a fail-safe fallback when the docs
// plugin is not in use
export const useAllDocsData = (): Record<string, GlobalPluginData> =>
useGlobalData()['docusaurus-plugin-content-docs'] ?? StableEmptyObject;
export const useDocsData = (pluginId: string | undefined): GlobalPluginData =>
usePluginData('docusaurus-plugin-content-docs', pluginId) as GlobalPluginData;
// TODO this feature should be provided by docusaurus core
export const useActivePlugin = (
options: GetActivePluginOptions = {},
): ActivePlugin | undefined => {
const data = useAllDocsData();
const {pathname} = useLocation();
return getActivePlugin(data, pathname, options);
};
export const useActivePluginAndVersion = (
options: GetActivePluginOptions = {},
):
| undefined
| {activePlugin: ActivePlugin; activeVersion: GlobalVersion | undefined} => {
const activePlugin = useActivePlugin(options);
const {pathname} = useLocation();
if (activePlugin) {
const activeVersion = getActiveVersion(activePlugin.pluginData, pathname);
return {
activePlugin,
activeVersion,
};
}
return undefined;
};
// versions are returned ordered (most recent first)
export const useVersions = (pluginId: string | undefined): GlobalVersion[] => {
const data = useDocsData(pluginId);
return data.versions;
};
export const useLatestVersion = (
pluginId: string | undefined,
): GlobalVersion => {
const data = useDocsData(pluginId);
return getLatestVersion(data);
};
// Note: return undefined on doc-unrelated pages,
// because there's no version currently considered as active
export const useActiveVersion = (
pluginId: string | undefined,
): GlobalVersion | undefined => {
const data = useDocsData(pluginId);
const {pathname} = useLocation();
return getActiveVersion(data, pathname);
};
export const useActiveDocContext = (
pluginId: string | undefined,
): ActiveDocContext => {
const data = useDocsData(pluginId);
const {pathname} = useLocation();
return getActiveDocContext(data, pathname);
};
// Useful to say "hey, you are not on the latest docs version, please switch"
export const useDocVersionSuggestions = (
pluginId: string | undefined,
): DocVersionSuggestions => {
const data = useDocsData(pluginId);
const {pathname} = useLocation();
return getDocVersionSuggestions(data, pathname);
};

View file

@ -6,7 +6,12 @@
*/
// APIs available to Node.js
export * from '../constants';
export {
CURRENT_VERSION_NAME,
VERSIONED_DOCS_DIR,
VERSIONED_SIDEBARS_DIR,
VERSIONS_JSON_FILE,
} from './constants';
export {
filterVersions,
@ -16,4 +21,4 @@ export {
getVersionsFilePath,
readVersionsFile,
readVersionNames,
} from '../versions';
} from './versions';

View file

@ -303,7 +303,6 @@ Available document ids are:
label: string;
}
| undefined {
// eslint-disable-next-line no-restricted-syntax
for (const item of sidebar) {
if (item.type === 'doc') {
return {

View file

@ -9,4 +9,5 @@
// If you swizzled this, it is your responsibility to provide an implementation
// Tip: swizzle the SearchBar from the Algolia theme for inspiration:
// npm run swizzle @docusaurus/theme-search-algolia SearchBar
export {default} from '@docusaurus/Noop';

View file

@ -96,7 +96,6 @@ export function findSidebarCategory(
sidebar: PropSidebar,
predicate: (category: PropSidebarItemCategory) => boolean,
): PropSidebarItemCategory | undefined {
// eslint-disable-next-line no-restricted-syntax
for (const item of sidebar) {
if (item.type === 'category') {
if (predicate(item)) {
@ -119,7 +118,6 @@ export function findFirstCategoryLink(
return item.href;
}
// eslint-disable-next-line no-restricted-syntax
for (const subItem of item.items) {
if (subItem.type === 'link') {
return subItem.href;

View file

@ -7,7 +7,7 @@
declare module '@philpl/buble' {
import type {TransformOptions as OriginalTransformOptions} from 'buble';
// eslint-disable-next-line import/no-extraneous-dependencies
// eslint-disable-next-line import/no-extraneous-dependencies, no-restricted-syntax
export * from 'buble';
export const features: string[];
export interface TransformOptions extends OriginalTransformOptions {

View file

@ -44,7 +44,6 @@ export async function readDefaultCodeTranslationMessages({
// Return the content of the first file that match
// fr_FR.json => fr.json => nothing
// eslint-disable-next-line no-restricted-syntax
for (const localeToTry of localesToTry) {
const filePath = path.resolve(dirPath, localeToTry, `${name}.json`);

View file

@ -268,8 +268,6 @@ async function updateCodeTranslations() {
const stats = {};
let messageCount = 0;
const {2: newLocale} = process.argv;
// Order is important. The log messages must be in the same order as execution
// eslint-disable-next-line no-restricted-syntax
for (const theme of Themes) {
const {baseFile, localesFiles} = await getCodeTranslationFiles(theme.name);
logger.info`Will update base file for name=${theme.name}\n`;
@ -289,7 +287,6 @@ async function updateCodeTranslations() {
)} was already created!`;
}
} else {
// eslint-disable-next-line no-restricted-syntax
for (const localeFile of localesFiles) {
const localeName = path.basename(path.dirname(localeFile));
const pluginName = path.basename(localeFile, path.extname(localeFile));

View file

@ -9,5 +9,21 @@
export {default as Joi} from './Joi';
export {JoiFrontMatter} from './JoiFrontMatter';
export * from './validationUtils';
export * from './validationSchemas';
export {
isValidationDisabledEscapeHatch,
logValidationBugReportHint,
printWarning,
normalizePluginOptions,
normalizeThemeConfig,
validateFrontMatter,
} from './validationUtils';
export {
PluginIdSchema,
RemarkPluginsSchema,
RehypePluginsSchema,
AdmonitionsSchema,
URISchema,
PathnameSchema,
FrontMatterTagsSchema,
FrontMatterTOCHeadingLevels,
} from './validationSchemas';

View file

@ -22,17 +22,68 @@ import resolvePathnameUnsafe from 'resolve-pathname';
import {simpleHash, docuHash} from './hashUtils';
import {DEFAULT_PLUGIN_ID} from './constants';
export * from './constants';
export * from './urlUtils';
export * from './tags';
export * from './markdownParser';
export * from './markdownLinks';
export * from './slugger';
export * from './pathUtils';
export * from './hashUtils';
export * from './globUtils';
export * from './webpackUtils';
export * from './dataFileUtils';
export {
NODE_MAJOR_VERSION,
NODE_MINOR_VERSION,
DEFAULT_BUILD_DIR_NAME,
DEFAULT_CONFIG_FILE_NAME,
BABEL_CONFIG_FILE_NAME,
GENERATED_FILES_DIR_NAME,
SRC_DIR_NAME,
STATIC_DIR_NAME,
OUTPUT_STATIC_ASSETS_DIR_NAME,
THEME_PATH,
DEFAULT_PORT,
DEFAULT_PLUGIN_ID,
WEBPACK_URL_LOADER_LIMIT,
} from './constants';
export {normalizeUrl, getEditUrl} from './urlUtils';
export {
type Tag,
type FrontMatterTag,
type TaggedItemGroup,
normalizeFrontMatterTag,
normalizeFrontMatterTags,
groupTaggedItems,
} from './tags';
export {
parseMarkdownHeadingId,
createExcerpt,
parseFrontMatter,
parseMarkdownContentTitle,
parseMarkdownString,
} from './markdownParser';
export {
type ContentPaths,
type BrokenMarkdownLink,
type ReplaceMarkdownLinksParams,
type ReplaceMarkdownLinksReturn,
replaceMarkdownLinks,
} from './markdownLinks';
export {type SluggerOptions, type Slugger, createSlugger} from './slugger';
export {
isNameTooLong,
shortName,
posixPath,
toMessageRelativeFilePath,
aliasedSitePath,
escapePath,
} from './pathUtils';
export {md5Hash, simpleHash, docuHash} from './hashUtils';
export {
Globby,
GlobExcludeDefault,
createMatcher,
createAbsoluteFilePathMatcher,
} from './globUtils';
export {getFileLoaderUtils} from './webpackUtils';
export {
getDataFilePath,
getDataFileData,
getContentPathList,
findFolderContainingFile,
getFolderContainingFile,
} from './dataFileUtils';
const fileHash = new Map<string, string>();
export async function generate(
@ -251,7 +302,6 @@ export async function mapAsyncSequential<T, R>(
action: (t: T) => Promise<R>,
): Promise<R[]> {
const results: R[] = [];
// eslint-disable-next-line no-restricted-syntax
for (const t of array) {
const result = await action(t);
results.push(result);
@ -263,7 +313,6 @@ export async function findAsyncSequential<T>(
array: T[],
predicate: (t: T) => Promise<boolean>,
): Promise<T | undefined> {
// eslint-disable-next-line no-restricted-syntax
for (const t of array) {
if (await predicate(t)) {
return t;

View file

@ -38,7 +38,6 @@ export function createExcerpt(fileString: string): string | undefined {
let lastCodeFence = '';
/* eslint-disable no-continue */
// eslint-disable-next-line no-restricted-syntax
for (const fileLine of fileLines) {
// Skip empty line.
if (!fileLine.trim()) {

View file

@ -5,4 +5,5 @@
* LICENSE file in the root directory of this source tree.
*/
// eslint-disable-next-line no-restricted-syntax
export * from 'react-router-dom';

View file

@ -13,7 +13,6 @@ import {
getDocusaurusAliases,
createBaseConfig,
} from '../base';
// TODO seems to be a bug with how TS does star exports
import * as utils from '@docusaurus/utils/lib/webpackUtils';
import {posixPath} from '@docusaurus/utils';
import {mapValues} from 'lodash';

View file

@ -7,7 +7,7 @@
import React from 'react';
import {Props as Tweet} from '../../components/Tweet';
import type {Props as Tweet} from '../../components/Tweet';
export interface TweetItem extends Tweet {
showOnHomepage: boolean;

View file

@ -17,7 +17,7 @@ import Image from '@theme/IdealImage';
import Layout from '@theme/Layout';
import Tweet from '@site/src/components/Tweet';
import Tweets, {TweetItem} from '@site/src/data/tweets';
import Tweets, {type TweetItem} from '@site/src/data/tweets';
import clsx from 'clsx';

View file

@ -55,7 +55,6 @@ async function syncAvatars(authorsMap, generateDir) {
*/
const lastUpdateCache = await fs.readJSON(lastUpdateCachePath);
let limitReached = false;
// eslint-disable-next-line no-restricted-syntax
for (const username of Object.keys(authorsMap)) {
if (!limitReached && !lastUpdateCache[username]) {
if (!(await fetchImage(username, lastUpdateCache, authorsMap))) {
@ -69,7 +68,6 @@ async function syncAvatars(authorsMap, generateDir) {
const usersByLastUpdate = Object.entries(lastUpdateCache)
.sort((a, b) => a[1] - b[1])
.map((a) => a[0]);
// eslint-disable-next-line no-restricted-syntax
for (const username of usersByLastUpdate) {
if (
!limitReached &&