eslint-plugin-formatjs 5.4.2 → 6.0.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/context-compat.js +1 -5
- package/index.d.ts +15 -1
- package/index.js +46 -45
- package/package.json +12 -10
- package/rules/blocklist-elements.d.ts +1 -2
- package/rules/blocklist-elements.js +23 -26
- package/rules/enforce-default-message.js +8 -11
- package/rules/enforce-description.js +8 -11
- package/rules/enforce-id.d.ts +1 -0
- package/rules/enforce-id.js +21 -14
- package/rules/enforce-placeholders.js +14 -17
- package/rules/enforce-plural-rules.js +10 -13
- package/rules/no-camel-case.js +11 -14
- package/rules/no-complex-selectors.js +13 -16
- package/rules/no-emoji.js +11 -14
- package/rules/no-id.js +6 -9
- package/rules/no-invalid-icu.js +9 -12
- package/rules/no-literal-string-in-jsx.js +33 -13
- package/rules/no-literal-string-in-object.js +8 -11
- package/rules/no-missing-icu-plural-one-placeholders.js +15 -19
- package/rules/no-multiple-plurals.js +10 -13
- package/rules/no-multiple-whitespaces.js +27 -32
- package/rules/no-offset.js +10 -13
- package/rules/no-useless-message.js +13 -16
- package/rules/prefer-formatted-message.js +4 -7
- package/rules/prefer-pound-in-plural.js +25 -29
- package/util.js +5 -12
- package/lib_esnext/context-compat.d.ts +0 -3
- package/lib_esnext/context-compat.js +0 -6
- package/lib_esnext/index.d.ts +0 -1
- package/lib_esnext/index.js +0 -146
- package/lib_esnext/package.json +0 -31
- package/lib_esnext/rules/blocklist-elements.d.ts +0 -15
- package/lib_esnext/rules/blocklist-elements.js +0 -132
- package/lib_esnext/rules/enforce-default-message.d.ts +0 -10
- package/lib_esnext/rules/enforce-default-message.js +0 -68
- package/lib_esnext/rules/enforce-description.d.ts +0 -10
- package/lib_esnext/rules/enforce-description.js +0 -66
- package/lib_esnext/rules/enforce-id.d.ts +0 -10
- package/lib_esnext/rules/enforce-id.js +0 -153
- package/lib_esnext/rules/enforce-placeholders.d.ts +0 -8
- package/lib_esnext/rules/enforce-placeholders.js +0 -147
- package/lib_esnext/rules/enforce-plural-rules.d.ts +0 -17
- package/lib_esnext/rules/enforce-plural-rules.js +0 -103
- package/lib_esnext/rules/no-camel-case.d.ts +0 -5
- package/lib_esnext/rules/no-camel-case.js +0 -76
- package/lib_esnext/rules/no-complex-selectors.d.ts +0 -9
- package/lib_esnext/rules/no-complex-selectors.js +0 -136
- package/lib_esnext/rules/no-emoji.d.ts +0 -9
- package/lib_esnext/rules/no-emoji.js +0 -99
- package/lib_esnext/rules/no-id.d.ts +0 -5
- package/lib_esnext/rules/no-id.js +0 -58
- package/lib_esnext/rules/no-invalid-icu.d.ts +0 -5
- package/lib_esnext/rules/no-invalid-icu.js +0 -60
- package/lib_esnext/rules/no-literal-string-in-jsx.d.ts +0 -13
- package/lib_esnext/rules/no-literal-string-in-jsx.js +0 -179
- package/lib_esnext/rules/no-literal-string-in-object.d.ts +0 -9
- package/lib_esnext/rules/no-literal-string-in-object.js +0 -90
- package/lib_esnext/rules/no-missing-icu-plural-one-placeholders.d.ts +0 -6
- package/lib_esnext/rules/no-missing-icu-plural-one-placeholders.js +0 -99
- package/lib_esnext/rules/no-multiple-plurals.d.ts +0 -5
- package/lib_esnext/rules/no-multiple-plurals.js +0 -70
- package/lib_esnext/rules/no-multiple-whitespaces.d.ts +0 -5
- package/lib_esnext/rules/no-multiple-whitespaces.js +0 -141
- package/lib_esnext/rules/no-offset.d.ts +0 -5
- package/lib_esnext/rules/no-offset.js +0 -69
- package/lib_esnext/rules/no-useless-message.d.ts +0 -5
- package/lib_esnext/rules/no-useless-message.js +0 -71
- package/lib_esnext/rules/prefer-formatted-message.d.ts +0 -5
- package/lib_esnext/rules/prefer-formatted-message.js +0 -33
- package/lib_esnext/rules/prefer-pound-in-plural.d.ts +0 -5
- package/lib_esnext/rules/prefer-pound-in-plural.js +0 -191
- package/lib_esnext/util.d.ts +0 -32
- package/lib_esnext/util.js +0 -280
|
@@ -1,26 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser");
|
|
5
|
-
const context_compat_1 = require("../context-compat");
|
|
6
|
-
const util_1 = require("../util");
|
|
1
|
+
import { parse, TYPE, } from '@formatjs/icu-messageformat-parser';
|
|
2
|
+
import { getParserServices } from '../context-compat.js';
|
|
3
|
+
import { extractMessages, getSettings, patchMessage } from '../util.js';
|
|
7
4
|
function isAstValid(ast) {
|
|
8
5
|
for (const element of ast) {
|
|
9
6
|
switch (element.type) {
|
|
10
|
-
case
|
|
7
|
+
case TYPE.literal:
|
|
11
8
|
if (/\s{2,}/gm.test(element.value)) {
|
|
12
9
|
return false;
|
|
13
10
|
}
|
|
14
11
|
break;
|
|
15
|
-
case
|
|
16
|
-
case
|
|
17
|
-
case
|
|
18
|
-
case
|
|
19
|
-
case
|
|
20
|
-
case icu_messageformat_parser_1.TYPE.time:
|
|
12
|
+
case TYPE.argument:
|
|
13
|
+
case TYPE.date:
|
|
14
|
+
case TYPE.number:
|
|
15
|
+
case TYPE.pound:
|
|
16
|
+
case TYPE.time:
|
|
21
17
|
break;
|
|
22
|
-
case
|
|
23
|
-
case
|
|
18
|
+
case TYPE.plural:
|
|
19
|
+
case TYPE.select: {
|
|
24
20
|
for (const option of Object.values(element.options)) {
|
|
25
21
|
if (!isAstValid(option.value)) {
|
|
26
22
|
return false;
|
|
@@ -28,7 +24,7 @@ function isAstValid(ast) {
|
|
|
28
24
|
}
|
|
29
25
|
break;
|
|
30
26
|
}
|
|
31
|
-
case
|
|
27
|
+
case TYPE.tag:
|
|
32
28
|
return isAstValid(element.children);
|
|
33
29
|
}
|
|
34
30
|
}
|
|
@@ -39,24 +35,23 @@ function trimMultiWhitespaces(message, ast) {
|
|
|
39
35
|
const collectLiteralElements = (elements) => {
|
|
40
36
|
for (const element of elements) {
|
|
41
37
|
switch (element.type) {
|
|
42
|
-
case
|
|
38
|
+
case TYPE.literal:
|
|
43
39
|
literalElements.push(element);
|
|
44
40
|
break;
|
|
45
|
-
case
|
|
46
|
-
case
|
|
47
|
-
case
|
|
48
|
-
case
|
|
49
|
-
case
|
|
50
|
-
case icu_messageformat_parser_1.TYPE.time:
|
|
41
|
+
case TYPE.argument:
|
|
42
|
+
case TYPE.date:
|
|
43
|
+
case TYPE.number:
|
|
44
|
+
case TYPE.pound:
|
|
45
|
+
case TYPE.time:
|
|
51
46
|
break;
|
|
52
|
-
case
|
|
53
|
-
case
|
|
47
|
+
case TYPE.plural:
|
|
48
|
+
case TYPE.select: {
|
|
54
49
|
for (const option of Object.values(element.options)) {
|
|
55
50
|
collectLiteralElements(option.value);
|
|
56
51
|
}
|
|
57
52
|
break;
|
|
58
53
|
}
|
|
59
|
-
case
|
|
54
|
+
case TYPE.tag:
|
|
60
55
|
collectLiteralElements(element.children);
|
|
61
56
|
break;
|
|
62
57
|
}
|
|
@@ -79,14 +74,14 @@ function trimMultiWhitespaces(message, ast) {
|
|
|
79
74
|
return trimmedFragments.join('');
|
|
80
75
|
}
|
|
81
76
|
function checkNode(context, node) {
|
|
82
|
-
const msgs =
|
|
77
|
+
const msgs = extractMessages(node, getSettings(context));
|
|
83
78
|
for (const [{ message: { defaultMessage }, messageNode, },] of msgs) {
|
|
84
79
|
if (!defaultMessage || !messageNode) {
|
|
85
80
|
continue;
|
|
86
81
|
}
|
|
87
82
|
let ast;
|
|
88
83
|
try {
|
|
89
|
-
ast =
|
|
84
|
+
ast = parse(defaultMessage, { captureLocation: true });
|
|
90
85
|
}
|
|
91
86
|
catch (e) {
|
|
92
87
|
context.report({
|
|
@@ -97,7 +92,7 @@ function checkNode(context, node) {
|
|
|
97
92
|
return;
|
|
98
93
|
}
|
|
99
94
|
if (!isAstValid(ast)) {
|
|
100
|
-
const newMessage =
|
|
95
|
+
const newMessage = patchMessage(messageNode, ast, trimMultiWhitespaces);
|
|
101
96
|
context.report({
|
|
102
97
|
node: messageNode,
|
|
103
98
|
messageId: 'noMultipleWhitespaces',
|
|
@@ -108,8 +103,8 @@ function checkNode(context, node) {
|
|
|
108
103
|
}
|
|
109
104
|
}
|
|
110
105
|
}
|
|
111
|
-
|
|
112
|
-
|
|
106
|
+
export const name = 'no-multiple-whitespaces';
|
|
107
|
+
export const rule = {
|
|
113
108
|
meta: {
|
|
114
109
|
type: 'problem',
|
|
115
110
|
docs: {
|
|
@@ -126,7 +121,7 @@ exports.rule = {
|
|
|
126
121
|
defaultOptions: [],
|
|
127
122
|
create(context) {
|
|
128
123
|
const callExpressionVisitor = (node) => checkNode(context, node);
|
|
129
|
-
const parserServices =
|
|
124
|
+
const parserServices = getParserServices(context);
|
|
130
125
|
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser
|
|
131
126
|
if (parserServices?.defineTemplateBodyVisitor) {
|
|
132
127
|
//@ts-expect-error
|
package/rules/no-offset.js
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser");
|
|
5
|
-
const context_compat_1 = require("../context-compat");
|
|
6
|
-
const util_1 = require("../util");
|
|
1
|
+
import { isPluralElement, parse, } from '@formatjs/icu-messageformat-parser';
|
|
2
|
+
import { getParserServices } from '../context-compat.js';
|
|
3
|
+
import { extractMessages, getSettings } from '../util.js';
|
|
7
4
|
function verifyAst(ast) {
|
|
8
5
|
const errors = [];
|
|
9
6
|
for (const el of ast) {
|
|
10
|
-
if (
|
|
7
|
+
if (isPluralElement(el)) {
|
|
11
8
|
if (el.offset) {
|
|
12
9
|
errors.push({ messageId: 'noOffset', data: {} });
|
|
13
10
|
}
|
|
@@ -20,13 +17,13 @@ function verifyAst(ast) {
|
|
|
20
17
|
return errors;
|
|
21
18
|
}
|
|
22
19
|
function checkNode(context, node) {
|
|
23
|
-
const settings =
|
|
24
|
-
const msgs =
|
|
20
|
+
const settings = getSettings(context);
|
|
21
|
+
const msgs = extractMessages(node, settings);
|
|
25
22
|
for (const [{ message: { defaultMessage }, messageNode, },] of msgs) {
|
|
26
23
|
if (!defaultMessage || !messageNode) {
|
|
27
24
|
continue;
|
|
28
25
|
}
|
|
29
|
-
const errors = verifyAst(
|
|
26
|
+
const errors = verifyAst(parse(defaultMessage, {
|
|
30
27
|
ignoreTag: settings.ignoreTag,
|
|
31
28
|
}));
|
|
32
29
|
for (const error of errors) {
|
|
@@ -37,8 +34,8 @@ function checkNode(context, node) {
|
|
|
37
34
|
}
|
|
38
35
|
}
|
|
39
36
|
}
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
export const name = 'no-offset';
|
|
38
|
+
export const rule = {
|
|
42
39
|
meta: {
|
|
43
40
|
type: 'problem',
|
|
44
41
|
docs: {
|
|
@@ -54,7 +51,7 @@ exports.rule = {
|
|
|
54
51
|
defaultOptions: [],
|
|
55
52
|
create(context) {
|
|
56
53
|
const callExpressionVisitor = (node) => checkNode(context, node);
|
|
57
|
-
const parserServices =
|
|
54
|
+
const parserServices = getParserServices(context);
|
|
58
55
|
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser
|
|
59
56
|
if (parserServices?.defineTemplateBodyVisitor) {
|
|
60
57
|
//@ts-expect-error
|
|
@@ -1,32 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser");
|
|
5
|
-
const context_compat_1 = require("../context-compat");
|
|
6
|
-
const util_1 = require("../util");
|
|
1
|
+
import { parse, TYPE, } from '@formatjs/icu-messageformat-parser';
|
|
2
|
+
import { getParserServices } from '../context-compat.js';
|
|
3
|
+
import { extractMessages, getSettings } from '../util.js';
|
|
7
4
|
function verifyAst(ast) {
|
|
8
5
|
if (ast.length !== 1) {
|
|
9
6
|
return;
|
|
10
7
|
}
|
|
11
8
|
switch (ast[0].type) {
|
|
12
|
-
case
|
|
9
|
+
case TYPE.argument:
|
|
13
10
|
return 'unnecessaryFormat';
|
|
14
|
-
case
|
|
11
|
+
case TYPE.number:
|
|
15
12
|
return 'unnecessaryFormatNumber';
|
|
16
|
-
case
|
|
13
|
+
case TYPE.date:
|
|
17
14
|
return 'unnecessaryFormatDate';
|
|
18
|
-
case
|
|
15
|
+
case TYPE.time:
|
|
19
16
|
return 'unnecessaryFormatTime';
|
|
20
17
|
}
|
|
21
18
|
}
|
|
22
19
|
function checkNode(context, node) {
|
|
23
|
-
const settings =
|
|
24
|
-
const msgs =
|
|
20
|
+
const settings = getSettings(context);
|
|
21
|
+
const msgs = extractMessages(node, settings);
|
|
25
22
|
for (const [{ message: { defaultMessage }, messageNode, },] of msgs) {
|
|
26
23
|
if (!defaultMessage || !messageNode) {
|
|
27
24
|
continue;
|
|
28
25
|
}
|
|
29
|
-
const messageId = verifyAst(
|
|
26
|
+
const messageId = verifyAst(parse(defaultMessage, {
|
|
30
27
|
ignoreTag: settings.ignoreTag,
|
|
31
28
|
}));
|
|
32
29
|
if (messageId)
|
|
@@ -36,8 +33,8 @@ function checkNode(context, node) {
|
|
|
36
33
|
});
|
|
37
34
|
}
|
|
38
35
|
}
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
export const name = 'no-useless-message';
|
|
37
|
+
export const rule = {
|
|
41
38
|
meta: {
|
|
42
39
|
type: 'problem',
|
|
43
40
|
docs: {
|
|
@@ -56,7 +53,7 @@ exports.rule = {
|
|
|
56
53
|
defaultOptions: [],
|
|
57
54
|
create(context) {
|
|
58
55
|
const callExpressionVisitor = (node) => checkNode(context, node);
|
|
59
|
-
const parserServices =
|
|
56
|
+
const parserServices = getParserServices(context);
|
|
60
57
|
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser
|
|
61
58
|
if (parserServices?.defineTemplateBodyVisitor) {
|
|
62
59
|
//@ts-expect-error
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const util_1 = require("../util");
|
|
5
|
-
exports.name = 'prefer-formatted-message';
|
|
6
|
-
exports.rule = {
|
|
1
|
+
import { isIntlFormatMessageCall } from '../util.js';
|
|
2
|
+
export const name = 'prefer-formatted-message';
|
|
3
|
+
export const rule = {
|
|
7
4
|
meta: {
|
|
8
5
|
type: 'suggestion',
|
|
9
6
|
docs: {
|
|
@@ -22,7 +19,7 @@ exports.rule = {
|
|
|
22
19
|
JSXElement: (node) => {
|
|
23
20
|
node.children.forEach(child => {
|
|
24
21
|
if (child.type !== 'JSXExpressionContainer' ||
|
|
25
|
-
!
|
|
22
|
+
!isIntlFormatMessageCall(child.expression)) {
|
|
26
23
|
return;
|
|
27
24
|
}
|
|
28
25
|
context.report({
|
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser");
|
|
6
|
-
const magic_string_1 = tslib_1.__importDefault(require("magic-string"));
|
|
7
|
-
const context_compat_1 = require("../context-compat");
|
|
8
|
-
const util_1 = require("../util");
|
|
1
|
+
import { parse, TYPE, } from '@formatjs/icu-messageformat-parser';
|
|
2
|
+
import MagicString from 'magic-string';
|
|
3
|
+
import { getParserServices } from '../context-compat.js';
|
|
4
|
+
import { extractMessages, getSettings, patchMessage } from '../util.js';
|
|
9
5
|
function verifyAst(context, messageNode, ast) {
|
|
10
6
|
const patches = [];
|
|
11
7
|
_verifyAst(ast);
|
|
12
8
|
if (patches.length > 0) {
|
|
13
|
-
const patchedMessage =
|
|
9
|
+
const patchedMessage = patchMessage(messageNode, ast, content => {
|
|
14
10
|
return patches
|
|
15
11
|
.reduce((magicString, patch) => {
|
|
16
12
|
switch (patch.type) {
|
|
@@ -21,7 +17,7 @@ function verifyAst(context, messageNode, ast) {
|
|
|
21
17
|
case 'update':
|
|
22
18
|
return magicString.update(patch.start, patch.end, patch.content);
|
|
23
19
|
}
|
|
24
|
-
}, new
|
|
20
|
+
}, new MagicString(content))
|
|
25
21
|
.toString();
|
|
26
22
|
});
|
|
27
23
|
context.report({
|
|
@@ -36,32 +32,32 @@ function verifyAst(context, messageNode, ast) {
|
|
|
36
32
|
for (let i = 0; i < ast.length; i++) {
|
|
37
33
|
const current = ast[i];
|
|
38
34
|
switch (current.type) {
|
|
39
|
-
case
|
|
40
|
-
case
|
|
35
|
+
case TYPE.argument:
|
|
36
|
+
case TYPE.number: {
|
|
41
37
|
// Applicable to only plain argument or number argument without any style
|
|
42
|
-
if (current.type ===
|
|
38
|
+
if (current.type === TYPE.number && current.style) {
|
|
43
39
|
break;
|
|
44
40
|
}
|
|
45
41
|
const next = ast[i + 1];
|
|
46
42
|
const nextNext = ast[i + 2];
|
|
47
43
|
if (next &&
|
|
48
44
|
nextNext &&
|
|
49
|
-
next.type ===
|
|
45
|
+
next.type === TYPE.literal &&
|
|
50
46
|
next.value === ' ' &&
|
|
51
|
-
nextNext.type ===
|
|
47
|
+
nextNext.type === TYPE.plural &&
|
|
52
48
|
nextNext.value === current.value) {
|
|
53
49
|
// `{A} {A, plural, one {B} other {Bs}}` => `{A, plural, one {# B} other {# Bs}}`
|
|
54
50
|
_removeRangeAndPrependPluralClauses(current.location.start.offset, next.location.end.offset, nextNext, '# ');
|
|
55
51
|
}
|
|
56
52
|
else if (next &&
|
|
57
|
-
next.type ===
|
|
53
|
+
next.type === TYPE.plural &&
|
|
58
54
|
next.value === current.value) {
|
|
59
55
|
// `{A}{A, plural, one {B} other {Bs}}` => `{A, plural, one {#B} other {#Bs}}`
|
|
60
56
|
_removeRangeAndPrependPluralClauses(current.location.start.offset, current.location.end.offset, next, '#');
|
|
61
57
|
}
|
|
62
58
|
break;
|
|
63
59
|
}
|
|
64
|
-
case
|
|
60
|
+
case TYPE.plural: {
|
|
65
61
|
// `{A, plural, one {{A} B} other {{A} Bs}}` => `{A, plural, one {# B} other {# Bs}}`
|
|
66
62
|
const name = current.value;
|
|
67
63
|
for (const { value } of Object.values(current.options)) {
|
|
@@ -69,13 +65,13 @@ function verifyAst(context, messageNode, ast) {
|
|
|
69
65
|
}
|
|
70
66
|
break;
|
|
71
67
|
}
|
|
72
|
-
case
|
|
68
|
+
case TYPE.select: {
|
|
73
69
|
for (const { value } of Object.values(current.options)) {
|
|
74
70
|
_verifyAst(value);
|
|
75
71
|
}
|
|
76
72
|
break;
|
|
77
73
|
}
|
|
78
|
-
case
|
|
74
|
+
case TYPE.tag:
|
|
79
75
|
_verifyAst(current.children);
|
|
80
76
|
break;
|
|
81
77
|
default:
|
|
@@ -88,11 +84,11 @@ function verifyAst(context, messageNode, ast) {
|
|
|
88
84
|
function _replacementArgumentWithPound(name, ast) {
|
|
89
85
|
for (const element of ast) {
|
|
90
86
|
switch (element.type) {
|
|
91
|
-
case
|
|
92
|
-
case
|
|
87
|
+
case TYPE.argument:
|
|
88
|
+
case TYPE.number: {
|
|
93
89
|
if (element.value === name &&
|
|
94
90
|
// Either plain argument or number argument without any style
|
|
95
|
-
(element.type !==
|
|
91
|
+
(element.type !== TYPE.number || !element.style)) {
|
|
96
92
|
patches.push({
|
|
97
93
|
type: 'update',
|
|
98
94
|
start: element.location.start.offset,
|
|
@@ -102,11 +98,11 @@ function verifyAst(context, messageNode, ast) {
|
|
|
102
98
|
}
|
|
103
99
|
break;
|
|
104
100
|
}
|
|
105
|
-
case
|
|
101
|
+
case TYPE.tag: {
|
|
106
102
|
_replacementArgumentWithPound(name, element.children);
|
|
107
103
|
break;
|
|
108
104
|
}
|
|
109
|
-
case
|
|
105
|
+
case TYPE.select: {
|
|
110
106
|
for (const { value } of Object.values(element.options)) {
|
|
111
107
|
_replacementArgumentWithPound(name, value);
|
|
112
108
|
}
|
|
@@ -138,14 +134,14 @@ function verifyAst(context, messageNode, ast) {
|
|
|
138
134
|
}
|
|
139
135
|
}
|
|
140
136
|
function checkNode(context, node) {
|
|
141
|
-
const msgs =
|
|
137
|
+
const msgs = extractMessages(node, getSettings(context));
|
|
142
138
|
for (const [{ message: { defaultMessage }, messageNode, },] of msgs) {
|
|
143
139
|
if (!defaultMessage || !messageNode) {
|
|
144
140
|
continue;
|
|
145
141
|
}
|
|
146
142
|
let ast;
|
|
147
143
|
try {
|
|
148
|
-
ast =
|
|
144
|
+
ast = parse(defaultMessage, { captureLocation: true });
|
|
149
145
|
}
|
|
150
146
|
catch (e) {
|
|
151
147
|
context.report({
|
|
@@ -158,8 +154,8 @@ function checkNode(context, node) {
|
|
|
158
154
|
verifyAst(context, messageNode, ast);
|
|
159
155
|
}
|
|
160
156
|
}
|
|
161
|
-
|
|
162
|
-
|
|
157
|
+
export const name = 'prefer-pound-in-plural';
|
|
158
|
+
export const rule = {
|
|
163
159
|
meta: {
|
|
164
160
|
type: 'suggestion',
|
|
165
161
|
docs: {
|
|
@@ -177,7 +173,7 @@ exports.rule = {
|
|
|
177
173
|
// TODO: Vue support
|
|
178
174
|
create(context) {
|
|
179
175
|
const callExpressionVisitor = (node) => checkNode(context, node);
|
|
180
|
-
const parserServices =
|
|
176
|
+
const parserServices = getParserServices(context);
|
|
181
177
|
//@ts-expect-error defineTemplateBodyVisitor exists in Vue parser
|
|
182
178
|
if (parserServices?.defineTemplateBodyVisitor) {
|
|
183
179
|
//@ts-expect-error
|
package/util.js
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getSettings = getSettings;
|
|
4
|
-
exports.isIntlFormatMessageCall = isIntlFormatMessageCall;
|
|
5
|
-
exports.extractMessageDescriptor = extractMessageDescriptor;
|
|
6
|
-
exports.extractMessages = extractMessages;
|
|
7
|
-
exports.patchMessage = patchMessage;
|
|
8
1
|
const FORMAT_FUNCTION_NAMES = new Set(['$formatMessage', 'formatMessage', '$t']);
|
|
9
2
|
const COMPONENT_NAMES = new Set(['FormattedMessage']);
|
|
10
3
|
const DECLARATION_FUNCTION_NAMES = new Set(['defineMessage']);
|
|
11
|
-
function getSettings({ settings }) {
|
|
4
|
+
export function getSettings({ settings }) {
|
|
12
5
|
return settings.formatjs ?? settings;
|
|
13
6
|
}
|
|
14
7
|
function isStringLiteral(node) {
|
|
@@ -30,7 +23,7 @@ function staticallyEvaluateStringConcat(node) {
|
|
|
30
23
|
}
|
|
31
24
|
return ['', false];
|
|
32
25
|
}
|
|
33
|
-
function isIntlFormatMessageCall(node) {
|
|
26
|
+
export function isIntlFormatMessageCall(node) {
|
|
34
27
|
return (node.type === 'CallExpression' &&
|
|
35
28
|
node.callee.type === 'MemberExpression' &&
|
|
36
29
|
((node.callee.object.type === 'Identifier' &&
|
|
@@ -54,7 +47,7 @@ function isMultipleMessageDescriptorDeclaration(node) {
|
|
|
54
47
|
node.callee.type === 'Identifier' &&
|
|
55
48
|
node.callee.name === 'defineMessages');
|
|
56
49
|
}
|
|
57
|
-
function extractMessageDescriptor(node) {
|
|
50
|
+
export function extractMessageDescriptor(node) {
|
|
58
51
|
if (!node || node.type !== 'ObjectExpression') {
|
|
59
52
|
return;
|
|
60
53
|
}
|
|
@@ -220,7 +213,7 @@ function extractMessageDescriptors(node) {
|
|
|
220
213
|
}
|
|
221
214
|
return msgs;
|
|
222
215
|
}
|
|
223
|
-
function extractMessages(node, { additionalComponentNames, additionalFunctionNames, excludeMessageDeclCalls, } = {}) {
|
|
216
|
+
export function extractMessages(node, { additionalComponentNames, additionalFunctionNames, excludeMessageDeclCalls, } = {}) {
|
|
224
217
|
const allFormatFunctionNames = Array.isArray(additionalFunctionNames)
|
|
225
218
|
? new Set([
|
|
226
219
|
...Array.from(FORMAT_FUNCTION_NAMES),
|
|
@@ -268,7 +261,7 @@ function extractMessages(node, { additionalComponentNames, additionalFunctionNam
|
|
|
268
261
|
* `fixer.replaceText(messageNode, <return value>)`. If the return value is null,
|
|
269
262
|
* it means that the patch cannot be applied.
|
|
270
263
|
*/
|
|
271
|
-
function patchMessage(messageNode, ast, patcher) {
|
|
264
|
+
export function patchMessage(messageNode, ast, patcher) {
|
|
272
265
|
if (messageNode.type === 'Literal' &&
|
|
273
266
|
messageNode.value &&
|
|
274
267
|
typeof messageNode.value === 'string') {
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import type { ParserServicesWithoutTypeInformation, ParserServicesWithTypeInformation } from '@typescript-eslint/utils';
|
|
2
|
-
import { RuleContext } from '@typescript-eslint/utils/ts-eslint';
|
|
3
|
-
export declare const getParserServices: <TRuleContext extends RuleContext<string, unknown[]>>(context: TRuleContext) => Partial<ParserServicesWithoutTypeInformation> | Partial<ParserServicesWithTypeInformation> | undefined;
|
package/lib_esnext/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/lib_esnext/index.js
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import { name as blocklistElementRuleName, rule as blocklistElements, } from './rules/blocklist-elements';
|
|
2
|
-
import { rule as enforceDefaultMessage, name as enforceDefaultMessageName, } from './rules/enforce-default-message';
|
|
3
|
-
import { rule as enforceDescription, name as enforceDescriptionName, } from './rules/enforce-description';
|
|
4
|
-
import { rule as enforceId, name as enforceIdName } from './rules/enforce-id';
|
|
5
|
-
import { rule as enforcePlaceholders, name as enforcePlaceholdersName, } from './rules/enforce-placeholders';
|
|
6
|
-
import { rule as enforcePluralRules, name as enforcePluralRulesName, } from './rules/enforce-plural-rules';
|
|
7
|
-
import { rule as noCamelCase, name as noCamelCaseName, } from './rules/no-camel-case';
|
|
8
|
-
import { rule as noComplexSelectors, name as noComplexSelectorsName, } from './rules/no-complex-selectors';
|
|
9
|
-
import { rule as noEmoji, name as noEmojiName } from './rules/no-emoji';
|
|
10
|
-
import { rule as noId, name as noIdName } from './rules/no-id';
|
|
11
|
-
import { rule as noInvalidICU, name as noInvalidICUName, } from './rules/no-invalid-icu';
|
|
12
|
-
import { rule as noLiteralStringInJsx, name as noLiteralStringInJsxName, } from './rules/no-literal-string-in-jsx';
|
|
13
|
-
import { rule as noMissingIcuPluralOnePlaceholders, name as noMissingIcuPluralOnePlaceholdersName, } from './rules/no-missing-icu-plural-one-placeholders';
|
|
14
|
-
import { rule as noMultiplePlurals, name as noMultiplePluralsName, } from './rules/no-multiple-plurals';
|
|
15
|
-
import { rule as noMultipleWhitespaces, name as noMultipleWhitespacesName, } from './rules/no-multiple-whitespaces';
|
|
16
|
-
import { rule as noOffset, name as noOffsetName } from './rules/no-offset';
|
|
17
|
-
import { rule as noUselessMessage, name as noUselessMessageName, } from './rules/no-useless-message';
|
|
18
|
-
import { rule as preferFormattedMessage, name as preferFormattedMessageName, } from './rules/prefer-formatted-message';
|
|
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';
|
|
21
|
-
import { name, version } from './package.json';
|
|
22
|
-
// All rules
|
|
23
|
-
const rules = {
|
|
24
|
-
// @ts-expect-error
|
|
25
|
-
[blocklistElementRuleName]: blocklistElements,
|
|
26
|
-
// @ts-expect-error
|
|
27
|
-
[enforceDefaultMessageName]: enforceDefaultMessage,
|
|
28
|
-
// @ts-expect-error
|
|
29
|
-
[enforceDescriptionName]: enforceDescription,
|
|
30
|
-
// @ts-expect-error
|
|
31
|
-
[enforceIdName]: enforceId,
|
|
32
|
-
// @ts-expect-error
|
|
33
|
-
[enforcePlaceholdersName]: enforcePlaceholders,
|
|
34
|
-
// @ts-expect-error
|
|
35
|
-
[enforcePluralRulesName]: enforcePluralRules,
|
|
36
|
-
// @ts-expect-error
|
|
37
|
-
[noCamelCaseName]: noCamelCase,
|
|
38
|
-
// @ts-expect-error
|
|
39
|
-
[noComplexSelectorsName]: noComplexSelectors,
|
|
40
|
-
// @ts-expect-error
|
|
41
|
-
[noEmojiName]: noEmoji,
|
|
42
|
-
// @ts-expect-error
|
|
43
|
-
[noIdName]: noId,
|
|
44
|
-
// @ts-expect-error
|
|
45
|
-
[noInvalidICUName]: noInvalidICU,
|
|
46
|
-
// @ts-expect-error
|
|
47
|
-
[noLiteralStringInJsxName]: noLiteralStringInJsx,
|
|
48
|
-
// @ts-expect-error
|
|
49
|
-
[noMultiplePluralsName]: noMultiplePlurals,
|
|
50
|
-
// @ts-expect-error
|
|
51
|
-
[noMultipleWhitespacesName]: noMultipleWhitespaces,
|
|
52
|
-
// @ts-expect-error
|
|
53
|
-
[noOffsetName]: noOffset,
|
|
54
|
-
// @ts-expect-error
|
|
55
|
-
[noUselessMessageName]: noUselessMessage,
|
|
56
|
-
// @ts-expect-error
|
|
57
|
-
[preferFormattedMessageName]: preferFormattedMessage,
|
|
58
|
-
// @ts-expect-error
|
|
59
|
-
[preferPoundInPluralName]: preferPoundInPlural,
|
|
60
|
-
// @ts-expect-error
|
|
61
|
-
[noMissingIcuPluralOnePlaceholdersName]: noMissingIcuPluralOnePlaceholders,
|
|
62
|
-
// @ts-expect-error
|
|
63
|
-
[noLiteralStringInObjectName]: noLiteralStringInObject,
|
|
64
|
-
};
|
|
65
|
-
// Base plugin
|
|
66
|
-
const plugin = {
|
|
67
|
-
meta: { name, version },
|
|
68
|
-
rules,
|
|
69
|
-
};
|
|
70
|
-
// Configs
|
|
71
|
-
const configs = {
|
|
72
|
-
strict: {
|
|
73
|
-
name: 'formatjs/strict',
|
|
74
|
-
plugins: { formatjs: plugin },
|
|
75
|
-
rules: {
|
|
76
|
-
'formatjs/no-offset': 'error',
|
|
77
|
-
'formatjs/enforce-default-message': ['error', 'literal'],
|
|
78
|
-
'formatjs/enforce-description': ['error', 'literal'],
|
|
79
|
-
'formatjs/enforce-placeholders': 'error',
|
|
80
|
-
'formatjs/no-emoji': 'error',
|
|
81
|
-
'formatjs/no-multiple-whitespaces': 'error',
|
|
82
|
-
'formatjs/no-multiple-plurals': 'error',
|
|
83
|
-
'formatjs/no-complex-selectors': ['error', { limit: 20 }],
|
|
84
|
-
'formatjs/no-useless-message': 'error',
|
|
85
|
-
'formatjs/prefer-pound-in-plural': 'error',
|
|
86
|
-
'formatjs/no-missing-icu-plural-one-placeholders': 'error',
|
|
87
|
-
'formatjs/enforce-id': [
|
|
88
|
-
'error',
|
|
89
|
-
{
|
|
90
|
-
idInterpolationPattern: '[sha512:contenthash:base64:10]',
|
|
91
|
-
},
|
|
92
|
-
],
|
|
93
|
-
'formatjs/enforce-plural-rules': [
|
|
94
|
-
'error',
|
|
95
|
-
{
|
|
96
|
-
one: true,
|
|
97
|
-
other: true,
|
|
98
|
-
},
|
|
99
|
-
],
|
|
100
|
-
'formatjs/no-literal-string-in-jsx': [
|
|
101
|
-
'error',
|
|
102
|
-
{
|
|
103
|
-
props: {
|
|
104
|
-
include: [['*', '{label,placeholder,title}']],
|
|
105
|
-
},
|
|
106
|
-
},
|
|
107
|
-
],
|
|
108
|
-
'formatjs/blocklist-elements': ['error', ['selectordinal']],
|
|
109
|
-
},
|
|
110
|
-
},
|
|
111
|
-
recommended: {
|
|
112
|
-
name: 'formatjs/recommended',
|
|
113
|
-
plugins: { formatjs: plugin },
|
|
114
|
-
rules: {
|
|
115
|
-
'formatjs/no-offset': 'error',
|
|
116
|
-
'formatjs/enforce-default-message': ['error', 'literal'],
|
|
117
|
-
'formatjs/enforce-description': ['error', 'literal'],
|
|
118
|
-
'formatjs/enforce-placeholders': 'error',
|
|
119
|
-
'formatjs/no-emoji': 'error',
|
|
120
|
-
'formatjs/no-multiple-whitespaces': 'error',
|
|
121
|
-
'formatjs/no-multiple-plurals': 'error',
|
|
122
|
-
'formatjs/no-complex-selectors': ['error', { limit: 20 }],
|
|
123
|
-
'formatjs/no-useless-message': 'error',
|
|
124
|
-
'formatjs/prefer-pound-in-plural': 'error',
|
|
125
|
-
'formatjs/no-missing-icu-plural-one-placeholders': 'error',
|
|
126
|
-
'formatjs/enforce-plural-rules': [
|
|
127
|
-
'error',
|
|
128
|
-
{
|
|
129
|
-
one: true,
|
|
130
|
-
other: true,
|
|
131
|
-
},
|
|
132
|
-
],
|
|
133
|
-
'formatjs/no-literal-string-in-jsx': [
|
|
134
|
-
'warn',
|
|
135
|
-
{
|
|
136
|
-
props: {
|
|
137
|
-
include: [['*', '{label,placeholder,title}']],
|
|
138
|
-
},
|
|
139
|
-
},
|
|
140
|
-
],
|
|
141
|
-
'formatjs/blocklist-elements': ['error', ['selectordinal']],
|
|
142
|
-
},
|
|
143
|
-
},
|
|
144
|
-
};
|
|
145
|
-
plugin.configs = configs;
|
|
146
|
-
module.exports = plugin;
|
package/lib_esnext/package.json
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "eslint-plugin-formatjs",
|
|
3
|
-
"description": "ESLint plugin for formatjs",
|
|
4
|
-
"version": "5.4.2",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"author": "Long Ho <holevietlong@gmail.com>",
|
|
7
|
-
"dependencies": {
|
|
8
|
-
"@formatjs/icu-messageformat-parser": "workspace:*",
|
|
9
|
-
"@formatjs/ts-transformer": "workspace:*",
|
|
10
|
-
"@types/eslint": "^9.6.1",
|
|
11
|
-
"@types/picomatch": "^3",
|
|
12
|
-
"@typescript-eslint/utils": "^8.27.0",
|
|
13
|
-
"magic-string": "^0.30.0",
|
|
14
|
-
"picomatch": "2 || 3 || 4",
|
|
15
|
-
"tslib": "^2.8.0",
|
|
16
|
-
"unicode-emoji-utils": "^1.2.0"
|
|
17
|
-
},
|
|
18
|
-
"peerDependencies": {
|
|
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"
|
|
31
|
-
}
|