diff --git a/README.md b/README.md
index 17f4ad6..3be4cf0 100644
--- a/README.md
+++ b/README.md
@@ -250,6 +250,26 @@ switch (type) {
### Options
+### markupOnly
+
+If `markupOnly` option turn on, only JSX text and strings used as JSX attributes will be validated.
+
+JSX text:
+
+```jsx
+// incorrect
+
hello world
+{"hello world"}
+```
+
+Strings as JSX attribute:
+
+```jsx
+// incorrect
+
+
+```
+
#### ignore
The `ignore` option specifies exceptions not to check for
diff --git a/lib/rules/no-literal-string.js b/lib/rules/no-literal-string.js
index c98cd14..0218efc 100644
--- a/lib/rules/no-literal-string.js
+++ b/lib/rules/no-literal-string.js
@@ -45,6 +45,9 @@ module.exports = {
items: {
type: 'string'
}
+ },
+ markupOnly: {
+ type: 'boolean'
}
},
additionalProperties: false
@@ -152,6 +155,47 @@ module.exports = {
if (program && esTreeNodeToTSNodeMap)
typeChecker = program.getTypeChecker();
+ function validateLiteral(node) {
+ // visited and passed linting
+ if (visited.has(node)) return;
+ const trimed = node.value.trim();
+ if (!trimed) return;
+
+ const { parent } = node;
+
+ // allow statements like const a = "FOO"
+ if (isUpperCase(trimed)) return;
+
+ if (match(trimed)) return;
+
+ //
+ // TYPESCRIPT
+ //
+
+ if (typeChecker) {
+ const tsNode = esTreeNodeToTSNodeMap.get(node);
+ const typeObj = typeChecker.getTypeAtLocation(tsNode.parent);
+
+ // var a: 'abc' = 'abc'
+ if (typeObj.isStringLiteral()) {
+ return;
+ }
+
+ // var a: 'abc' | 'name' = 'abc'
+ if (typeObj.isUnion()) {
+ const found = typeObj.types.some(item => {
+ if (item.isStringLiteral() && item.value === node.value) {
+ return true;
+ }
+ });
+ if (found) return;
+ }
+ }
+ // • • • • •
+
+ context.report({ node, message });
+ }
+
const scriptVisitor = {
//
// ─── EXPORT AND IMPORT ───────────────────────────────────────────
@@ -186,6 +230,18 @@ module.exports = {
scriptVisitor.JSXText(node);
},
+ 'JSXExpressionContainer > Literal:exit'(node) {
+ if (option && option.markupOnly) {
+ validateLiteral(node);
+ }
+ },
+
+ 'JSXAttribute > Literal:exit'(node) {
+ if (option && option.markupOnly) {
+ validateLiteral(node);
+ }
+ },
+
'JSXAttribute Literal'(node) {
const parent = getNearestAncestor(node, 'JSXAttribute');
const attrName = parent.name.name;
@@ -283,44 +339,10 @@ module.exports = {
},
'Literal:exit'(node) {
- // visited and passed linting
- if (visited.has(node)) return;
- const trimed = node.value.trim();
- if (!trimed) return;
-
- const { parent } = node;
-
- // allow statements like const a = "FOO"
- if (isUpperCase(trimed)) return;
-
- if (match(trimed)) return;
-
- //
- // TYPESCRIPT
- //
-
- if (typeChecker) {
- const tsNode = esTreeNodeToTSNodeMap.get(node);
- const typeObj = typeChecker.getTypeAtLocation(tsNode.parent);
-
- // var a: 'abc' = 'abc'
- if (typeObj.isStringLiteral()) {
- return;
- }
-
- // var a: 'abc' | 'name' = 'abc'
- if (typeObj.isUnion()) {
- const found = typeObj.types.some(item => {
- if (item.isStringLiteral() && item.value === node.value) {
- return true;
- }
- });
- if (found) return;
- }
+ if (option && option.markupOnly) {
+ return;
}
- // • • • • •
-
- context.report({ node, message });
+ validateLiteral(node);
}
};
diff --git a/tests/lib/rules/no-literal-string.js b/tests/lib/rules/no-literal-string.js
index 76e9020..e96e03b 100644
--- a/tests/lib/rules/no-literal-string.js
+++ b/tests/lib/rules/no-literal-string.js
@@ -90,11 +90,23 @@ ruleTester.run('no-literal-string', rule, {
},
{ code: '' },
{ code: '' },
- { code: '', errors },
+ { code: '' },
{ code: '' },
{ code: '', options: [{ ignoreAttribute: ['foo'] }] },
{ code: 'foo' },
- { code: 'bar' }
+ { code: 'bar' },
+ { code: 'a + "b"', options: [{ markupOnly: true }] },
+ { code: '{import("abc")}
', options: [{ markupOnly: true }] },
+ {
+ code: '{[].map(item=>"abc")}
',
+ options: [{ markupOnly: true }]
+ },
+ { code: '{"hello" + "world"}
', options: [{ markupOnly: true }] },
+ { code: '', options: [{ markupOnly: true }] },
+ {
+ code: '',
+ options: [{ markupOnly: true, ignoreAttribute: ['foo'] }]
+ }
],
invalid: [
@@ -119,8 +131,16 @@ ruleTester.run('no-literal-string', rule, {
},
// JSX
{ code: 'foo
', errors },
+ { code: 'foo
', options: [{ markupOnly: true }], errors },
{ code: 'FOO
', errors },
+ {
+ code: '{"hello world"}
',
+ options: [{ markupOnly: true }],
+ errors
+ },
{ code: '', errors },
+ { code: '', options: [{ markupOnly: true }], errors },
+ { code: '', options: [{ markupOnly: true }], errors },
{ code: '', errors },
{ code: '', errors }
]