@docusaurus/eslint-plugin 0.0.0-5415 → 0.0.0-5416

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts CHANGED
@@ -10,12 +10,16 @@ declare const _default: {
10
10
  ignoredStrings: string[];
11
11
  }], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
12
12
  'string-literal-i18n-messages': import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"translateChildren" | "translateArg", [], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
13
+ 'no-html-links': import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"link", [{
14
+ ignoreFullyResolved: boolean;
15
+ }], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
13
16
  };
14
17
  configs: {
15
18
  recommended: {
16
19
  plugins: string[];
17
20
  rules: {
18
21
  '@docusaurus/string-literal-i18n-messages': string;
22
+ '@docusaurus/no-html-links': string;
19
23
  };
20
24
  };
21
25
  all: {
@@ -23,6 +27,7 @@ declare const _default: {
23
27
  rules: {
24
28
  '@docusaurus/string-literal-i18n-messages': string;
25
29
  '@docusaurus/no-untranslated-text': string;
30
+ '@docusaurus/no-html-links': string;
26
31
  };
27
32
  };
28
33
  };
package/lib/index.js CHANGED
@@ -14,6 +14,7 @@ module.exports = {
14
14
  plugins: ['@docusaurus'],
15
15
  rules: {
16
16
  '@docusaurus/string-literal-i18n-messages': 'error',
17
+ '@docusaurus/no-html-links': 'warn',
17
18
  },
18
19
  },
19
20
  all: {
@@ -21,6 +22,7 @@ module.exports = {
21
22
  rules: {
22
23
  '@docusaurus/string-literal-i18n-messages': 'error',
23
24
  '@docusaurus/no-untranslated-text': 'warn',
25
+ '@docusaurus/no-html-links': 'warn',
24
26
  },
25
27
  },
26
28
  },
@@ -9,5 +9,8 @@ declare const _default: {
9
9
  ignoredStrings: string[];
10
10
  }], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
11
11
  'string-literal-i18n-messages': import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"translateChildren" | "translateArg", [], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
12
+ 'no-html-links': import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"link", [{
13
+ ignoreFullyResolved: boolean;
14
+ }], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
12
15
  };
13
16
  export default _default;
@@ -7,9 +7,11 @@
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  const tslib_1 = require("tslib");
10
+ const no_html_links_1 = tslib_1.__importDefault(require("./no-html-links"));
10
11
  const no_untranslated_text_1 = tslib_1.__importDefault(require("./no-untranslated-text"));
11
12
  const string_literal_i18n_messages_1 = tslib_1.__importDefault(require("./string-literal-i18n-messages"));
