@nkzw/eslint-plugin-fbtee 0.1.2 → 0.1.4
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/README.md +13 -3
- package/docs/rules/no-unhelpful-desc.md +1 -1
- package/docs/rules/no-unwrapped-strings.md +55 -0
- package/lib/index.cjs +184 -34
- package/lib/index.d.cts +10 -0
- package/lib/index.d.ts +10 -0
- package/lib/index.js +184 -34
- package/package.json +1 -1
- package/src/__tests__/no-empty-strings-test.tsx +144 -13
- package/src/__tests__/no-unhelpful-desc-test.tsx +20 -0
- package/src/__tests__/no-untranslated-strings-test.tsx +223 -0
- package/src/index.tsx +9 -0
- package/src/rules/no-empty-strings.tsx +44 -41
- package/src/rules/no-unhelpful-desc.tsx +3 -6
- package/src/rules/no-untranslated-strings.tsx +141 -0
- package/src/utils.tsx +50 -2
package/lib/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// package.json
|
|
2
2
|
var package_default = {
|
|
3
3
|
name: "@nkzw/eslint-plugin-fbtee",
|
|
4
|
-
version: "0.1.
|
|
4
|
+
version: "0.1.4",
|
|
5
5
|
description: "",
|
|
6
6
|
keywords: [],
|
|
7
7
|
repository: {
|
|
@@ -29,7 +29,7 @@ var package_default = {
|
|
|
29
29
|
// src/utils.tsx
|
|
30
30
|
import { ESLintUtils } from "@typescript-eslint/utils";
|
|
31
31
|
var createRule = ESLintUtils.RuleCreator(
|
|
32
|
-
(name) => `https://github.com/nkzw-tech/fbtee/
|
|
32
|
+
(name) => `https://github.com/nkzw-tech/fbtee/blob/main/packages/eslint-plugin-fbtee/docs/rules/${name}.md`
|
|
33
33
|
);
|
|
34
34
|
function resolveMemberExpressions(object, property) {
|
|
35
35
|
if (object.type === "JSXMemberExpression") {
|
|
@@ -95,13 +95,47 @@ function resolveNodeValue(node) {
|
|
|
95
95
|
}
|
|
96
96
|
return null;
|
|
97
97
|
}
|
|
98
|
+
function getPropName(prop) {
|
|
99
|
+
if (prop.name.type === "JSXNamespacedName") {
|
|
100
|
+
return `${prop.name.namespace.name}:${prop.name.name.name}`;
|
|
101
|
+
}
|
|
102
|
+
return prop.name.name;
|
|
103
|
+
}
|
|
104
|
+
function hasFbtParent(node) {
|
|
105
|
+
let current = node.parent;
|
|
106
|
+
while (current) {
|
|
107
|
+
if (isFbtNode(current)) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
current = current.parent;
|
|
111
|
+
}
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
function isFbtNode(node) {
|
|
115
|
+
if (!node) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
if (node.type === "JSXElement") {
|
|
119
|
+
const name = elementType(node);
|
|
120
|
+
return name === "fbt" || name === "fbs" || name?.startsWith("fbt:");
|
|
121
|
+
}
|
|
122
|
+
if (node.type === "CallExpression" && node.callee.type === "Identifier") {
|
|
123
|
+
const name = node.callee.name;
|
|
124
|
+
return name === "fbt" || name === "fbs";
|
|
125
|
+
}
|
|
126
|
+
if (node.type === "MemberExpression" && node.object.type === "CallExpression" && node.object.callee.type === "Identifier") {
|
|
127
|
+
const name = node.object.callee.name;
|
|
128
|
+
return name === "fbt" || name === "fbs";
|
|
129
|
+
}
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
98
132
|
|
|
99
133
|
// src/rules/no-empty-strings.tsx
|
|
100
134
|
var no_empty_strings_default = createRule({
|
|
101
135
|
create(context) {
|
|
102
136
|
return {
|
|
103
137
|
CallExpression(node) {
|
|
104
|
-
if (
|
|
138
|
+
if (!isFbtNode(node)) {
|
|
105
139
|
return;
|
|
106
140
|
}
|
|
107
141
|
const [text] = node.arguments;
|
|
@@ -113,18 +147,18 @@ var no_empty_strings_default = createRule({
|
|
|
113
147
|
}
|
|
114
148
|
},
|
|
115
149
|
JSXElement(node) {
|
|
116
|
-
if (
|
|
150
|
+
if (!isFbtNode(node)) {
|
|
117
151
|
return;
|
|
118
152
|
}
|
|
119
|
-
|
|
120
|
-
|
|
153
|
+
if (node.openingElement.name.type === "JSXNamespacedName") {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const hasTextContent = validateChildren(node);
|
|
121
157
|
if (!hasTextContent) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
});
|
|
127
|
-
}
|
|
158
|
+
context.report({
|
|
159
|
+
messageId: "jsxEmptyString",
|
|
160
|
+
node
|
|
161
|
+
});
|
|
128
162
|
}
|
|
129
163
|
}
|
|
130
164
|
};
|
|
@@ -135,43 +169,45 @@ var no_empty_strings_default = createRule({
|
|
|
135
169
|
description: "Disallow empty strings in fbt elements or function calls."
|
|
136
170
|
},
|
|
137
171
|
messages: {
|
|
138
|
-
emptyString: "Empty strings are not allowed in fbt()
|
|
139
|
-
jsxEmptyString: "Empty strings are not allowed as children of
|
|
172
|
+
emptyString: "Empty strings are not allowed in fbt() and fbs() function arguments.",
|
|
173
|
+
jsxEmptyString: "Empty strings are not allowed as children of `<fbt>` and `<fbs>` tags."
|
|
140
174
|
},
|
|
141
175
|
schema: [],
|
|
142
176
|
type: "problem"
|
|
143
177
|
},
|
|
144
178
|
name: "no-empty-strings"
|
|
145
179
|
});
|
|
146
|
-
function validateChildren(node
|
|
180
|
+
function validateChildren(node) {
|
|
147
181
|
let hasTextContent = false;
|
|
148
182
|
for (const child of node.children) {
|
|
149
|
-
if (child.type === "JSXText" &&
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
183
|
+
if (child.type === "JSXText" && child.value.trim() !== "") {
|
|
184
|
+
hasTextContent = true;
|
|
185
|
+
}
|
|
186
|
+
if (child.type === "JSXExpressionContainer") {
|
|
187
|
+
if (child.expression.type === "JSXEmptyExpression") {
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (child.expression.type === "Identifier" && child.expression.name !== "undefined") {
|
|
153
191
|
hasTextContent = true;
|
|
192
|
+
continue;
|
|
154
193
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (isEmptyString(child.expression) && (node.children.length === 1 || node.children.every(
|
|
158
|
-
(otherChild) => child === otherChild || otherChild.type === "JSXText" && otherChild.value.trim() === ""
|
|
159
|
-
))) {
|
|
160
|
-
nodesToReport.add(child.expression);
|
|
161
|
-
} else {
|
|
194
|
+
const value = resolveNodeValue(child.expression)?.trim();
|
|
195
|
+
if (value) {
|
|
162
196
|
hasTextContent = true;
|
|
163
197
|
}
|
|
164
198
|
}
|
|
165
199
|
if (child.type === "JSXElement" || child.type === "JSXFragment") {
|
|
166
|
-
|
|
200
|
+
const childName = elementType(child);
|
|
201
|
+
if (/^[A-Z]/.test(childName) || childName.startsWith("fbt:")) {
|
|
202
|
+
hasTextContent = true;
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
hasTextContent ||= validateChildren(child);
|
|
167
206
|
}
|
|
168
207
|
if (hasTextContent) {
|
|
169
208
|
break;
|
|
170
209
|
}
|
|
171
210
|
}
|
|
172
|
-
if (!hasTextContent && nodesToReport.size === 0) {
|
|
173
|
-
nodesToReport.add(node);
|
|
174
|
-
}
|
|
175
211
|
return hasTextContent;
|
|
176
212
|
}
|
|
177
213
|
function isEmptyString(node) {
|
|
@@ -183,7 +219,7 @@ var no_unhelpful_desc_default = createRule({
|
|
|
183
219
|
create(context) {
|
|
184
220
|
return {
|
|
185
221
|
CallExpression(node) {
|
|
186
|
-
if (
|
|
222
|
+
if (!isFbtNode(node)) {
|
|
187
223
|
return;
|
|
188
224
|
}
|
|
189
225
|
const [textArg, descArg] = node.arguments;
|
|
@@ -211,7 +247,7 @@ var no_unhelpful_desc_default = createRule({
|
|
|
211
247
|
}
|
|
212
248
|
},
|
|
213
249
|
JSXAttribute(node) {
|
|
214
|
-
if (
|
|
250
|
+
if (!isFbtNode(node.parent.parent)) {
|
|
215
251
|
return;
|
|
216
252
|
}
|
|
217
253
|
if (node.name.name !== "desc" || !node.value) {
|
|
@@ -262,6 +298,112 @@ var no_unhelpful_desc_default = createRule({
|
|
|
262
298
|
name: "no-unhelpful-desc"
|
|
263
299
|
});
|
|
264
300
|
|
|
301
|
+
// src/rules/no-untranslated-strings.tsx
|
|
302
|
+
var attributes = /* @__PURE__ */ new Set([
|
|
303
|
+
"title",
|
|
304
|
+
"placeholder",
|
|
305
|
+
"alt",
|
|
306
|
+
"label",
|
|
307
|
+
"aria-label",
|
|
308
|
+
"aria-errormessage"
|
|
309
|
+
]);
|
|
310
|
+
var no_untranslated_strings_default = createRule({
|
|
311
|
+
create(context, options) {
|
|
312
|
+
const ignoredWords = new Set(
|
|
313
|
+
options[0].ignoredWords.map((s) => s.trim().toLowerCase())
|
|
314
|
+
);
|
|
315
|
+
function isIgnoredWord(value) {
|
|
316
|
+
return ignoredWords.has(value.trim().toLowerCase());
|
|
317
|
+
}
|
|
318
|
+
return {
|
|
319
|
+
JSXAttribute(node) {
|
|
320
|
+
const propName = getPropName(node);
|
|
321
|
+
if (!attributes.has(propName)) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
const value = node.value ? resolveNodeValue(node.value) : null;
|
|
325
|
+
if (!value) {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
if (isIgnoredWord(value)) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
if (node.value?.type === "JSXExpressionContainer" && isFbtNode(node.value.expression)) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
context.report({
|
|
335
|
+
messageId: "unwrappedString",
|
|
336
|
+
node
|
|
337
|
+
});
|
|
338
|
+
},
|
|
339
|
+
JSXExpressionContainer(node) {
|
|
340
|
+
if (node.parent.type === "JSXAttribute") {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
const value = resolveNodeValue(node.expression);
|
|
344
|
+
if (!value) {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
if (isIgnoredWord(value)) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
if (!hasFbtParent(node)) {
|
|
351
|
+
context.report({
|
|
352
|
+
messageId: "unwrappedString",
|
|
353
|
+
node
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
JSXText(node) {
|
|
358
|
+
const value = node.value.trim();
|
|
359
|
+
if (!value) {
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
if (isIgnoredWord(value)) {
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
if (!hasFbtParent(node)) {
|
|
366
|
+
const startOffset = node.range[0] + node.value.indexOf(value);
|
|
367
|
+
const endOffset = startOffset + value.length;
|
|
368
|
+
context.report({
|
|
369
|
+
loc: {
|
|
370
|
+
end: context.sourceCode.getLocFromIndex(endOffset),
|
|
371
|
+
start: context.sourceCode.getLocFromIndex(startOffset)
|
|
372
|
+
},
|
|
373
|
+
messageId: "unwrappedString"
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
},
|
|
379
|
+
defaultOptions: [{ ignoredWords: [] }],
|
|
380
|
+
meta: {
|
|
381
|
+
docs: {
|
|
382
|
+
description: "Enforce text content to be wrapped with `<fbt>`, `fbt()` or `fbs()`"
|
|
383
|
+
},
|
|
384
|
+
messages: {
|
|
385
|
+
unwrappedString: "Text content must be wrapped in `<fbt>`, `fbt()` or `fbs()`"
|
|
386
|
+
},
|
|
387
|
+
schema: [
|
|
388
|
+
{
|
|
389
|
+
additionalProperties: false,
|
|
390
|
+
properties: {
|
|
391
|
+
ignoredWords: {
|
|
392
|
+
items: {
|
|
393
|
+
type: "string"
|
|
394
|
+
},
|
|
395
|
+
type: "array",
|
|
396
|
+
uniqueItems: true
|
|
397
|
+
}
|
|
398
|
+
},
|
|
399
|
+
type: "object"
|
|
400
|
+
}
|
|
401
|
+
],
|
|
402
|
+
type: "problem"
|
|
403
|
+
},
|
|
404
|
+
name: "no-untranslated-strings"
|
|
405
|
+
});
|
|
406
|
+
|
|
265
407
|
// src/index.tsx
|
|
266
408
|
var meta = {
|
|
267
409
|
name: package_default.name,
|
|
@@ -269,14 +411,22 @@ var meta = {
|
|
|
269
411
|
};
|
|
270
412
|
var rules = {
|
|
271
413
|
"no-empty-strings": no_empty_strings_default,
|
|
272
|
-
"no-unhelpful-desc": no_unhelpful_desc_default
|
|
414
|
+
"no-unhelpful-desc": no_unhelpful_desc_default,
|
|
415
|
+
"no-untranslated-strings": no_untranslated_strings_default
|
|
273
416
|
};
|
|
274
417
|
var configs = {
|
|
275
|
-
|
|
418
|
+
recommended: {
|
|
276
419
|
rules: {
|
|
277
420
|
"@nkzw/fbtee/no-empty-strings": 2,
|
|
278
421
|
"@nkzw/fbtee/no-unhelpful-desc": 2
|
|
279
422
|
}
|
|
423
|
+
},
|
|
424
|
+
strict: {
|
|
425
|
+
rules: {
|
|
426
|
+
"@nkzw/fbtee/no-empty-strings": 2,
|
|
427
|
+
"@nkzw/fbtee/no-unhelpful-desc": 2,
|
|
428
|
+
"@nkzw/fbtee/no-untranslated-strings": 2
|
|
429
|
+
}
|
|
280
430
|
}
|
|
281
431
|
};
|
|
282
432
|
export {
|
package/package.json
CHANGED
|
@@ -13,6 +13,7 @@ const ruleTester = new RuleTester({
|
|
|
13
13
|
|
|
14
14
|
ruleTester.run('no-empty-strings', rule, {
|
|
15
15
|
invalid: [
|
|
16
|
+
// <fbt>
|
|
16
17
|
{
|
|
17
18
|
code: `
|
|
18
19
|
<fbt desc="Greeting"></fbt>;
|
|
@@ -65,7 +66,70 @@ ruleTester.run('no-empty-strings', rule, {
|
|
|
65
66
|
`,
|
|
66
67
|
errors: [
|
|
67
68
|
{
|
|
68
|
-
line:
|
|
69
|
+
line: 2,
|
|
70
|
+
messageId: 'jsxEmptyString',
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
code: `
|
|
76
|
+
<fbt desc="Greeting">{}</fbt>;
|
|
77
|
+
`,
|
|
78
|
+
errors: [
|
|
79
|
+
{
|
|
80
|
+
line: 2,
|
|
81
|
+
messageId: 'jsxEmptyString',
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
code: `
|
|
87
|
+
<fbt desc="Greeting">
|
|
88
|
+
{}
|
|
89
|
+
</fbt>;
|
|
90
|
+
`,
|
|
91
|
+
errors: [
|
|
92
|
+
{
|
|
93
|
+
line: 2,
|
|
94
|
+
messageId: 'jsxEmptyString',
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
code: `
|
|
100
|
+
<fbt desc="Greeting">
|
|
101
|
+
{null}
|
|
102
|
+
</fbt>;
|
|
103
|
+
`,
|
|
104
|
+
errors: [
|
|
105
|
+
{
|
|
106
|
+
line: 2,
|
|
107
|
+
messageId: 'jsxEmptyString',
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
code: `
|
|
113
|
+
<fbt desc="Greeting">
|
|
114
|
+
{undefined}
|
|
115
|
+
</fbt>;
|
|
116
|
+
`,
|
|
117
|
+
errors: [
|
|
118
|
+
{
|
|
119
|
+
line: 2,
|
|
120
|
+
messageId: 'jsxEmptyString',
|
|
121
|
+
},
|
|
122
|
+
],
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
code: `
|
|
126
|
+
<fbt desc="Greeting">
|
|
127
|
+
{/* This is a comment */}
|
|
128
|
+
</fbt>;
|
|
129
|
+
`,
|
|
130
|
+
errors: [
|
|
131
|
+
{
|
|
132
|
+
line: 2,
|
|
69
133
|
messageId: 'jsxEmptyString',
|
|
70
134
|
},
|
|
71
135
|
],
|
|
@@ -78,7 +142,7 @@ ruleTester.run('no-empty-strings', rule, {
|
|
|
78
142
|
`,
|
|
79
143
|
errors: [
|
|
80
144
|
{
|
|
81
|
-
line:
|
|
145
|
+
line: 2,
|
|
82
146
|
messageId: 'jsxEmptyString',
|
|
83
147
|
},
|
|
84
148
|
],
|
|
@@ -91,11 +155,26 @@ ruleTester.run('no-empty-strings', rule, {
|
|
|
91
155
|
`,
|
|
92
156
|
errors: [
|
|
93
157
|
{
|
|
94
|
-
line:
|
|
158
|
+
line: 2,
|
|
159
|
+
messageId: 'jsxEmptyString',
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
// <fbs>
|
|
165
|
+
{
|
|
166
|
+
code: `
|
|
167
|
+
<fbs desc="Greeting"></fbs>;
|
|
168
|
+
`,
|
|
169
|
+
errors: [
|
|
170
|
+
{
|
|
171
|
+
line: 2,
|
|
95
172
|
messageId: 'jsxEmptyString',
|
|
96
173
|
},
|
|
97
174
|
],
|
|
98
175
|
},
|
|
176
|
+
|
|
177
|
+
// fbt()
|
|
99
178
|
{
|
|
100
179
|
code: `
|
|
101
180
|
fbt('', 'Greeting');
|
|
@@ -140,6 +219,8 @@ ruleTester.run('no-empty-strings', rule, {
|
|
|
140
219
|
},
|
|
141
220
|
],
|
|
142
221
|
},
|
|
222
|
+
|
|
223
|
+
// fbs()
|
|
143
224
|
{
|
|
144
225
|
code: `
|
|
145
226
|
fbs('', 'Greeting');
|
|
@@ -153,6 +234,7 @@ ruleTester.run('no-empty-strings', rule, {
|
|
|
153
234
|
},
|
|
154
235
|
],
|
|
155
236
|
valid: [
|
|
237
|
+
// <fbt>
|
|
156
238
|
{
|
|
157
239
|
code: `
|
|
158
240
|
<fbt desc="Greeting">Hello world</fbt>;
|
|
@@ -160,28 +242,24 @@ ruleTester.run('no-empty-strings', rule, {
|
|
|
160
242
|
},
|
|
161
243
|
{
|
|
162
244
|
code: `
|
|
163
|
-
<fbt desc="Greeting">
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
{
|
|
167
|
-
code: `
|
|
168
|
-
<fbt desc="Greeting">Hello {name}</fbt>;
|
|
245
|
+
<fbt desc="Greeting">
|
|
246
|
+
Hello <span>world</span>
|
|
247
|
+
</fbt>;
|
|
169
248
|
`,
|
|
170
249
|
},
|
|
171
250
|
{
|
|
172
251
|
code: `
|
|
173
|
-
<fbt desc="Greeting">{
|
|
252
|
+
<fbt desc="Greeting">{dynamicValue}</fbt>;
|
|
174
253
|
`,
|
|
175
254
|
},
|
|
176
255
|
{
|
|
177
256
|
code: `
|
|
178
|
-
fbt
|
|
257
|
+
<fbt desc="Greeting">Hello {name}</fbt>;
|
|
179
258
|
`,
|
|
180
259
|
},
|
|
181
260
|
{
|
|
182
261
|
code: `
|
|
183
|
-
|
|
184
|
-
fbt(text, 'Greeting');
|
|
262
|
+
<fbt desc="Greeting">{'Hello'}</fbt>;
|
|
185
263
|
`,
|
|
186
264
|
},
|
|
187
265
|
{
|
|
@@ -213,6 +291,59 @@ ruleTester.run('no-empty-strings', rule, {
|
|
|
213
291
|
</fbt>;
|
|
214
292
|
`,
|
|
215
293
|
},
|
|
294
|
+
{
|
|
295
|
+
code: `
|
|
296
|
+
<fbt desc="buy prompt">
|
|
297
|
+
Buy a new
|
|
298
|
+
<fbt:enum
|
|
299
|
+
enum-range={{
|
|
300
|
+
CAR: 'car',
|
|
301
|
+
HOUSE: 'house',
|
|
302
|
+
BOAT: 'boat',
|
|
303
|
+
HOUSEBOAT: 'houseboat',
|
|
304
|
+
}}
|
|
305
|
+
value={enumVal}
|
|
306
|
+
/>!
|
|
307
|
+
</fbt>;
|
|
308
|
+
`,
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
code: `
|
|
312
|
+
<fbt desc="welcome message">
|
|
313
|
+
Hello
|
|
314
|
+
<fbt:param name="name" value="Steve" />
|
|
315
|
+
</fbt>;
|
|
316
|
+
`,
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
code: `
|
|
320
|
+
<fbt desc="greeting">
|
|
321
|
+
<Component />
|
|
322
|
+
</fbt>;
|
|
323
|
+
`,
|
|
324
|
+
},
|
|
325
|
+
|
|
326
|
+
// <fbs>
|
|
327
|
+
{
|
|
328
|
+
code: `
|
|
329
|
+
<fbs desc="Greeting">Hello world</fbs>;
|
|
330
|
+
`,
|
|
331
|
+
},
|
|
332
|
+
|
|
333
|
+
// fbt()
|
|
334
|
+
{
|
|
335
|
+
code: `
|
|
336
|
+
fbt('Hello world', 'Greeting');
|
|
337
|
+
`,
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
code: `
|
|
341
|
+
const text = 'Hello';
|
|
342
|
+
fbt(text, 'Greeting');
|
|
343
|
+
`,
|
|
344
|
+
},
|
|
345
|
+
|
|
346
|
+
// other
|
|
216
347
|
{
|
|
217
348
|
code: `
|
|
218
349
|
name.replaceAll(' ', '-');
|
|
@@ -114,6 +114,19 @@ ruleTester.run('unhelpful-desc', rule, {
|
|
|
114
114
|
],
|
|
115
115
|
},
|
|
116
116
|
|
|
117
|
+
// <fbs>
|
|
118
|
+
{
|
|
119
|
+
code: `
|
|
120
|
+
<fbt desc="">Hello world</fbt>;
|
|
121
|
+
`,
|
|
122
|
+
errors: [
|
|
123
|
+
{
|
|
124
|
+
line: 2,
|
|
125
|
+
messageId: 'jsxEmptyDesc',
|
|
126
|
+
},
|
|
127
|
+
],
|
|
128
|
+
},
|
|
129
|
+
|
|
117
130
|
// fbt()
|
|
118
131
|
{
|
|
119
132
|
code: `
|
|
@@ -274,6 +287,13 @@ ruleTester.run('unhelpful-desc', rule, {
|
|
|
274
287
|
`,
|
|
275
288
|
},
|
|
276
289
|
|
|
290
|
+
// <fbs>
|
|
291
|
+
{
|
|
292
|
+
code: `
|
|
293
|
+
<fbs desc="Greeting">Hello world</fbs>;
|
|
294
|
+
`,
|
|
295
|
+
},
|
|
296
|
+
|
|
277
297
|
// fbt()
|
|
278
298
|
{
|
|
279
299
|
code: `
|