@nkzw/eslint-plugin-fbtee 0.1.4 → 0.2.1
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 +109 -11
- package/lib/index.cjs +40 -35
- package/lib/index.d.cts +25 -23
- package/lib/index.d.ts +25 -23
- package/lib/index.js +37 -26
- package/package.json +4 -3
- package/src/__tests__/no-untranslated-strings-test.tsx +57 -1
- package/src/index.tsx +22 -22
- package/src/utils.tsx +14 -0
package/README.md
CHANGED
|
@@ -18,7 +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
|
|
21
|
+
npm install fbtee
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
In addition to `fbtee`, you need to install the Babel preset and React plugin for Vite:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install -D @nkzw/babel-preset-fbtee @vitejs/plugin-react
|
|
22
28
|
```
|
|
23
29
|
|
|
24
30
|
In your `vite.config.ts`:
|
|
@@ -43,20 +49,26 @@ export default {
|
|
|
43
49
|
```json
|
|
44
50
|
{
|
|
45
51
|
"scripts": {
|
|
46
|
-
"fbtee:collect": "fbtee collect --manifest < .src_manifest.json > .source_strings.json",
|
|
47
52
|
"fbtee:manifest": "fbtee manifest --src src",
|
|
53
|
+
"fbtee:collect": "fbtee collect --manifest < .src_manifest.json > .source_strings.json",
|
|
48
54
|
"fbtee:translate": "fbtee translate --translations translations/*.json --jenkins > src/translations.json"
|
|
49
55
|
}
|
|
50
56
|
}
|
|
51
57
|
```
|
|
52
58
|
|
|
53
|
-
|
|
59
|
+
Here is what each command does:
|
|
60
|
+
|
|
61
|
+
- `fbtee manifest --src src` searches through files in the `src` directory and generates a manifest file (`.src_manifest.json`) that lists all the files translatable strings marked with `<fbt>`. In addition it creates `.enum_manifest.json` which lists all the files containing `<fbt:enum>` tags. Since these files are auto-generated, we recommend adding them to your `.gitignore`.
|
|
62
|
+
- `fbtee collect --manifest < .src_manifest.json > .source_strings.json` reads the manifest file and extracts all the strings marked for translation into a `.source_strings.json` file. This file should be uploaded to your translation provider as the source for your translations.
|
|
63
|
+
- `fbtee translate --translations translations/*.json --jenkins > src/translations.json` reads all the translations in the `translations/` directory and compiles them into a single `src/translations.json` file. This file is used by **fbtee** to display translated content in your app. The `--translations` parameter specifies the path to the translation files. The `--jenkins` flag is used to define the utilized [hash function](https://en.wikipedia.org/wiki/Jenkins_hash_function). You can adjust the `--translations` parameter to point to your translation directory. If your translations are within your app directory in a folder called `i18n`, for example, you'd use `--translations app/i18n/*.json`. The output is the translation file used by **fbtee**. This file is going to be referred to in your applications entry point, therefor it needs to be generated as part of the build, but should not be part of version control. This command requires the translations to be present in the `translations/` directory, created based on real translations of what was previously collected using the `collect` command.
|
|
64
|
+
|
|
65
|
+
Now, the first step is to run these commands to set up the initial strings for translation:
|
|
54
66
|
|
|
55
67
|
```bash
|
|
56
|
-
npm run fbtee:manifest && npm run fbtee:collect
|
|
68
|
+
npm run fbtee:manifest && npm run fbtee:collect
|
|
57
69
|
```
|
|
58
70
|
|
|
59
|
-
The files generated by these commands
|
|
71
|
+
The files generated by these commands should be added to `.gitignore`:
|
|
60
72
|
|
|
61
73
|
```
|
|
62
74
|
.src_manifest.json
|
|
@@ -82,13 +94,13 @@ setupFbtee({
|
|
|
82
94
|
});
|
|
83
95
|
```
|
|
84
96
|
|
|
85
|
-
|
|
97
|
+
Next up, if you are using React and TypeScript in your project, you need to add TypeScript types for **fbtee** to enable proper type checking in JSX. You can do this by referencing the `ReactTypes.d.ts` file in your main `index.tsx` file or a global type declaration file (e.g., `types.d.ts`):
|
|
86
98
|
|
|
87
99
|
```tsx
|
|
88
100
|
/// <reference types="fbtee/ReactTypes.d.ts" />
|
|
89
101
|
```
|
|
90
102
|
|
|
91
|
-
_You’re now ready to
|
|
103
|
+
_You’re now ready to define your first translatable element!_
|
|
92
104
|
|
|
93
105
|
## Usage
|
|
94
106
|
|
|
@@ -141,16 +153,102 @@ _Note: `<fbt>` is auto-imported for you by the `@nkzw/babel-preset-fbtee` plugin
|
|
|
141
153
|
After marking your strings for translation with `<fbt>`, run the following commands to extract, and compile translations:
|
|
142
154
|
|
|
143
155
|
```bash
|
|
144
|
-
npm run fbtee:collect
|
|
156
|
+
npm run fbtee:manifest && npm run fbtee:collect
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
You can now upload the `.source_strings.json` file to your translation provider. One sample for such a translation provider is [Crowdin](https://crowdin.com/).
|
|
160
|
+
|
|
161
|
+
### Generated File Structure
|
|
162
|
+
|
|
163
|
+
Your `.source_strings.json` might look like this:
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"childParentMappings": {},
|
|
168
|
+
"phrases": [
|
|
169
|
+
{
|
|
170
|
+
"hashToLeaf": {
|
|
171
|
+
"MB6OYuvCF1VzjOmqinI42g==": {
|
|
172
|
+
"desc": "What's next question",
|
|
173
|
+
"text": "What's next?"
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
"col_beg": 12,
|
|
177
|
+
"col_end": 68,
|
|
178
|
+
"filepath": "app/welcome/welcome.tsx",
|
|
179
|
+
"line_beg": 43,
|
|
180
|
+
"line_end": 43,
|
|
181
|
+
"project": "",
|
|
182
|
+
"jsfbt": {
|
|
183
|
+
"m": [],
|
|
184
|
+
"t": {
|
|
185
|
+
"desc": "What's next question",
|
|
186
|
+
"text": "What's next?"
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
]
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Based on the above source string, the US English translation (ie. `translations/en_US.json`) might look like this:
|
|
195
|
+
|
|
196
|
+
```json
|
|
197
|
+
{
|
|
198
|
+
"fb-locale": "en_US",
|
|
199
|
+
"translations": {
|
|
200
|
+
"MB6OYuvCF1VzjOmqinI42g==": {
|
|
201
|
+
"tokens": [],
|
|
202
|
+
"types": [],
|
|
203
|
+
"translations": [
|
|
204
|
+
{
|
|
205
|
+
"translation": "What's next?",
|
|
206
|
+
"variations": []
|
|
207
|
+
}
|
|
208
|
+
]
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
145
212
|
```
|
|
146
213
|
|
|
147
|
-
|
|
214
|
+
And German (`translations/de_DE.json`) might look like this:
|
|
215
|
+
|
|
216
|
+
```json
|
|
217
|
+
{
|
|
218
|
+
"fb-locale": "de_DE",
|
|
219
|
+
"translations": {
|
|
220
|
+
"MB6OYuvCF1VzjOmqinI42g==": {
|
|
221
|
+
"tokens": [],
|
|
222
|
+
"types": [],
|
|
223
|
+
"translations": [
|
|
224
|
+
{
|
|
225
|
+
"translation": "Was kommt jetzt?",
|
|
226
|
+
"variations": []
|
|
227
|
+
}
|
|
228
|
+
]
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Once you have the translated strings stored in a `translations/` folder as JSON files, you can run the following command to generate the translations file:
|
|
148
235
|
|
|
149
236
|
```bash
|
|
150
237
|
npm run fbtee:translate
|
|
151
238
|
```
|
|
152
239
|
|
|
153
|
-
|
|
240
|
+
This will generate the `translation.json` file referred to in the setup done before. This file might look like this:
|
|
241
|
+
|
|
242
|
+
```json
|
|
243
|
+
{
|
|
244
|
+
"de_DE": { "2HVYhv": "Was kommt jetzt?" },
|
|
245
|
+
"en_US": { "2HVYhv": "What's next?" }
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
After generating the translations file, your app is ready to display translated content in other languages. The error you had until now in the `setupFbtee` with regards to the imported translations file should be resolved now.
|
|
250
|
+
|
|
251
|
+
Since the `translations.json` is an auto-generated file part of your build process, the `fbtee:translate` command should be added to your build step.
|
|
154
252
|
|
|
155
253
|
## ESLint Plugin
|
|
156
254
|
|
|
@@ -200,7 +298,7 @@ The open-source version of `fbt`, however, became unmaintained, difficult to set
|
|
|
200
298
|
- **Easier Setup:** fbtee works with modern tools like Vite.
|
|
201
299
|
- **Statically Typed:** The fbtee compiler ensures correct usage of fbtee, libary TypeScript types are provided, and an eslint plugin helps fix common mistakes.
|
|
202
300
|
- **Improved React Compatibility:** Removed React-specific hacks and added support for implicit React fragments (`<>`).
|
|
203
|
-
- **Enhanced Features:** Fixed and exported `
|
|
301
|
+
- **Enhanced Features:** Fixed and exported `inltList` as a new `<fbt:list>` construt, which was not functional in the original `fbt`.
|
|
204
302
|
- **Modernized Codebase:** Rewritten using TypeScript, ES modules (ESM), eslint, and modern JavaScript standards. Removed cruft and legacy code.
|
|
205
303
|
- **Updated Tooling:** Uses modern tools like pnpm, Vite, and esbuild for faster and more efficient development of **fbtee**.
|
|
206
304
|
|
package/lib/index.cjs
CHANGED
|
@@ -18,18 +18,16 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
|
|
20
20
|
// src/index.tsx
|
|
21
|
-
var
|
|
22
|
-
__export(
|
|
23
|
-
|
|
24
|
-
meta: () => meta,
|
|
25
|
-
rules: () => rules
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
default: () => index_default
|
|
26
24
|
});
|
|
27
|
-
module.exports = __toCommonJS(
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
28
26
|
|
|
29
27
|
// package.json
|
|
30
28
|
var package_default = {
|
|
31
29
|
name: "@nkzw/eslint-plugin-fbtee",
|
|
32
|
-
version: "0.1
|
|
30
|
+
version: "0.2.1",
|
|
33
31
|
description: "",
|
|
34
32
|
keywords: [],
|
|
35
33
|
repository: {
|
|
@@ -43,14 +41,15 @@ var package_default = {
|
|
|
43
41
|
import: "./lib/index.js",
|
|
44
42
|
require: "./lib/index.cjs"
|
|
45
43
|
},
|
|
44
|
+
main: "lib/index.cjs",
|
|
46
45
|
scripts: {
|
|
47
46
|
build: "tsup src/index.tsx -d lib --target=node22 --format=esm,cjs --clean --no-splitting --dts"
|
|
48
47
|
},
|
|
49
48
|
dependencies: {
|
|
50
|
-
"@typescript-eslint/utils": "^8.
|
|
49
|
+
"@typescript-eslint/utils": "^8.19.1"
|
|
51
50
|
},
|
|
52
51
|
devDependencies: {
|
|
53
|
-
"@typescript-eslint/rule-tester": "^8.
|
|
52
|
+
"@typescript-eslint/rule-tester": "^8.19.1"
|
|
54
53
|
}
|
|
55
54
|
};
|
|
56
55
|
|
|
@@ -121,6 +120,16 @@ function resolveNodeValue(node) {
|
|
|
121
120
|
if (node.type === "JSXExpressionContainer") {
|
|
122
121
|
return resolveNodeValue(node.expression);
|
|
123
122
|
}
|
|
123
|
+
if (node.type === "ConditionalExpression") {
|
|
124
|
+
const consequent = resolveNodeValue(node.consequent);
|
|
125
|
+
const alternate = resolveNodeValue(node.alternate);
|
|
126
|
+
return consequent || alternate || null;
|
|
127
|
+
}
|
|
128
|
+
if (node.type === "LogicalExpression") {
|
|
129
|
+
const left = resolveNodeValue(node.left);
|
|
130
|
+
const right = resolveNodeValue(node.right);
|
|
131
|
+
return left || right || null;
|
|
132
|
+
}
|
|
124
133
|
return null;
|
|
125
134
|
}
|
|
126
135
|
function getPropName(prop) {
|
|
@@ -433,33 +442,29 @@ var no_untranslated_strings_default = createRule({
|
|
|
433
442
|
});
|
|
434
443
|
|
|
435
444
|
// src/index.tsx
|
|
436
|
-
var
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
445
|
+
var index_default = {
|
|
446
|
+
configs: {
|
|
447
|
+
recommended: {
|
|
448
|
+
rules: {
|
|
449
|
+
"@nkzw/fbtee/no-empty-strings": 2,
|
|
450
|
+
"@nkzw/fbtee/no-unhelpful-desc": 2
|
|
451
|
+
}
|
|
452
|
+
},
|
|
453
|
+
strict: {
|
|
454
|
+
rules: {
|
|
455
|
+
"@nkzw/fbtee/no-empty-strings": 2,
|
|
456
|
+
"@nkzw/fbtee/no-unhelpful-desc": 2,
|
|
457
|
+
"@nkzw/fbtee/no-untranslated-strings": 2
|
|
458
|
+
}
|
|
450
459
|
}
|
|
451
460
|
},
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
461
|
+
meta: {
|
|
462
|
+
name: package_default.name,
|
|
463
|
+
version: package_default.version
|
|
464
|
+
},
|
|
465
|
+
rules: {
|
|
466
|
+
"no-empty-strings": no_empty_strings_default,
|
|
467
|
+
"no-unhelpful-desc": no_unhelpful_desc_default,
|
|
468
|
+
"no-untranslated-strings": no_untranslated_strings_default
|
|
458
469
|
}
|
|
459
470
|
};
|
|
460
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
461
|
-
0 && (module.exports = {
|
|
462
|
-
configs,
|
|
463
|
-
meta,
|
|
464
|
-
rules
|
|
465
|
-
});
|
package/lib/index.d.cts
CHANGED
|
@@ -1,30 +1,32 @@
|
|
|
1
1
|
import * as _typescript_eslint_utils_ts_eslint from '@typescript-eslint/utils/ts-eslint';
|
|
2
2
|
|
|
3
|
-
declare const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
'no-untranslated-strings': _typescript_eslint_utils_ts_eslint.RuleModule<"unwrappedString", [{
|
|
11
|
-
ignoredWords: Array<string>;
|
|
12
|
-
}], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
13
|
-
};
|
|
14
|
-
declare const configs: {
|
|
15
|
-
recommended: {
|
|
16
|
-
rules: {
|
|
17
|
-
'@nkzw/fbtee/no-empty-strings': number;
|
|
18
|
-
'@nkzw/fbtee/no-unhelpful-desc': number;
|
|
3
|
+
declare const _default: {
|
|
4
|
+
configs: {
|
|
5
|
+
recommended: {
|
|
6
|
+
rules: {
|
|
7
|
+
'@nkzw/fbtee/no-empty-strings': number;
|
|
8
|
+
'@nkzw/fbtee/no-unhelpful-desc': number;
|
|
9
|
+
};
|
|
19
10
|
};
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
11
|
+
strict: {
|
|
12
|
+
rules: {
|
|
13
|
+
'@nkzw/fbtee/no-empty-strings': number;
|
|
14
|
+
'@nkzw/fbtee/no-unhelpful-desc': number;
|
|
15
|
+
'@nkzw/fbtee/no-untranslated-strings': number;
|
|
16
|
+
};
|
|
26
17
|
};
|
|
27
18
|
};
|
|
19
|
+
meta: {
|
|
20
|
+
name: string;
|
|
21
|
+
version: string;
|
|
22
|
+
};
|
|
23
|
+
rules: {
|
|
24
|
+
'no-empty-strings': _typescript_eslint_utils_ts_eslint.RuleModule<"emptyString" | "jsxEmptyString", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
25
|
+
'no-unhelpful-desc': _typescript_eslint_utils_ts_eslint.RuleModule<"emptyDesc" | "jsxEmptyDesc" | "duplicateDesc" | "shortDesc", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
26
|
+
'no-untranslated-strings': _typescript_eslint_utils_ts_eslint.RuleModule<"unwrappedString", [{
|
|
27
|
+
ignoredWords: Array<string>;
|
|
28
|
+
}], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
29
|
+
};
|
|
28
30
|
};
|
|
29
31
|
|
|
30
|
-
export {
|
|
32
|
+
export { _default as default };
|
package/lib/index.d.ts
CHANGED
|
@@ -1,30 +1,32 @@
|
|
|
1
1
|
import * as _typescript_eslint_utils_ts_eslint from '@typescript-eslint/utils/ts-eslint';
|
|
2
2
|
|
|
3
|
-
declare const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
'no-untranslated-strings': _typescript_eslint_utils_ts_eslint.RuleModule<"unwrappedString", [{
|
|
11
|
-
ignoredWords: Array<string>;
|
|
12
|
-
}], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
13
|
-
};
|
|
14
|
-
declare const configs: {
|
|
15
|
-
recommended: {
|
|
16
|
-
rules: {
|
|
17
|
-
'@nkzw/fbtee/no-empty-strings': number;
|
|
18
|
-
'@nkzw/fbtee/no-unhelpful-desc': number;
|
|
3
|
+
declare const _default: {
|
|
4
|
+
configs: {
|
|
5
|
+
recommended: {
|
|
6
|
+
rules: {
|
|
7
|
+
'@nkzw/fbtee/no-empty-strings': number;
|
|
8
|
+
'@nkzw/fbtee/no-unhelpful-desc': number;
|
|
9
|
+
};
|
|
19
10
|
};
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
11
|
+
strict: {
|
|
12
|
+
rules: {
|
|
13
|
+
'@nkzw/fbtee/no-empty-strings': number;
|
|
14
|
+
'@nkzw/fbtee/no-unhelpful-desc': number;
|
|
15
|
+
'@nkzw/fbtee/no-untranslated-strings': number;
|
|
16
|
+
};
|
|
26
17
|
};
|
|
27
18
|
};
|
|
19
|
+
meta: {
|
|
20
|
+
name: string;
|
|
21
|
+
version: string;
|
|
22
|
+
};
|
|
23
|
+
rules: {
|
|
24
|
+
'no-empty-strings': _typescript_eslint_utils_ts_eslint.RuleModule<"emptyString" | "jsxEmptyString", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
25
|
+
'no-unhelpful-desc': _typescript_eslint_utils_ts_eslint.RuleModule<"emptyDesc" | "jsxEmptyDesc" | "duplicateDesc" | "shortDesc", [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
26
|
+
'no-untranslated-strings': _typescript_eslint_utils_ts_eslint.RuleModule<"unwrappedString", [{
|
|
27
|
+
ignoredWords: Array<string>;
|
|
28
|
+
}], unknown, _typescript_eslint_utils_ts_eslint.RuleListener>;
|
|
29
|
+
};
|
|
28
30
|
};
|
|
29
31
|
|
|
30
|
-
export {
|
|
32
|
+
export { _default as default };
|
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.2.1",
|
|
5
5
|
description: "",
|
|
6
6
|
keywords: [],
|
|
7
7
|
repository: {
|
|
@@ -15,14 +15,15 @@ var package_default = {
|
|
|
15
15
|
import: "./lib/index.js",
|
|
16
16
|
require: "./lib/index.cjs"
|
|
17
17
|
},
|
|
18
|
+
main: "lib/index.cjs",
|
|
18
19
|
scripts: {
|
|
19
20
|
build: "tsup src/index.tsx -d lib --target=node22 --format=esm,cjs --clean --no-splitting --dts"
|
|
20
21
|
},
|
|
21
22
|
dependencies: {
|
|
22
|
-
"@typescript-eslint/utils": "^8.
|
|
23
|
+
"@typescript-eslint/utils": "^8.19.1"
|
|
23
24
|
},
|
|
24
25
|
devDependencies: {
|
|
25
|
-
"@typescript-eslint/rule-tester": "^8.
|
|
26
|
+
"@typescript-eslint/rule-tester": "^8.19.1"
|
|
26
27
|
}
|
|
27
28
|
};
|
|
28
29
|
|
|
@@ -93,6 +94,16 @@ function resolveNodeValue(node) {
|
|
|
93
94
|
if (node.type === "JSXExpressionContainer") {
|
|
94
95
|
return resolveNodeValue(node.expression);
|
|
95
96
|
}
|
|
97
|
+
if (node.type === "ConditionalExpression") {
|
|
98
|
+
const consequent = resolveNodeValue(node.consequent);
|
|
99
|
+
const alternate = resolveNodeValue(node.alternate);
|
|
100
|
+
return consequent || alternate || null;
|
|
101
|
+
}
|
|
102
|
+
if (node.type === "LogicalExpression") {
|
|
103
|
+
const left = resolveNodeValue(node.left);
|
|
104
|
+
const right = resolveNodeValue(node.right);
|
|
105
|
+
return left || right || null;
|
|
106
|
+
}
|
|
96
107
|
return null;
|
|
97
108
|
}
|
|
98
109
|
function getPropName(prop) {
|
|
@@ -405,32 +416,32 @@ var no_untranslated_strings_default = createRule({
|
|
|
405
416
|
});
|
|
406
417
|
|
|
407
418
|
// src/index.tsx
|
|
408
|
-
var
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
419
|
+
var index_default = {
|
|
420
|
+
configs: {
|
|
421
|
+
recommended: {
|
|
422
|
+
rules: {
|
|
423
|
+
"@nkzw/fbtee/no-empty-strings": 2,
|
|
424
|
+
"@nkzw/fbtee/no-unhelpful-desc": 2
|
|
425
|
+
}
|
|
426
|
+
},
|
|
427
|
+
strict: {
|
|
428
|
+
rules: {
|
|
429
|
+
"@nkzw/fbtee/no-empty-strings": 2,
|
|
430
|
+
"@nkzw/fbtee/no-unhelpful-desc": 2,
|
|
431
|
+
"@nkzw/fbtee/no-untranslated-strings": 2
|
|
432
|
+
}
|
|
422
433
|
}
|
|
423
434
|
},
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
435
|
+
meta: {
|
|
436
|
+
name: package_default.name,
|
|
437
|
+
version: package_default.version
|
|
438
|
+
},
|
|
439
|
+
rules: {
|
|
440
|
+
"no-empty-strings": no_empty_strings_default,
|
|
441
|
+
"no-unhelpful-desc": no_unhelpful_desc_default,
|
|
442
|
+
"no-untranslated-strings": no_untranslated_strings_default
|
|
430
443
|
}
|
|
431
444
|
};
|
|
432
445
|
export {
|
|
433
|
-
|
|
434
|
-
meta,
|
|
435
|
-
rules
|
|
446
|
+
index_default as default
|
|
436
447
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nkzw/eslint-plugin-fbtee",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"repository": {
|
|
@@ -14,11 +14,12 @@
|
|
|
14
14
|
"import": "./lib/index.js",
|
|
15
15
|
"require": "./lib/index.cjs"
|
|
16
16
|
},
|
|
17
|
+
"main": "lib/index.cjs",
|
|
17
18
|
"dependencies": {
|
|
18
|
-
"@typescript-eslint/utils": "^8.
|
|
19
|
+
"@typescript-eslint/utils": "^8.19.1"
|
|
19
20
|
},
|
|
20
21
|
"devDependencies": {
|
|
21
|
-
"@typescript-eslint/rule-tester": "^8.
|
|
22
|
+
"@typescript-eslint/rule-tester": "^8.19.1"
|
|
22
23
|
},
|
|
23
24
|
"scripts": {
|
|
24
25
|
"build": "tsup src/index.tsx -d lib --target=node22 --format=esm,cjs --clean --no-splitting --dts"
|
|
@@ -72,7 +72,48 @@ ruleTester.run('no-untranslated-strings', rule, {
|
|
|
72
72
|
},
|
|
73
73
|
{
|
|
74
74
|
code: `
|
|
75
|
-
<>Hello world
|
|
75
|
+
<>Hello world</>;
|
|
76
|
+
`,
|
|
77
|
+
errors: [
|
|
78
|
+
{
|
|
79
|
+
messageId: 'unwrappedString',
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
code: `
|
|
85
|
+
<span>{foo ? 'bar' : 'baz'}</span>;
|
|
86
|
+
`,
|
|
87
|
+
errors: [
|
|
88
|
+
{
|
|
89
|
+
messageId: 'unwrappedString',
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
code: `
|
|
95
|
+
<span>{foo ?? 'bar'}</span>;
|
|
96
|
+
`,
|
|
97
|
+
errors: [
|
|
98
|
+
{
|
|
99
|
+
messageId: 'unwrappedString',
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
code: `
|
|
105
|
+
<span>{foo || 'bar'}</span>;
|
|
106
|
+
`,
|
|
107
|
+
errors: [
|
|
108
|
+
{
|
|
109
|
+
messageId: 'unwrappedString',
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
code: `
|
|
115
|
+
const foo = true;
|
|
116
|
+
<span>{foo && 'bar'}</span>;
|
|
76
117
|
`,
|
|
77
118
|
errors: [
|
|
78
119
|
{
|
|
@@ -219,5 +260,20 @@ ruleTester.run('no-untranslated-strings', rule, {
|
|
|
219
260
|
foo.bar('Baz')
|
|
220
261
|
`,
|
|
221
262
|
},
|
|
263
|
+
{
|
|
264
|
+
code: `
|
|
265
|
+
const foo = isGreeting ? 'Hello' : 'Goodbye'
|
|
266
|
+
`,
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
code: `
|
|
270
|
+
const foo = helloGreeting ?? 'goodbye'
|
|
271
|
+
`,
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
code: `
|
|
275
|
+
const foo = helloGreeting || 'goodbye'
|
|
276
|
+
`,
|
|
277
|
+
},
|
|
222
278
|
],
|
|
223
279
|
});
|
package/src/index.tsx
CHANGED
|
@@ -3,29 +3,29 @@ import noEmptyStringsRule from './rules/no-empty-strings.tsx';
|
|
|
3
3
|
import noUnhelpfulDesc from './rules/no-unhelpful-desc.tsx';
|
|
4
4
|
import noUntranslatedStrings from './rules/no-untranslated-strings.tsx';
|
|
5
5
|
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
'no-unhelpful-desc': noUnhelpfulDesc,
|
|
14
|
-
'no-untranslated-strings': noUntranslatedStrings,
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export const configs = {
|
|
18
|
-
recommended: {
|
|
19
|
-
rules: {
|
|
20
|
-
'@nkzw/fbtee/no-empty-strings': 2,
|
|
21
|
-
'@nkzw/fbtee/no-unhelpful-desc': 2,
|
|
6
|
+
export default {
|
|
7
|
+
configs: {
|
|
8
|
+
recommended: {
|
|
9
|
+
rules: {
|
|
10
|
+
'@nkzw/fbtee/no-empty-strings': 2,
|
|
11
|
+
'@nkzw/fbtee/no-unhelpful-desc': 2,
|
|
12
|
+
},
|
|
22
13
|
},
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
14
|
+
strict: {
|
|
15
|
+
rules: {
|
|
16
|
+
'@nkzw/fbtee/no-empty-strings': 2,
|
|
17
|
+
'@nkzw/fbtee/no-unhelpful-desc': 2,
|
|
18
|
+
'@nkzw/fbtee/no-untranslated-strings': 2,
|
|
19
|
+
},
|
|
29
20
|
},
|
|
30
21
|
},
|
|
22
|
+
meta: {
|
|
23
|
+
name: packageJson.name,
|
|
24
|
+
version: packageJson.version,
|
|
25
|
+
},
|
|
26
|
+
rules: {
|
|
27
|
+
'no-empty-strings': noEmptyStringsRule,
|
|
28
|
+
'no-unhelpful-desc': noUnhelpfulDesc,
|
|
29
|
+
'no-untranslated-strings': noUntranslatedStrings,
|
|
30
|
+
},
|
|
31
31
|
};
|
package/src/utils.tsx
CHANGED
|
@@ -105,6 +105,20 @@ export function resolveNodeValue(
|
|
|
105
105
|
return resolveNodeValue(node.expression);
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
if (node.type === 'ConditionalExpression') {
|
|
109
|
+
const consequent = resolveNodeValue(node.consequent);
|
|
110
|
+
const alternate = resolveNodeValue(node.alternate);
|
|
111
|
+
|
|
112
|
+
return consequent || alternate || null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (node.type === 'LogicalExpression') {
|
|
116
|
+
const left = resolveNodeValue(node.left);
|
|
117
|
+
const right = resolveNodeValue(node.right);
|
|
118
|
+
|
|
119
|
+
return left || right || null;
|
|
120
|
+
}
|
|
121
|
+
|
|
108
122
|
return null;
|
|
109
123
|
}
|
|
110
124
|
|