12
13
  exports.default = {
13
14
  'no-untranslated-text': no_untranslated_text_1.default,
14
15
  'string-literal-i18n-messages': string_literal_i18n_messages_1.default,
16
+ 'no-html-links': no_html_links_1.default,
15
17
  };
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ declare type Options = [
8
+ {
9
+ ignoreFullyResolved: boolean;
10
+ }
11
+ ];
12
+ declare const _default: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"link", Options, import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
13
+ export default _default;
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) Facebook, Inc. and its affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ const util_1 = require("../util");
10
+ const docsUrl = 'https://docusaurus.io/docs/docusaurus-core#link';
11
+ function isFullyResolvedUrl(urlString) {
12
+ try {
13
+ // href gets coerced to a string when it gets rendered anyway
14
+ const url = new URL(String(urlString));
15
+ if (url.protocol) {
16
+ return true;
17
+ }
18
+ }
19
+ catch (e) { }
20
+ return false;
21
+ }
22
+ exports.default = (0, util_1.createRule)({
23
+ name: 'no-html-links',
24
+ meta: {
25
+ type: 'problem',
26
+ docs: {
27
+ description: 'enforce using Docusaurus Link component instead of <a> tag',
28
+ recommended: false,
29
+ },
30
+ schema: [
31
+ {
32
+ type: 'object',
33
+ properties: {
34
+ ignoreFullyResolved: {
35
+ type: 'boolean',
36
+ },
37
+ },
38
+ additionalProperties: false,
39
+ },
40
+ ],
41
+ messages: {
42
+ link: `Do not use an \`<a>\` element to navigate. Use the \`<Link />\` component from \`@docusaurus/Link\` instead. See: ${docsUrl}`,
43
+ },
44
+ },
45
+ defaultOptions: [
46
+ {
47
+ ignoreFullyResolved: false,
48
+ },
49
+ ],
50
+ create(context, [options]) {
51
+ const { ignoreFullyResolved } = options;
52
+ return {
53
+ JSXOpeningElement(node) {
54
+ if (node.name.name !== 'a') {
55
+ return;
56
+ }
57
+ if (ignoreFullyResolved) {
58
+ const hrefAttr = node.attributes.find((attr) => attr.type === 'JSXAttribute' && attr.name.name === 'href');
59
+ if (hrefAttr?.value?.type === 'Literal') {
60
+ if (isFullyResolvedUrl(String(hrefAttr.value.value))) {
61
+ return;
62
+ }
63
+ }
64
+ if (hrefAttr?.value?.type === 'JSXExpressionContainer') {
65
+ const container = hrefAttr.value;
66
+ const { expression } = container;
67
+ if (expression.type === 'TemplateLiteral') {
68
+ // Simple static string template literals
69
+ if (expression.expressions.length === 0 &&
70
+ expression.quasis.length === 1 &&
71
+ expression.quasis[0]?.type === 'TemplateElement' &&
72
+ isFullyResolvedUrl(String(expression.quasis[0].value.raw))) {
73
+ return;
74
+ }
75
+ // TODO add more complex TemplateLiteral cases here
76
+ }
77
+ }
78
+ }
79
+ context.report({ node, messageId: 'link' });
80
+ },
81
+ };
82
+ },
83
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docusaurus/eslint-plugin",
3
- "version": "0.0.0-5415",
3
+ "version": "0.0.0-5416",
4
4
  "description": "ESLint plugin to enforce best Docusaurus practices.",
5
5
  "main": "lib/index.js",
6
6
  "keywords": [
@@ -33,5 +33,5 @@
33
33
  "engines": {
34
34
  "node": ">=16.14"
35
35
  },
36
- "gitHead": "75a8c6e99031132fc1c96cf1154a026b27714055"
36
+ "gitHead": "58fa9168665fa4cb70b0eb722e0d56d6e26ac8c6"
37
37
  }
package/src/index.ts CHANGED
@@ -14,6 +14,7 @@ export = {
14
14
  plugins: ['@docusaurus'],
15
15
  rules: {
16
16
  '@docusaurus/string-literal-i18n-messages': 'error',
17
+ '@docusaurus/no-html-links': 'warn',
17
18
  },
18
19
  },
19
20
  all: {
@@ -21,6 +22,7 @@ export = {
21
22
  rules: {
22
23
  '@docusaurus/string-literal-i18n-messages': 'error',
23
24
  '@docusaurus/no-untranslated-text': 'warn',
25
+ '@docusaurus/no-html-links': 'warn',
24
26
  },
25
27
  },
26
28
  },
@@ -5,10 +5,12 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
+ import noHtmlLinks from './no-html-links';
8
9
  import noUntranslatedText from './no-untranslated-text';
9
10
  import stringLiteralI18nMessages from './string-literal-i18n-messages';
10
11
 
11
12
  export default {
12
13
  'no-untranslated-text': noUntranslatedText,
13
14
  'string-literal-i18n-messages': stringLiteralI18nMessages,
15
+ 'no-html-links': noHtmlLinks,
14
16
  };
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import {createRule} from '../util';
9
+ import type {TSESTree} from '@typescript-eslint/types/dist/ts-estree';
10
+
11
+ const docsUrl = 'https://docusaurus.io/docs/docusaurus-core#link';
12
+
13
+ type Options = [
14
+ {
15
+ ignoreFullyResolved: boolean;
16
+ },
17
+ ];
18
+
19
+ type MessageIds = 'link';
20
+
21
+ function isFullyResolvedUrl(urlString: string): boolean {
22
+ try {
23
+ // href gets coerced to a string when it gets rendered anyway
24
+ const url = new URL(String(urlString));
25
+ if (url.protocol) {
26
+ return true;
27
+ }
28
+ } catch (e) {}
29
+ return false;
30
+ }
31
+
32
+ export default createRule<Options, MessageIds>({
33
+ name: 'no-html-links',
34
+ meta: {
35
+ type: 'problem',
36
+ docs: {
37
+ description: 'enforce using Docusaurus Link component instead of <a> tag',
38
+ recommended: false,
39
+ },
40
+ schema: [
41
+ {
42
+ type: 'object',
43
+ properties: {
44
+ ignoreFullyResolved: {
45
+ type: 'boolean',
46
+ },
47
+ },
48
+ additionalProperties: false,
49
+ },
50
+ ],
51
+ messages: {
52
+ link: `Do not use an \`<a>\` element to navigate. Use the \`<Link />\` component from \`@docusaurus/Link\` instead. See: ${docsUrl}`,
53
+ },
54
+ },
55
+ defaultOptions: [
56
+ {
57
+ ignoreFullyResolved: false,
58
+ },
59
+ ],
60
+
61
+ create(context, [options]) {
62
+ const {ignoreFullyResolved} = options;
63
+
64
+ return {
65
+ JSXOpeningElement(node) {
66
+ if ((node.name as TSESTree.JSXIdentifier).name !== 'a') {
67
+ return;
68
+ }
69
+
70
+ if (ignoreFullyResolved) {
71
+ const hrefAttr = node.attributes.find(
72
+ (attr): attr is TSESTree.JSXAttribute =>
73
+ attr.type === 'JSXAttribute' && attr.name.name === 'href',
74
+ );
75
+
76
+ if (hrefAttr?.value?.type === 'Literal') {
77
+ if (isFullyResolvedUrl(String(hrefAttr.value.value))) {
78
+ return;
79
+ }
80
+ }
81
+ if (hrefAttr?.value?.type === 'JSXExpressionContainer') {
82
+ const container: TSESTree.JSXExpressionContainer = hrefAttr.value;
83
+ const {expression} = container;
84
+ if (expression.type === 'TemplateLiteral') {
85
+ // Simple static string template literals
86
+ if (
87
+ expression.expressions.length === 0 &&
88
+ expression.quasis.length === 1 &&
89
+ expression.quasis[0]?.type === 'TemplateElement' &&
90
+ isFullyResolvedUrl(String(expression.quasis[0].value.raw))
91
+ ) {
92
+ return;
93
+ }
94
+ // TODO add more complex TemplateLiteral cases here
95
+ }
96
+ }
97
+ }
98
+
99
+ context.report({node, messageId: 'link'});
100
+ },
101
+ };
102
+ },
103
+ });