eslint-plugin-formatjs 4.11.3 → 4.12.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.
Files changed (40) hide show
  1. package/index.d.ts +3 -23
  2. package/index.js +36 -37
  3. package/package.json +5 -5
  4. package/rules/blocklist-elements.d.ts +17 -3
  5. package/rules/blocklist-elements.js +50 -46
  6. package/rules/enforce-default-message.d.ts +10 -3
  7. package/rules/enforce-default-message.js +21 -9
  8. package/rules/enforce-description.d.ts +10 -3
  9. package/rules/enforce-description.js +19 -6
  10. package/rules/enforce-id.d.ts +10 -3
  11. package/rules/enforce-id.js +53 -24
  12. package/rules/enforce-placeholders.d.ts +8 -3
  13. package/rules/enforce-placeholders.js +18 -7
  14. package/rules/enforce-plural-rules.d.ts +17 -3
  15. package/rules/enforce-plural-rules.js +20 -20
  16. package/rules/no-camel-case.d.ts +6 -3
  17. package/rules/no-camel-case.js +20 -20
  18. package/rules/no-complex-selectors.d.ts +9 -3
  19. package/rules/no-complex-selectors.js +18 -16
  20. package/rules/no-emoji.d.ts +9 -3
  21. package/rules/no-emoji.js +6 -4
  22. package/rules/no-id.d.ts +6 -3
  23. package/rules/no-id.js +11 -4
  24. package/rules/no-invalid-icu.d.ts +6 -3
  25. package/rules/no-invalid-icu.js +12 -5
  26. package/rules/no-literal-string-in-jsx.d.ts +13 -3
  27. package/rules/no-literal-string-in-jsx.js +10 -7
  28. package/rules/no-multiple-plurals.d.ts +6 -3
  29. package/rules/no-multiple-plurals.js +20 -20
  30. package/rules/no-multiple-whitespaces.d.ts +6 -3
  31. package/rules/no-multiple-whitespaces.js +10 -5
  32. package/rules/no-offset.d.ts +6 -3
  33. package/rules/no-offset.js +19 -19
  34. package/rules/no-useless-message.d.ts +6 -3
  35. package/rules/no-useless-message.js +23 -39
  36. package/rules/prefer-formatted-message.d.ts +6 -3
  37. package/rules/prefer-formatted-message.js +5 -3
  38. package/rules/prefer-pound-in-plural.d.ts +6 -3
  39. package/rules/prefer-pound-in-plural.js +10 -4
  40. package/util.d.ts +2 -2
@@ -1,3 +1,6 @@
1
- import { Rule } from 'eslint';
2
- declare const rule: Rule.RuleModule;
3
- export default rule;
1
+ import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint';
2
+ type MessageIds = 'noMultiplePlurals';
3
+ type Options = [];
4
+ export declare const name = "no-multiple-plurals";
5
+ export declare const rule: RuleModule<MessageIds, Options, RuleListener>;
6
+ export {};
@@ -1,26 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rule = exports.name = void 0;
3
4
  const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser");
4
5
  const util_1 = require("../util");
5
- class MultiplePlurals extends Error {
6
- constructor() {
7
- super(...arguments);
8
- this.message = 'Cannot specify more than 1 plural rules';
9
- }
10
- }
11
6
  function verifyAst(ast, pluralCount = { count: 0 }) {
7
+ const errors = [];
12
8
  for (const el of ast) {
13
9
  if ((0, icu_messageformat_parser_1.isPluralElement)(el)) {
14
10
  pluralCount.count++;
15
11
  if (pluralCount.count > 1) {
16
- throw new MultiplePlurals();
12
+ errors.push({ messageId: 'noMultiplePlurals', data: {} });
17
13
  }
18
14
  const { options } = el;
19
15
  for (const selector of Object.keys(options)) {
20
- verifyAst(options[selector].value, pluralCount);
16
+ errors.push(...verifyAst(options[selector].value, pluralCount));
21
17
  }
22
18
  }
23
19
  }
20
+ return errors;
24
21
  }
