From 7ebf98bdc2cd6e2fb1e92a9e1d5645c69366a7d2 Mon Sep 17 00:00:00 2001 From: edvardchen Date: Mon, 20 Jul 2020 00:26:29 +0800 Subject: [PATCH] feat: add onlyAttribute option fix #25 --- lib/helper.js | 13 ++++++++++ lib/rules/no-literal-string.js | 37 +++++++++++++++++++--------- tests/lib/rules/no-literal-string.js | 5 +++- 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/lib/helper.js b/lib/helper.js index 397b19d..0221dd3 100644 --- a/lib/helper.js +++ b/lib/helper.js @@ -21,5 +21,18 @@ function isAllowedDOMAttr(tag, attr) { return false; } +function generateFullMatchRegExp(source) { + if (source instanceof RegExp) { + return source; + } + if (typeof source !== 'string') { + console.error('generateFullMatchRegExp: expect string but get', source); + return new RegExp(); + } + // allow dot ahead + return new RegExp(`(^|\\.)${source}${source.endsWith('$') ? '' : '$'}`); +} + exports.isUpperCase = isUpperCase; exports.isAllowedDOMAttr = isAllowedDOMAttr; +exports.generateFullMatchRegExp = generateFullMatchRegExp; diff --git a/lib/rules/no-literal-string.js b/lib/rules/no-literal-string.js index bfd02b8..6987697 100644 --- a/lib/rules/no-literal-string.js +++ b/lib/rules/no-literal-string.js @@ -4,7 +4,12 @@ */ 'use strict'; -const { isUpperCase, isAllowedDOMAttr } = require('../helper'); +const { + isUpperCase, + generateFullMatchRegExp, + isAllowedDOMAttr +} = require('../helper'); +const { createOptimisticUniqueName } = require('typescript'); // const { TypeFlags, SyntaxKind } = require('typescript'); //------------------------------------------------------------------------------ @@ -50,6 +55,12 @@ module.exports = { }, markupOnly: { type: 'boolean' + }, + onlyAttribute: { + type: 'array', + items: { + type: 'string' + } } }, additionalProperties: false @@ -100,13 +111,7 @@ module.exports = { const validCalleeList = [ ...popularCallee, ...((option && option.ignoreCallee) || []) - ].map(item => { - if (item instanceof RegExp) { - return item; - } - // allow dot ahead - return new RegExp(`(^|\\.)${item}${item.endsWith('$') ? '' : '$'}`); - }); + ].map(generateFullMatchRegExp); function isValidFunctionCall({ callee }) { let calleeName = callee.name; @@ -137,6 +142,10 @@ module.exports = { ...ignoredAttributes ]; function isValidAttrName(name) { + if (option && option.onlyAttribute) { + // only validate those attributes in onlyAttribute option + return !option.onlyAttribute.includes(name); + } return userJSXAttrs.includes(name); } @@ -231,6 +240,9 @@ module.exports = { context.report({ node, message }); } + // onlyAttribute would turn on markOnly + const markupOnly = option && (option.markupOnly || !!option.onlyAttribute); + const scriptVisitor = { // // ─── EXPORT AND IMPORT ─────────────────────────────────────────── @@ -266,13 +278,16 @@ module.exports = { }, 'JSXExpressionContainer > Literal:exit'(node) { - if (option && option.markupOnly) { + if (markupOnly) { validateLiteral(node); } }, 'JSXAttribute > Literal:exit'(node) { - if (option && option.markupOnly) { + if (markupOnly) { + const { + name: { name: attrName } + } = getNearestAncestor(node, 'JSXAttribute'); validateLiteral(node); } }, @@ -374,7 +389,7 @@ module.exports = { }, 'Literal:exit'(node) { - if (option && option.markupOnly) { + if (markupOnly) { return; } validateLiteral(node); diff --git a/tests/lib/rules/no-literal-string.js b/tests/lib/rules/no-literal-string.js index 36af5bd..eb7f482 100644 --- a/tests/lib/rules/no-literal-string.js +++ b/tests/lib/rules/no-literal-string.js @@ -116,7 +116,10 @@ ruleTester.run('no-literal-string', rule, { { code: '
', options: [{ markupOnly: true, ignoreAttribute: ['foo'] }] - } + }, + // when onlyAttribute was configured, the markOnly would be treated as true + { code: 'const a = "foo";', options: [{ onlyAttribute: ['bar'] }] }, + { code: '
', options: [{ onlyAttribute: ['bar'] }] } ], invalid: [