@sgfe/eslint-plugin-sg 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. package/LICENSE.md +25 -0
  2. package/README.md +188 -0
  3. package/configs/all-type-checked.js +10 -0
  4. package/configs/all.js +11 -0
  5. package/configs/recommended.js +11 -0
  6. package/configs/rules-recommended.js +11 -0
  7. package/configs/rules.js +11 -0
  8. package/configs/tests-recommended.js +11 -0
  9. package/configs/tests.js +11 -0
  10. package/lib/index.js +90 -0
  11. package/lib/rules/consistent-output.js +70 -0
  12. package/lib/rules/fixer-return.js +170 -0
  13. package/lib/rules/meta-property-ordering.js +108 -0
  14. package/lib/rules/no-deprecated-context-methods.js +98 -0
  15. package/lib/rules/no-deprecated-report-api.js +83 -0
  16. package/lib/rules/no-identical-tests.js +87 -0
  17. package/lib/rules/no-missing-message-ids.js +101 -0
  18. package/lib/rules/no-missing-placeholders.js +131 -0
  19. package/lib/rules/no-only-tests.js +99 -0
  20. package/lib/rules/no-property-in-node.js +86 -0
  21. package/lib/rules/no-unused-message-ids.js +139 -0
  22. package/lib/rules/no-unused-placeholders.js +127 -0
  23. package/lib/rules/no-useless-token-range.js +174 -0
  24. package/lib/rules/prefer-message-ids.js +109 -0
  25. package/lib/rules/prefer-object-rule.js +83 -0
  26. package/lib/rules/prefer-output-null.js +77 -0
  27. package/lib/rules/prefer-placeholders.js +102 -0
  28. package/lib/rules/prefer-replace-text.js +91 -0
  29. package/lib/rules/report-message-format.js +133 -0
  30. package/lib/rules/require-meta-docs-description.js +110 -0
  31. package/lib/rules/require-meta-docs-url.js +175 -0
  32. package/lib/rules/require-meta-fixable.js +137 -0
  33. package/lib/rules/require-meta-has-suggestions.js +168 -0
  34. package/lib/rules/require-meta-schema.js +162 -0
  35. package/lib/rules/require-meta-type.js +77 -0
  36. package/lib/rules/test-case-property-ordering.js +107 -0
  37. package/lib/rules/test-case-shorthand-strings.js +124 -0
  38. package/lib/utils.js +936 -0
  39. package/package.json +76 -0
