feat: Docusaurus ESLint plugin to enforce best Docusaurus practices (#7206)

* feat: add eslint plugin

* refactor

* add tests

* fixups!

* fix(no-dynamic-i18n-messages): make translate() recognize template literals

* refactor: rename rule no-dynamic-i18n-messages --> string-literal-i18n-messages

* feat: add ignoreStrings option and refactor

* docs: migrate docs to /docs/api/plugins

* docs: fix anchor links in README.md

* fix: add some ignored strings

* docs: update eslint-plugin docs

* fix: update README link

* docs: various updates

- Reorder sidebar entries
- Fix title size
- Use Markdown file paths
- Simplify relative links

* address reviews

* wording polish

* add npmignore

* fix all internal warnings

* doc improvements

* fix test

Co-authored-by: Joshua Chen <sidachen2003@gmail.com>
This commit is contained in:
Elias Papavasileiou 2022-04-29 19:04:25 +03:00 committed by GitHub
parent ae788c536f
commit 3b1170eb44
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 885 additions and 52 deletions

View file

@ -0,0 +1,147 @@
/**
* 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.
*/
const rule = require('../no-untranslated-text');
const {RuleTester} = require('eslint');
const {getCommonValidTests} = require('../../util');
const errorsJSX = [{messageId: 'translateChildren', type: 'JSXElement'}];
const errorsJSXFragment = [
{messageId: 'translateChildren', type: 'JSXFragment'},
];
const ruleTester = new RuleTester({
parserOptions: {
ecmaVersion: 2022,
ecmaFeatures: {jsx: true},
},
});
ruleTester.run('no-untranslated-text', rule, {
valid: [
...getCommonValidTests(),
{
code: '<Component>·</Component>',
options: [{ignoreStrings: ['·', '—', '×']}],
},
{
code: '<Component>· </Component>',
options: [{ignoreStrings: ['·', '—', '×']}],
},
{
code: '<Component> · </Component>',
options: [{ignoreStrings: ['·', '—', '×']}],
},
{
code: '<Component>· ·</Component>',
options: [{ignoreStrings: ['·', '—', '×']}],
},
{
code: '<Component>· — ×</Component>',
options: [{ignoreStrings: ['·', '—', '×']}],
},
{
code: '<Component>{"·"}</Component>',
options: [{ignoreStrings: ['·']}],
},
{
code: "<Component>{'·'}</Component>",
options: [{ignoreStrings: ['·']}],
},
{
code: '<Component>{`·`}</Component>',
options: [{ignoreStrings: ['·', '—', '×']}],
},
{
code: '<Component>Docusaurus</Component>',
options: [{ignoreStrings: ['Docusaurus']}],
},
{
code: '<Component>&#8203;</Component>',
options: [{ignoreStrings: ['']}],
},
{
code: `<>
{' · '}
</>`,
options: [{ignoreStrings: ['·', "'"]}],
},
],
invalid: [
{
code: '<Component>text</Component>',
errors: errorsJSX,
},
{
code: '<Component> text </Component>',
errors: errorsJSX,
},
{
code: '<Component>"text"</Component>',
errors: errorsJSX,
},
{
code: "<Component>'text'</Component>",
errors: errorsJSX,
},
{
code: '<Component>`text`</Component>',
errors: errorsJSX,
},
{
code: '<Component>{"text"}</Component>',
errors: errorsJSX,
},
{
code: "<Component>{'text'}</Component>",
errors: errorsJSX,
},
{
code: '<Component>{`text`}</Component>',
errors: errorsJSX,
},
{
code: '<>text</>',
errors: errorsJSXFragment,
},
{
code: '<Component>· — ×</Component>',
errors: errorsJSX,
options: [{ignoreStrings: ['·', '—']}],
},
{
code: '<Component>··</Component>',
errors: errorsJSX,
options: [{ignoreStrings: ['·', '—', '×']}],
},
{
code: '<Component> ·· </Component>',
errors: errorsJSX,
options: [{ignoreStrings: ['·', '—', '×']}],
},
{
code: '<Component>"·"</Component>',
errors: errorsJSX,
options: [{ignoreStrings: ['·', '—', '×']}],
},
{
code: "<Component>'·'</Component>",
errors: errorsJSX,
options: [{ignoreStrings: ['·', '—', '×']}],
},
{
code: '<Component>`·`</Component>',
errors: errorsJSX,
options: [{ignoreStrings: ['·', '—', '×']}],
},
{
code: '<Component>Docusaurus</Component>',
errors: errorsJSX,
options: [{ignoreStrings: ['Docu', 'saurus']}],
},
],
});

View file

@ -0,0 +1,51 @@
/**
* 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.
*/
const rule = require('../string-literal-i18n-messages');
const {RuleTester} = require('eslint');
const {getCommonValidTests} = require('../../util');
const errorsJSX = [{messageId: 'translateChildren', type: 'JSXElement'}];
const errorsFunc = [{messageId: 'translateArg', type: 'Identifier'}];
const ruleTester = new RuleTester({
parserOptions: {
ecmaVersion: 2022,
ecmaFeatures: {jsx: true},
},
});
ruleTester.run('string-literal-i18n-messages', rule, {
valid: [...getCommonValidTests()],
invalid: [
{
code: '<Translate>{text}</Translate>',
errors: errorsJSX,
},
{
code: '<Translate>Hi {text} my friend</Translate>',
errors: errorsJSX,
},
{
code: '<Translate> {text} </Translate>',
errors: errorsJSX,
},
{
code: '<Translate>`{text}`</Translate>',
errors: errorsJSX,
},
{
// eslint-disable-next-line no-template-curly-in-string
code: '<Translate>{`${text}`}</Translate>',
errors: errorsJSX,
},
{
code: 'translate({message: metaTitle})',
errors: errorsFunc,
},
],
});