@nkzw/eslint-plugin-fbtee 0.1.3 → 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 +179 -34
- package/lib/index.d.cts +10 -0
- package/lib/index.d.ts +10 -0
- package/lib/index.js +179 -34
- package/package.json +1 -1
- package/src/__tests__/no-empty-strings-test.tsx +93 -3
- 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 +37 -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/README.md
CHANGED
|
@@ -18,13 +18,13 @@ This is a fork of Facebook's original `fbt` library, which has been archived. Th
|
|
|
18
18
|
**fbtee** requires at least Node 22, and React 19 if you are using React.
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
|
-
npm install fbtee @nkzw/babel-fbtee
|
|
21
|
+
npm install fbtee @nkzw/babel-preset-fbtee
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
In your `vite.config.ts`:
|
|
25
25
|
|
|
26
26
|
```ts
|
|
27
|
-
import fbteePreset from '@nkzw/babel-fbtee';
|
|
27
|
+
import fbteePreset from '@nkzw/babel-preset-fbtee';
|
|
28
28
|
import react from '@vitejs/plugin-react';
|
|
29
29
|
|
|
30
30
|
export default {
|
|
@@ -136,7 +136,7 @@ const Greeting = ({ name }) => (
|
|
|
136
136
|
);
|
|
137
137
|
```
|
|
138
138
|
|
|
139
|
-
_Note: `<fbt>` is auto-imported for you by the `@nkzw/babel-fbtee` plugin._
|
|
139
|
+
_Note: `<fbt>` is auto-imported for you by the `@nkzw/babel-preset-fbtee` plugin._
|
|
140
140
|
|
|
141
141
|
After marking your strings for translation with `<fbt>`, run the following commands to extract, and compile translations:
|
|
142
142
|
|
|
@@ -162,6 +162,15 @@ npm install @nkzw/eslint-plugin-fbtee
|
|
|
162
162
|
|
|
163
163
|
Add the following configuration to your ESLint configuration:
|
|
164
164
|
|
|
165
|
+
```js
|
|
166
|
+
{
|
|
167
|
+
extends: ['plugin:@nkzw/eslint-plugin-fbtee/recommended'],
|
|
168
|
+
plugins: ['@nkzw/eslint-plugin-fbtee'],
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
If you want stricter enforcement of translation rules, you can use the strict configuration, which enables the `no-untranslated-strings` rule. This ensures that all strings in your codebase are marked for translation.
|
|
173
|
+
|
|
165
174
|
```js
|
|
166
175
|
{
|
|
167
176
|
extends: ['plugin:@nkzw/eslint-plugin-fbtee/strict'],
|
|
@@ -177,6 +186,7 @@ Or, if you'd like more granular control over the rules:
|
|
|
177
186
|
rules: {
|
|
178
187
|
'@nkzw/fbtee/no-empty-strings': 'error',
|
|
179
188
|
'@nkzw/fbtee/no-unhelpful-desc': 'error',
|
|
189
|
+
'@nkzw/fbtee/no-untranslated-strings': 'error',
|
|
180
190
|
},
|
|
181
191
|
}
|
|
182
192
|
```
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Rule Details
|
|
4
4
|
|
|
5
|
-
This rule enforces that meaningful and non-empty descriptions are provided to
|
|
5
|
+
This rule enforces that meaningful and non-empty descriptions are provided to `<fbt>` elements and fbt()/fbs() function calls. Descriptions (desc) are crucial for ensuring proper translation context and avoiding ambiguous or unhelpful translations.
|
|
6
6
|
|
|
7
7
|
Examples of **incorrect** code for this rule:
|
|
8
8
|
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Enforce strings to be wrapped with `<fbt>` (fbtee/no-untranslated-strings)
|
|
2
|
+
|
|
3
|
+
## Rule Details
|
|
4
|
+
|
|
5
|
+
This rule enforces that all literal strings in your JSX are wrapped with an `<fbt>` tag, or translated using `fbt()`/`fbs()` functions, ensuring they are properly marked for translation.
|
|
6
|
+
|
|
7
|
+
Examples of **incorrect** code for this rule:
|
|
8
|
+
|
|
9
|
+
```jsx
|
|
10
|
+
<h1>Hello</h1>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```jsx
|
|
14
|
+
<h1>{`Hello`}</h1>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```jsx
|
|
18
|
+
<span title="Hello" />
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Examples of **correct** code for this rule:
|
|
22
|
+
|
|
23
|
+
```jsx
|
|
24
|
+
<h1>
|
|
25
|
+
<fbt desc="Greeting">Hello</fbt>
|
|
26
|
+
</h1>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```jsx
|
|
30
|
+
<h1>{fbt('Hello', 'Greeting')}</h1>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```jsx
|
|
34
|
+
<span title={fbs('Hello', 'Greeting')} />
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Rule Options
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
...
|
|
41
|
+
"fbt/no-untranslated-strings": [<enabled>, {"ignoredWords": Array<string>}]
|
|
42
|
+
...
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### `ignoredWords`
|
|
46
|
+
|
|
47
|
+
A list of words that are not required to be translated. Like so:
|
|
48
|
+
|
|
49
|
+
```jsx
|
|
50
|
+
"fbt/no-untranslated-strings": ["warn", { "ignoredWords": ["GitHub"] }]
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## When Not To Use It
|
|
54
|
+
|
|
55
|
+
If you do not want to enforce all strings to be marked for translation, then you can disable this rule.
|
package/lib/index.cjs
CHANGED
|
@@ -29,7 +29,7 @@ module.exports = __toCommonJS(src_exports);
|
|
|
29
29
|
// package.json
|
|
30
30
|
var package_default = {
|
|
31
31
|
name: "@nkzw/eslint-plugin-fbtee",
|
|
32
|
-
version: "0.1.
|
|
32
|
+
version: "0.1.4",
|
|
33
33
|
description: "",
|
|
34
34
|
keywords: [],
|
|
35
35
|
repository: {
|
|
@@ -57,7 +57,7 @@ var package_default = {
|
|
|
57
57
|
// src/utils.tsx
|
|
58
58
|
var import_utils = require("@typescript-eslint/utils");
|
|
59
59
|
var createRule = import_utils.ESLintUtils.RuleCreator(
|
|
60
|
-
(name) => `https://github.com/nkzw-tech/fbtee/
|
|
60
|
+
(name) => `https://github.com/nkzw-tech/fbtee/blob/main/packages/eslint-plugin-fbtee/docs/rules/${name}.md`
|
|
61
61
|
);
|
|
62
62
|
function resolveMemberExpressions(object, property) {
|
|
63
63
|
if (object.type === "JSXMemberExpression") {
|
|
@@ -123,13 +123,47 @@ function resolveNodeValue(node) {
|
|
|
123
123
|
}
|
|
124
124
|
return null;
|
|
125
125
|
}
|
|
126
|
+
function getPropName(prop) {
|
|
127
|
+
if (prop.name.type === "JSXNamespacedName") {
|
|
128
|
+
return `${prop.name.namespace.name}:${prop.name.name.name}`;
|
|
129
|
+
}
|
|
130
|
+
return prop.name.name;
|
|
131
|
+
}
|
|
132
|
+
function hasFbtParent(node) {
|
|
133
|
+
let current = node.parent;
|
|
134
|
+
while (current) {
|
|
135
|
+
if (isFbtNode(current)) {
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
current = current.parent;
|
|
139
|
+
}
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
function isFbtNode(node) {
|
|
143
|
+
if (!node) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
if (node.type === "JSXElement") {
|
|
147
|
+
const name = elementType(node);
|
|
148
|
+
return name === "fbt" || name === "fbs" || name?.startsWith("fbt:");
|
|
149
|
+
}
|
|
150
|
+
if (node.type === "CallExpression" && node.callee.type === "Identifier") {
|
|
151
|
+
const name = node.callee.name;
|
|
152
|
+
return name === "fbt" || name === "fbs";
|
|
153
|
+
}
|
|
154
|
+
if (node.type === "MemberExpression" && node.object.type === "CallExpression" && node.object.callee.type === "Identifier") {
|
|
155
|
+
const name = node.object.callee.name;
|
|
156
|
+
return name === "fbt" || name === "fbs";
|
|
157
|
+
}
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
126
160
|
|
|
127
161
|
// src/rules/no-empty-strings.tsx
|
|
128
162
|
var no_empty_strings_default = createRule({
|
|
129
163
|
create(context) {
|
|
130
164
|
return {
|
|
131
165
|
CallExpression(node) {
|
|
132
|
-
if (
|
|
166
|
+
if (!isFbtNode(node)) {
|
|
133
167
|
return;
|
|
134
168
|
}
|
|
135
169
|
const [text] = node.arguments;
|
|
@@ -141,18 +175,18 @@ var no_empty_strings_default = createRule({
|
|
|
141
175
|
}
|
|
142
176
|
},
|
|
143
177
|
JSXElement(node) {
|
|
144
|
-
if (
|
|
178
|
+
if (!isFbtNode(node)) {
|
|
145
179
|
return;
|
|
146
180
|
}
|
|
147
|
-
|
|
148
|
-
|
|
181
|
+
if (node.openingElement.name.type === "JSXNamespacedName") {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const hasTextContent = validateChildren(node);
|
|
149
185
|
if (!hasTextContent) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
});
|
|
155
|
-
}
|
|
186
|
+
context.report({
|
|
187
|
+
messageId: "jsxEmptyString",
|
|
188
|
+
node
|
|
189
|
+
});
|
|
156
190
|
}
|
|
157
191
|
}
|
|
158
192
|
};
|
|
@@ -163,30 +197,30 @@ var no_empty_strings_default = createRule({
|
|
|
163
197
|
description: "Disallow empty strings in fbt elements or function calls."
|
|
164
198
|
},
|
|
165
199
|
messages: {
|
|
166
|
-
emptyString: "Empty strings are not allowed in fbt()
|
|
167
|
-
jsxEmptyString: "Empty strings are not allowed as children of
|
|
200
|
+
emptyString: "Empty strings are not allowed in fbt() and fbs() function arguments.",
|
|
201
|
+
jsxEmptyString: "Empty strings are not allowed as children of `<fbt>` and `<fbs>` tags."
|
|
168
202
|
},
|
|
169
203
|
schema: [],
|
|
170
204
|
type: "problem"
|
|
171
205
|
},
|
|
172
206
|
name: "no-empty-strings"
|
|
173
207
|
});
|
|
174
|
-
function validateChildren(node
|
|
208
|
+
function validateChildren(node) {
|
|
175
209
|
let hasTextContent = false;
|
|
176
210
|
for (const child of node.children) {
|
|
177
|
-
if (child.type === "JSXText" &&
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
211
|
+
if (child.type === "JSXText" && child.value.trim() !== "") {
|
|
212
|
+
hasTextContent = true;
|
|
213
|
+
}
|
|
214
|
+
if (child.type === "JSXExpressionContainer") {
|
|
215
|
+
if (child.expression.type === "JSXEmptyExpression") {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
if (child.expression.type === "Identifier" && child.expression.name !== "undefined") {
|
|
181
219
|
hasTextContent = true;
|
|
220
|
+
continue;
|
|
182
221
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
if (isEmptyString(child.expression) && (node.children.length === 1 || node.children.every(
|
|
186
|
-
(otherChild) => child === otherChild || otherChild.type === "JSXText" && otherChild.value.trim() === ""
|
|
187
|
-
))) {
|
|
188
|
-
nodesToReport.add(child.expression);
|
|
189
|
-
} else {
|
|
222
|
+
const value = resolveNodeValue(child.expression)?.trim();
|
|
223
|
+
if (value) {
|
|
190
224
|
hasTextContent = true;
|
|
191
225
|
}
|
|
192
226
|
}
|
|
@@ -196,15 +230,12 @@ function validateChildren(node, nodesToReport) {
|
|
|
196
230
|
hasTextContent = true;
|
|
197
231
|
continue;
|
|
198
232
|
}
|
|
199
|
-
hasTextContent ||= validateChildren(child
|
|
233
|
+
hasTextContent ||= validateChildren(child);
|
|
200
234
|
}
|
|
201
235
|
if (hasTextContent) {
|
|
202
236
|
break;
|
|
203
237
|
}
|
|
204
238
|
}
|
|
205
|
-
if (!hasTextContent && nodesToReport.size === 0) {
|
|
206
|
-
nodesToReport.add(node);
|
|
207
|
-
}
|
|
208
239
|
return hasTextContent;
|
|
209
240
|
}
|
|
210
241
|
function isEmptyString(node) {
|
|
@@ -216,7 +247,7 @@ var no_unhelpful_desc_default = createRule({
|
|
|
216
247
|
create(context) {
|
|
217
248
|
return {
|
|
218
249
|
CallExpression(node) {
|
|
219
|
-
if (
|
|
250
|
+
if (!isFbtNode(node)) {
|
|
220
251
|
return;
|
|
221
252
|
}
|
|
222
253
|
const [textArg, descArg] = node.arguments;
|
|
@@ -244,7 +275,7 @@ var no_unhelpful_desc_default = createRule({
|
|
|
244
275
|
}
|
|
245
276
|
},
|
|
246
277
|
JSXAttribute(node) {
|
|
247
|
-
if (
|
|
278
|
+
if (!isFbtNode(node.parent.parent)) {
|
|
248
279
|
return;
|
|
249
280
|
}
|
|
250
281
|
if (node.name.name !== "desc" || !node.value) {
|
|
@@ -295,6 +326,112 @@ var no_unhelpful_desc_default = createRule({
|
|
|
295
326
|
name: "no-unhelpful-desc"
|
|
296
327
|
});
|
|
297
328
|
|
|
329
|
+
// src/rules/no-untranslated-strings.tsx
|
|
330
|
+
var attributes = /* @__PURE__ */ new Set([
|
|
331
|
+
"title",
|
|
332
|
+
"placeholder",
|
|
333
|
+
"alt",
|
|
334
|
+
"label",
|
|
335
|
+
"aria-label",
|
|
336
|
+
"aria-errormessage"
|
|
337
|
+
]);
|
|
338
|
+
var no_untranslated_strings_default = createRule({
|
|
339
|
+
create(context, options) {
|
|
340
|
+
const ignoredWords = new Set(
|
|
341
|
+
options[0].ignoredWords.map((s) => s.trim().toLowerCase())
|
|
342
|
+
);
|
|
343
|
+
function isIgnoredWord(value) {
|
|
344
|
+
return ignoredWords.has(value.trim().toLowerCase());
|
|
345
|
+
}
|
|
346
|
+
return {
|
|
347
|
+
JSXAttribute(node) {
|
|
348
|
+
const propName = getPropName(node);
|
|
349
|
+
if (!attributes.has(propName)) {
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
const value = node.value ? resolveNodeValue(node.value) : null;
|
|
353
|
+
if (!value) {
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
if (isIgnoredWord(value)) {
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
if (node.value?.type === "JSXExpressionContainer" && isFbtNode(node.value.expression)) {
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
context.report({
|
|
363
|
+
messageId: "unwrappedString",
|
|
364
|
+
node
|
|
365
|
+
});
|
|
366
|
+
},
|
|
367
|
+
JSXExpressionContainer(node) {
|
|
368
|
+
if (node.parent.type === "JSXAttribute") {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
const value = resolveNodeValue(node.expression);
|
|
372
|
+
if (!value) {
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
if (isIgnoredWord(value)) {
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
if (!hasFbtParent(node)) {
|
|
379
|
+
context.report({
|
|
380
|
+
messageId: "unwrappedString",
|
|
381
|
+
node
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
},
|
|
385
|
+
JSXText(node) {
|
|
386
|
+
const value = node.value.trim();
|
|
387
|
+
if (!value) {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
if (isIgnoredWord(value)) {
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
if (!hasFbtParent(node)) {
|
|
394
|
+
const startOffset = node.range[0] + node.value.indexOf(value);
|
|
395
|
+
const endOffset = startOffset + value.length;
|
|
396
|
+
context.report({
|
|
397
|
+
loc: {
|
|
398
|
+
end: context.sourceCode.getLocFromIndex(endOffset),
|
|
399
|
+
start: context.sourceCode.getLocFromIndex(startOffset)
|
|
400
|
+
},
|
|
401
|
+
messageId: "unwrappedString"
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
},
|
|
407
|
+
defaultOptions: [{ ignoredWords: [] }],
|
|
408
|
+
meta: {
|
|
409
|
+
docs: {
|
|
410
|
+
description: "Enforce text content to be wrapped with `<fbt>`, `fbt()` or `fbs()`"
|
|
411
|
+
},
|
|
412
|
+
messages: {
|
|
413
|
+
unwrappedString: "Text content must be wrapped in `<fbt>`, `fbt()` or `fbs()`"
|
|
414
|
+
},
|
|
415
|
+
schema: [
|
|
416
|
+
{
|
|
417
|
+
additionalProperties: false,
|
|
418
|
+
properties: {
|
|
419
|
+
ignoredWords: {
|
|
420
|
+
items: {
|
|
421
|
+
type: "string"
|
|
422
|
+
},
|
|
423
|
+
type: "array",
|
|
424
|
+
uniqueItems: true
|
|
425
|
+
}
|
|
426
|
+
},
|
|
427
|
+
type: "object"
|
|
428
|
+
}
|
|
429
|
+
],
|
|
430
|
+
type: "problem"
|
|
431
|
+
},
|
|
432
|
+
name: "no-untranslated-strings"
|
|
433
|
+
});
|
|
434
|
+
|
|
298
435
|
// src/index.tsx
|
|
299
436
|
var meta = {
|
|
300
437
|
name: package_default.name,
|
|
@@ -302,14 +439,22 @@ var meta = {
|
|
|
302
439
|
};
|
|
303
440
|
var rules = {
|
|
304
441
|
"no-empty-strings": no_empty_strings_default,
|
|
305
|
-
"no-unhelpful-desc": no_unhelpful_desc_default
|
|
442
|
+
"no-unhelpful-desc": no_unhelpful_desc_default,
|
|
443
|
+
"no-untranslated-strings": no_untranslated_strings_default
|
|
306
444
|
};
|
|
307
445
|
var configs = {
|
|
308
|
-
|
|
446
|
+
recommended: {
|
|
309
447
|
rules: {
|
|
310
448
|
"@nkzw/fbtee/no-empty-strings": 2,
|
|
311
449
|
"@nkzw/fbtee/no-unhelpful-desc": 2
|
|
312
450
|
}
|
|
451
|
+
},
|
|
452
|
+
strict: {
|
|
453
|
+
rules: {
|
|
454
|
+
"@nkzw/fbtee/no-empty-strings": 2,
|
|
455
|
+
"@nkzw/fbtee/no-unhelpful-desc": 2,
|
|
456
|
+
"@nkzw/fbtee/no-untranslated-strings": 2
|
|
457
|
+
}
|
|
313
458
|
}
|
|
314
459
|
};
|
|
315
460
|
// Annotate the CommonJS export names for ESM import in node:
|
package/lib/index.d.cts
CHANGED
|
@@ -7,12 +7,22 @@ declare const meta: {
|
|
|
7
7
|
declare const rules: {
|
|
8
8
|
'no-empty-strings': _typescript_eslint_utils_ts_eslint.RuleModule<"emptyString" | "jsxEmptyString", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
9
9
|
'no-unhelpful-desc': _typescript_eslint_utils_ts_eslint.RuleModule<"emptyDesc" | "jsxEmptyDesc" | "duplicateDesc" | "shortDesc", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
10
|
+
'no-untranslated-strings': _typescript_eslint_utils_ts_eslint.RuleModule<"unwrappedString", [{
|
|
11
|
+
ignoredWords: Array<string>;
|
|
12
|
+
}], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
10
13
|
};
|
|
11
14
|
declare const configs: {
|
|
15
|
+
recommended: {
|
|
16
|
+
rules: {
|
|
17
|
+
'@nkzw/fbtee/no-empty-strings': number;
|
|
18
|
+
'@nkzw/fbtee/no-unhelpful-desc': number;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
12
21
|
strict: {
|
|
13
22
|
rules: {
|
|
14
23
|
'@nkzw/fbtee/no-empty-strings': number;
|
|
15
24
|
'@nkzw/fbtee/no-unhelpful-desc': number;
|
|
25
|
+
'@nkzw/fbtee/no-untranslated-strings': number;
|
|
16
26
|
};
|
|
17
27
|
};
|
|
18
28
|
};
|
package/lib/index.d.ts
CHANGED
|
@@ -7,12 +7,22 @@ declare const meta: {
|
|
|
7
7
|
declare const rules: {
|
|
8
8
|
'no-empty-strings': _typescript_eslint_utils_ts_eslint.RuleModule<"emptyString" | "jsxEmptyString", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
9
9
|
'no-unhelpful-desc': _typescript_eslint_utils_ts_eslint.RuleModule<"emptyDesc" | "jsxEmptyDesc" | "duplicateDesc" | "shortDesc", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
10
|
+
'no-untranslated-strings': _typescript_eslint_utils_ts_eslint.RuleModule<"unwrappedString", [{
|
|
11
|
+
ignoredWords: Array<string>;
|
|
12
|
+
}], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
10
13
|
};
|
|
11
14
|
declare const configs: {
|
|
15
|
+
recommended: {
|
|
16
|
+
rules: {
|
|
17
|
+
'@nkzw/fbtee/no-empty-strings': number;
|
|
18
|
+
'@nkzw/fbtee/no-unhelpful-desc': number;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
12
21
|
strict: {
|
|
13
22
|
rules: {
|
|
14
23
|
'@nkzw/fbtee/no-empty-strings': number;
|
|
15
24
|
'@nkzw/fbtee/no-unhelpful-desc': number;
|
|
25
|
+
'@nkzw/fbtee/no-untranslated-strings': number;
|
|
16
26
|
};
|
|
17
27
|
};
|
|
18
28
|
};
|