@@ -0,0 +1,110 @@
1
+ 'use strict';
2
+
3
+ const { getStaticValue } = require('eslint-utils');
4
+ const utils = require('../utils');
5
+
6
+ // ------------------------------------------------------------------------------
7
+ // Rule Definition
8
+ // ------------------------------------------------------------------------------
9
+
10
+ const DEFAULT_PATTERN = new RegExp('^(enforce|require|disallow)');
11
+
12
+ /** @type {import('eslint').Rule.RuleModule} */
13
+ module.exports = {
14
+ meta: {
15
+ type: 'suggestion',
16
+ docs: {
17
+ description:
18
+ 'require rules to implement a `meta.docs.description` property with the correct format',
19
+ category: 'Rules',
20
+ recommended: false,
21
+ url: 'https://github.com/eslint-community/eslint-plugin-eslint-plugin/tree/HEAD/docs/rules/require-meta-docs-description.md',
22
+ },
23
+ fixable: null,
24
+ schema: [
25
+ {
26
+ type: 'object',
27
+ properties: {
28
+ pattern: {
29
+ type: 'string',
30
+ description:
31
+ "A regular expression that the description must match. Use `'.+'` to allow anything.",
32
+ default: '^(enforce|require|disallow)',
33
+ },
34
+ },
35
+ additionalProperties: false,
36
+ },
37
+ ],
38
+ messages: {
39
+ extraWhitespace:
40
+ '`meta.docs.description` must not have leading nor trailing whitespace.',
41
+ mismatch: '`meta.docs.description` must match the regexp {{pattern}}.',
42
+ missing: '`meta.docs.description` is required.',
43
+ wrongType: '`meta.docs.description` must be a non-empty string.',
44
+ },
45
+ },
46
+
47
+ create(context) {
48
+ const sourceCode = context.sourceCode || context.getSourceCode(); // TODO: just use context.sourceCode when dropping eslint < v9
49
+ const ruleInfo = utils.getRuleInfo(sourceCode);
50
+ if (!ruleInfo) {
51
+ return {};
52
+ }
53
+
54
+ return {
55
+ Program(ast) {
56
+ const scope = sourceCode.getScope?.(ast) || context.getScope(); // TODO: just use sourceCode.getScope() when we drop support for ESLint < v9.0.0
57
+ const { scopeManager } = sourceCode;
58
+
59
+ const pattern =
60
+ context.options[0] && context.options[0].pattern
61
+ ? new RegExp(context.options[0].pattern)
62
+ : DEFAULT_PATTERN;
63
+
64
+ const metaNode = ruleInfo.meta;
65
+ const docsNode = utils
66
+ .evaluateObjectProperties(metaNode, scopeManager)
67
+ .find((p) => p.type === 'Property' && utils.getKeyName(p) === 'docs');
68
+
69
+ const descriptionNode = utils
70
+ .evaluateObjectProperties(docsNode && docsNode.value, scopeManager)
71
+ .find(
72
+ (p) =>
73
+ p.type === 'Property' && utils.getKeyName(p) === 'description'
74
+ );
75
+
76
+ if (!descriptionNode) {
77
+ context.report({
78
+ node: docsNode || metaNode || ruleInfo.create,
79
+ messageId: 'missing',
80
+ });
81
+ return;
82
+ }
83
+
84
+ const staticValue = getStaticValue(descriptionNode.value, scope);
85
+ if (!staticValue) {
86
+ // Ignore non-static values since we can't determine what they look like.
87
+ return;
88
+ }
89
+
90
+ if (typeof staticValue.value !== 'string' || staticValue.value === '') {
91
+ context.report({
92
+ node: descriptionNode.value,
93
+ messageId: 'wrongType',
94
+ });
95
+ } else if (staticValue.value !== staticValue.value.trim()) {
96
+ context.report({
97
+ node: descriptionNode.value,
98
+ messageId: 'extraWhitespace',
99
+ });
100
+ } else if (!pattern.test(staticValue.value)) {
101
+ context.report({
102
+ node: descriptionNode.value,
103
+ messageId: 'mismatch',
104
+ data: { pattern },
105
+ });
106
+ }
107
+ },
108
+ };
109
+ },
110
+ };
@@ -0,0 +1,175 @@
1
+ /**
2
+ * @author Toru Nagashima <https://github.com/mysticatea>
3
+ */
4
+
5
+ 'use strict';
6
+
7
+ // -----------------------------------------------------------------------------
8
+ // Requirements
9
+ // -----------------------------------------------------------------------------
10
+
11
+ const path = require('path');
12
+ const util = require('../utils');
13
+ const { getStaticValue } = require('eslint-utils');
14
+
15
+ // -----------------------------------------------------------------------------
16
+ // Rule Definition
17
+ // -----------------------------------------------------------------------------
18
+
19
+ /** @type {import('eslint').Rule.RuleModule} */
20
+ module.exports = {
21
+ meta: {
22
+ type: 'suggestion',
23
+ docs: {
24
+ description: 'require rules to implement a `meta.docs.url` property',
25
+ category: 'Rules',
26
+ recommended: false,
27
+ url: 'https://github.com/eslint-community/eslint-plugin-eslint-plugin/tree/HEAD/docs/rules/require-meta-docs-url.md',
28
+ },
29
+ fixable: 'code',
30
+ schema: [
31
+ {
32
+ type: 'object',
33
+ properties: {
34
+ pattern: {
35
+ type: 'string',
36
+ description:
37
+ "A pattern to enforce rule's document URL. It replaces `{{name}}` placeholder by each rule name. The rule name is the basename of each rule file. Omitting this allows any URL.",
38
+ },
39
+ },
40
+ additionalProperties: false,
41
+ },
42
+ ],
43
+ messages: {
44
+ mismatch: '`meta.docs.url` property must be `{{expectedUrl}}`.',
45
+ missing: '`meta.docs.url` property is missing.',
46
+ wrongType: '`meta.docs.url` property must be a string.',
47
+ },
48
+ },
49
+
50
+ /**
51
+ * Creates AST event handlers for require-meta-docs-url.
52
+ * @param {RuleContext} context - The rule context.
53
+ * @returns {Object} AST event handlers.
54
+ */
55
+ create(context) {
56
+ const options = context.options[0] || {};
57
+ const filename = context.filename || context.getFilename(); // TODO: just use context.filename when dropping eslint < v9
58
+ const ruleName =
59
+ filename === '<input>'
60
+ ? undefined
61
+ : path.basename(filename, path.extname(filename));
62
+ const expectedUrl =
63
+ !options.pattern || !ruleName
64
+ ? undefined
65
+ : options.pattern.replaceAll(/{{\s*name\s*}}/g, ruleName);
66
+
67
+ /**
68
+ * Check whether a given URL is the expected URL.
69
+ * @param {string} url The URL to check.
70
+ * @returns {boolean} `true` if the node is the expected URL.
71
+ */
72
+ function isExpectedUrl(url) {
73
+ return Boolean(
74
+ typeof url === 'string' &&
75
+ (expectedUrl === undefined || url === expectedUrl)
76
+ );
77
+ }
78
+
79
+ const sourceCode = context.sourceCode || context.getSourceCode(); // TODO: just use context.sourceCode when dropping eslint < v9
80
+ const ruleInfo = util.getRuleInfo(sourceCode);
81
+ if (!ruleInfo) {
82
+ return {};
83
+ }
84
+
85
+ return {
86
+ Program(ast) {
87
+ const scope = sourceCode.getScope?.(ast) || context.getScope(); // TODO: just use sourceCode.getScope() when we drop support for ESLint < v9.0.0
88
+ const { scopeManager } = sourceCode;
89
+
90
+ const metaNode = ruleInfo.meta;
91
+ const docsPropNode = util
92
+ .evaluateObjectProperties(metaNode, scopeManager)
93
+ .find((p) => p.type === 'Property' && util.getKeyName(p) === 'docs');
94
+ const urlPropNode = util
95
+ .evaluateObjectProperties(
96
+ docsPropNode && docsPropNode.value,
97
+ scopeManager
98
+ )
99
+ .find((p) => p.type === 'Property' && util.getKeyName(p) === 'url');
100
+
101
+ const staticValue = urlPropNode
102
+ ? getStaticValue(urlPropNode.value, scope)
103
+ : undefined;
104
+ if (urlPropNode && !staticValue) {
105
+ // Ignore non-static values since we can't determine what they look like.
106
+ return;
107
+ }
108
+
109
+ if (isExpectedUrl(staticValue && staticValue.value)) {
110
+ return;
111
+ }
112
+
113
+ context.report({
114
+ node:
115
+ (urlPropNode && urlPropNode.value) ||
116
+ (docsPropNode && docsPropNode.value) ||
117
+ metaNode ||
118
+ ruleInfo.create,
119
+
120
+ // eslint-disable-next-line unicorn/no-negated-condition -- actually more clear like this
121
+ messageId: !urlPropNode
122
+ ? 'missing'
123
+ : // eslint-disable-next-line unicorn/no-nested-ternary,unicorn/no-negated-condition -- this is fine for now
124
+ !expectedUrl
125
+ ? 'wrongType'
126
+ : /* otherwise */ 'mismatch',
127
+
128
+ data: {
129
+ expectedUrl,
130
+ },
131
+
132
+ fix(fixer) {
133
+ if (!expectedUrl) {
134
+ return null;
135
+ }
136
+
137
+ const urlString = JSON.stringify(expectedUrl);
138
+ if (urlPropNode) {
139
+ if (
140
+ urlPropNode.value.type === 'Literal' ||
141
+ (urlPropNode.value.type === 'Identifier' &&
142
+ urlPropNode.value.name === 'undefined')
143
+ ) {
144
+ return fixer.replaceText(urlPropNode.value, urlString);
145
+ }
146
+ } else if (
147
+ docsPropNode &&
148
+ docsPropNode.value.type === 'ObjectExpression'
149
+ ) {
150
+ return util.insertProperty(
151
+ fixer,
152
+ docsPropNode.value,
153
+ `url: ${urlString}`,
154
+ sourceCode
155
+ );
156
+ } else if (
157
+ !docsPropNode &&
158
+ metaNode &&
159
+ metaNode.type === 'ObjectExpression'
160
+ ) {
161
+ return util.insertProperty(
162
+ fixer,
163
+ metaNode,
164
+ `docs: {\nurl: ${urlString}\n}`,
165
+ sourceCode
166
+ );
167
+ }
168
+
169
+ return null;
170
+ },
171
+ });
172
+ },
173
+ };
174
+ },
175
+ };
@@ -0,0 +1,137 @@
1
+ /**
2
+ * @fileoverview require rules to implement a `meta.fixable` property
3
+ * @author Teddy Katz
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const { getStaticValue } = require('eslint-utils');
9
+ const utils = require('../utils');
10
+
11
+ // ------------------------------------------------------------------------------
12
+ // Rule Definition
13
+ // ------------------------------------------------------------------------------
14
+
15
+ /** @type {import('eslint').Rule.RuleModule} */
16
+ module.exports = {
17
+ meta: {
18
+ type: 'problem',
19
+ docs: {
20
+ description: 'require rules to implement a `meta.fixable` property',
21
+ category: 'Rules',
22
+ recommended: true,
23
+ url: 'https://github.com/eslint-community/eslint-plugin-eslint-plugin/tree/HEAD/docs/rules/require-meta-fixable.md',
24
+ },
25
+ schema: [
26
+ {
27
+ type: 'object',
28
+ properties: {
29
+ catchNoFixerButFixableProperty: {
30
+ type: 'boolean',
31
+ default: false,
32
+ description:
33
+ "Whether the rule should attempt to detect rules that do not have a fixer but enable the `meta.fixable` property. This option is off by default because it increases the chance of false positives since fixers can't always be detected when helper functions are used.",
34
+ },
35
+ },
36
+ additionalProperties: false,
37
+ },
38
+ ],
39
+ messages: {
40
+ invalid: '`meta.fixable` must be either `code`, `whitespace`, or `null`.',
41
+ missing:
42
+ '`meta.fixable` must be either `code` or `whitespace` for fixable rules.',
43
+ noFixerButFixableValue:
44
+ '`meta.fixable` is enabled but no fixer detected.',
45
+ },
46
+ },
47
+
48
+ create(context) {
49
+ const catchNoFixerButFixableProperty =
50
+ context.options[0] && context.options[0].catchNoFixerButFixableProperty;
51
+
52
+ const sourceCode = context.sourceCode || context.getSourceCode(); // TODO: just use context.sourceCode when dropping eslint < v9
53
+ const { scopeManager } = sourceCode;
54
+ const ruleInfo = utils.getRuleInfo(sourceCode);
55
+ let contextIdentifiers;
56
+ let usesFixFunctions;
57
+
58
+ if (!ruleInfo) {
59
+ return {};
60
+ }
61
+
62
+ return {
63
+ Program(ast) {
64
+ contextIdentifiers = utils.getContextIdentifiers(scopeManager, ast);
65
+ },
66
+ CallExpression(node) {
67
+ if (
68
+ node.callee.type === 'MemberExpression' &&
69
+ contextIdentifiers.has(node.callee.object) &&
70
+ node.callee.property.type === 'Identifier' &&
71
+ node.callee.property.name === 'report' &&
72
+ (node.arguments.length > 4 ||
73
+ (node.arguments.length === 1 &&
74
+ utils
75
+ .evaluateObjectProperties(node.arguments[0], scopeManager)
76
+ .some((prop) => utils.getKeyName(prop) === 'fix')))
77
+ ) {
78
+ usesFixFunctions = true;
79
+ }
80
+ },
81
+ 'Program:exit'(ast) {
82
+ const scope = sourceCode.getScope?.(ast) || context.getScope(); // TODO: just use sourceCode.getScope() when we drop support for ESLint < v9.0.0
83
+ const metaFixableProp =
84
+ ruleInfo &&
85
+ utils
86
+ .evaluateObjectProperties(ruleInfo.meta, scopeManager)
87
+ .find((prop) => utils.getKeyName(prop) === 'fixable');
88
+
89
+ if (metaFixableProp) {
90
+ const staticValue = getStaticValue(metaFixableProp.value, scope);
91
+ if (!staticValue) {
92
+ // Ignore non-static values since we can't determine what they look like.
93
+ return;
94
+ }
95
+
96
+ if (
97
+ !['code', 'whitespace', null, undefined].includes(staticValue.value)
98
+ ) {
99
+ // `fixable` property has an invalid value.
100
+ context.report({
101
+ node: metaFixableProp.value,
102
+ messageId: 'invalid',
103
+ });
104
+ return;
105
+ }
106
+
107
+ if (
108
+ usesFixFunctions &&
109
+ !['code', 'whitespace'].includes(staticValue.value)
110
+ ) {
111
+ // Rule is fixable but `fixable` property does not have a fixable value.
112
+ context.report({
113
+ node: metaFixableProp.value,
114
+ messageId: 'missing',
115
+ });
116
+ } else if (
117
+ catchNoFixerButFixableProperty &&
118
+ !usesFixFunctions &&
119
+ ['code', 'whitespace'].includes(staticValue.value)
120
+ ) {
121
+ // Rule is NOT fixable but `fixable` property has a fixable value.
122
+ context.report({
123
+ node: metaFixableProp.value,
124
+ messageId: 'noFixerButFixableValue',
125
+ });
126
+ }
127
+ } else if (!metaFixableProp && usesFixFunctions) {
128
+ // Rule is fixable but is missing the `fixable` property.
129
+ context.report({
130
+ node: ruleInfo.meta || ruleInfo.create,
131
+ messageId: 'missing',
132
+ });
133
+ }
134
+ },
135
+ };
136
+ },
137
+ };
@@ -0,0 +1,168 @@
1
+ 'use strict';
2
+
3
+ const utils = require('../utils');
4
+ const { getStaticValue } = require('eslint-utils');
5
+
6
+ // ------------------------------------------------------------------------------
7
+ // Rule Definition
8
+ // ------------------------------------------------------------------------------
9
+
10
+ /** @type {import('eslint').Rule.RuleModule} */
11
+ module.exports = {
12
+ meta: {
13
+ type: 'problem',
14
+ docs: {
15
+ description:
16
+ 'require suggestable rules to implement a `meta.hasSuggestions` property',
17
+ category: 'Rules',
18
+ recommended: true,
19
+ url: 'https://github.com/eslint-community/eslint-plugin-eslint-plugin/tree/HEAD/docs/rules/require-meta-has-suggestions.md',
20
+ },
21
+ fixable: 'code',
22
+ schema: [],
23
+ messages: {
24
+ shouldBeSuggestable:
25
+ '`meta.hasSuggestions` must be `true` for suggestable rules.',
26
+ shouldNotBeSuggestable:
27
+ '`meta.hasSuggestions` cannot be `true` for non-suggestable rules.',
28
+ },
29
+ },
30
+
31
+ create(context) {
32
+ const sourceCode = context.sourceCode || context.getSourceCode(); // TODO: just use context.sourceCode when dropping eslint < v9
33
+ const { scopeManager } = sourceCode;
34
+ const ruleInfo = utils.getRuleInfo(sourceCode);
35
+ if (!ruleInfo) {
36
+ return {};
37
+ }
38
+ let contextIdentifiers;
39
+ let ruleReportsSuggestions;
40
+
41
+ /**
42
+ * Check if a "suggest" object property from a rule violation report should be considered to contain suggestions.
43
+ * @param {Node} node - the "suggest" object property to check
44
+ * @returns {boolean} whether this property should be considered to contain suggestions
45
+ */
46
+ function doesPropertyContainSuggestions(node) {
47
+ const scope = sourceCode.getScope?.(node) || context.getScope(); // TODO: just use sourceCode.getScope() when we drop support for ESLint < v9.0.0
48
+ const staticValue = getStaticValue(node.value, scope);
49
+ if (
50
+ !staticValue ||
51
+ (Array.isArray(staticValue.value) && staticValue.value.length > 0) ||
52
+ (Array.isArray(staticValue.value) &&
53
+ staticValue.value.length === 0 &&
54
+ node.value.type === 'Identifier') // Array variable can have suggestions pushed to it.
55
+ ) {
56
+ // These are all considered reporting suggestions:
57
+ // suggest: [{...}]
58
+ // suggest: getSuggestions()
59
+ // suggest: MY_SUGGESTIONS
60
+ return true;
61
+ }
62
+ return false;
63
+ }
64
+
65
+ return {
66
+ Program(ast) {
67
+ contextIdentifiers = utils.getContextIdentifiers(scopeManager, ast);
68
+ },
69
+ CallExpression(node) {
70
+ if (
71
+ node.callee.type === 'MemberExpression' &&
72
+ contextIdentifiers.has(node.callee.object) &&
73
+ node.callee.property.type === 'Identifier' &&
74
+ node.callee.property.name === 'report' &&
75
+ (node.arguments.length > 4 ||
76
+ (node.arguments.length === 1 &&
77
+ node.arguments[0].type === 'ObjectExpression'))
78
+ ) {
79
+ const suggestProp = utils
80
+ .evaluateObjectProperties(node.arguments[0], scopeManager)
81
+ .find((prop) => utils.getKeyName(prop) === 'suggest');
82
+ if (suggestProp && doesPropertyContainSuggestions(suggestProp)) {
83
+ ruleReportsSuggestions = true;
84
+ }
85
+ }
86
+ },
87
+ Property(node) {
88
+ // In order to reduce false positives, we will also check for a `suggest` property anywhere in the file.
89
+ // This is helpful especially in the event that helper functions are used for reporting violations.
90
+ if (
91
+ node.key.type === 'Identifier' &&
92
+ node.key.name === 'suggest' &&
93
+ doesPropertyContainSuggestions(node)
94
+ ) {
95
+ ruleReportsSuggestions = true;
96
+ }
97
+ },
98
+ 'Program:exit'(node) {
99
+ const scope = sourceCode.getScope?.(node) || context.getScope(); // TODO: just use sourceCode.getScope() when we drop support for ESLint < v9.0.0
100
+ const metaNode = ruleInfo && ruleInfo.meta;
101
+ const hasSuggestionsProperty = utils
102
+ .evaluateObjectProperties(metaNode, scopeManager)
103
+ .find((prop) => utils.getKeyName(prop) === 'hasSuggestions');
104
+ const hasSuggestionsStaticValue =
105
+ hasSuggestionsProperty &&
106
+ getStaticValue(hasSuggestionsProperty.value, scope);
107
+
108
+ if (ruleReportsSuggestions) {
109
+ if (!hasSuggestionsProperty) {
110
+ // Rule reports suggestions but is missing the `meta.hasSuggestions` property altogether.
111
+ context.report({
112
+ node: metaNode || ruleInfo.create,
113
+ messageId: 'shouldBeSuggestable',
114
+ fix(fixer) {
115
+ if (metaNode && metaNode.type === 'ObjectExpression') {
116
+ if (metaNode.properties.length === 0) {
117
+ // If object is empty, just replace entire object.
118
+ return fixer.replaceText(
119
+ metaNode,
120
+ '{ hasSuggestions: true }'
121
+ );
122
+ }
123
+ // Add new property to start of property list.
124
+ return fixer.insertTextBefore(
125
+ metaNode.properties[0],
126
+ 'hasSuggestions: true, '
127
+ );
128
+ }
129
+ },
130
+ });
131
+ } else if (
132
+ hasSuggestionsStaticValue &&
133
+ hasSuggestionsStaticValue.value !== true
134
+ ) {
135
+ // Rule reports suggestions but does not have `meta.hasSuggestions` property enabled.
136
+ context.report({
137
+ node: hasSuggestionsProperty.value,
138
+ messageId: 'shouldBeSuggestable',
139
+ fix(fixer) {
140
+ if (
141
+ hasSuggestionsProperty.value.type === 'Literal' ||
142
+ (hasSuggestionsProperty.value.type === 'Identifier' &&
143
+ hasSuggestionsProperty.value.name === 'undefined')
144
+ ) {
145
+ return fixer.replaceText(
146
+ hasSuggestionsProperty.value,
147
+ 'true'
148
+ );
149
+ }
150
+ },
151
+ });
152
+ }
153
+ } else if (
154
+ !ruleReportsSuggestions &&
155
+ hasSuggestionsProperty &&
156
+ hasSuggestionsStaticValue &&
157
+ hasSuggestionsStaticValue.value === true
158
+ ) {
159
+ // Rule does not report suggestions but has the `meta.hasSuggestions` property enabled.
160
+ context.report({
161
+ node: hasSuggestionsProperty.value,
162
+ messageId: 'shouldNotBeSuggestable',
163
+ });
164
+ }
165
+ },
166
+ };
167
+ },
168
+ };