25
22
  function checkNode(context, node) {
26
23
  const settings = (0, util_1.getSettings)(context);
@@ -29,33 +26,37 @@ function checkNode(context, node) {
29
26
  if (!defaultMessage || !messageNode) {
30
27
  continue;
31
28
  }
32
- try {
33
- verifyAst((0, icu_messageformat_parser_1.parse)(defaultMessage, {
34
- ignoreTag: settings.ignoreTag,
35
- }));
36
- }
37
- catch (e) {
29
+ const errors = verifyAst((0, icu_messageformat_parser_1.parse)(defaultMessage, {
30
+ ignoreTag: settings.ignoreTag,
31
+ }));
32
+ for (const error of errors) {
38
33
  context.report({
39
- node: messageNode,
40
- message: e instanceof Error ? e.message : String(e),
34
+ node,
35
+ ...error,
41
36
  });
42
37
  }
43
38
  }
44
39
  }
45
- const rule = {
40
+ exports.name = 'no-multiple-plurals';
41
+ exports.rule = {
46
42
  meta: {
47
43
  type: 'problem',
48
44
  docs: {
49
45
  description: 'Disallow multiple plural rules in the same message',
50
- category: 'Errors',
51
- recommended: false,
52
46
  url: 'https://formatjs.io/docs/tooling/linter#no-multiple-plurals',
53
47
  },
54
48
  fixable: 'code',
49
+ schema: [],
50
+ messages: {
51
+ noMultiplePlurals: 'Multiple plural rules in the same message',
52
+ },
55
53
  },
54
+ defaultOptions: [],
56
55
  create(context) {
57
56
  const callExpressionVisitor = (node) => checkNode(context, node);
57
+ //@ts-expect-error defineTemplateBodyVisitor exists in Vue parser
58
58
  if (context.parserServices.defineTemplateBodyVisitor) {
59
+ //@ts-expect-error
59
60
  return context.parserServices.defineTemplateBodyVisitor({
60
61
  CallExpression: callExpressionVisitor,
61
62
  }, {
@@ -68,4 +69,3 @@ const rule = {
68
69
  };
69
70
  },
70
71
  };
71
- exports.default = rule;
@@ -1,3 +1,6 @@
1
- import { Rule } from 'eslint';
2
- declare const rule: Rule.RuleModule;
3
- export default rule;
1
+ import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint';
2
+ type MessageIds = 'noMultipleWhitespaces' | 'parserError';
3
+ type Options = [];
4
+ export declare const name = "no-multiple-whitespaces";
5
+ export declare const rule: RuleModule<MessageIds, Options, RuleListener>;
6
+ export {};
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rule = exports.name = void 0;
3
4
  const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser");
4
5
  const util_1 = require("../util");
5
6
  function isAstValid(ast) {
@@ -89,7 +90,8 @@ function checkNode(context, node) {
89
90
  catch (e) {
90
91
  context.report({
91
92
  node: messageNode,
92
- message: e instanceof Error ? e.message : String(e),
93
+ messageId: 'parserError',
94
+ data: { message: e instanceof Error ? e.message : String(e) },
93
95
  });
94
96
  return;
95
97
  }
@@ -105,23 +107,27 @@ function checkNode(context, node) {
105
107
  }
106
108
  }
107
109
  }
108
- const rule = {
110
+ exports.name = 'no-multiple-whitespaces';
111
+ exports.rule = {
109
112
  meta: {
110
113
  type: 'problem',
111
114
  docs: {
112
115
  description: 'Prevents usage of multiple consecutive whitespaces in message',
113
- category: 'Errors',
114
- recommended: false,
115
116
  url: 'https://formatjs.io/docs/tooling/linter#no-multiple-whitespaces',
116
117
  },
117
118
  messages: {
118
119
  noMultipleWhitespaces: 'Multiple consecutive whitespaces are not allowed',
120
+ parserError: '{{message}}',
119
121
  },
120
122
  fixable: 'code',
123
+ schema: [],
121
124
  },
125
+ defaultOptions: [],
122
126
  create(context) {
123
127
  const callExpressionVisitor = (node) => checkNode(context, node);
128
+ //@ts-expect-error defineTemplateBodyVisitor exists in Vue parser
124
129
  if (context.parserServices.defineTemplateBodyVisitor) {
130
+ //@ts-expect-error
125
131
  return context.parserServices.defineTemplateBodyVisitor({
126
132
  CallExpression: callExpressionVisitor,
127
133
  }, {
@@ -134,4 +140,3 @@ const rule = {
134
140
  };
135
141
  },
136
142
  };
137
- exports.default = rule;
@@ -1,3 +1,6 @@
1
- import { Rule } from 'eslint';
2
- declare const rule: Rule.RuleModule;
3
- export default rule;
1
+ import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint';
2
+ type MessageIds = 'noOffset';
3
+ type Options = [];
4
+ export declare const name = "no-offset";
5
+ export declare const rule: RuleModule<MessageIds, Options, RuleListener>;
6
+ export {};
@@ -1,25 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rule = exports.name = void 0;
3
4
  const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser");
4
5
  const util_1 = require("../util");
5
- class NoOffsetError extends Error {
6
- constructor() {
7
- super(...arguments);
8
- this.message = 'offset are not allowed in plural rules';
9
- }
10
- }
11
6
  function verifyAst(ast) {
7
+ const errors = [];
12
8
  for (const el of ast) {
13
9
  if ((0, icu_messageformat_parser_1.isPluralElement)(el)) {
14
10
  if (el.offset) {
15
- throw new NoOffsetError();
11
+ errors.push({ messageId: 'noOffset', data: {} });
16
12
  }
17
13
  const { options } = el;
18
14
  for (const selector of Object.keys(options)) {
19
- verifyAst(options[selector].value);
15
+ errors.push(...verifyAst(options[selector].value));
20
16
  }
21
17
  }
22
18
  }
19
+ return errors;
23
20
  }
24
21
  function checkNode(context, node) {
25
22
  const settings = (0, util_1.getSettings)(context);
@@ -28,33 +25,37 @@ function checkNode(context, node) {
28
25
  if (!defaultMessage || !messageNode) {
29
26
  continue;
30
27
  }
31
- try {
32
- verifyAst((0, icu_messageformat_parser_1.parse)(defaultMessage, {
33
- ignoreTag: settings.ignoreTag,
34
- }));
35
- }
36
- catch (e) {
28
+ const errors = verifyAst((0, icu_messageformat_parser_1.parse)(defaultMessage, {
29
+ ignoreTag: settings.ignoreTag,
30
+ }));
31
+ for (const error of errors) {
37
32
  context.report({
38
33
  node: messageNode,
39
- message: e.message,
34
+ ...error,
40
35
  });
41
36
  }
42
37
  }
43
38
  }
44
- const rule = {
39
+ exports.name = 'no-offset';
40
+ exports.rule = {
45
41
  meta: {
46
42
  type: 'problem',
47
43
  docs: {
48
44
  description: 'Disallow offset in plural rules',
49
- category: 'Errors',
50
- recommended: false,
51
45
  url: 'https://formatjs.io/docs/tooling/linter#no-offset',
52
46
  },
53
47
  fixable: 'code',
48
+ messages: {
49
+ noOffset: 'offset is not allowed',
50
+ },
51
+ schema: [],
54
52
  },
53
+ defaultOptions: [],
55
54
  create(context) {
56
55
  const callExpressionVisitor = (node) => checkNode(context, node);
56
+ //@ts-expect-error defineTemplateBodyVisitor exists in Vue parser
57
57
  if (context.parserServices.defineTemplateBodyVisitor) {
58
+ //@ts-expect-error
58
59
  return context.parserServices.defineTemplateBodyVisitor({
59
60
  CallExpression: callExpressionVisitor,
60
61
  }, {
@@ -67,4 +68,3 @@ const rule = {
67
68
  };
68
69
  },
69
70
  };
70
- exports.default = rule;
@@ -1,3 +1,6 @@
1
- import { Rule } from 'eslint';
2
- declare const rule: Rule.RuleModule;
3
- export default rule;
1
+ import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint';
2
+ type MessageIds = 'unnecessaryFormat' | 'unnecessaryFormatNumber' | 'unnecessaryFormatDate' | 'unnecessaryFormatTime';
3
+ type Options = [];
4
+ export declare const name = "no-useless-message";
5
+ export declare const rule: RuleModule<MessageIds, Options, RuleListener>;
6
+ export {};
@@ -1,44 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rule = exports.name = void 0;
3
4
  const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser");
4
5
  const util_1 = require("../util");
5
- class JustArgument extends Error {
6
- constructor() {
7
- super(...arguments);
8
- this.message = 'Unnecessary formatted message.';
9
- }
10
- }
11
- class JustNumber extends Error {
12
- constructor() {
13
- super(...arguments);
14
- this.message = 'Unnecessary formatted message: just use FormattedNumber or intl.formatNumber.';
15
- }
16
- }
17
- class JustDate extends Error {
18
- constructor() {
19
- super(...arguments);
20
- this.message = 'Unnecessary formatted message: just use FormattedDate or intl.formatDate.';
21
- }
22
- }
23
- class JustTime extends Error {
24
- constructor() {
25
- super(...arguments);
26
- this.message = 'Unnecessary formatted message: just use FormattedTime or intl.formatTime.';
27
- }
28
- }
29
6
  function verifyAst(ast) {
30
7
  if (ast.length !== 1) {
31
8
  return;
32
9
  }
33
10
  switch (ast[0].type) {
34
11
  case icu_messageformat_parser_1.TYPE.argument:
35
- throw new JustArgument();
12
+ return 'unnecessaryFormat';
36
13
  case icu_messageformat_parser_1.TYPE.number:
37
- throw new JustNumber();
14
+ return 'unnecessaryFormatNumber';
38
15
  case icu_messageformat_parser_1.TYPE.date:
39
- throw new JustDate();
16
+ return 'unnecessaryFormatDate';
40
17
  case icu_messageformat_parser_1.TYPE.time:
41
- throw new JustTime();
18
+ return 'unnecessaryFormatTime';
42
19
  }
43
20
  }
44
21
  function checkNode(context, node) {
@@ -48,32 +25,40 @@ function checkNode(context, node) {
48
25
  if (!defaultMessage || !messageNode) {
49
26
  continue;
50
27
  }
51
- try {
52
- verifyAst((0, icu_messageformat_parser_1.parse)(defaultMessage, {
53
- ignoreTag: settings.ignoreTag,
54
- }));
55
- }
56
- catch (e) {
28
+ const messageId = verifyAst((0, icu_messageformat_parser_1.parse)(defaultMessage, {
29
+ ignoreTag: settings.ignoreTag,
30
+ }));
31
+ if (messageId)
57
32
  context.report({
58
33
  node: messageNode,
59
- message: e instanceof Error ? e.message : String(e),
34
+ messageId,
60
35
  });
61
- }
62
36
  }
63
37
  }
64
- const rule = {
38
+ exports.name = 'no-useless-message';
39
+ exports.rule = {
65
40
  meta: {
66
41
  type: 'problem',
67
42
  docs: {
68
43
  description: 'Disallow unnecessary formatted message',
69
- recommended: true,
44
+ recommended: 'recommended',
70
45
  url: 'https://formatjs.io/docs/tooling/linter#no-useless-message',
71
46
  },
72
47
  fixable: 'code',
48
+ schema: [],
49
+ messages: {
50
+ unnecessaryFormat: 'Unnecessary formatted message.',
51
+ unnecessaryFormatNumber: 'Unnecessary formatted message: just use FormattedNumber or intl.formatNumber.',
52
+ unnecessaryFormatDate: 'Unnecessary formatted message: just use FormattedDate or intl.formatDate.',
53
+ unnecessaryFormatTime: 'Unnecessary formatted message: just use FormattedTime or intl.formatTime.',
54
+ },
73
55
  },
56
+ defaultOptions: [],
74
57
  create(context) {
75
58
  const callExpressionVisitor = (node) => checkNode(context, node);
59
+ //@ts-expect-error defineTemplateBodyVisitor exists in Vue parser
76
60
  if (context.parserServices.defineTemplateBodyVisitor) {
61
+ //@ts-expect-error
77
62
  return context.parserServices.defineTemplateBodyVisitor({
78
63
  CallExpression: callExpressionVisitor,
79
64
  }, {
@@ -86,4 +71,3 @@ const rule = {
86
71
  };
87
72
  },
88
73
  };
89
- exports.default = rule;
@@ -1,3 +1,6 @@
1
- import type { Rule } from 'eslint';
2
- declare const rule: Rule.RuleModule;
3
- export default rule;
1
+ import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint';
2
+ type MessageIds = 'jsxChildren';
3
+ type Options = [];
4
+ export declare const name = "prefer-formatted-message";
5
+ export declare const rule: RuleModule<MessageIds, Options, RuleListener>;
6
+ export {};
@@ -1,18 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rule = exports.name = void 0;
3
4
  const util_1 = require("../util");
4
- const rule = {
5
+ exports.name = 'prefer-formatted-message';
6
+ exports.rule = {
5
7
  meta: {
6
8
  type: 'suggestion',
7
9
  docs: {
8
10
  description: 'Prefer `FormattedMessage` component over `intl.formatMessage` if applicable.',
9
- recommended: false,
10
11
  url: 'https://formatjs.io/docs/tooling/linter#prefer-formatted-message',
11
12
  },
12
13
  messages: {
13
14
  jsxChildren: 'Prefer `FormattedMessage` over `intl.formatMessage` in the JSX children expression.',
14
15
  },
16
+ schema: [],
15
17
  },
18
+ defaultOptions: [],
16
19
  // TODO: Vue support
17
20
  create(context) {
18
21
  return {
@@ -31,4 +34,3 @@ const rule = {
31
34
  };
32
35
  },
33
36
  };
34
- exports.default = rule;
@@ -1,3 +1,6 @@
1
- import type { Rule } from 'eslint';
2
- declare const rule: Rule.RuleModule;
3
- export default rule;
1
+ import { RuleModule, RuleListener } from '@typescript-eslint/utils/ts-eslint';
2
+ type MessageIds = 'preferPoundInPlurals' | 'parseError';
3
+ type Options = [];
4
+ export declare const name = "prefer-pound-in-plural";
5
+ export declare const rule: RuleModule<MessageIds, Options, RuleListener>;
6
+ export {};
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rule = exports.name = void 0;
3
4
  const tslib_1 = require("tslib");
4
5
  const icu_messageformat_parser_1 = require("@formatjs/icu-messageformat-parser");
5
6
  const magic_string_1 = tslib_1.__importDefault(require("magic-string"));
@@ -148,30 +149,36 @@ function checkNode(context, node) {
148
149
  catch (e) {
149
150
  context.report({
150
151
  node: messageNode,
151
- message: e instanceof Error ? e.message : String(e),
152
+ messageId: 'parseError',
153
+ data: { message: e instanceof Error ? e.message : String(e) },
152
154
  });
153
155
  return;
154
156
  }
155
157
  verifyAst(context, messageNode, ast);
156
158
  }
157
159
  }
158
- const rule = {
160
+ exports.name = 'prefer-pound-in-plural';
161
+ exports.rule = {
159
162
  meta: {
160
163
  type: 'suggestion',
161
164
  docs: {
162
165
  description: 'Prefer using # to reference the count in the plural argument.',
163
- recommended: false,
164
166
  url: 'https://formatjs.io/docs/tooling/linter#prefer-pound-in-plurals',
165
167
  },
166
168
  messages: {
167
169
  preferPoundInPlurals: 'Prefer using # to reference the count in the plural argument instead of repeating the argument.',
170
+ parseError: '{{message}}',
168
171
  },
169
172
  fixable: 'code',
173
+ schema: [],
170
174
  },
175
+ defaultOptions: [],
171
176
  // TODO: Vue support
172
177
  create(context) {
173
178
  const callExpressionVisitor = (node) => checkNode(context, node);
179
+ //@ts-expect-error defineTemplateBodyVisitor exists in Vue parser
174
180
  if (context.parserServices.defineTemplateBodyVisitor) {
181
+ //@ts-expect-error
175
182
  return context.parserServices.defineTemplateBodyVisitor({
176
183
  CallExpression: callExpressionVisitor,
177
184
  }, {
@@ -184,4 +191,3 @@ const rule = {
184
191
  };
185
192
  },
186
193
  };
187
- exports.default = rule;
package/util.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { MessageFormatElement } from '@formatjs/icu-messageformat-parser';
2
2
  import { TSESTree } from '@typescript-eslint/utils';
3
- import { Rule } from 'eslint';
3
+ import { RuleContext } from '@typescript-eslint/utils/ts-eslint';
4
4
  export interface MessageDescriptor {
5
5
  id?: string;
6
6
  defaultMessage?: string;
@@ -20,7 +20,7 @@ export interface MessageDescriptorNodeInfo {
20
20
  idValueNode?: TSESTree.Property['value'] | TSESTree.JSXAttribute['value'];
21
21
  idPropNode?: TSESTree.Property | TSESTree.JSXAttribute;
22
22
  }
23
- export declare function getSettings({ settings }: Rule.RuleContext): Settings;
23
+ export declare function getSettings<TMessageIds extends string, TOptions extends readonly unknown[]>({ settings }: RuleContext<TMessageIds, TOptions>): Settings;
24
24
  export declare function isIntlFormatMessageCall(node: TSESTree.Node): node is TSESTree.CallExpression;
25
25
  export declare function extractMessageDescriptor(node?: TSESTree.Expression): MessageDescriptorNodeInfo | undefined;
26
26
  export declare function extractMessages(node: TSESTree.Node, { additionalComponentNames, additionalFunctionNames, excludeMessageDeclCalls, }?: Settings): Array<[MessageDescriptorNodeInfo, TSESTree.Expression | undefined]>;