eslint-plugin-formatjs 5.2.14 → 5.3.0
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/index.js +3 -0
- package/lib_esnext/index.js +3 -0
- package/lib_esnext/package.json +18 -23
- package/lib_esnext/rules/no-literal-string-in-object.d.ts +9 -0
- package/lib_esnext/rules/no-literal-string-in-object.js +90 -0
- package/package.json +20 -25
- package/rules/no-literal-string-in-object.d.ts +9 -0
- package/rules/no-literal-string-in-object.js +93 -0
package/index.js
CHANGED
|
@@ -19,6 +19,7 @@ const no_offset_1 = require("./rules/no-offset");
|
|
|
19
19
|
const no_useless_message_1 = require("./rules/no-useless-message");
|
|
20
20
|
const prefer_formatted_message_1 = require("./rules/prefer-formatted-message");
|
|
21
21
|
const prefer_pound_in_plural_1 = require("./rules/prefer-pound-in-plural");
|
|
22
|
+
const no_literal_string_in_object_1 = require("./rules/no-literal-string-in-object");
|
|
22
23
|
const package_json_1 = require("./package.json");
|
|
23
24
|
// All rules
|
|
24
25
|
const rules = {
|
|
@@ -60,6 +61,8 @@ const rules = {
|
|
|
60
61
|
[prefer_pound_in_plural_1.name]: prefer_pound_in_plural_1.rule,
|
|
61
62
|
// @ts-expect-error
|
|
62
63
|
[no_missing_icu_plural_one_placeholders_1.name]: no_missing_icu_plural_one_placeholders_1.rule,
|
|
64
|
+
// @ts-expect-error
|
|
65
|
+
[no_literal_string_in_object_1.name]: no_literal_string_in_object_1.rule,
|
|
63
66
|
};
|
|
64
67
|
// Base plugin
|
|
65
68
|
const plugin = {
|
package/lib_esnext/index.js
CHANGED
|
@@ -17,6 +17,7 @@ import { rule as noOffset, name as noOffsetName } from './rules/no-offset';
|
|
|
17
17
|
import { rule as noUselessMessage, name as noUselessMessageName, } from './rules/no-useless-message';
|
|
18
18
|
import { rule as preferFormattedMessage, name as preferFormattedMessageName, } from './rules/prefer-formatted-message';
|
|
19
19
|
import { rule as preferPoundInPlural, name as preferPoundInPluralName, } from './rules/prefer-pound-in-plural';
|
|
20
|
+
import { rule as noLiteralStringInObject, name as noLiteralStringInObjectName, } from './rules/no-literal-string-in-object';
|
|
20
21
|
import { name, version } from './package.json';
|
|
21
22
|
// All rules
|
|
22
23
|
const rules = {
|
|
@@ -58,6 +59,8 @@ const rules = {
|
|
|
58
59
|
[preferPoundInPluralName]: preferPoundInPlural,
|
|
59
60
|
// @ts-expect-error
|
|
60
61
|
[noMissingIcuPluralOnePlaceholdersName]: noMissingIcuPluralOnePlaceholders,
|
|
62
|
+
// @ts-expect-error
|
|
63
|
+
[noLiteralStringInObjectName]: noLiteralStringInObject,
|
|
61
64
|
};
|
|
62
65
|
// Base plugin
|
|
63
66
|
const plugin = {
|
package/lib_esnext/package.json
CHANGED
|
@@ -1,36 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-formatjs",
|
|
3
|
-
"version": "5.2.14",
|
|
4
3
|
"description": "ESLint plugin for formatjs",
|
|
5
|
-
"
|
|
6
|
-
"repository": {
|
|
7
|
-
"type": "git",
|
|
8
|
-
"url": "git+ssh://git@github.com/formatjs/formatjs.git"
|
|
9
|
-
},
|
|
10
|
-
"keywords": [
|
|
11
|
-
"eslint",
|
|
12
|
-
"eslintplugin",
|
|
13
|
-
"i18n",
|
|
14
|
-
"formatjs"
|
|
15
|
-
],
|
|
16
|
-
"author": "Long Ho <holevietlong@gmail.com>",
|
|
4
|
+
"version": "5.3.0",
|
|
17
5
|
"license": "MIT",
|
|
18
|
-
"
|
|
19
|
-
"url": "https://github.com/formatjs/formatjs/issues"
|
|
20
|
-
},
|
|
21
|
-
"homepage": "https://github.com/formatjs/formatjs#readme",
|
|
6
|
+
"author": "Long Ho <holevietlong@gmail.com>",
|
|
22
7
|
"dependencies": {
|
|
23
8
|
"@formatjs/icu-messageformat-parser": "workspace:*",
|
|
24
9
|
"@formatjs/ts-transformer": "workspace:*",
|
|
25
|
-
"@types/eslint": "9",
|
|
26
|
-
"@types/picomatch": "3",
|
|
27
|
-
"@typescript-eslint/utils": "8.
|
|
10
|
+
"@types/eslint": "^9.6.1",
|
|
11
|
+
"@types/picomatch": "^3",
|
|
12
|
+
"@typescript-eslint/utils": "^8.27.0",
|
|
28
13
|
"magic-string": "^0.30.0",
|
|
29
14
|
"picomatch": "2 || 3 || 4",
|
|
30
|
-
"tslib": "2",
|
|
15
|
+
"tslib": "^2.8.0",
|
|
31
16
|
"unicode-emoji-utils": "^1.2.0"
|
|
32
17
|
},
|
|
33
18
|
"peerDependencies": {
|
|
34
|
-
"eslint": "9"
|
|
35
|
-
}
|
|
19
|
+
"eslint": "^9.23.0"
|
|
20
|
+
},
|
|
21
|
+
"bugs": "https://github.com/formatjs/formatjs/issues",
|
|
22
|
+
"homepage": "https://github.com/formatjs/formatjs#readme",
|
|
23
|
+
"keywords": [
|
|
24
|
+
"eslint",
|
|
25
|
+
"eslintplugin",
|
|
26
|
+
"formatjs",
|
|
27
|
+
"i18n"
|
|
28
|
+
],
|
|
29
|
+
"main": "index.js",
|
|
30
|
+
"repository": "formatjs/formatjs.git"
|
|
36
31
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { RuleModule } from '@typescript-eslint/utils/ts-eslint';
|
|
2
|
+
type MessageIds = 'untranslatedProperty';
|
|
3
|
+
type PropertyConfig = {
|
|
4
|
+
include: string[];
|
|
5
|
+
};
|
|
6
|
+
type Options = [PropertyConfig?];
|
|
7
|
+
export declare const name = "no-literal-string-in-object";
|
|
8
|
+
export declare const rule: RuleModule<MessageIds, Options>;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
import { getParserServices } from '../context-compat';
|
|
3
|
+
export const name = 'no-literal-string-in-object';
|
|
4
|
+
export const rule = {
|
|
5
|
+
meta: {
|
|
6
|
+
type: 'problem',
|
|
7
|
+
docs: {
|
|
8
|
+
description: 'Enforce translation of specific object properties',
|
|
9
|
+
url: 'https://formatjs.github.io/docs/tooling/linter#no-literal-string-in-object',
|
|
10
|
+
},
|
|
11
|
+
schema: [
|
|
12
|
+
{
|
|
13
|
+
type: 'object',
|
|
14
|
+
properties: {
|
|
15
|
+
include: {
|
|
16
|
+
type: 'array',
|
|
17
|
+
items: { type: 'string' },
|
|
18
|
+
default: ['label'],
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
additionalProperties: false,
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
messages: {
|
|
25
|
+
untranslatedProperty: 'Object property: `{{propertyKey}}` might contain an untranslated literal string',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
defaultOptions: [],
|
|
29
|
+
create(context) {
|
|
30
|
+
const propertyVisitor = (node) => {
|
|
31
|
+
checkProperty(context, node);
|
|
32
|
+
};
|
|
33
|
+
const parserServices = getParserServices(context);
|
|
34
|
+
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser
|
|
35
|
+
if (parserServices?.defineTemplateBodyVisitor) {
|
|
36
|
+
//@ts-expect-error
|
|
37
|
+
return parserServices.defineTemplateBodyVisitor({
|
|
38
|
+
Property: propertyVisitor,
|
|
39
|
+
}, {
|
|
40
|
+
Property: propertyVisitor,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
Property: propertyVisitor,
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
function checkProperty(context, node) {
|
|
49
|
+
const config = {
|
|
50
|
+
include: ['label'],
|
|
51
|
+
...(context.options[0] || {}),
|
|
52
|
+
};
|
|
53
|
+
const propertyKey = node.key.type === TSESTree.AST_NODE_TYPES.Identifier
|
|
54
|
+
? node.key.name
|
|
55
|
+
: node.key.type === TSESTree.AST_NODE_TYPES.Literal &&
|
|
56
|
+
typeof node.key.value === 'string'
|
|
57
|
+
? node.key.value
|
|
58
|
+
: null;
|
|
59
|
+
if (!propertyKey || !config.include.includes(propertyKey)) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
checkPropertyValue(context, node.value, propertyKey);
|
|
63
|
+
}
|
|
64
|
+
function checkPropertyValue(context, node, propertyKey) {
|
|
65
|
+
if ((node.type === 'Literal' &&
|
|
66
|
+
typeof node.value === 'string' &&
|
|
67
|
+
node.value.length > 0) ||
|
|
68
|
+
(node.type === 'TemplateLiteral' &&
|
|
69
|
+
(node.quasis.length > 1 || node.quasis[0].value.raw.length > 0))) {
|
|
70
|
+
context.report({
|
|
71
|
+
node: node,
|
|
72
|
+
messageId: 'untranslatedProperty',
|
|
73
|
+
data: {
|
|
74
|
+
propertyKey: propertyKey,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
else if (node.type === 'BinaryExpression' && node.operator === '+') {
|
|
79
|
+
checkPropertyValue(context, node.left, propertyKey);
|
|
80
|
+
checkPropertyValue(context, node.right, propertyKey);
|
|
81
|
+
}
|
|
82
|
+
else if (node.type === 'ConditionalExpression') {
|
|
83
|
+
checkPropertyValue(context, node.consequent, propertyKey);
|
|
84
|
+
checkPropertyValue(context, node.alternate, propertyKey);
|
|
85
|
+
}
|
|
86
|
+
else if (node.type === 'LogicalExpression') {
|
|
87
|
+
checkPropertyValue(context, node.left, propertyKey);
|
|
88
|
+
checkPropertyValue(context, node.right, propertyKey);
|
|
89
|
+
}
|
|
90
|
+
}
|
package/package.json
CHANGED
|
@@ -1,36 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-formatjs",
|
|
3
|
-
"version": "5.2.14",
|
|
4
3
|
"description": "ESLint plugin for formatjs",
|
|
5
|
-
"
|
|
6
|
-
"repository": {
|
|
7
|
-
"type": "git",
|
|
8
|
-
"url": "git+ssh://git@github.com/formatjs/formatjs.git"
|
|
9
|
-
},
|
|
10
|
-
"keywords": [
|
|
11
|
-
"eslint",
|
|
12
|
-
"eslintplugin",
|
|
13
|
-
"i18n",
|
|
14
|
-
"formatjs"
|
|
15
|
-
],
|
|
16
|
-
"author": "Long Ho <holevietlong@gmail.com>",
|
|
4
|
+
"version": "5.3.0",
|
|
17
5
|
"license": "MIT",
|
|
18
|
-
"
|
|
19
|
-
"url": "https://github.com/formatjs/formatjs/issues"
|
|
20
|
-
},
|
|
21
|
-
"homepage": "https://github.com/formatjs/formatjs#readme",
|
|
6
|
+
"author": "Long Ho <holevietlong@gmail.com>",
|
|
22
7
|
"dependencies": {
|
|
23
|
-
"@types/eslint": "9",
|
|
24
|
-
"@types/picomatch": "3",
|
|
25
|
-
"@typescript-eslint/utils": "8.
|
|
8
|
+
"@types/eslint": "^9.6.1",
|
|
9
|
+
"@types/picomatch": "^3",
|
|
10
|
+
"@typescript-eslint/utils": "^8.27.0",
|
|
26
11
|
"magic-string": "^0.30.0",
|
|
27
12
|
"picomatch": "2 || 3 || 4",
|
|
28
|
-
"tslib": "2",
|
|
13
|
+
"tslib": "^2.8.0",
|
|
29
14
|
"unicode-emoji-utils": "^1.2.0",
|
|
30
|
-
"@formatjs/icu-messageformat-parser": "2.11.
|
|
31
|
-
"@formatjs/ts-transformer": "3.13.
|
|
15
|
+
"@formatjs/icu-messageformat-parser": "2.11.2",
|
|
16
|
+
"@formatjs/ts-transformer": "3.13.33"
|
|
32
17
|
},
|
|
33
18
|
"peerDependencies": {
|
|
34
|
-
"eslint": "9"
|
|
35
|
-
}
|
|
19
|
+
"eslint": "^9.23.0"
|
|
20
|
+
},
|
|
21
|
+
"bugs": "https://github.com/formatjs/formatjs/issues",
|
|
22
|
+
"homepage": "https://github.com/formatjs/formatjs#readme",
|
|
23
|
+
"keywords": [
|
|
24
|
+
"eslint",
|
|
25
|
+
"eslintplugin",
|
|
26
|
+
"formatjs",
|
|
27
|
+
"i18n"
|
|
28
|
+
],
|
|
29
|
+
"main": "index.js",
|
|
30
|
+
"repository": "formatjs/formatjs.git"
|
|
36
31
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { RuleModule } from '@typescript-eslint/utils/ts-eslint';
|
|
2
|
+
type MessageIds = 'untranslatedProperty';
|
|
3
|
+
type PropertyConfig = {
|
|
4
|
+
include: string[];
|
|
5
|
+
};
|
|
6
|
+
type Options = [PropertyConfig?];
|
|
7
|
+
export declare const name = "no-literal-string-in-object";
|
|
8
|
+
export declare const rule: RuleModule<MessageIds, Options>;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rule = exports.name = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
const context_compat_1 = require("../context-compat");
|
|
6
|
+
exports.name = 'no-literal-string-in-object';
|
|
7
|
+
exports.rule = {
|
|
8
|
+
meta: {
|
|
9
|
+
type: 'problem',
|
|
10
|
+
docs: {
|
|
11
|
+
description: 'Enforce translation of specific object properties',
|
|
12
|
+
url: 'https://formatjs.github.io/docs/tooling/linter#no-literal-string-in-object',
|
|
13
|
+
},
|
|
14
|
+
schema: [
|
|
15
|
+
{
|
|
16
|
+
type: 'object',
|
|
17
|
+
properties: {
|
|
18
|
+
include: {
|
|
19
|
+
type: 'array',
|
|
20
|
+
items: { type: 'string' },
|
|
21
|
+
default: ['label'],
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
additionalProperties: false,
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
messages: {
|
|
28
|
+
untranslatedProperty: 'Object property: `{{propertyKey}}` might contain an untranslated literal string',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
defaultOptions: [],
|
|
32
|
+
create(context) {
|
|
33
|
+
const propertyVisitor = (node) => {
|
|
34
|
+
checkProperty(context, node);
|
|
35
|
+
};
|
|
36
|
+
const parserServices = (0, context_compat_1.getParserServices)(context);
|
|
37
|
+
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser
|
|
38
|
+
if (parserServices?.defineTemplateBodyVisitor) {
|
|
39
|
+
//@ts-expect-error
|
|
40
|
+
return parserServices.defineTemplateBodyVisitor({
|
|
41
|
+
Property: propertyVisitor,
|
|
42
|
+
}, {
|
|
43
|
+
Property: propertyVisitor,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
Property: propertyVisitor,
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
function checkProperty(context, node) {
|
|
52
|
+
const config = {
|
|
53
|
+
include: ['label'],
|
|
54
|
+
...(context.options[0] || {}),
|
|
55
|
+
};
|
|
56
|
+
const propertyKey = node.key.type === utils_1.TSESTree.AST_NODE_TYPES.Identifier
|
|
57
|
+
? node.key.name
|
|
58
|
+
: node.key.type === utils_1.TSESTree.AST_NODE_TYPES.Literal &&
|
|
59
|
+
typeof node.key.value === 'string'
|
|
60
|
+
? node.key.value
|
|
61
|
+
: null;
|
|
62
|
+
if (!propertyKey || !config.include.includes(propertyKey)) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
checkPropertyValue(context, node.value, propertyKey);
|
|
66
|
+
}
|
|
67
|
+
function checkPropertyValue(context, node, propertyKey) {
|
|
68
|
+
if ((node.type === 'Literal' &&
|
|
69
|
+
typeof node.value === 'string' &&
|
|
70
|
+
node.value.length > 0) ||
|
|
71
|
+
(node.type === 'TemplateLiteral' &&
|
|
72
|
+
(node.quasis.length > 1 || node.quasis[0].value.raw.length > 0))) {
|
|
73
|
+
context.report({
|
|
74
|
+
node: node,
|
|
75
|
+
messageId: 'untranslatedProperty',
|
|
76
|
+
data: {
|
|
77
|
+
propertyKey: propertyKey,
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
else if (node.type === 'BinaryExpression' && node.operator === '+') {
|
|
82
|
+
checkPropertyValue(context, node.left, propertyKey);
|
|
83
|
+
checkPropertyValue(context, node.right, propertyKey);
|
|
84
|
+
}
|
|
85
|
+
else if (node.type === 'ConditionalExpression') {
|
|
86
|
+
checkPropertyValue(context, node.consequent, propertyKey);
|
|
87
|
+
checkPropertyValue(context, node.alternate, propertyKey);
|
|
88
|
+
}
|
|
89
|
+
else if (node.type === 'LogicalExpression') {
|
|
90
|
+
checkPropertyValue(context, node.left, propertyKey);
|
|
91
|
+
checkPropertyValue(context, node.right, propertyKey);
|
|
92
|
+
}
|
|
93
|
+
}
|